| ... | ... | @@ -12,7 +12,7 @@ pub const ArenaAllocator = struct { |
| 12 | 12 | /// Inner state of ArenaAllocator. Can be stored rather than the entire ArenaAllocator |
| 13 | 13 | /// as a memory-saving optimization. |
| 14 | 14 | pub const State = struct { |
| 15 | | buffer_list: std.SinglyLinkedList([]u8) = @as(std.SinglyLinkedList([]u8), .{}), |
| 15 | buffer_list: std.SinglyLinkedList(usize) = .{}, |
| 16 | 16 | end_index: usize = 0, |
| 17 | 17 | |
| 18 | 18 | pub fn promote(self: State, child_allocator: Allocator) ArenaAllocator { |
| ... | ... | @@ -34,7 +34,7 @@ pub const ArenaAllocator = struct { |
| 34 | 34 | }; |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | | const BufNode = std.SinglyLinkedList([]u8).Node; |
| 37 | const BufNode = std.SinglyLinkedList(usize).Node; |
| 38 | 38 | |
| 39 | 39 | pub fn init(child_allocator: Allocator) ArenaAllocator { |
| 40 | 40 | return (State{}).promote(child_allocator); |
| ... | ... | @@ -47,7 +47,9 @@ pub const ArenaAllocator = struct { |
| 47 | 47 | while (it) |node| { |
| 48 | 48 | // this has to occur before the free because the free frees node |
| 49 | 49 | const next_it = node.next; |
| 50 | | self.child_allocator.free(node.data); |
| 50 | const align_bits = std.math.log2_int(usize, @alignOf(BufNode)); |
| 51 | const alloc_buf = @ptrCast([*]u8, node)[0..node.data]; |
| 52 | self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress()); |
| 51 | 53 | it = next_it; |
| 52 | 54 | } |
| 53 | 55 | } |
| ... | ... | @@ -73,7 +75,7 @@ pub const ArenaAllocator = struct { |
| 73 | 75 | while (it) |node| : (it = node.next) { |
| 74 | 76 | // Compute the actually allocated size excluding the |
| 75 | 77 | // linked list node. |
| 76 | | size += node.data.len - @sizeOf(BufNode); |
| 78 | size += node.data - @sizeOf(BufNode); |
| 77 | 79 | } |
| 78 | 80 | return size; |
| 79 | 81 | } |
| ... | ... | @@ -121,6 +123,7 @@ pub const ArenaAllocator = struct { |
| 121 | 123 | .retain_with_limit => |limit| std.math.min(limit, current_capacity), |
| 122 | 124 | .free_all => unreachable, |
| 123 | 125 | }; |
| 126 | const align_bits = std.math.log2_int(usize, @alignOf(BufNode)); |
| 124 | 127 | // Free all nodes except for the last one |
| 125 | 128 | var it = self.state.buffer_list.first; |
| 126 | 129 | const maybe_first_node = while (it) |node| { |
| ... | ... | @@ -128,7 +131,8 @@ pub const ArenaAllocator = struct { |
| 128 | 131 | const next_it = node.next; |
| 129 | 132 | if (next_it == null) |
| 130 | 133 | break node; |
| 131 | | self.child_allocator.free(node.data); |
| 134 | const alloc_buf = @ptrCast([*]u8, node)[0..node.data]; |
| 135 | self.child_allocator.rawFree(alloc_buf, align_bits, @returnAddress()); |
| 132 | 136 | it = next_it; |
| 133 | 137 | } else null; |
| 134 | 138 | std.debug.assert(maybe_first_node == null or maybe_first_node.?.next == null); |
| ... | ... | @@ -136,23 +140,21 @@ pub const ArenaAllocator = struct { |
| 136 | 140 | self.state.end_index = 0; |
| 137 | 141 | if (maybe_first_node) |first_node| { |
| 138 | 142 | // perfect, no need to invoke the child_allocator |
| 139 | | if (first_node.data.len == total_size) |
| 143 | if (first_node.data == total_size) |
| 140 | 144 | return true; |
| 141 | | const align_bits = std.math.log2_int(usize, @alignOf(BufNode)); |
| 142 | | if (self.child_allocator.rawResize(first_node.data, align_bits, total_size, @returnAddress())) { |
| 145 | const first_alloc_buf = @ptrCast([*]u8, first_node)[0..first_node.data]; |
| 146 | if (self.child_allocator.rawResize(first_alloc_buf, align_bits, total_size, @returnAddress())) { |
| 143 | 147 | // successful resize |
| 144 | | first_node.data.len = total_size; |
| 148 | first_node.data = total_size; |
| 145 | 149 | } else { |
| 146 | 150 | // manual realloc |
| 147 | 151 | const new_ptr = self.child_allocator.rawAlloc(total_size, align_bits, @returnAddress()) orelse { |
| 148 | 152 | // we failed to preheat the arena properly, signal this to the user. |
| 149 | 153 | return false; |
| 150 | 154 | }; |
| 151 | | self.child_allocator.rawFree(first_node.data, align_bits, @returnAddress()); |
| 155 | self.child_allocator.rawFree(first_alloc_buf, align_bits, @returnAddress()); |
| 152 | 156 | const node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), new_ptr)); |
| 153 | | node.* = BufNode{ |
| 154 | | .data = new_ptr[0..total_size], |
| 155 | | }; |
| 157 | node.* = .{ .data = total_size }; |
| 156 | 158 | self.state.buffer_list.first = node; |
| 157 | 159 | } |
| 158 | 160 | } |
| ... | ... | @@ -167,10 +169,7 @@ pub const ArenaAllocator = struct { |
| 167 | 169 | const ptr = self.child_allocator.rawAlloc(len, log2_align, @returnAddress()) orelse |
| 168 | 170 | return null; |
| 169 | 171 | const buf_node = @ptrCast(*BufNode, @alignCast(@alignOf(BufNode), ptr)); |
| 170 | | buf_node.* = BufNode{ |
| 171 | | .data = ptr[0..len], |
| 172 | | .next = null, |
| 173 | | }; |
| 172 | buf_node.* = .{ .data = len }; |
| 174 | 173 | self.state.buffer_list.prepend(buf_node); |
| 175 | 174 | self.state.end_index = 0; |
| 176 | 175 | return buf_node; |
| ... | ... | @@ -186,7 +185,8 @@ pub const ArenaAllocator = struct { |
| 186 | 185 | else |
| 187 | 186 | (self.createNode(0, n + ptr_align) orelse return null); |
| 188 | 187 | while (true) { |
| 189 | | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; |
| 188 | const cur_alloc_buf = @ptrCast([*]u8, cur_node)[0..cur_node.data]; |
| 189 | const cur_buf = cur_alloc_buf[@sizeOf(BufNode)..]; |
| 190 | 190 | const addr = @ptrToInt(cur_buf.ptr) + self.state.end_index; |
| 191 | 191 | const adjusted_addr = mem.alignForward(addr, ptr_align); |
| 192 | 192 | const adjusted_index = self.state.end_index + (adjusted_addr - addr); |
| ... | ... | @@ -199,8 +199,9 @@ pub const ArenaAllocator = struct { |
| 199 | 199 | } |
| 200 | 200 | |
| 201 | 201 | const bigger_buf_size = @sizeOf(BufNode) + new_end_index; |
| 202 | | if (self.child_allocator.resize(cur_node.data, bigger_buf_size)) { |
| 203 | | cur_node.data.len = bigger_buf_size; |
| 202 | const log2_align = comptime std.math.log2_int(usize, @alignOf(BufNode)); |
| 203 | if (self.child_allocator.rawResize(cur_alloc_buf, log2_align, bigger_buf_size, @returnAddress())) { |
| 204 | cur_node.data = bigger_buf_size; |
| 204 | 205 | } else { |
| 205 | 206 | // Allocate a new node if that's not possible |
| 206 | 207 | cur_node = self.createNode(cur_buf.len, n + ptr_align) orelse return null; |
| ... | ... | @@ -214,7 +215,7 @@ pub const ArenaAllocator = struct { |
| 214 | 215 | _ = ret_addr; |
| 215 | 216 | |
| 216 | 217 | const cur_node = self.state.buffer_list.first orelse return false; |
| 217 | | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; |
| 218 | const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data]; |
| 218 | 219 | if (@ptrToInt(cur_buf.ptr) + self.state.end_index != @ptrToInt(buf.ptr) + buf.len) { |
| 219 | 220 | // It's not the most recent allocation, so it cannot be expanded, |
| 220 | 221 | // but it's fine if they want to make it smaller. |
| ... | ... | @@ -239,7 +240,7 @@ pub const ArenaAllocator = struct { |
| 239 | 240 | const self = @ptrCast(*ArenaAllocator, @alignCast(@alignOf(ArenaAllocator), ctx)); |
| 240 | 241 | |
| 241 | 242 | const cur_node = self.state.buffer_list.first orelse return; |
| 242 | | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; |
| 243 | const cur_buf = @ptrCast([*]u8, cur_node)[@sizeOf(BufNode)..cur_node.data]; |
| 243 | 244 | |
| 244 | 245 | if (@ptrToInt(cur_buf.ptr) + self.state.end_index == @ptrToInt(buf.ptr) + buf.len) { |
| 245 | 246 | self.state.end_index -= buf.len; |