Packages

Erlang collection of hash algorithms

Current section

Files

Jump to
erl_hash c_src erl_hash_nif.cc
Raw

c_src/erl_hash_nif.cc

#include "erl_hash_nif.h"
#include "nif_utils.h"
#include "macros.h"
#include "murmur2.h"
#include "murmur3.h"
#include "fnv.h"
#include "xxhash.h"
const char kAtomError[] = "error";
const char kAtomBadArg[] = "badarg";
atoms ATOMS;
namespace {
inline void hash_128_to_bytes(uint64_t high64, uint64_t low64, unsigned char* out)
{
// High 64 bits
out[0] = static_cast<unsigned char>((high64 >> 56) & 0xFF);
out[1] = static_cast<unsigned char>((high64 >> 48) & 0xFF);
out[2] = static_cast<unsigned char>((high64 >> 40) & 0xFF);
out[3] = static_cast<unsigned char>((high64 >> 32) & 0xFF);
out[4] = static_cast<unsigned char>((high64 >> 24) & 0xFF);
out[5] = static_cast<unsigned char>((high64 >> 16) & 0xFF);
out[6] = static_cast<unsigned char>((high64 >> 8) & 0xFF);
out[7] = static_cast<unsigned char>( high64 & 0xFF);
// Low 64 bits
out[8] = static_cast<unsigned char>((low64 >> 56) & 0xFF);
out[9] = static_cast<unsigned char>((low64 >> 48) & 0xFF);
out[10] = static_cast<unsigned char>((low64 >> 40) & 0xFF);
out[11] = static_cast<unsigned char>((low64 >> 32) & 0xFF);
out[12] = static_cast<unsigned char>((low64 >> 24) & 0xFF);
out[13] = static_cast<unsigned char>((low64 >> 16) & 0xFF);
out[14] = static_cast<unsigned char>((low64 >> 8) & 0xFF);
out[15] = static_cast<unsigned char>( low64 & 0xFF);
}
}
int on_nif_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
UNUSED(load_info);
ATOMS.atomError = make_atom(env, kAtomError);
ATOMS.atomBadArg = make_atom(env, kAtomBadArg);
*priv_data = NULL;
return 0;
}
void on_nif_unload(ErlNifEnv* env, void* priv_data)
{
UNUSED(env);
UNUSED(priv_data);
}
int on_nif_upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
{
UNUSED(env);
UNUSED(old_priv);
UNUSED(info);
*priv = NULL;
return 0;
}
ERL_NIF_TERM hash_murmur3_x64_128_legacy_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
uint32_t seed;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
if (!enif_get_uint(env, argv[1], &seed))
return make_badarg(env);
return enif_make_int(env, hash_murmur3_x64_128_legacy(key.data, key.size, seed));
}
ERL_NIF_TERM hash_murmur3_x64_128_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
uint32_t seed;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
if (!enif_get_uint(env, argv[1], &seed))
return make_badarg(env);
murmur3_128_t hash = hash_murmur3_x64_128(key.data, key.size, seed);
unsigned char result_buf[16];
hash_128_to_bytes(hash.high, hash.low, result_buf);
return make_binary(env, result_buf, 16);
}
ERL_NIF_TERM hash_murmur2_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
return enif_make_uint(env, hash_murmur2(key.data, key.size));
}
ERL_NIF_TERM hash_fnv1_64_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
return enif_make_uint(env, hash_fnv1_64(key.data, key.size));
}
ERL_NIF_TERM hash_fnv1a_64_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
return enif_make_uint(env, hash_fnv1a_64(key.data, key.size));
}
ERL_NIF_TERM hash_fnv1_32_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
return enif_make_uint(env, hash_fnv1_32(key.data, key.size));
}
ERL_NIF_TERM hash_fnv1a_32_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
return enif_make_uint(env, hash_fnv1a_32(key.data, key.size));
}
static ERL_NIF_TERM xxhash32_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
uint32_t seed;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
if (!enif_get_uint(env, argv[1], &seed))
return make_badarg(env);
return enif_make_uint(env, XXH32(key.data, key.size, seed));
}
static ERL_NIF_TERM xxhash64_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
uint32_t seed;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
if (!enif_get_uint(env, argv[1], &seed))
return make_badarg(env);
return enif_make_uint64(env, XXH64(key.data, key.size, seed));
}
static ERL_NIF_TERM xxh128_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
UNUSED(argc);
ErlNifBinary key;
uint32_t seed;
if (!get_binary(env, argv[0], &key))
return make_badarg(env);
if (!enif_get_uint(env, argv[1], &seed))
return make_badarg(env);
XXH128_hash_t hash = XXH3_128bits_withSeed(key.data, key.size, seed);
unsigned char result_buf[16];
hash_128_to_bytes(hash.high64, hash.low64, result_buf);
return make_binary(env, result_buf, 16);
}
static ErlNifFunc nif_funcs[] =
{
{"murmur3_x64_128_legacy", 2, hash_murmur3_x64_128_legacy_nif},
{"murmur3_x64_128", 2, hash_murmur3_x64_128_nif},
{"murmur2", 1, hash_murmur2_nif},
{"fnv1_64", 1, hash_fnv1_64_nif},
{"fnv1a_64", 1, hash_fnv1a_64_nif},
{"fnv1_32", 1, hash_fnv1_32_nif},
{"fnv1a_32", 1, hash_fnv1a_32_nif},
{"xxhash_32", 2, xxhash32_nif},
{"xxhash_64", 2, xxhash64_nif},
{"xxhash_128", 2, xxh128_nif}
};
ERL_NIF_INIT(erl_hash_nif, nif_funcs, on_nif_load, NULL, on_nif_upgrade, on_nif_unload)