p2p/stingray_sdk/plugin_foundation/hash_function.h
Lucas Schwiderski 2c9ce46dd2
chore: Rework project structure
There likely won't be much need for multiple separate crates.
2023-05-26 23:42:01 +02:00

193 lines
3.9 KiB
C++

#pragma once
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#include <stdint.h>
#include <string.h>
namespace stingray_plugin_foundation {
// Implementation of the 64 bit murmur hash function
// http://murmurhash.googlepages.com/
inline uint64_t murmur_hash_64(const void * key, int len, uint64_t seed)
{
const uint64_t m = 0xc6a4a7935bd1e995ULL;
const int r = 47;
uint64_t h = seed ^ (len * m);
const uint64_t * data = (const uint64_t *)key;
const uint64_t * end = data + (len/8);
while(data != end)
{
#if defined(ANDROID) || defined(IOS) || defined(WEB) // Unaligned 64bit reads not supported!
uint64_t k;
char *p = (char *)&k, *d = (char *)data;
p[0] = d[0]; p[1] = d[1]; p[2] = d[2]; p[3] = d[3];
p[4] = d[4]; p[5] = d[5]; p[6] = d[6]; p[7] = d[7];
data++;
#elif defined(WINDOWSPC) || defined(UWP) || defined(XBOXONE) || defined(__ORBIS__) || defined(MACOSX) || defined(LINUXPC)
uint64_t k = *data++;
#else
#error Unaligned 64bit reads undefined!
#endif
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
}
const unsigned char * data2 = (const unsigned char*)data;
switch(len & 7)
{
case 7: h ^= uint64_t(data2[6]) << 48;
case 6: h ^= uint64_t(data2[5]) << 40;
case 5: h ^= uint64_t(data2[4]) << 32;
case 4: h ^= uint64_t(data2[3]) << 24;
case 3: h ^= uint64_t(data2[2]) << 16;
case 2: h ^= uint64_t(data2[1]) << 8;
case 1: h ^= uint64_t(data2[0]);
h *= m;
};
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
}
inline uint64_t hash64(const char *s)
{
return murmur_hash_64(s, int(strlen(s)), 0);
}
inline unsigned hash32(const char *s)
{
uint64_t id64 = murmur_hash_64(s, int(strlen(s)), 0);
return unsigned(id64 >> 32);
}
inline unsigned hash32(const void * key, int len)
{
uint64_t id64 = murmur_hash_64(key, len, 0);
return unsigned(id64 >> 32);
}
// A quick hash for four byte sized values based on a single
// iteration of the murmur hash function.
//
// Another option would be to convert the bit pattern directly to
// an int. That would be faster, but might lead to clustering if
// the input values do not distribute evenly.
inline unsigned int four_byte_hash(const void * key)
{
const unsigned int m = 0x5bd1e995;
const int r = 24;
unsigned int k = *(unsigned int *)key;
k *= m;
k ^= k >> r;
k *= m;
return k;
}
inline uint64_t eight_byte_hash_64(const void * key)
{
const uint64_t m = 0xc6a4a7935bd1e995ULL;
const int r = 47;
uint64_t k = *(const uint64_t *)key;
k *= m;
k ^= k >> r;
k *= m;
return k;
}
// Default hashing for builtin-types.
template <class T> struct default_hash;
template <class T> struct default_hash<T *>
{
unsigned operator()(T *t) const
{
#ifdef PLATFORM_64BIT
return (unsigned)eight_byte_hash_64(&t);
#else
return four_byte_hash(&t);
#endif
}
};
template <class T> struct default_hash<const T *>
{
unsigned operator()(const T *t) const
{
#ifdef PLATFORM_64BIT
return (unsigned)eight_byte_hash_64(&t);
#else
return four_byte_hash(&t);
#endif
}
};
template <> struct default_hash<unsigned>
{
unsigned operator()(unsigned t) const { return four_byte_hash(&t); }
};
template <> struct default_hash<int>
{
unsigned operator()(int t) const { return four_byte_hash(&t); }
};
template <> struct default_hash<uint64_t>
{
unsigned operator()(uint64_t t) const { return hash32(&t, sizeof(t)); }
};
template <> struct default_hash<int64_t>
{
unsigned operator()(int64_t t) const { return hash32(&t, sizeof(t)); }
};
// Utility functions
inline uint64_t mix(uint64_t h, uint64_t k)
{
const uint64_t m = 0xc6a4a7935bd1e995ULL;
const int r = 47;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
return h;
}
inline unsigned mix(unsigned h, unsigned k)
{
const unsigned int m = 0x5bd1e995;
const int r = 24;
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
return h;
}
} // namespace stingray_plugin_foundation
#pragma GCC diagnostic push