For my chess I have some hashtables for different elements.
These work with an indexing scheme based on key % len, which is the usual thing in chess programs.
The 3 hashtables I have can then be wrappers around this one below.
If people see optimizations, let me know!!
(Too bad the empty_element is not doable with std.mem.zeroes() because of unions and enums inside the Elements).
fn HashTable(Element: type) type {
return struct {
const Self = @This();
const elementsize: usize = @sizeOf(Element);
const empty_element: Element = get_empty_element();
/// Array allocated on the heap.
data: []Element,
fn init(size_in_bytes: usize) !Self {
const len: usize = size_in_bytes / elementsize;
return .{
.data = try create_data(len),
};
}
fn deinit(self: *Self) void {
ctx.galloc.free(self.data);
}
fn clear(self: *Self) void {
clear_data(self.data);
}
fn resize(self: *Self, size_in_bytes: usize) !void {
const len: usize = size_in_bytes / elementsize;
self.data = try ctx.galloc.realloc(self.data, len);
self.clear();
}
fn put(self: *Self, key: u64, value: Element) void {
self.data[key % self.data.len] = value;
}
fn get(self: *Self, key: u64) *Element {
return &self.data[key % self.data.len];
}
fn create_data(len: usize) ![]Element {
const data: []Element = try ctx.galloc.alloc(Element, len);
clear_data(data);
return data;
}
fn clear_data(data: []Element) void {
@memset(data, empty_element);
}
fn get_empty_element() Element {
return switch (Element) {
Entry => Entry.empty,
EvalEntry => EvalEntry.empty,
PawnEntry => PawnEntry.empty,
else => @compileError("invalid type"),
};
}
};
}
