55#  Stateful string
66mutable struct  GenericIOBuffer{T<: AbstractVector{UInt8} } <:  IO 
77    data:: T  #  T should support: getindex, setindex!, length, copyto!, and resize!
8+     reinit:: Bool  #  if true, data needs to be re-allocated (after take!)
89    readable:: Bool 
910    writable:: Bool 
1011    seekable:: Bool  #  if not seekable, implementation is free to destroy (compact) past read data
@@ -17,7 +18,7 @@ mutable struct GenericIOBuffer{T<:AbstractVector{UInt8}} <: IO
1718    function  GenericIOBuffer {T} (data:: T , readable:: Bool , writable:: Bool , seekable:: Bool , append:: Bool ,
1819                                maxsize:: Integer ) where  T<: AbstractVector{UInt8} 
1920        require_one_based_indexing (data)
20-         new (data,readable,writable,seekable,append,length (data),maxsize,1 ,- 1 )
21+         new (data,false , readable,writable,seekable,append,length (data),maxsize,1 ,- 1 )
2122    end 
2223end 
2324const  IOBuffer =  GenericIOBuffer{Vector{UInt8}}
@@ -137,8 +138,12 @@ PipeBuffer(data::Vector{UInt8}=UInt8[]; maxsize::Int = typemax(Int)) =
137138    GenericIOBuffer (data,true ,true ,false ,true ,maxsize)
138139PipeBuffer (maxsize:: Integer ) =  (x =  PipeBuffer (StringVector (maxsize), maxsize =  maxsize); x. size= 0 ; x)
139140
141+ _similar_data (b:: GenericIOBuffer , len:: Int ) =  similar (b. data, len)
142+ _similar_data (b:: IOBuffer , len:: Int ) =  StringVector (len)
143+ 
140144function  copy (b:: GenericIOBuffer )
141-     ret =  typeof (b)(b. writable ?  copy (b. data) :  b. data,
145+     ret =  typeof (b)(b. reinit ?  _similar_data (b, 0 ) :  b. writable ? 
146+                     copyto! (_similar_data (b, length (b. data)), b. data) :  b. data,
142147                    b. readable, b. writable, b. seekable, b. append, b. maxsize)
143148    ret. size =  b. size
144149    ret. ptr  =  b. ptr
@@ -270,7 +275,10 @@ function truncate(io::GenericIOBuffer, n::Integer)
270275    io. seekable ||  throw (ArgumentError (" truncate failed, IOBuffer is not seekable" 
271276    n <  0  &&  throw (ArgumentError (" truncate failed, n bytes must be ≥ 0, got $n " 
272277    n >  io. maxsize &&  throw (ArgumentError (" truncate failed, $(n)  bytes is exceeds IOBuffer maxsize $(io. maxsize) " 
273-     if  n >  length (io. data)
278+     if  io. reinit
279+         io. data =  _similar_data (io, n)
280+         io. reinit =  false 
281+     elseif  n >  length (io. data)
274282        resize! (io. data, n)
275283    end 
276284    io. data[io. size+ 1 : n] .=  0 
325333        ensureroom_slowpath (io, nshort)
326334    end 
327335    n =  min ((nshort %  Int) +  (io. append ?  io. size :  io. ptr- 1 ), io. maxsize)
328-     l =  length (io. data)
329-     if  n >  l
330-         _growend! (io. data, (n -  l) %  UInt)
336+     if  io. reinit
337+         io. data =  _similar_data (io, n)
338+         io. reinit =  false 
339+     else 
340+         l =  length (io. data)
341+         if  n >  l
342+             _growend! (io. data, (n -  l) %  UInt)
343+         end 
331344    end 
332345    return  io
333346end 
@@ -390,18 +403,26 @@ end
390403function  take! (io:: IOBuffer )
391404    ismarked (io) &&  unmark (io)
392405    if  io. seekable
393-         data =  io. data
394406        if  io. writable
395-             maxsize =  (io. maxsize ==  typemax (Int) ?  0  :  min (length (io. data),io. maxsize))
396-             io. data =  StringVector (maxsize)
407+             if  io. reinit
408+                 data =  StringVector (0 )
409+             else 
410+                 data =  resize! (io. data, io. size)
411+                 io. reinit =  true 
412+             end 
397413        else 
398-             data =  copy ( data)
414+             data =  copyto! ( StringVector (io . size),  1 , io . data,  1 , io . size )
399415        end 
400-         resize! (data,io. size)
401416    else 
402417        nbytes =  bytesavailable (io)
403-         a =  StringVector (nbytes)
404-         data =  read! (io, a)
418+         if  io. writable
419+             data =  io. data
420+             io. reinit =  true 
421+             _deletebeg! (data, io. ptr- 1 )
422+             resize! (data, nbytes)
423+         else 
424+             data =  read! (io, StringVector (nbytes))
425+         end 
405426    end 
406427    if  io. writable
407428        io. ptr =  1 
@@ -410,6 +431,19 @@ function take!(io::IOBuffer)
410431    return  data
411432end 
412433
434+ """ 
435+     _unsafe_take!(io::IOBuffer) 
436+ 
437+ This simply returns the raw resized `io.data`, with no checks to be 
438+ sure that `io` is readable etcetera, and leaves `io` in an inconsistent 
439+ state.  This should only be used internally for performance-critical 
440+ `String` routines that immediately discard `io` afterwards, and it 
441+ *assumes* that `io` is writable and seekable. 
442+ 
443+ It saves no allocations compared to `take!`, it just omits some checks. 
444+ """ 
445+ _unsafe_take! (io:: IOBuffer ) =  resize! (io. data, io. size)
446+ 
413447function  write (to:: IO , from:: GenericIOBuffer )
414448    if  to ===  from
415449        from. ptr =  from. size +  1 
0 commit comments