What is the fastest hash function for pointers?

c++, hash, performance, pointers

Solution

After letting this question lay for a while, I'll post my best hash function for pointers so far:

template<typename Tval>
struct MyTemplatePointerHash1 {
    size_t operator()(const Tval* val) const {
        static const size_t shift = (size_t)log2(1 + sizeof(Tval));
        return (size_t)(val) >> shift;
    }
};

It's high performing for various block sizes. If someone has a better function, I'll change the accepted answer.

Problem

Hash table based containers are very fast associative array (e.g. `unordered_map`, `unordered_set`). Their performance is highly dependent on that hash function used to create an index for each entry. As hash tables grow, elements are rehashed again and again. Pointers are simple type, basically a 4/8 byte value that uniquely identify an object. The problem is that using an address as a result of the hash function is not efficient due to several LSB being zero. Example: ``` struct MyVoidPointerHash { size_t operator()(const void* val) const { return (size_t)val; } }; ``` A faster implementation is to lose a few bits: ``` struct MyVoidPointerHash2 { size_t operator()(const void* val) const { return ((size_t)val) >> 3; // 3 on 64 bit, 1 on 32 bit } }; ``` The latter produced 10-20% performance increase on a large application that uses hash sets and maps with tens of thousands of elements that are frequently built and cleared. Can someone offer a better scheme for hashing pointers? The function needs to be: - Fast! and must inline well. - Offer a reasonable distribution, rare collisions are allowed. Update - benchmark results I ran two sets of tests, one for `int*` and for a class pointer that has a size of 4KB. The results are very interesting. I used `std::unordered_set` for all test with data size being 16MB that was allocated in a single `new` call. The first algorithm ran twice to make sure sure caches are as hot as possible and the CPU is running at full speed. Setup: VS2013 (x64), i7-2600, Windows 8.1 x64. - VS2013 default hash function - Hash1: `return (size_t)(val);` - Hash2: `return '(size_t)(val) >> 3;` - Hash3(@BasileStarynkevitch): `uintptr_t ad = (uintptr_t)val; return (size_t)((13 * ad) ^ (ad >> 15));` - Hash4(@Roddy): `uintptr_t ad = (uintptr_t)val; return (size_t)(ad ^ (ad >> 16));` - Hash5(@egur): Code: ``` template<typename Tval> struct MyTemplatePointerHash1 { size_t operator()(const Tval* val) const { static const size_t shift = (size_t)log2(1 + sizeof(Tval)); return (size_t)(val) >> shift; } }; ``` Test 1 - `int*`: - VS2013 default took 1292ms - Hash1 took 742ms - Hash2 took 343ms - Hash3 took 1008ms - Hash4 took 629ms - Hash5 took 350ms Test 1 - `4K_class*`: - VS2013 default took 0.423ms - Hash1 took 23.889ms - Hash2 took 6.331ms - Hash3 took 0.366ms - Hash4 took 0.390ms - Hash5 took 0.290ms Update2: Winner so far is the templated hash (Hash5) function. Best level of performance for speed for various block sizes. Update 3: Added default hash function for baseline. Turns out it's far from optimal.

Original source