Skip to content

Commit 2d2d420

Browse files
authored
Allow unread of AbstractVector{UInt8} (#212)
1 parent a79c78f commit 2d2d420

File tree

6 files changed

+55
-11
lines changed

6 files changed

+55
-11
lines changed

src/buffer.jl

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ end
127127

128128
# Make margin with ≥`minsize` and return the size of it.
129129
# If eager is true, it tries to move data even when the buffer has enough margin.
130-
function makemargin!(buf::Buffer, minsize::Integer; eager::Bool = false)
130+
function makemargin!(buf::Buffer, minsize::Int; eager::Bool = false)
131131
@assert minsize 0
132132
if buffersize(buf) == 0 && buf.markpos == 0
133133
buf.bufferpos = buf.marginpos = 1
@@ -156,7 +156,7 @@ function makemargin!(buf::Buffer, minsize::Integer; eager::Bool = false)
156156
# At least enough for minsize, but otherwise 1.5 times
157157
if marginsize(buf) < minsize
158158
datasize = length(buf.data)
159-
resize!(buf.data, max(buf.marginpos + minsize - 1, datasize + div(datasize, 2)))
159+
resize!(buf.data, max(Base.checked_add(buf.marginpos, minsize) - 1, datasize + div(datasize, 2)))
160160
end
161161
@assert marginsize(buf) minsize
162162
return marginsize(buf)
@@ -185,7 +185,7 @@ end
185185

186186
# Copy data from `data` to `buf`.
187187
function copydata!(buf::Buffer, data::Ptr{UInt8}, nbytes::Integer)
188-
makemargin!(buf, nbytes)
188+
makemargin!(buf, Int(nbytes))
189189
GC.@preserve buf unsafe_copyto!(marginptr(buf), data, nbytes)
190190
supplied!(buf, nbytes)
191191
return buf
@@ -202,7 +202,9 @@ function copydata!(data::Ptr{UInt8}, buf::Buffer, nbytes::Integer)
202202
end
203203

204204
# Insert data to the current buffer.
205-
function insertdata!(buf::Buffer, data::Ptr{UInt8}, nbytes::Integer)
205+
# `data` must not alias `buf`
206+
function insertdata!(buf::Buffer, data::Union{AbstractArray{UInt8}, Memory})
207+
nbytes = Int(length(data))
206208
makemargin!(buf, nbytes)
207209
datapos = if iszero(buf.markpos)
208210
# If data is not marked we must not discard buffered (nonconsumed) data
@@ -213,7 +215,9 @@ function insertdata!(buf::Buffer, data::Ptr{UInt8}, nbytes::Integer)
213215
end
214216
datasize = buf.marginpos - datapos
215217
copyto!(buf.data, datapos + nbytes, buf.data, datapos, datasize)
216-
GC.@preserve buf unsafe_copyto!(bufferptr(buf), data, nbytes)
218+
for i in 0:nbytes-1
219+
buf.data[buf.bufferpos + i] = data[firstindex(data) + i]
220+
end
217221
supplied!(buf, nbytes)
218222
if !iszero(buf.markpos)
219223
buf.markpos += nbytes

src/memory.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ end
1919
return mem.size
2020
end
2121

22+
@inline function Base.firstindex(mem::Memory)
23+
return 1
24+
end
25+
2226
@inline function Base.lastindex(mem::Memory)
2327
return Int(mem.size)
2428
end

src/noop.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ function Base.unsafe_write(stream::NoopStream, input::Ptr{UInt8}, nbytes::UInt):
120120
end
121121
buffer = stream.buffer1
122122
if marginsize(buffer) nbytes
123-
copydata!(buffer, input, nbytes)
123+
copydata!(buffer, input, Int(nbytes))
124124
return Int(nbytes)
125125
else
126126
flushbuffer(stream)

src/stream.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -442,15 +442,18 @@ function Base.readavailable(stream::TranscodingStream)
442442
end
443443

444444
"""
445-
unread(stream::TranscodingStream, data::Vector{UInt8})
445+
unread(stream::TranscodingStream, data::AbstractVector{UInt8})
446446
447447
Insert `data` to the current reading position of `stream`.
448448
449449
The next `read(stream, sizeof(data))` call will read data that are just
450450
inserted.
451+
452+
`data` must not alias any internal buffers in `stream`
451453
"""
452-
function unread(stream::TranscodingStream, data::ByteData)
453-
GC.@preserve data unsafe_unread(stream, pointer(data), sizeof(data))
454+
function unread(stream::TranscodingStream, data::AbstractVector{UInt8})
455+
insertdata!(stream.buffer1, data)
456+
return nothing
454457
end
455458

456459
"""
@@ -460,13 +463,15 @@ Insert `nbytes` pointed by `data` to the current reading position of `stream`.
460463
461464
The data are copied into the internal buffer and hence `data` can be safely used
462465
after the operation without interfering the stream.
466+
467+
`data` must not alias any internal buffers in `stream`
463468
"""
464469
function unsafe_unread(stream::TranscodingStream, data::Ptr, nbytes::Integer)
465470
if nbytes < 0
466471
throw(ArgumentError("negative nbytes"))
467472
end
468473
ready_to_read!(stream)
469-
insertdata!(stream.buffer1, convert(Ptr{UInt8}, data), nbytes)
474+
insertdata!(stream.buffer1, Memory(convert(Ptr{UInt8}, data), UInt(nbytes)))
470475
return nothing
471476
end
472477

@@ -702,7 +707,7 @@ function callprocess(stream::TranscodingStream, inbuf::Buffer, outbuf::Buffer)
702707
if stream.state.mode == :read
703708
if stream.stream isa TranscodingStream && !has_sharedbuf(stream) && !iszero(buffersize(inbuf))
704709
# unread data to match behavior if inbuf was shared.
705-
GC.@preserve inbuf unsafe_unread(stream.stream, bufferptr(inbuf), buffersize(inbuf))
710+
unread(stream.stream, view(inbuf.data, inbuf.bufferpos:inbuf.marginpos-1))
706711
end
707712
changemode!(stream, :stop)
708713
end

test/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
[deps]
22
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
3+
FillArrays = "1a297f60-69ca-5386-bcde-b61e274b549b"
4+
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
35
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
46
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
57
TranscodingStreams = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"

test/codecnoop.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using OffsetArrays: OffsetArray
2+
using FillArrays: Zeros
3+
14
@testset "Noop Codec" begin
25
source = IOBuffer("")
36
stream = TranscodingStream(Noop(), source)
@@ -339,6 +342,32 @@
339342
stream = NoopStream(IOBuffer("foobar"))
340343
@test_throws ArgumentError TranscodingStreams.unsafe_unread(stream, pointer(b"foo"), -1)
341344
close(stream)
345+
346+
stream = NoopStream(IOBuffer("foo"))
347+
@test read(stream, 3) == b"foo"
348+
@test TranscodingStreams.unread(stream, OffsetArray(b"bar", -5:-3)) === nothing
349+
@test read(stream, 3) == b"bar"
350+
close(stream)
351+
352+
stream = NoopStream(IOBuffer("foobar"))
353+
@test read(stream, 3) == b"foo"
354+
@test_throws OverflowError TranscodingStreams.unread(stream, Zeros{UInt8}(typemax(Int))) === nothing
355+
close(stream)
356+
357+
stream = NoopStream(IOBuffer("foo"))
358+
@test read(stream, 3) == b"foo"
359+
@test TranscodingStreams.unread(stream, Zeros{UInt8}(big(3))) === nothing
360+
@test read(stream, 3) == b"\0\0\0"
361+
close(stream)
362+
363+
stream = NoopStream(IOBuffer("foo"))
364+
@test read(stream, 3) == b"foo"
365+
d = b"bar"
366+
GC.@preserve d begin
367+
@test TranscodingStreams.unsafe_unread(stream, pointer(d), 3) === nothing
368+
end
369+
@test read(stream, 3) == b"bar"
370+
close(stream)
342371
end
343372

344373
stream = NoopStream(IOBuffer(""))

0 commit comments

Comments
 (0)