mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std.ArrayList: fix shrinkAndFree
Fixes a regression introduced in
e35f297aeb.
Now there is test coverage for ArrayList.shrinkAndFree in the case when
resizing fails.
This commit is contained in:
parent
c84bc3a06b
commit
16caea38d1
2 changed files with 33 additions and 34 deletions
|
|
@ -314,32 +314,9 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
|
||||||
/// Reduce allocated capacity to `new_len`.
|
/// Reduce allocated capacity to `new_len`.
|
||||||
/// May invalidate element pointers.
|
/// May invalidate element pointers.
|
||||||
pub fn shrinkAndFree(self: *Self, new_len: usize) void {
|
pub fn shrinkAndFree(self: *Self, new_len: usize) void {
|
||||||
assert(new_len <= self.items.len);
|
var unmanaged = self.moveToUnmanaged();
|
||||||
|
unmanaged.shrinkAndFree(self.allocator, new_len);
|
||||||
if (@sizeOf(T) == 0) {
|
self.* = unmanaged.toManaged(self.allocator);
|
||||||
self.items.len = new_len;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const old_memory = self.allocatedSlice();
|
|
||||||
if (self.allocator.resize(old_memory, new_len)) {
|
|
||||||
self.capacity = new_len;
|
|
||||||
self.items.len = new_len;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const new_memory = self.allocator.alignedAlloc(T, alignment, new_len) catch |e| switch (e) {
|
|
||||||
error.OutOfMemory => {
|
|
||||||
// No problem, capacity is still correct then.
|
|
||||||
self.items.len = new_len;
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
mem.copy(T, new_memory, self.items);
|
|
||||||
self.allocator.free(old_memory);
|
|
||||||
self.items = new_memory;
|
|
||||||
self.capacity = new_memory.len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reduce length to `new_len`.
|
/// Reduce length to `new_len`.
|
||||||
|
|
@ -782,7 +759,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
mem.copy(T, new_memory, self.items);
|
mem.copy(T, new_memory, self.items[0..new_len]);
|
||||||
allocator.free(old_memory);
|
allocator.free(old_memory);
|
||||||
self.items = new_memory;
|
self.items = new_memory;
|
||||||
self.capacity = new_memory.len;
|
self.capacity = new_memory.len;
|
||||||
|
|
@ -1488,14 +1465,18 @@ test "std.ArrayListUnmanaged(u8) implements writer" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMemory" {
|
test "shrink still sets length when resizing is disabled" {
|
||||||
// use an arena allocator to make sure realloc returns error.OutOfMemory
|
// Use the testing allocator but with resize disabled.
|
||||||
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
var a = testing.allocator;
|
||||||
defer arena.deinit();
|
a.vtable = &.{
|
||||||
const a = arena.allocator();
|
.alloc = a.vtable.alloc,
|
||||||
|
.resize = Allocator.noResize,
|
||||||
|
.free = a.vtable.free,
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
var list = ArrayList(i32).init(a);
|
var list = ArrayList(i32).init(a);
|
||||||
|
defer list.deinit();
|
||||||
|
|
||||||
try list.append(1);
|
try list.append(1);
|
||||||
try list.append(2);
|
try list.append(2);
|
||||||
|
|
@ -1506,6 +1487,7 @@ test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMe
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
var list = ArrayListUnmanaged(i32){};
|
var list = ArrayListUnmanaged(i32){};
|
||||||
|
defer list.deinit(a);
|
||||||
|
|
||||||
try list.append(a, 1);
|
try list.append(a, 1);
|
||||||
try list.append(a, 2);
|
try list.append(a, 2);
|
||||||
|
|
@ -1516,6 +1498,22 @@ test "std.ArrayList/ArrayListUnmanaged.shrink still sets length on error.OutOfMe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "shrinkAndFree with a copy" {
|
||||||
|
// Use the testing allocator but with resize disabled.
|
||||||
|
var a = testing.allocator;
|
||||||
|
a.vtable = &.{
|
||||||
|
.alloc = a.vtable.alloc,
|
||||||
|
.resize = Allocator.noResize,
|
||||||
|
.free = a.vtable.free,
|
||||||
|
};
|
||||||
|
var list = ArrayList(i32).init(a);
|
||||||
|
defer list.deinit();
|
||||||
|
|
||||||
|
try list.appendNTimes(3, 16);
|
||||||
|
list.shrinkAndFree(4);
|
||||||
|
try testing.expect(mem.eql(i32, list.items, &.{ 3, 3, 3, 3 }));
|
||||||
|
}
|
||||||
|
|
||||||
test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" {
|
test "std.ArrayList/ArrayListUnmanaged.addManyAsArray" {
|
||||||
const a = std.testing.allocator;
|
const a = std.testing.allocator;
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,9 @@ pub const ArenaAllocator = struct {
|
||||||
const cur_node = self.state.buffer_list.first orelse return false;
|
const cur_node = self.state.buffer_list.first orelse return false;
|
||||||
const cur_buf = cur_node.data[@sizeOf(BufNode)..];
|
const cur_buf = cur_node.data[@sizeOf(BufNode)..];
|
||||||
if (@ptrToInt(cur_buf.ptr) + self.state.end_index != @ptrToInt(buf.ptr) + buf.len) {
|
if (@ptrToInt(cur_buf.ptr) + self.state.end_index != @ptrToInt(buf.ptr) + buf.len) {
|
||||||
if (new_len > buf.len) return false;
|
// It's not the most recent allocation, so it cannot be expanded,
|
||||||
return true;
|
// but it's fine if they want to make it smaller.
|
||||||
|
return new_len <= buf.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf.len >= new_len) {
|
if (buf.len >= new_len) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue