Skip to content

Instantly share code, notes, and snippets.

@andrewrk
Last active July 23, 2021 07:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andrewrk/2cfb915754d5388226ebca00e68a2cd4 to your computer and use it in GitHub Desktop.
Save andrewrk/2cfb915754d5388226ebca00e68a2cd4 to your computer and use it in GitHub Desktop.
how to use hash map contexts to save memory when doing a string table
const std = @import("std");
const mem = std.mem;
const Foo = struct {
string_bytes: std.ArrayListUnmanaged(u8),
/// Key is string_bytes index.
string_table: std.HashMapUnmanaged(u32, void, IndexContext, std.hash_map.default_max_load_percentage),
};
const IndexContext = struct {
string_bytes: *std.ArrayListUnmanaged(u8),
pub fn eql(self: IndexContext, a: u32, b: u32) bool {
_ = self;
return a == b;
}
pub fn hash(self: IndexContext, x: u32) u64 {
const x_slice = mem.spanZ(@ptrCast([*:0]const u8, self.string_bytes.items.ptr) + x);
return std.hash_map.hashString(x_slice);
}
};
const SliceAdapter = struct {
string_bytes: *std.ArrayListUnmanaged(u8),
pub fn eql(self: SliceAdapter, a_slice: []const u8, b: u32) bool {
const b_slice = mem.spanZ(@ptrCast([*:0]const u8, self.string_bytes.items.ptr) + b);
return mem.eql(u8, a_slice, b_slice);
}
pub fn hash(self: SliceAdapter, adapted_key: []const u8) u64 {
_ = self;
return std.hash_map.hashString(adapted_key);
}
};
test "hash contexts" {
const gpa = std.testing.allocator;
var foo: Foo = .{
.string_bytes = .{},
.string_table = .{},
};
defer foo.string_bytes.deinit(gpa);
defer foo.string_table.deinit(gpa);
const index_context: IndexContext = .{ .string_bytes = &foo.string_bytes };
const hello_index = @intCast(u32, foo.string_bytes.items.len);
try foo.string_bytes.appendSlice(gpa, "hello\x00");
try foo.string_table.putContext(gpa, hello_index, {}, index_context);
const world_index = @intCast(u32, foo.string_bytes.items.len);
try foo.string_bytes.appendSlice(gpa, "world\x00");
try foo.string_table.putContext(gpa, world_index, {}, index_context);
// now we want to check if a string exists based on a string literal
const slice_context: SliceAdapter = .{ .string_bytes = &foo.string_bytes };
const found_entry = foo.string_table.getEntryAdapted(@as([]const u8, "world"), slice_context).?;
try std.testing.expectEqual(found_entry.key_ptr.*, world_index);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment