Skip to content

Commit 581e65d

Browse files
vtjnashgiordano
authored andcommitted
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 (cherry picked from commit fc40e62)
1 parent 48e1a72 commit 581e65d

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
@@ -351,6 +351,17 @@ copy
351351
return $(Expr(:new, :(typeof(a)), :(memoryref(newmem)), :(a.size)))
352352
end
353353

354+
# a mutating version of copyto! that results in dst aliasing src afterwards
355+
function _take!(dst::Array{T,N}, src::Array{T,N}) where {T,N}
356+
if getfield(dst, :ref) !== getfield(src, :ref)
357+
setfield!(dst, :ref, getfield(src, :ref))
358+
end
359+
if getfield(dst, :size) !== getfield(src, :size)
360+
setfield!(dst, :size, getfield(src, :size))
361+
end
362+
return dst
363+
end
364+
354365
## Constructors ##
355366

356367
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
@@ -940,6 +940,7 @@ function readbytes!(s::LibuvStream, a::Vector{UInt8}, nb::Int)
940940
if bytesavailable(sbuf) >= nb
941941
nread = readbytes!(sbuf, a, nb)
942942
else
943+
initsize = length(a)
943944
newbuf = PipeBuffer(a, maxsize=nb)
944945
newbuf.size = newbuf.offset # reset the write pointer to the beginning
945946
nread = try
@@ -950,7 +951,8 @@ function readbytes!(s::LibuvStream, a::Vector{UInt8}, nb::Int)
950951
finally
951952
s.buffer = sbuf
952953
end
953-
compact(newbuf)
954+
_take!(a, _unsafe_take!(newbuf))
955+
length(a) >= initsize || resize!(a, initsize)
954956
end
955957
iolock_end()
956958
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)