Как написать и вызвать std :: ha sh? - для mpz_class и mpz_t в gmp - PullRequest
1 голос
/ 18 июня 2020

Я думаю, что большая часть работы сделана здесь, только небольшая деталь отсутствует в конце. Читайте дальше.

Я пытаюсь написать связующий код для использования MurmurHash3 в ha sh большие целые числа (mpz_t и mpz_class) из GMP библиотека на C ++. Я делаю это, чтобы позже использовать их в std::unordered_map<mpz_class, int>.

Я хочу, чтобы код компилировался полезным способом для 32-битных и 64-битных систем и был легко расширяемым, когда требуются 128-битные системы. . Поэтому я написал функцию MurmurHash3_size_t(), которая вызывает правильную функцию ha sh MurmurHash3, а затем преобразует результат в size_t. Я предполагаю, что size_t имеет правильный размер битов с точки зрения 32/64/128 битных систем. (Не знаю, полезно ли это предположение.) Эта часть кода прекрасно компилируется.

Проблема возникает, когда я хочу определить функцию std::hash. Я получаю ошибку компилятора для своего кода (см. Комментарий в коде). Как правильно писать эти std::hash функции и как их вызывать?

( щелкните, чтобы просмотреть MurmurHash3.h )

Файл 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());
}

}

1 Ответ

2 голосов
/ 18 июня 2020

Нашел решение, которое работает для меня:

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());
}

}

Затем вы можете использовать функцию ha sh следующим образом:

#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;
}

Вывод:

a      : 402669288768856477614113920779288576
hash(a): 11740158581999522595
map[a] : 2

Комментарии приветствуются.

...