How to use / build the context parameter for HashMap and other data structures

Hi, so I’m currently trying to use a HashMap in Zig, I just have problem with the Context parameter, as I understand this is a small struct containing two custom functions one for equality “eql” and one for hashing “hash”, so I’ve declared a small struct like this :

pub fn PushSwapContext() type {
    return struct {
        eql: std.hash_map.getAutoEqlFn([:0]u8, undefined),
        hash: std.hash_map.getAutoHashFn([:0]u8, undefined),
    };
}

Of course it doesn’t work, I was pretty sure undefined wasn’t the correct answer and I was right, but I still don’t understand how I’m supposed to do it, so if someone could provide some guidance, that would be really helpful. I’m not sure do I need to declare member functions ? if so what is the syntax around that, basically I just want a basic string comparison for the equality and any hash will do, I just need the hash map, to identify duplicates.

Here’re some good usage examples:

  1. Zig's HashMap - Part 1 (there’s a Custom Context section)
  2. How to use hash map contexts to save memory when doing a string table - Zig NEWS
2 Likes

First, you don’t need to make a function returning a struct if it isn’t parameterized, you can just declare it like this:

const StructName = struct {
    // ...
};

Secondly, this would make eql and hash members of instances of your struct, not member functions which are constant in type. Member functions are declared like this:

const OuterStruct = struct {
    fn innerFunction() void {}
};

Functions are treated mostly the same as constants, so in your case, you can do:

const PushSwapContext = struct {
    pub const eql = std.hash_map.getAutoEqlFn([:0]u8, undefined);
    pub const hash = std.hash_map.getAutoHashFn([:0]u8, undefined);
};
1 Like

Very helpful, article, I should have looked a bit more on google, so basically for my usecase I can probably get away with using StringHashMap, or I can just provide a simple struct if I want a more custom behavior, Thanks for the response it’s very helpful, :wink:

3 Likes

DecimalContext is used for a Decimal struct (a decimal number).
You just define two functions to check equality and generate a hash for keys.

pub const DecimalContext = struct {
        /// Returns a wyhash generated value for the Decimal.
        pub fn hash(_: DecimalContext, d: Decimal) u64 {
            return d.hash();
        }
        
        /// Returns true if `x = y`.
        pub fn eql(_: DecimalContext, x: Decimal, y: Decimal) bool {
            return x.eql(y);
        }
    };
    
    test DecimalContext {
        // set of decimals
        const DecimalSet = std.HashMap(Decimal, void, DecimalContext, std.hash_map.default_max_load_percentage);
        var set = DecimalSet.init(testing.allocator);
        defer set.deinit();

        try set.put(dec(1), {});
        ...
    }
2 Likes

Thanks for the clarification :wink: