| ... | ... | @@ -15,6 +15,7 @@ pub const ArenaAllocator = struct { |
| 15 | 15 | /// as a memory-saving optimization. |
| 16 | 16 | pub const State = struct { |
| 17 | 17 | buffer_list: std.SinglyLinkedList([]u8) = @as(std.SinglyLinkedList([]u8), .{}), |
| 18 | /// The first available index in the front buffer of `buffer_list` |
| 18 | 19 | end_index: usize = 0, |
| 19 | 20 | |
| 20 | 21 | pub fn promote(self: State, child_allocator: *Allocator) ArenaAllocator { |
| ... | ... | @@ -45,39 +46,36 @@ pub const ArenaAllocator = struct { |
| 45 | 46 | } |
| 46 | 47 | } |
| 47 | 48 | |
| 48 | | fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode { |
| 49 | | const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16); |
| 50 | | const big_enough_len = prev_len + actual_min_size; |
| 51 | | const len = big_enough_len + big_enough_len / 2; |
| 52 | | const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len); |
| 53 | | const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]); |
| 54 | | const buf_node = &buf_node_slice[0]; |
| 55 | | buf_node.* = BufNode{ |
| 56 | | .data = buf, |
| 57 | | .next = null, |
| 58 | | }; |
| 49 | fn getBufNodeAddr(buf: []u8) usize { |
| 50 | return mem.alignBackward(@ptrToInt(buf.ptr) + buf.len - @sizeOf(BufNode), @alignOf(BufNode)); |
| 51 | } |
| 52 | |
| 53 | fn allocBuf(self: *ArenaAllocator, len: usize, ptr_align: u29) ![]u8 { |
| 54 | const alloc_len = len + @sizeOf(BufNode) + @alignOf(BufNode) - 1; |
| 55 | const buf = try self.child_allocator.callAllocFn(alloc_len, ptr_align, 1); |
| 56 | const buf_node = @intToPtr(*BufNode, getBufNodeAddr(buf)); |
| 57 | buf_node.* = .{ .data = buf, .next = null }; |
| 58 | assert(@ptrToInt(buf_node) - @ptrToInt(buf.ptr) >= len); |
| 59 | 59 | self.state.buffer_list.prepend(buf_node); |
| 60 | | self.state.end_index = 0; |
| 61 | | return buf_node; |
| 60 | self.state.end_index = len; |
| 61 | return buf[0..len]; |
| 62 | 62 | } |
| 63 | 63 | |
| 64 | 64 | fn alloc(allocator: *Allocator, n: usize, ptr_align: u29, len_align: u29) ![]u8 { |
| 65 | 65 | const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator); |
| 66 | 66 | |
| 67 | | var cur_node = if (self.state.buffer_list.first) |first_node| first_node else try self.createNode(0, n + ptr_align); |
| 68 | | while (true) { |
| 69 | | const cur_buf = cur_node.data[@sizeOf(BufNode)..]; |
| 67 | if (self.state.buffer_list.first) |node_full_buf| { |
| 68 | assert(self.state.end_index > 0); |
| 69 | const cur_buf = node_full_buf.data[0.. |
| 70 | getBufNodeAddr(node_full_buf.data) - @ptrToInt(node_full_buf.data.ptr)]; |
| 70 | 71 | const addr = @ptrToInt(cur_buf.ptr) + self.state.end_index; |
| 71 | | const adjusted_addr = mem.alignForward(addr, ptr_align); |
| 72 | | const adjusted_index = self.state.end_index + (adjusted_addr - addr); |
| 73 | | const new_end_index = adjusted_index + n; |
| 74 | | if (new_end_index > cur_buf.len) { |
| 75 | | cur_node = try self.createNode(cur_buf.len, n + ptr_align); |
| 76 | | continue; |
| 72 | const aligned_index = self.state.end_index + (mem.alignForward(addr, ptr_align) - addr); |
| 73 | const aligned_end_index = aligned_index + n; |
| 74 | if (aligned_end_index <= cur_buf.len) { |
| 75 | self.state.end_index = aligned_end_index; |
| 76 | return cur_buf[aligned_index..aligned_end_index]; |
| 77 | 77 | } |
| 78 | | const result = cur_buf[adjusted_index..new_end_index]; |
| 79 | | self.state.end_index = new_end_index; |
| 80 | | return result; |
| 81 | 78 | } |
| 79 | return try self.allocBuf(n, ptr_align); |
| 82 | 80 | } |
| 83 | 81 | }; |