| 1 | pub fn TableSection(comptime Entry: type) type { |
| 2 | return struct { |
| 3 | entries: std.ArrayList(Entry) = .empty, |
| 4 | free_list: std.ArrayList(Index) = .empty, |
| 5 | lookup: std.AutoHashMapUnmanaged(Entry, Index) = .empty, |
| 6 | |
| 7 | pub fn deinit(self: *Self, allocator: Allocator) void { |
| 8 | self.entries.deinit(allocator); |
| 9 | self.free_list.deinit(allocator); |
| 10 | self.lookup.deinit(allocator); |
| 11 | } |
| 12 | |
| 13 | pub fn allocateEntry(self: *Self, allocator: Allocator, entry: Entry) Allocator.Error!Index { |
| 14 | try self.entries.ensureUnusedCapacity(allocator, 1); |
| 15 | const index = blk: { |
| 16 | if (self.free_list.pop()) |index| { |
| 17 | log.debug(" (reusing entry index {d})", .{index}); |
| 18 | break :blk index; |
| 19 | } else { |
| 20 | log.debug(" (allocating entry at index {d})", .{self.entries.items.len}); |
| 21 | const index = @as(u32, @intCast(self.entries.items.len)); |
| 22 | _ = self.entries.addOneAssumeCapacity(); |
| 23 | break :blk index; |
| 24 | } |
| 25 | }; |
| 26 | self.entries.items[index] = entry; |
| 27 | try self.lookup.putNoClobber(allocator, entry, index); |
| 28 | return index; |
| 29 | } |
| 30 | |
| 31 | pub fn freeEntry(self: *Self, allocator: Allocator, entry: Entry) void { |
| 32 | const index = self.lookup.get(entry) orelse return; |
| 33 | self.free_list.append(allocator, index) catch {}; |
| 34 | self.entries.items[index] = undefined; |
| 35 | _ = self.lookup.remove(entry); |
| 36 | } |
| 37 | |
| 38 | pub fn count(self: Self) usize { |
| 39 | return self.entries.items.len; |
| 40 | } |
| 41 | |
| 42 | pub fn format(self: Self, writer: *std.Io.Writer) std.Io.Writer.Error!void { |
| 43 | try writer.writeAll("TableSection:\n"); |
| 44 | for (self.entries.items, 0..) |entry, i| { |
| 45 | try writer.print(" {d} => {}\n", .{ i, entry }); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | const Self = @This(); |
| 50 | pub const Index = u32; |
| 51 | }; |
| 52 | } |
| 53 | |
| 54 | const std = @import("std"); |
| 55 | const assert = std.debug.assert; |
| 56 | const log = std.log.scoped(.link); |
| 57 | |
| 58 | const Allocator = std.mem.Allocator; |