From 742f966e14a044024d30162077554cbcb5134b19 Mon Sep 17 00:00:00 2001 From: Vivianne Langdon Date: Tue, 26 Jul 2022 03:00:15 -0700 Subject: [PATCH] update table to use packed ID and limit size to fit in 32 bytes. --- src/containers/table.zig | 62 +++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/containers/table.zig b/src/containers/table.zig index 1261402..e72fcc5 100644 --- a/src/containers/table.zig +++ b/src/containers/table.zig @@ -18,9 +18,9 @@ pub fn Table(comptime K: type, comptime V: type) type { const Self = @This(); /// The ID for the table (index + generation) - pub const Id = struct { - index: usize, + pub const Id = packed struct { gen: u8, + index: u24, }; // Collections sharing an index: @@ -35,19 +35,19 @@ pub fn Table(comptime K: type, comptime V: type) type { // Other fields /// List of indices which have previously been freed and are available to fill. - free_list: Queue(usize), + free_list: Queue(u24), /// Used for mapping the key to its index. - lookup: std.AutoHashMap(K, usize), + lookup: std.AutoHashMap(K, u24), /// The amount of items in the table (not the allocated size) - len: usize, + len: u24, pub fn init(allocator: std.mem.Allocator) Self { return Self{ .gens = std.ArrayList(u8).init(allocator), .values = std.ArrayList(?V).init(allocator), .keys = std.ArrayList(?K).init(allocator), - .free_list = Queue(usize).init(allocator), - .lookup = std.AutoHashMap(K, usize).init(allocator), + .free_list = Queue(u24).init(allocator), + .lookup = std.AutoHashMap(K, u24).init(allocator), .len = 0, }; } @@ -77,7 +77,7 @@ pub fn Table(comptime K: type, comptime V: type) type { } pub fn exists(self: *const Self, id: Id) bool { - return id.index < self.values.items.len and id.gen == self.gens.items[id.index]; + return id.index < self.values.items.len and id.gen == self.gens.items[@as(usize, id.index)]; } pub const AddResult = struct { @@ -94,9 +94,11 @@ pub fn Table(comptime K: type, comptime V: type) type { } if (self.free_list.popOrNull()) |index| { - const gen = self.gens.items[index]; - self.keys.items[index] = key; - self.values.items[index] = val; + const uindex = @as(usize, index); + + const gen = self.gens.items[uindex]; + self.keys.items[uindex] = key; + self.values.items[uindex] = val; try self.lookup.putNoClobber(key, index); self.len += 1; return AddResult{ @@ -116,7 +118,7 @@ pub fn Table(comptime K: type, comptime V: type) type { assert(self.keys.items.len == self.values.items.len); assert(self.values.items.len == self.gens.items.len); - const index = self.keys.items.len - 1; + const index = @intCast(u24, self.keys.items.len - 1); try self.lookup.putNoClobber(key, index); return AddResult{ @@ -132,29 +134,31 @@ pub fn Table(comptime K: type, comptime V: type) type { pub fn remove(self: *Self, id: Id) !V { assert(self.len > 0); - const index = id.index; + const uindex = @as(usize, id.index); - const key = self.keys.items[index] orelse unreachable; + const key = self.keys.items[uindex] orelse unreachable; const removed = self.lookup.remove(key); assert(removed); - self.keys.items[index] = null; + self.keys.items[uindex] = null; - self.gens.items[index] += 1; - const val = self.values.items[index] orelse unreachable; - self.values.items[index] = null; - try self.free_list.push(index); + self.gens.items[uindex] += 1; + const val = self.values.items[uindex] orelse unreachable; + self.values.items[uindex] = null; + try self.free_list.push(id.index); self.len -= 1; return val; } pub fn get(self: *Self, id: Id) ?*V { - return if (self.exists(id)) &(self.values.items[id.index] orelse unreachable) else null; + return if (self.exists(id)) &(self.values.items[@as(usize, id.index)] orelse unreachable) else null; } pub fn find(self: *Self, key: K) ?Id { if (self.lookup.get(key)) |index| { - const gen = self.gens.items[index]; + const uindex = @as(usize, index); + + const gen = self.gens.items[uindex]; return Id{ .index = index, .gen = gen, @@ -165,7 +169,7 @@ pub fn Table(comptime K: type, comptime V: type) type { } pub fn getKey(self: *Self, id: Id) ?K { - return if (self.exists(id)) (self.keys.items[id.index] orelse unreachable) else null; + return if (self.exists(id)) (self.keys.items[@as(usize, id.index)] orelse unreachable) else null; } }; } @@ -182,12 +186,12 @@ test "general table test" { const first_result = try table.add(56, .{ .a = 42, .b = 87 }); try std.testing.expect(first_result.added); try std.testing.expectEqual(@as(u8, 0), first_result.id.gen); - try std.testing.expectEqual(@as(usize, 0), first_result.id.index); + try std.testing.expectEqual(@as(u24, 0), first_result.id.index); const second_result = try table.add(62, .{ .a = 1, .b = 12 }); try std.testing.expect(second_result.added); try std.testing.expectEqual(@as(u8, 0), second_result.id.gen); - try std.testing.expectEqual(@as(usize, 1), second_result.id.index); + try std.testing.expectEqual(@as(u24, 1), second_result.id.index); var second_id = table.find(62) orelse unreachable; var second_val = table.get(second_id) orelse unreachable; @@ -272,7 +276,7 @@ pub fn RefTable(comptime K: type, comptime V: type) type { } pub fn remove(self: *Self, id: Id) !V { - self.ref_counts.items[id.index] = 0; + self.ref_counts.items[@as(usize, id.index)] = 0; return self.table.remove(id); } @@ -333,7 +337,7 @@ pub fn RefTable(comptime K: type, comptime V: type) type { assert(result.id.index == self.ref_counts.items.len); try self.ref_counts.append(1); } else { - self.ref_counts.items[result.id.index] = 1; + self.ref_counts.items[@as(usize, result.id.index)] = 1; } return result; @@ -360,12 +364,12 @@ test "general ref table test" { const first_result = try table.add(56, .{ .a = 42, .b = 87 }); try std.testing.expect(first_result.added); try std.testing.expectEqual(@as(u8, 0), first_result.id.gen); - try std.testing.expectEqual(@as(usize, 0), first_result.id.index); + try std.testing.expectEqual(@as(u24, 0), first_result.id.index); const second_result = try table.add(62, .{ .a = 1, .b = 12 }); try std.testing.expect(second_result.added); try std.testing.expectEqual(@as(u8, 0), second_result.id.gen); - try std.testing.expectEqual(@as(usize, 1), second_result.id.index); + try std.testing.expectEqual(@as(u24, 1), second_result.id.index); var second_id = table.find(62) orelse unreachable; var second_val = table.get(second_id) orelse unreachable; @@ -406,7 +410,7 @@ test "ref counting" { first_result = try table.add(12, .{ .a = 6, .b = 5 }); try std.testing.expect(first_result.added); - try std.testing.expectEqual(@as(usize, 0), first_result.id.index); + try std.testing.expectEqual(@as(u24, 0), first_result.id.index); try std.testing.expectEqual(@as(u8, 1), first_result.id.gen); const second_result = try table.add(12, .{ .a = 1, .b = 2 }); try std.testing.expect(!second_result.added);