authorgravatar for erik.arvstedt@gmail.comErik Arvstedt <erik.arvstedt@gmail.com> 2023-06-12 22:21:31+02:00
committergravatar for erik.arvstedt@gmail.comErik Arvstedt <erik.arvstedt@gmail.com> 2023-06-13 09:48:51+02:00
log89bd29a9058eabf23c735761c49809bb63a68842
treeff4248f657d3a71f335f0648dc8df947ef90e253
parent5d3c8f4913884a4503e9f183e471b6090bb5bc92

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.

1 files changed, 7 insertions(+), 10 deletions(-)

lib/std/heap/arena_allocator.zig+7-10
...@@ -108,21 +108,18 @@ pub const ArenaAllocator = struct {...@@ -108,21 +108,18 @@ pub const ArenaAllocator = struct {
108 // Thus, only the first hand full of calls to reset() will actually need to iterate the linked108 // Thus, only the first hand full of calls to reset() will actually need to iterate the linked
109 // list, all future calls are just taking the first node, and only resetting the `end_index`109 // list, all future calls are just taking the first node, and only resetting the `end_index`
110 // value.110 // value.
111 const current_capacity = if (mode != .free_all)111 const requested_capacity = switch (mode) {
112 @sizeOf(BufNode) + self.queryCapacity() // we need at least space for exactly one node + the current capacity112 .retain_capacity => self.queryCapacity(),
113 else113 .retain_with_limit => |limit| std.math.min(limit, self.queryCapacity()),
114 0;114 .free_all => 0,
115 if (mode == .free_all or current_capacity == 0) {115 };
116 if (requested_capacity == 0) {
116 // just reset when we don't have anything to reallocate117 // just reset when we don't have anything to reallocate
117 self.deinit();118 self.deinit();
118 self.state = State{};119 self.state = State{};
119 return true;120 return true;
120 }121 }
121 const total_size = switch (mode) {122 const total_size = requested_capacity + @sizeOf(BufNode);
122 .retain_capacity => current_capacity,
123 .retain_with_limit => |limit| std.math.min(@sizeOf(BufNode) + limit, current_capacity),
124 .free_all => unreachable,
125 };
126 const align_bits = std.math.log2_int(usize, @alignOf(BufNode));123 const align_bits = std.math.log2_int(usize, @alignOf(BufNode));
127 // Free all nodes except for the last one124 // Free all nodes except for the last one
128 var it = self.state.buffer_list.first;125 var it = self.state.buffer_list.first;