i have two []const u8
values whose “contents” are equal, but whose memory pointers clearly are not…
what’s the most straightforward way to implement a hashmap with string slices as keys…
if it helps, the map would have ~100 entries with keys of length ~10… performance is not an issue at this point…
i only ask because of i’m creating []const u8
values at run-time…
std.StringHashMap
(which is think is the same as std.hash_map.StringHashMap
) appears to work for me…
and FWIW, so did std.StringArrayHashMap
…
i’m happy that these work for me – but now i’m curious about what’s really going am i truly comparing string contents???
This might help: Zig’s HashMap
std.StringHashMap
internally gives std.HashMap
the following context
:
pub const StringContext = struct {
pub fn hash(self: @This(), s: []const u8) u64 {
_ = self;
return hashString(s);
}
pub fn eql(self: @This(), a: []const u8, b: []const u8) bool {
_ = self;
return eqlString(a, b);
}
};
hashString
hashes the contents of the string it is passed:
pub fn hashString(s: []const u8) u64 {
return std.hash.Wyhash.hash(0, s);
}
eqlString
just calls std.mem.eql
:
pub fn eqlString(a: []const u8, b: []const u8) bool {
return mem.eql(u8, a, b);
}
/// Compares two slices and returns whether they are equal.
pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
if (@sizeOf(T) == 0) return true;
if (!@inComptime() and std.meta.hasUniqueRepresentation(T) and backend_can_use_eql_bytes) return eqlBytes(sliceAsBytes(a), sliceAsBytes(b));
if (a.len != b.len) return false;
if (a.len == 0 or a.ptr == b.ptr) return true;
for (a, b) |a_elem, b_elem| {
if (a_elem != b_elem) return false;
}
return true;
}
which itself calls std.mem.eqlBytes
, which is slightly more complicated but boils down to:
// not the actual implementation
fn eqlBytes(a: []const u8, b: []const u8) bool {
for (a, b) |a_item, b_item| {
if (a_item != b_item) return false;
}
return true;
}
1 Like