master
1pub 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
54const std = @import("std");
55const assert = std.debug.assert;
56const log = std.log.scoped(.link);
57
58const Allocator = std.mem.Allocator;