I think most of the work is done here, just a little detail is missing at the end. Read on.
I'm trying to write the glue code for using MurmurHash3 to hash big integers (mpz_t
and mpz_class
) of the GMP library in C++. I do this in order to later use them in a std::unordered_map<mpz_class, int>
.
I want the code to compile in a useful way for 32 bit and for 64 bit systems and to be easily extensible when 128 bit systems are required. Therefor I've written the MurmurHash3_size_t()
function which calls the right hash function of MurmurHash3 and then converts the result to size_t
. I assume that size_t
is of the correct bit size in terms of 32/64/128 bit systems. (I don't know if this assumption is useful.) This part of the code compiles nicely.
The problem arises when I want to define the std::hash
function. I get a compiler error for my code (see comment in code). How to write these std::hash
functions correctly and how to call them?
File hash_mpz.cpp
:
#include "hash_mpz.h"
#include <gmpxx.h>
#include "MurmurHash3.h"
size_t MurmurHash3_size_t(const void *key, int len, uint32_t seed) {
#if SIZE_MAX==0xffffffff
size_t result;
MurmurHash3_x86_32(key, len, seed, &result);
return result;
#elif SIZE_MAX==0xffffffffffffffff
size_t result[2];
MurmurHash3_x64_128(key, len, seed, &result);
return result[0] ^ result[1];
#else
#error cannot determine correct version of MurmurHash3, because SIZE_MAX is neither 0xffffffff nor 0xffffffffffffffff
#endif
}
namespace std {
size_t hash<mpz_t>::operator()(const mpz_t &x) const {
// found 1846872219 by randomly hitting digits on my keyboard
return MurmurHash3_size_t(x->_mp_d, x->_mp_size * sizeof(mp_limb_t), 1846872219);
}
size_t hash<mpz_class>::operator()(const mpz_class &x) const {
// compiler error in next statement
// error: no matching function for call to ‘std::hash<__mpz_struct [1]>::operator()(mpz_srcptr)’
return hash<mpz_t>::operator()(x.get_mpz_t());
}
}
Found a solution which works for me:
namespace std {
size_t hash<mpz_srcptr>::operator()(const mpz_srcptr x) const {
// found 1846872219 by randomly typing digits on my keyboard
return MurmurHash3_size_t(x->_mp_d, x->_mp_size * sizeof(mp_limb_t),
1846872219);
}
size_t hash<mpz_t>::operator()(const mpz_t &x) const {
return hash<mpz_srcptr> { }((mpz_srcptr) x);
}
size_t hash<mpz_class>::operator()(const mpz_class &x) const {
return hash<mpz_srcptr> { }(x.get_mpz_t());
}
}
Then you can use the hash function as follows:
#include <iostream>
#include <gmpxx.h>
#include <unordered_map>
#include "hash_mpz.h"
using namespace std;
int main() {
mpz_class a;
mpz_ui_pow_ui(a.get_mpz_t(), 168, 16);
cout << "a : " << a << endl;
cout << "hash(a): " << (hash<mpz_class> { }(a)) << endl;
unordered_map<mpz_class, int> map;
map[a] = 2;
cout << "map[a] : " << map[a] << endl;
return 0;
}
Output:
a : 402669288768856477614113920779288576
hash(a): 11740158581999522595
map[a] : 2
Comments are appreciated.
User contributions licensed under CC BY-SA 3.0