5
5
# Stateful string
6
6
mutable struct GenericIOBuffer{T<: AbstractVector{UInt8} } <: IO
7
7
data:: T # T should support: getindex, setindex!, length, copyto!, and resize!
8
+ reinit:: Bool # if true, data needs to be re-allocated (after take!)
8
9
readable:: Bool
9
10
writable:: Bool
10
11
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
17
18
function GenericIOBuffer {T} (data:: T , readable:: Bool , writable:: Bool , seekable:: Bool , append:: Bool ,
18
19
maxsize:: Integer ) where T<: AbstractVector{UInt8}
19
20
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 )
21
22
end
22
23
end
23
24
const IOBuffer = GenericIOBuffer{Vector{UInt8}}
@@ -137,8 +138,12 @@ PipeBuffer(data::Vector{UInt8}=UInt8[]; maxsize::Int = typemax(Int)) =
137
138
GenericIOBuffer (data,true ,true ,false ,true ,maxsize)
138
139
PipeBuffer (maxsize:: Integer ) = (x = PipeBuffer (StringVector (maxsize), maxsize = maxsize); x. size= 0 ; x)
139
140
141
+ _similar_data (b:: GenericIOBuffer , len:: Int ) = similar (b. data, len)
142
+ _similar_data (b:: IOBuffer , len:: Int ) = StringVector (len)
143
+
140
144
function 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,
142
147
b. readable, b. writable, b. seekable, b. append, b. maxsize)
143
148
ret. size = b. size
144
149
ret. ptr = b. ptr
@@ -270,7 +275,10 @@ function truncate(io::GenericIOBuffer, n::Integer)
270
275
io. seekable || throw (ArgumentError (" truncate failed, IOBuffer is not seekable" ))
271
276
n < 0 && throw (ArgumentError (" truncate failed, n bytes must be ≥ 0, got $n " ))
272
277
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)
274
282
resize! (io. data, n)
275
283
end
276
284
io. data[io. size+ 1 : n] .= 0
325
333
ensureroom_slowpath (io, nshort)
326
334
end
327
335
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
331
344
end
332
345
return io
333
346
end
@@ -390,18 +403,26 @@ end
390
403
function take! (io:: IOBuffer )
391
404
ismarked (io) && unmark (io)
392
405
if io. seekable
393
- data = io. data
394
406
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
397
413
else
398
- data = copy ( data)
414
+ data = copyto! ( StringVector (io . size), 1 , io . data, 1 , io . size )
399
415
end
400
- resize! (data,io. size)
401
416
else
402
417
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
405
426
end
406
427
if io. writable
407
428
io. ptr = 1
@@ -410,6 +431,19 @@ function take!(io::IOBuffer)
410
431
return data
411
432
end
412
433
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
+
413
447
function write (to:: IO , from:: GenericIOBuffer )
414
448
if to === from
415
449
from. ptr = from. size + 1
0 commit comments