Moving around some math macros.
This commit is contained in:
@@ -38,19 +38,21 @@
|
||||
|
||||
#include <xenia/core/hash.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <string.h> // for memcpy and memset
|
||||
|
||||
namespace xe {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef std::pair<uint64_t, uint64_t> uint128_t;
|
||||
|
||||
inline uint64_t Uint128Low64(const uint128_t& x) { return x.first; }
|
||||
inline uint64_t Uint128High64(const uint128_t& x) { return x.second; }
|
||||
inline uint64_t Uint128Low64(const uint128_t &x) { return x.first; }
|
||||
inline uint64_t Uint128High64(const uint128_t &x) { return x.second; }
|
||||
|
||||
// Hash 128 input bits down to 64 bits of output.
|
||||
// This is intended to be a reasonably good hash function.
|
||||
inline uint64_t Hash128to64(const uint128_t& x) {
|
||||
inline uint64_t Hash128to64(const uint128_t &x) {
|
||||
// Murmur-inspired hashing.
|
||||
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
|
||||
uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
|
||||
@@ -61,37 +63,14 @@ inline uint64_t Hash128to64(const uint128_t& x) {
|
||||
return b;
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
|
||||
#if 0
|
||||
static uint64_t UNALIGNED_LOAD64(const char *p) {
|
||||
uint64_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
static uint32_t UNALIGNED_LOAD32(const char *p) {
|
||||
uint32_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
XEFORCEINLINE uint64_t UNALIGNED_LOAD64(const char *p) {
|
||||
const uint64_t* p64 = (const uint64_t*)p;
|
||||
const uint64_t *p64 = (const uint64_t *)p;
|
||||
return *p64;
|
||||
}
|
||||
XEFORCEINLINE uint32_t UNALIGNED_LOAD32(const char *p) {
|
||||
const uint32_t* p32 = (const uint32_t*)p;
|
||||
const uint32_t *p32 = (const uint32_t *)p;
|
||||
return *p32;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if XE_CPU_BIGENDIAN
|
||||
#define uint32_t_in_expected_order(x) (poly::byte_swap(x))
|
||||
#define uint64_in_expected_order(x) (poly::byte_swap(x))
|
||||
#else
|
||||
#define uint32_t_in_expected_order(x) (x)
|
||||
#define uint64_in_expected_order(x) (x)
|
||||
#endif // XE_CPU_BIGENDIAN
|
||||
|
||||
#if !defined(LIKELY)
|
||||
#if HAVE_BUILTIN_EXPECT
|
||||
@@ -101,13 +80,9 @@ XEFORCEINLINE uint32_t UNALIGNED_LOAD32(const char *p) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static uint64_t Fetch64(const char *p) {
|
||||
return uint64_in_expected_order(UNALIGNED_LOAD64(p));
|
||||
}
|
||||
static uint64_t Fetch64(const char *p) { return UNALIGNED_LOAD64(p); }
|
||||
|
||||
static uint32_t Fetch32(const char *p) {
|
||||
return uint32_t_in_expected_order(UNALIGNED_LOAD32(p));
|
||||
}
|
||||
static uint32_t Fetch32(const char *p) { return UNALIGNED_LOAD32(p); }
|
||||
|
||||
// Some primes between 2^63 and 2^64 for various uses.
|
||||
static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
|
||||
@@ -119,8 +94,7 @@ static const uint32_t c1 = 0xcc9e2d51;
|
||||
static const uint32_t c2 = 0x1b873593;
|
||||
|
||||
// A 32-bit to 32-bit integer hash copied from Murmur3.
|
||||
static uint32_t fmix(uint32_t h)
|
||||
{
|
||||
static uint32_t fmix(uint32_t h) {
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
@@ -135,7 +109,11 @@ static uint32_t Rotate32(uint32_t val, int shift) {
|
||||
}
|
||||
|
||||
#undef PERMUTE3
|
||||
#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0)
|
||||
#define PERMUTE3(a, b, c) \
|
||||
do { \
|
||||
std::swap(a, b); \
|
||||
std::swap(a, c); \
|
||||
} while (0)
|
||||
|
||||
static uint32_t Mur(uint32_t a, uint32_t h) {
|
||||
// Helper from Murmur3 for combining two 32-bit values.
|
||||
@@ -180,9 +158,9 @@ static uint32_t Hash32Len5to12(const char *s, size_t len) {
|
||||
|
||||
uint32_t CityHash32(const char *s, size_t len) {
|
||||
if (len <= 24) {
|
||||
return len <= 12 ?
|
||||
(len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) :
|
||||
Hash32Len13to24(s, len);
|
||||
return len <= 12
|
||||
? (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len))
|
||||
: Hash32Len13to24(s, len);
|
||||
}
|
||||
|
||||
// len > 24
|
||||
@@ -254,9 +232,7 @@ static uint64_t Rotate(uint64_t val, int shift) {
|
||||
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
|
||||
}
|
||||
|
||||
static uint64_t ShiftMix(uint64_t val) {
|
||||
return val ^ (val >> 47);
|
||||
}
|
||||
static uint64_t ShiftMix(uint64_t val) { return val ^ (val >> 47); }
|
||||
|
||||
static uint64_t HashLen16(uint64_t u, uint64_t v) {
|
||||
return Hash128to64(uint128_t(u, v));
|
||||
@@ -311,7 +287,7 @@ static uint64_t HashLen17to32(const char *s, size_t len) {
|
||||
|
||||
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
||||
// Callers do best to use "random-looking" values for a and b.
|
||||
static pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
|
||||
static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
|
||||
uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) {
|
||||
a += w;
|
||||
b = Rotate(b + a + z, 21);
|
||||
@@ -319,18 +295,15 @@ static pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
|
||||
a += x;
|
||||
a += y;
|
||||
b += Rotate(a, 44);
|
||||
return make_pair(a + z, b + c);
|
||||
return std::make_pair(a + z, b + c);
|
||||
}
|
||||
|
||||
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
||||
static pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
|
||||
const char* s, uint64_t a, uint64_t b) {
|
||||
return WeakHashLen32WithSeeds(Fetch64(s),
|
||||
Fetch64(s + 8),
|
||||
Fetch64(s + 16),
|
||||
Fetch64(s + 24),
|
||||
a,
|
||||
b);
|
||||
static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s,
|
||||
uint64_t a,
|
||||
uint64_t b) {
|
||||
return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
|
||||
Fetch64(s + 24), a, b);
|
||||
}
|
||||
|
||||
// Return an 8-byte hash for 33 to 64 bytes.
|
||||
@@ -371,8 +344,10 @@ uint64_t CityHash64(const char *s, size_t len) {
|
||||
uint64_t x = Fetch64(s + len - 40);
|
||||
uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
|
||||
uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
|
||||
pair<uint64_t, uint64_t> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
|
||||
pair<uint64_t, uint64_t> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
||||
std::pair<uint64_t, uint64_t> v =
|
||||
WeakHashLen32WithSeeds(s + len - 64, len, z);
|
||||
std::pair<uint64_t, uint64_t> w =
|
||||
WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
|
||||
x = x * k1 + Fetch64(s);
|
||||
|
||||
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
|
||||
@@ -395,7 +370,8 @@ uint64_t CityHash64(const char *s, size_t len) {
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
uint64_t xe_hash64(const void* data, size_t length, uint64_t seed) {
|
||||
return HashLen16(CityHash64((const char*)data, length) - k2, seed);
|
||||
uint64_t hash64(const void *data, size_t length, uint64_t seed) {
|
||||
return HashLen16(CityHash64((const char *)data, length) - k2, seed);
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
@@ -12,8 +12,19 @@
|
||||
|
||||
#include <xenia/common.h>
|
||||
|
||||
namespace xe {
|
||||
|
||||
uint64_t xe_hash64(const void* data, size_t length, uint64_t seed = 0);
|
||||
inline size_t hash_combine(size_t seed) { return seed; }
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
size_t hash_combine(size_t seed, const T& v, const Ts&... vs) {
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9E3779B9 + (seed << 6) + (seed >> 2);
|
||||
return hash_combine(seed, vs...);
|
||||
}
|
||||
|
||||
uint64_t hash64(const void* data, size_t length, uint64_t seed = 0);
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_CORE_HASH_H_
|
||||
|
||||
Reference in New Issue
Block a user