Skip to content

Commit fc40e62

Browse files
authored
stream: fix reading LibuvStream into array (#56092)
Adds a new internal function `_take!(dst::Array{T,N}, src::Array{T,N})` for doing an efficient `copyto!` equivalent. Previously it was assumed that `compact` did this automatically, which wasn't a great assumption. Fixes #56078
1 parent 1157c6f commit fc40e62

File tree

3 files changed

+29
-8
lines changed

3 files changed

+29
-8
lines changed

base/array.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,17 @@ copy
355355
return $(Expr(:new, :(typeof(a)), :(memoryref(newmem)), :(a.size)))
356356
end
357357

358+
# a mutating version of copyto! that results in dst aliasing src afterwards
359+
function _take!(dst::Array{T,N}, src::Array{T,N}) where {T,N}
360+
if getfield(dst, :ref) !== getfield(src, :ref)
361+
setfield!(dst, :ref, getfield(src, :ref))
362+
end
363+
if getfield(dst, :size) !== getfield(src, :size)
364+
setfield!(dst, :size, getfield(src, :size))
365+
end
366+
return dst
367+
end
368+
358369
## Constructors ##
359370

360371
similar(a::Array{T,1}) where {T} = Vector{T}(undef, size(a,1))

base/stream.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,7 @@ function readbytes!(s::LibuvStream, a::Vector{UInt8}, nb::Int)
941941
if bytesavailable(sbuf) >= nb
942942
nread = readbytes!(sbuf, a, nb)
943943
else
944+
initsize = length(a)
944945
newbuf = PipeBuffer(a, maxsize=nb)
945946
newbuf.size = newbuf.offset # reset the write pointer to the beginning
946947
nread = try
@@ -951,7 +952,8 @@ function readbytes!(s::LibuvStream, a::Vector{UInt8}, nb::Int)
951952
finally
952953
s.buffer = sbuf
953954
end
954-
compact(newbuf)
955+
_take!(a, _unsafe_take!(newbuf))
956+
length(a) >= initsize || resize!(a, initsize)
955957
end
956958
iolock_end()
957959
return nread

test/read.jl

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,27 @@ for (name, f) in l
268268
n2 = readbytes!(s2, a2)
269269
@test n1 == n2
270270
@test length(a1) == length(a2)
271-
@test a1[1:n1] == a2[1:n2]
271+
let l = min(l, n)
272+
@test a1[1:l] == a2[1:l]
273+
end
272274
@test n <= length(text) || eof(s1)
273275
@test n <= length(text) || eof(s2)
274276

275277
cleanup()
276278
end
277279

280+
# Test growing output array
281+
let x = UInt8[],
282+
io = io()
283+
n = readbytes!(io, x)
284+
@test n == 0
285+
@test isempty(x)
286+
n = readbytes!(io, x, typemax(Int))
287+
@test n == length(x)
288+
@test x == codeunits(text)
289+
cleanup()
290+
end
291+
278292
verbose && println("$name read!...")
279293
l = length(text)
280294
for n = [1, 2, l-2, l-1, l]
@@ -477,12 +491,6 @@ let s = "qwerty"
477491
@test read(IOBuffer(s)) == codeunits(s)
478492
@test read(IOBuffer(s), 10) == codeunits(s)
479493
@test read(IOBuffer(s), 1) == codeunits(s)[1:1]
480-
481-
# Test growing output array
482-
x = UInt8[]
483-
n = readbytes!(IOBuffer(s), x, 10)
484-
@test x == codeunits(s)
485-
@test n == length(x)
486494
end
487495

488496

0 commit comments

Comments
 (0)