arena_allocator/reset: avoid zero-capacity allocations

1. When the arena is already empty, resetting with `retain_capacity` no longer
   results in allocating a buffer with zero capacity.
   This behavior was previously intended by the `(current_capacity == 0)` check,
   but wasn't correctly implemented.

2. Resetting with `.{ .retain_with_limit = 0 }` is now equivalent to
   `free_all` and a new buffer with zero capacity is no longer created.
   This is a useful side-effect of the above fixes.
This commit is contained in:
Erik Arvstedt 2023-06-12 22:21:31 +02:00
parent 5d3c8f4913
commit 89bd29a905

View File

@ -108,21 +108,18 @@ pub const ArenaAllocator = struct {
// Thus, only the first hand full of calls to reset() will actually need to iterate the linked
// list, all future calls are just taking the first node, and only resetting the `end_index`
// value.
const current_capacity = if (mode != .free_all)
@sizeOf(BufNode) + self.queryCapacity() // we need at least space for exactly one node + the current capacity
else
0;
if (mode == .free_all or current_capacity == 0) {
const requested_capacity = switch (mode) {
.retain_capacity => self.queryCapacity(),
.retain_with_limit => |limit| std.math.min(limit, self.queryCapacity()),
.free_all => 0,
};
if (requested_capacity == 0) {
// just reset when we don't have anything to reallocate
self.deinit();
self.state = State{};
return true;
}
const total_size = switch (mode) {
.retain_capacity => current_capacity,
.retain_with_limit => |limit| std.math.min(@sizeOf(BufNode) + limit, current_capacity),
.free_all => unreachable,
};
const total_size = requested_capacity + @sizeOf(BufNode);
const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
// Free all nodes except for the last one
var it = self.state.buffer_list.first;