Skip to content

Commit 478afb5

Browse files
committed
Address some reviewer comments
1 parent 00aff58 commit 478afb5

File tree

2 files changed

+34
-27
lines changed

2 files changed

+34
-27
lines changed

base/iobuffer.jl

+21-25
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ mutable struct GenericIOBuffer{T<:AbstractVector{UInt8}} <: IO
7878
# which can be seeked back using `reset`, even for non-seekable buffers.
7979
# For non-seekable buffers that can be compacted, data before the mark can be
8080
# destroyed.
81-
# This value is always in -1 : size-offset-1
81+
# This value is always in -1 : size - offset
8282
mark::Int
8383

8484
# Unsafe constructor which does not do any checking
@@ -128,7 +128,15 @@ function GenericIOBuffer(data::Vector{UInt8}, readable::Bool, writable::Bool, se
128128
mem = ref.mem
129129
len = length(data)
130130
offset = memoryrefoffset(ref) - 1
131-
buf = GenericIOBuffer(mem, readable, writable, seekable, append, maxsize)
131+
132+
# The user may pass a vector of length <= maxsize, but where the underlying memory
133+
# is larger than maxsize. Don't throw an error in that case.
134+
mz = Int(maxsize)::Int
135+
len = Int(length(data))::Int
136+
if mz < len
137+
throw(ArgumentError("maxsize must not be smaller than data length"))
138+
end
139+
buf = GenericIOBuffer{Memory{UInt8}}(unsafe_method, mem, readable, writable, seekable, append, max(mz, length(mem)))
132140
buf.size = len + offset
133141
buf.ptr = offset + 1
134142
buf.offset = offset
@@ -239,12 +247,8 @@ function IOBuffer(;
239247
flags = open_flags(read=read, write=write, append=append, truncate=truncate)
240248
# A common usecase of IOBuffer is to incrementally construct strings. By using StringMemory
241249
# as the default storage, we can turn the result into a string without copying.
242-
# TODO: Do we need to zero this here?
243-
data = fill!(StringMemory(size), 0)
244-
buf = GenericIOBuffer{Memory{UInt8}}(unsafe_method, data, flags.read, flags.write, true, flags.append, mz)
245-
if flags.truncate
246-
buf.size = buf.offset
247-
end
250+
buf = GenericIOBuffer{Memory{UInt8}}(unsafe_method, StringMemory(size), flags.read, flags.write, true, flags.append, mz)
251+
buf.size = 0
248252
return buf
249253
end
250254

@@ -382,17 +386,6 @@ function read(from::GenericIOBuffer, T::MultiByteBitNumberType)
382386
return x
383387
end
384388

385-
function read_sub(from::GenericIOBuffer, a::MutableDenseArrayType{T}, offs, nel) where T
386-
require_one_based_indexing(a)
387-
from.readable || _throw_not_readable()
388-
if offs+nel-1 > length(a) || offs < 1 || nel < 0
389-
throw(BoundsError())
390-
end
391-
nb = UInt(nel * sizeof(T))
392-
GC.@preserve a unsafe_read(from, pointer(a, offs), nb)
393-
return a
394-
end
395-
396389
@inline function read(from::GenericIOBuffer, ::Type{UInt8})
397390
from.readable || _throw_not_readable()
398391
ptr = from.ptr
@@ -496,7 +489,7 @@ function _resize!(io::GenericIOBuffer, new_size::Int)
496489
end
497490

498491
# TODO: These errors cannot be converted to LazyString, but it's wasteful to interpolate them here.
499-
function truncate(io::GenericIOBuffer, n::Integer)
492+
function truncate(io::GenericIOBuffer, n::Integer)
500493
io.writable || throw(ArgumentError("truncate failed, IOBuffer is not writeable"))
501494
# Non-seekable buffers can only be constructed with `PipeBuffer`, which is explicitly
502495
# documented to not be truncatable.
@@ -812,13 +805,16 @@ end
812805
end
813806

814807
readbytes!(io::GenericIOBuffer, b::MutableDenseArrayType{UInt8}, nb=length(b)) = readbytes!(io, b, Int(nb))
808+
815809
function readbytes!(io::GenericIOBuffer, b::MutableDenseArrayType{UInt8}, nb::Int)
816-
nr = min(nb, bytesavailable(io))
817-
if length(b) < nr
818-
resize!(b, nr)
810+
io.readable || _throw_not_readable()
811+
to_read = min(nb, bytesavailable(io))
812+
if length(b) < to_read
813+
resize!(b, to_read)
819814
end
820-
read_sub(io, b, 1, nr)
821-
return nr
815+
checkbounds(b, 1:to_read)
816+
GC.@preserve b unsafe_read(io, pointer(b), to_read)
817+
to_read
822818
end
823819
read(io::GenericIOBuffer) = read!(io, StringVector(bytesavailable(io)))
824820

test/iobuffer.jl

+13-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ end
4242

4343
# Reading more bytes than available will not error
4444
@test read(buf, 100) == b"EFGHIJ"
45+
46+
# Passing truncate=false will still truncate an IOBuffer with no
47+
# initialized data
48+
@test isempty(read(IOBuffer(;sizehint=34, truncate=false)))
4549
end
4650

4751
@testset "Byte occursin GenericIOBuffer" begin
@@ -185,6 +189,12 @@ end
185189
write(buf, collect(0x99:0xff))
186190
seekstart(buf)
187191
@test read(buf) == 0x00:UInt8(127)
192+
193+
# Edge case: When passing a Vector, does not error if the
194+
# underlying mem is larger than maxsize
195+
v = pushfirst!([0x01], 0x02)
196+
io = IOBuffer(v; maxsize=2)
197+
@test read(io) == b"\x02\x01"
188198
end
189199

190200
@testset "Write to self" begin
@@ -245,7 +255,7 @@ end
245255
@test position(io) == 0
246256
truncate(io, 10)
247257
@test position(io) == 0
248-
@test all(io.data .== 0)
258+
@test all(view(io.data, 1:10) .== 0)
249259
@test write(io, Int16[1, 2, 3, 4, 5, 6]) === 12
250260
seek(io, 2)
251261
truncate(io, 10)
@@ -604,8 +614,9 @@ end
604614
v = @view a[1:2]
605615
io = IOBuffer()
606616
write(io,1)
617+
write(io,0)
607618
seek(io,0)
608-
@test Base.read_sub(io,v,1,1) == [1,0]
619+
@test read!(io, v) == [1, 0]
609620
end
610621

611622
@testset "with offset" begin

0 commit comments

Comments
 (0)