Skip to content

Commit d4ca92c

Browse files
authored
fix _growbeg! unncessary resizing (#56029)
This was very explicitly designed such that if there was a bunch of extra space at the end of the array, we would copy rather than allocating, but by making `newmemlen` be at least `overallocation(memlen)` rather than `overallocation(len)`, this branch was never hit. found by #56026
1 parent 44620b6 commit d4ca92c

File tree

2 files changed

+12
-2
lines changed

2 files changed

+12
-2
lines changed

base/array.jl

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,13 +1071,14 @@ function _growbeg!(a::Vector, delta::Integer)
10711071
setfield!(a, :ref, @inbounds memoryref(ref, 1 - delta))
10721072
else
10731073
@noinline (function()
1074+
@_terminates_locally_meta
10741075
memlen = length(mem)
10751076
if offset + len - 1 > memlen || offset < 1
10761077
throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks"))
10771078
end
10781079
# since we will allocate the array in the middle of the memory we need at least 2*delta extra space
10791080
# the +1 is because I didn't want to have an off by 1 error.
1080-
newmemlen = max(overallocation(memlen), len + 2 * delta + 1)
1081+
newmemlen = max(overallocation(len), len + 2 * delta + 1)
10811082
newoffset = div(newmemlen - newlen, 2) + 1
10821083
# If there is extra data after the end of the array we can use that space so long as there is enough
10831084
# space at the end that there won't be quadratic behavior with a mix of growth from both ends.
@@ -1086,10 +1087,14 @@ function _growbeg!(a::Vector, delta::Integer)
10861087
if newoffset + newlen < memlen
10871088
newoffset = div(memlen - newlen, 2) + 1
10881089
newmem = mem
1090+
unsafe_copyto!(newmem, newoffset + delta, mem, offset, len)
1091+
for j in offset:newoffset+delta-1
1092+
@inbounds _unsetindex!(mem, j)
1093+
end
10891094
else
10901095
newmem = array_new_memory(mem, newmemlen)
1096+
unsafe_copyto!(newmem, newoffset + delta, mem, offset, len)
10911097
end
1092-
unsafe_copyto!(newmem, newoffset + delta, mem, offset, len)
10931098
if ref !== a.ref
10941099
@noinline throw(ConcurrencyViolationError("Vector can not be resized concurrently"))
10951100
end

test/arrayops.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,11 @@ end
496496
@test vc == [v[1:(i-1)]; 5; v[i:end]]
497497
end
498498
@test_throws BoundsError insert!(v, 5, 5)
499+
500+
# test that data is copied when there is plenty of room to do so
501+
v = empty!(collect(1:100))
502+
pushfirst!(v, 1)
503+
@test length(v.ref.mem) == 100
499504
end
500505

501506
@testset "popat!(::Vector, i, [default])" begin

0 commit comments

Comments
 (0)