Idiom for a hashmap with []const u8 slices as keys

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…

Maybe std.hash_map.StringHashMap?

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 :smiley: – but now i’m curious about what’s really going :confused: am i truly comparing string contents???

Yup, it’s just calling std.mem.eql.

1 Like

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