Skip to content

Commit 454e7e9

Browse files
committed
Improve the annotated join method and dispatch
With the initial implementation, join could work for AnnotatedStrings, however only when the eltype of the iterator or delim was itself a Annotated{String,Char}. This was better than nothing, but seems inconsistent in the face of mixed iterators. Furthermore, the implementation of an annotated join was far from optimised, relying on zipping and then calling annotatedstring(xs...). By contrast, the non-annotated implementation relies on printing to IO and even has manually defined alternative methods for optional arguments to minimise code generation. With the advent of AnnotatedIOBuffer and _isannotated, we can improve on both those aspects. The new AnnotatedIOBuffer type allows us to re-use the optimised join(::IO, ...) methods, and we can more reliably dispatch to them with _isannotated. Since this is a type-based decision, the Julia compiler is kind enough to work out which branch is taken at compile-time, making this zero-overhead in the unannotated case.
1 parent 98542d7 commit 454e7e9

File tree

1 file changed

+9
-21
lines changed

1 file changed

+9
-21
lines changed

base/strings/io.jl

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -353,31 +353,19 @@ function join(io::IO, iterator, delim="")
353353
end
354354
end
355355

356-
# TODO: If/when we have `AnnotatedIO`, we can revisit this and
357-
# implement it more nicely.
358-
function join_annotated(iterator, delim="", last=delim)
359-
xs = zip(iterator, Iterators.repeated(delim)) |> Iterators.flatten |> collect
360-
xs = xs[1:end-1]
361-
if length(xs) > 1
362-
xs[end-1] = last
363-
end
364-
annotatedstring(xs...)::AnnotatedString{String}
365-
end
366-
367-
function _join_maybe_annotated(args...)
368-
if any(function (arg)
369-
t = eltype(arg)
370-
!(t == Union{}) && (t <: AnnotatedString || t <: AnnotatedChar)
371-
end, args)
372-
join_annotated(args...)
356+
function _join_preserve_annotations(iterator, args...)
357+
if _isannotated(eltype(iterator)) || any(_isannotated, args)
358+
io = AnnotatedIOBuffer()
359+
join(io, iterator, args...)
360+
read(io, AnnotatedString{String})
373361
else
374-
sprint(join, args...)
362+
sprint(join, iterator, args...)
375363
end
376364
end
377365

378-
join(iterator) = _join_maybe_annotated(iterator)
379-
join(iterator, delim) = _join_maybe_annotated(iterator, delim)
380-
join(iterator, delim, last) = _join_maybe_annotated(iterator, delim, last)
366+
join(iterator) = _join_preserve_annotations(iterator)
367+
join(iterator, delim) = _join_preserve_annotations(iterator, delim)
368+
join(iterator, delim, last) = _join_preserve_annotations(iterator, delim, last)
381369

382370
## string escaping & unescaping ##
383371

0 commit comments

Comments
 (0)