Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions spec/std/array_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,24 @@ describe "Array" do
a[3..] = [4, 5, 6]
a.should eq([1, 2, 3, 4, 5, 6])
end

it "reuses the buffer if possible" do
a = [1, 2, 3, 4, 5]
a.pop
a[4, 0] = [6]
a.should eq([1, 2, 3, 4, 6])
a.@capacity.should eq(5)
a.@offset_to_buffer.should eq(0)
end

it "resizes the buffer if capacity is not enough" do
a = [1, 2, 3, 4, 5]
a.shift
a[4, 0] = [6, 7, 8, 9]
a.should eq([2, 3, 4, 5, 6, 7, 8, 9])
a.@capacity.should eq(10)
a.@offset_to_buffer.should eq(1)
end
end

describe "values_at" do
Expand Down
18 changes: 10 additions & 8 deletions src/array.cr
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ class Array(T)
@size -= diff
else
# Need to grow
resize_to_capacity(Math.pw2ceil(@size + diff))
resize_if_cant_insert(diff)
(@buffer + start + values.size).move_from(@buffer + start + count, size - start - count)
(@buffer + start).copy_from(values.to_unsafe, values.size)
@size += diff
Expand Down Expand Up @@ -2071,6 +2071,10 @@ class Array(T)
end

private def calculate_new_capacity(new_size)
# Resizing is done via `Pointer#realloc` on the root buffer, so the space
# between the root and real buffers remains untouched
new_size += @offset_to_buffer

new_capacity = @capacity == 0 ? INITIAL_CAPACITY : @capacity
while new_capacity < new_size
if new_capacity < CAPACITY_THRESHOLD
Expand Down Expand Up @@ -2118,13 +2122,11 @@ class Array(T)
end

private def resize_if_cant_insert(insert_size)
# Resize if we exceed the remaining capacity.
# `remaining_capacity - @size` is the actual number of slots we have
# to push new elements.
if insert_size > remaining_capacity - @size
# The new capacity that we need is what we already have occupied
# because of shift (`@offset_to_buffer`) plus my size plus the insert size.
resize_to_capacity(Math.pw2ceil(@offset_to_buffer + @size + insert_size))
# Resize if we exceed the remaining capacity. This is less than `@capacity`
# if the array has been shifted and `@offset_to_buffer` is nonzero
new_size = @size + insert_size
if new_size > remaining_capacity
resize_to_capacity(calculate_new_capacity(new_size))
end
end

Expand Down