Skip to content

Commit 9fccbda

Browse files
authored
move growend_internal! and growbeg_internal! out to proper functions (#58211)
@gbaraldi has told me that this leads to a better calling convention (and is clearer to read)
1 parent 48bd673 commit 9fccbda

File tree

1 file changed

+72
-57
lines changed

1 file changed

+72
-57
lines changed

base/array.jl

Lines changed: 72 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,41 @@ end
10661066

10671067
array_new_memory(mem::Memory, newlen::Int) = typeof(mem)(undef, newlen) # when implemented, this should attempt to first expand mem
10681068

1069+
function _growbeg_internal!(a::Vector, delta::Int, len::Int)
1070+
@_terminates_locally_meta
1071+
ref = a.ref
1072+
mem = ref.mem
1073+
offset = memoryrefoffset(ref)
1074+
newlen = len + delta
1075+
memlen = length(mem)
1076+
if offset + len - 1 > memlen || offset < 1
1077+
throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks"))
1078+
end
1079+
# since we will allocate the array in the middle of the memory we need at least 2*delta extra space
1080+
# the +1 is because I didn't want to have an off by 1 error.
1081+
newmemlen = max(overallocation(len), len + 2 * delta + 1)
1082+
newoffset = div(newmemlen - newlen, 2) + 1
1083+
# If there is extra data after the end of the array we can use that space so long as there is enough
1084+
# space at the end that there won't be quadratic behavior with a mix of growth from both ends.
1085+
# Specifically, we want to ensure that we will only do this operation once before
1086+
# increasing the size of the array, and that we leave enough space at both the beginning and the end.
1087+
if newoffset + newlen < memlen
1088+
newoffset = div(memlen - newlen, 2) + 1
1089+
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
1094+
else
1095+
newmem = array_new_memory(mem, newmemlen)
1096+
unsafe_copyto!(newmem, newoffset + delta, mem, offset, len)
1097+
end
1098+
if ref !== a.ref
1099+
throw(ConcurrencyViolationError("Vector can not be resized concurrently"))
1100+
end
1101+
setfield!(a, :ref, @inbounds memoryref(newmem, newoffset))
1102+
end
1103+
10691104
function _growbeg!(a::Vector, delta::Integer)
10701105
@_noub_meta
10711106
delta = Int(delta)
@@ -1081,40 +1116,46 @@ function _growbeg!(a::Vector, delta::Integer)
10811116
if delta <= offset - 1
10821117
setfield!(a, :ref, @inbounds memoryref(ref, 1 - delta))
10831118
else
1084-
@noinline (function()
1085-
@_terminates_locally_meta
1086-
memlen = length(mem)
1087-
if offset + len - 1 > memlen || offset < 1
1088-
throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks"))
1089-
end
1090-
# since we will allocate the array in the middle of the memory we need at least 2*delta extra space
1091-
# the +1 is because I didn't want to have an off by 1 error.
1092-
newmemlen = max(overallocation(len), len + 2 * delta + 1)
1093-
newoffset = div(newmemlen - newlen, 2) + 1
1094-
# If there is extra data after the end of the array we can use that space so long as there is enough
1095-
# space at the end that there won't be quadratic behavior with a mix of growth from both ends.
1096-
# Specifically, we want to ensure that we will only do this operation once before
1097-
# increasing the size of the array, and that we leave enough space at both the beginning and the end.
1098-
if newoffset + newlen < memlen
1099-
newoffset = div(memlen - newlen, 2) + 1
1100-
newmem = mem
1101-
unsafe_copyto!(newmem, newoffset + delta, mem, offset, len)
1102-
for j in offset:newoffset+delta-1
1103-
@inbounds _unsetindex!(mem, j)
1104-
end
1105-
else
1106-
newmem = array_new_memory(mem, newmemlen)
1107-
unsafe_copyto!(newmem, newoffset + delta, mem, offset, len)
1108-
end
1109-
if ref !== a.ref
1110-
@noinline throw(ConcurrencyViolationError("Vector can not be resized concurrently"))
1111-
end
1112-
setfield!(a, :ref, @inbounds memoryref(newmem, newoffset))
1113-
end)()
1119+
@noinline _growbeg_internal!(a, delta, len)
11141120
end
11151121
return
11161122
end
11171123

1124+
function _growend_internal!(a::Vector, delta::Int, len::Int)
1125+
ref = a.ref
1126+
mem = ref.mem
1127+
memlen = length(mem)
1128+
newlen = len + delta
1129+
offset = memoryrefoffset(ref)
1130+
newmemlen = offset + newlen - 1
1131+
if offset + len - 1 > memlen || offset < 1
1132+
throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks"))
1133+
end
1134+
1135+
if offset - 1 > div(5 * newlen, 4)
1136+
# If the offset is far enough that we can copy without resizing
1137+
# while maintaining proportional spacing on both ends of the array
1138+
# note that this branch prevents infinite growth when doing combinations
1139+
# of push! and popfirst! (i.e. when using a Vector as a queue)
1140+
newmem = mem
1141+
newoffset = div(newlen, 8) + 1
1142+
else
1143+
# grow either by our computed overallocation factor
1144+
# or exactly the requested size, whichever is larger
1145+
# TODO we should possibly increase the offset if the current offset is nonzero.
1146+
newmemlen2 = max(overallocation(memlen), newmemlen)
1147+
newmem = array_new_memory(mem, newmemlen2)
1148+
newoffset = offset
1149+
end
1150+
newref = @inbounds memoryref(newmem, newoffset)
1151+
unsafe_copyto!(newref, ref, len)
1152+
if ref !== a.ref
1153+
@noinline throw(ConcurrencyViolationError("Vector can not be resized concurrently"))
1154+
end
1155+
setfield!(a, :ref, newref)
1156+
return
1157+
end
1158+
11181159
function _growend!(a::Vector, delta::Integer)
11191160
@_noub_meta
11201161
delta = Int(delta)
@@ -1128,33 +1169,7 @@ function _growend!(a::Vector, delta::Integer)
11281169
setfield!(a, :size, (newlen,))
11291170
newmemlen = offset + newlen - 1
11301171
if memlen < newmemlen
1131-
@noinline (function()
1132-
if offset + len - 1 > memlen || offset < 1
1133-
throw(ConcurrencyViolationError("Vector has invalid state. Don't modify internal fields incorrectly, or resize without correct locks"))
1134-
end
1135-
1136-
if offset - 1 > div(5 * newlen, 4)
1137-
# If the offset is far enough that we can copy without resizing
1138-
# while maintaining proportional spacing on both ends of the array
1139-
# note that this branch prevents infinite growth when doing combinations
1140-
# of push! and popfirst! (i.e. when using a Vector as a queue)
1141-
newmem = mem
1142-
newoffset = div(newlen, 8) + 1
1143-
else
1144-
# grow either by our computed overallocation factor
1145-
# or exactly the requested size, whichever is larger
1146-
# TODO we should possibly increase the offset if the current offset is nonzero.
1147-
newmemlen2 = max(overallocation(memlen), newmemlen)
1148-
newmem = array_new_memory(mem, newmemlen2)
1149-
newoffset = offset
1150-
end
1151-
newref = @inbounds memoryref(newmem, newoffset)
1152-
unsafe_copyto!(newref, ref, len)
1153-
if ref !== a.ref
1154-
@noinline throw(ConcurrencyViolationError("Vector can not be resized concurrently"))
1155-
end
1156-
setfield!(a, :ref, newref)
1157-
end)()
1172+
@noinline _growend_internal!(a, delta, len)
11581173
end
11591174
return
11601175
end

0 commit comments

Comments
 (0)