@@ -152,10 +152,10 @@ flush(io::AbstractPipe) = flush(pipe_writer(io))
152
152
read (io:: AbstractPipe , byte:: Type{UInt8} ) = read (pipe_reader (io), byte)
153
153
unsafe_read (io:: AbstractPipe , p:: Ptr{UInt8} , nb:: UInt ) = unsafe_read (pipe_reader (io), p, nb)
154
154
read (io:: AbstractPipe ) = read (pipe_reader (io))
155
- readuntil (io:: AbstractPipe , arg:: UInt8 ) = readuntil (pipe_reader (io), arg)
156
- readuntil (io:: AbstractPipe , arg:: Char ) = readuntil (pipe_reader (io), arg)
157
- readuntil (io:: AbstractPipe , arg :: AbstractString ) = readuntil (pipe_reader (io), arg )
158
- readuntil (io :: AbstractPipe , arg) = readuntil ( pipe_reader (io), arg)
155
+ readuntil (io:: AbstractPipe , arg:: UInt8 ) = readuntil (pipe_reader (io), arg)
156
+ readuntil (io:: AbstractPipe , arg:: Char ) = readuntil (pipe_reader (io), arg)
157
+ readuntil_indexable (io:: AbstractPipe , target #= ::Indexable{T} =# , out ) = readuntil_indexable (pipe_reader (io), target, out )
158
+
159
159
readavailable (io:: AbstractPipe ) = readavailable (pipe_reader (io))
160
160
161
161
isreadable (io:: AbstractPipe ) = isreadable (pipe_reader (io))
@@ -499,7 +499,7 @@ function readuntil(s::IO, delim::Char)
499
499
end
500
500
501
501
function readuntil (s:: IO , delim:: T ) where T
502
- out = T[]
502
+ out = (T === UInt8 ? StringVector ( 0 ) : Vector {T} ())
503
503
while ! eof (s)
504
504
c = read (s, T)
505
505
push! (out, c)
@@ -510,39 +510,89 @@ function readuntil(s::IO, delim::T) where T
510
510
return out
511
511
end
512
512
513
- # based on code by Glen Hertz
514
- function readuntil (s:: IO , t:: AbstractString )
515
- l = length (t)
516
- if l == 0
517
- return " "
518
- end
519
- if l > 40
520
- warn (" readuntil(IO,AbstractString) will perform poorly with a long string" )
513
+ # requires that indices for target are small ordered integers bounded by start and endof
514
+ function readuntil_indexable (io:: IO , target#= ::Indexable{T}=# , out)
515
+ T = eltype (target)
516
+ first = start (target)
517
+ if done (target, first)
518
+ return
521
519
end
522
- out = IOBuffer ( )
523
- m = Vector {Char} (l) # last part of stream to match
524
- t = collect (t)
525
- i = 0
526
- while ! eof (s)
527
- i += 1
528
- c = read (s, Char )
529
- write (out, c)
530
- if i <= l
531
- m[i] = c
520
+ len = endof (target )
521
+ local cache # will be lazy initialized when needed
522
+ second = next (target, first)[ 2 ]
523
+ max_pos = second
524
+ pos = first
525
+ while ! eof (io)
526
+ c = read (io, T )
527
+ # Backtrack until the next target character matches what was found
528
+ if out isa IO
529
+ write (out, c)
532
530
else
533
- # shift to last part of s
534
- for j = 2 : l
535
- m[j- 1 ] = m[j]
536
- end
537
- m[l] = c
531
+ push! (out, c)
538
532
end
539
- if i >= l && m == t
540
- break
533
+ while true
534
+ c1, pos1 = next (target, pos)
535
+ if c == c1
536
+ pos = pos1
537
+ break
538
+ elseif pos == first
539
+ break
540
+ elseif pos == second
541
+ pos = first
542
+ else
543
+ # grow cache to contain up to `pos`
544
+ if ! @isdefined (cache)
545
+ cache = zeros (Int, len)
546
+ end
547
+ while max_pos < pos
548
+ b = cache[max_pos] + first
549
+ cb, b1 = next (target, b)
550
+ ci, max_pos1 = next (target, max_pos)
551
+ if ci == cb
552
+ cache[max_pos1] = b1 - first
553
+ end
554
+ max_pos = max_pos1
555
+ end
556
+ pos = cache[pos] + first
557
+ end
541
558
end
559
+ done (target, pos) && break
542
560
end
543
- return String (take! (out))
544
561
end
545
562
563
+ function readuntil (io:: IO , target:: AbstractString )
564
+ # small-string target optimizations
565
+ i = start (target)
566
+ done (target, i) && return " "
567
+ c, i = next (target, start (target))
568
+ if done (target, i) && c < Char (0x80 )
569
+ return readuntil_string (io, c % UInt8)
570
+ end
571
+ # decide how we can index target
572
+ if target isa String
573
+ # convert String to a utf8-byte-iterator
574
+ target = Vector {UInt8} (target)
575
+ # elseif applicable(codeunit, target)
576
+ # TODO : a more general version of above optimization
577
+ # would be to permit accessing any string via codeunit
578
+ # target = CodeUnitVector(target)
579
+ elseif ! (target isa SubString{String})
580
+ # type with unknown indexing behavior: convert to array
581
+ target = collect (target)
582
+ end
583
+ out = (eltype (target) === UInt8 ? StringVector (0 ) : IOBuffer ())
584
+ readuntil_indexable (io, target, out)
585
+ out = isa (out, IO) ? take! (out) : out
586
+ return String (out)
587
+ end
588
+
589
+ function readuntil (io:: IO , target:: AbstractVector{T} ) where T
590
+ out = (T === UInt8 ? StringVector (0 ) : Vector {T} ())
591
+ readuntil_indexable (io, target, out)
592
+ return out
593
+ end
594
+
595
+
546
596
"""
547
597
readchomp(x)
548
598
@@ -592,6 +642,7 @@ function read(s::IO, nb::Integer = typemax(Int))
592
642
end
593
643
594
644
read (s:: IO , :: Type{String} ) = String (read (s))
645
+ read (s:: IO , T:: Type ) = error (" The IO stream does not support reading objects of type $T ." )
595
646
596
647
# # high-level iterator interfaces ##
597
648
0 commit comments