Search code examples
c++functionhashfunctorunordered-map

c++ : How to pass a normal c function as hash functor for unordered_map


I've got this hash function is C style:

static size_t Wang_Jenkins_hash(size_t h) {
    h += (h << 15) ^ 0xffffcd7d;
    h ^= (h >> 10);
    h += (h << 3);
    h ^= (h >> 6);
    h += (h << 2) + (h << 14);
    return h ^ (h >> 16);
}

Then I try to use it for unordered_map's hash parameter. Do I always need to write a c++ functor as a wrapper inorder to use it? Or is there a more convenient ways to pass it as template parameter?

Thanks!


Solution

  • Functors are probably the easiest way to do this. When you use a free function the syntax becomes

    std::unordered_map<std::size_t, std::size_t, decltype(&Wang_Jenkins_hash)>
    

    but that is only half of what you need. Since we are using a function pointer type we need to pass to the map the function to use, and to do that you have to specify how many initial buckets you want along with the function to actually use. That could be done like

    std::unordered_map<std::size_t, std::size_t, decltype(&Wang_Jenkins_hash)> foo(1024, &Wang_Jenkins_hash);
    

    If you instead switch to a functor then code can be changed to

    struct Wang_Jenkins_hash
    {
        std::size_t operator()(std::size_t h) noexcept const
        {
            h += (h << 15) ^ 0xffffcd7d;
            h ^= (h >> 10);
            h += (h << 3);
            h ^= (h >> 6);
            h += (h << 2) + (h << 14);
            return h ^ (h >> 16);
        }
    };
    
    std::unordered_map<std::size_t, std::size_t, Wang_Jenkins_hash> foo;
    

    If you can use C++20 or newer then you can wrap the fucntion in a lambda to use with the map like

    auto my_hash = [](auto val) { return Wang_Jenkins_hash(val); };
    std::unordered_map<std::size_t, std::size_t, decltype(my_hash)> foo;