update table to use packed ID and limit size to fit in 32 bytes.
This commit is contained in:
parent
0aa55ae1a9
commit
742f966e14
1 changed files with 33 additions and 29 deletions
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue