mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 16:03:29 +00:00
Merge pull request #111361 from Ivorforce/cleanup-hashfuncs
Clean up `hashfuncs.h`
This commit is contained in:
commit
7efb51c9d3
3 changed files with 168 additions and 152 deletions
151
core/templates/hashfuncs.cpp
Normal file
151
core/templates/hashfuncs.cpp
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/**************************************************************************/
|
||||||
|
/* hashfuncs.cpp */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/**************************************************************************/
|
||||||
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||||
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "hashfuncs.h"
|
||||||
|
|
||||||
|
uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed) {
|
||||||
|
union {
|
||||||
|
float f;
|
||||||
|
uint32_t i;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||||
|
if (p_in == 0.0f) {
|
||||||
|
u.f = 0.0;
|
||||||
|
} else if (Math::is_nan(p_in)) {
|
||||||
|
u.f = Math::NaN;
|
||||||
|
} else {
|
||||||
|
u.f = p_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash_murmur3_one_32(u.i, p_seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed) {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t i;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||||
|
if (p_in == 0.0f) {
|
||||||
|
u.d = 0.0;
|
||||||
|
} else if (Math::is_nan(p_in)) {
|
||||||
|
u.d = Math::NaN;
|
||||||
|
} else {
|
||||||
|
u.d = p_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash_murmur3_one_64(u.i, p_seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hash_murmur3_buffer(const void *key, int length, const uint32_t seed) {
|
||||||
|
// Although not required, this is a random prime number.
|
||||||
|
const uint8_t *data = (const uint8_t *)key;
|
||||||
|
const int nblocks = length / 4;
|
||||||
|
|
||||||
|
uint32_t h1 = seed;
|
||||||
|
|
||||||
|
const uint32_t c1 = 0xcc9e2d51;
|
||||||
|
const uint32_t c2 = 0x1b873593;
|
||||||
|
|
||||||
|
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
|
||||||
|
|
||||||
|
for (int i = -nblocks; i; i++) {
|
||||||
|
uint32_t k1 = blocks[i];
|
||||||
|
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = hash_rotl32(k1, 15);
|
||||||
|
k1 *= c2;
|
||||||
|
|
||||||
|
h1 ^= k1;
|
||||||
|
h1 = hash_rotl32(h1, 13);
|
||||||
|
h1 = h1 * 5 + 0xe6546b64;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
|
||||||
|
|
||||||
|
uint32_t k1 = 0;
|
||||||
|
|
||||||
|
switch (length & 3) {
|
||||||
|
case 3:
|
||||||
|
k1 ^= tail[2] << 16;
|
||||||
|
[[fallthrough]];
|
||||||
|
case 2:
|
||||||
|
k1 ^= tail[1] << 8;
|
||||||
|
[[fallthrough]];
|
||||||
|
case 1:
|
||||||
|
k1 ^= tail[0];
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = hash_rotl32(k1, 15);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Finalize with additional bit mixing.
|
||||||
|
h1 ^= length;
|
||||||
|
return hash_fmix32(h1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev) {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t i;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||||
|
if (p_in == 0.0f) {
|
||||||
|
u.d = 0.0;
|
||||||
|
} else if (Math::is_nan(p_in)) {
|
||||||
|
u.d = Math::NaN;
|
||||||
|
} else {
|
||||||
|
u.d = p_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev) {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t i;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
// Normalize +/- 0.0 and NaN values so they hash the same.
|
||||||
|
if (p_in == 0.0f) {
|
||||||
|
u.d = 0.0;
|
||||||
|
} else if (Math::is_nan(p_in)) {
|
||||||
|
u.d = Math::NaN;
|
||||||
|
} else {
|
||||||
|
u.d = p_in;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((p_prev << 5) + p_prev) + u.i;
|
||||||
|
}
|
|
@ -50,7 +50,7 @@ struct Pair;
|
||||||
* @param C String
|
* @param C String
|
||||||
* @return 32-bits hashcode
|
* @return 32-bits hashcode
|
||||||
*/
|
*/
|
||||||
static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
|
_FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
|
||||||
const unsigned char *chr = (const unsigned char *)p_cstr;
|
const unsigned char *chr = (const unsigned char *)p_cstr;
|
||||||
uint32_t hash = 5381;
|
uint32_t hash = 5381;
|
||||||
uint32_t c = *chr++;
|
uint32_t c = *chr++;
|
||||||
|
@ -63,7 +63,7 @@ static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) {
|
_FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len, uint32_t p_prev = 5381) {
|
||||||
uint32_t hash = p_prev;
|
uint32_t hash = p_prev;
|
||||||
|
|
||||||
for (int i = 0; i < p_len; i++) {
|
for (int i = 0; i < p_len; i++) {
|
||||||
|
@ -73,7 +73,7 @@ static _FORCE_INLINE_ uint32_t hash_djb2_buffer(const uint8_t *p_buff, int p_len
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) {
|
_FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) {
|
||||||
return ((p_prev << 5) + p_prev) ^ p_in;
|
return ((p_prev << 5) + p_prev) ^ p_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ static _FORCE_INLINE_ uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev =
|
||||||
* @param p_int - 64-bit unsigned integer key to be hashed
|
* @param p_int - 64-bit unsigned integer key to be hashed
|
||||||
* @return unsigned 32-bit value representing hashcode
|
* @return unsigned 32-bit value representing hashcode
|
||||||
*/
|
*/
|
||||||
static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
|
_FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
|
||||||
uint64_t v = p_int;
|
uint64_t v = p_int;
|
||||||
v = (~v) + (v << 18); // v = (v << 18) - v - 1;
|
v = (~v) + (v << 18); // v = (v << 18) - v - 1;
|
||||||
v = v ^ (v >> 31);
|
v = v ^ (v >> 31);
|
||||||
|
@ -95,7 +95,7 @@ static _FORCE_INLINE_ uint32_t hash_one_uint64(const uint64_t p_int) {
|
||||||
return uint32_t(v);
|
return uint32_t(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) {
|
_FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) {
|
||||||
key ^= seed;
|
key ^= seed;
|
||||||
key ^= key >> 33;
|
key ^= key >> 33;
|
||||||
key *= 0xff51afd7ed558ccd;
|
key *= 0xff51afd7ed558ccd;
|
||||||
|
@ -109,7 +109,7 @@ static _FORCE_INLINE_ uint64_t hash64_murmur3_64(uint64_t key, uint64_t seed) {
|
||||||
// Murmurhash3 32-bit version.
|
// Murmurhash3 32-bit version.
|
||||||
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
|
// All MurmurHash versions are public domain software, and the author disclaims all copyright to their code.
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
_FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||||
p_in *= 0xcc9e2d51;
|
p_in *= 0xcc9e2d51;
|
||||||
p_in = (p_in << 15) | (p_in >> 17);
|
p_in = (p_in << 15) | (p_in >> 17);
|
||||||
p_in *= 0x1b873593;
|
p_in *= 0x1b873593;
|
||||||
|
@ -121,48 +121,15 @@ static _FORCE_INLINE_ uint32_t hash_murmur3_one_32(uint32_t p_in, uint32_t p_see
|
||||||
return p_seed;
|
return p_seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
_FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||||
union {
|
|
||||||
float f;
|
|
||||||
uint32_t i;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
|
||||||
if (p_in == 0.0f) {
|
|
||||||
u.f = 0.0;
|
|
||||||
} else if (Math::is_nan(p_in)) {
|
|
||||||
u.f = Math::NaN;
|
|
||||||
} else {
|
|
||||||
u.f = p_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash_murmur3_one_32(u.i, p_seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_64(uint64_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
|
||||||
p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed);
|
p_seed = hash_murmur3_one_32(p_in & 0xFFFFFFFF, p_seed);
|
||||||
return hash_murmur3_one_32(p_in >> 32, p_seed);
|
return hash_murmur3_one_32(p_in >> 32, p_seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
uint32_t hash_murmur3_one_float(float p_in, uint32_t p_seed = HASH_MURMUR3_SEED);
|
||||||
union {
|
uint32_t hash_murmur3_one_double(double p_in, uint32_t p_seed = HASH_MURMUR3_SEED);
|
||||||
double d;
|
|
||||||
uint64_t i;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
_FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
||||||
if (p_in == 0.0f) {
|
|
||||||
u.d = 0.0;
|
|
||||||
} else if (Math::is_nan(p_in)) {
|
|
||||||
u.d = Math::NaN;
|
|
||||||
} else {
|
|
||||||
u.d = p_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash_murmur3_one_64(u.i, p_seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_seed = HASH_MURMUR3_SEED) {
|
|
||||||
#ifdef REAL_T_IS_DOUBLE
|
#ifdef REAL_T_IS_DOUBLE
|
||||||
return hash_murmur3_one_double(p_in, p_seed);
|
return hash_murmur3_one_double(p_in, p_seed);
|
||||||
#else
|
#else
|
||||||
|
@ -170,11 +137,11 @@ static _FORCE_INLINE_ uint32_t hash_murmur3_one_real(real_t p_in, uint32_t p_see
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) {
|
_FORCE_INLINE_ uint32_t hash_rotl32(uint32_t x, int8_t r) {
|
||||||
return (x << r) | (x >> (32 - r));
|
return (x << r) | (x >> (32 - r));
|
||||||
}
|
}
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) {
|
_FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) {
|
||||||
h ^= h >> 16;
|
h ^= h >> 16;
|
||||||
h *= 0x85ebca6b;
|
h *= 0x85ebca6b;
|
||||||
h ^= h >> 13;
|
h ^= h >> 13;
|
||||||
|
@ -184,117 +151,15 @@ static _FORCE_INLINE_ uint32_t hash_fmix32(uint32_t h) {
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_murmur3_buffer(const void *key, int length, const uint32_t seed = HASH_MURMUR3_SEED) {
|
uint32_t hash_murmur3_buffer(const void *key, int length, uint32_t seed = HASH_MURMUR3_SEED);
|
||||||
// Although not required, this is a random prime number.
|
|
||||||
const uint8_t *data = (const uint8_t *)key;
|
|
||||||
const int nblocks = length / 4;
|
|
||||||
|
|
||||||
uint32_t h1 = seed;
|
uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381);
|
||||||
|
uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381);
|
||||||
|
|
||||||
const uint32_t c1 = 0xcc9e2d51;
|
_FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) {
|
||||||
const uint32_t c2 = 0x1b873593;
|
|
||||||
|
|
||||||
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
|
|
||||||
|
|
||||||
for (int i = -nblocks; i; i++) {
|
|
||||||
uint32_t k1 = blocks[i];
|
|
||||||
|
|
||||||
k1 *= c1;
|
|
||||||
k1 = hash_rotl32(k1, 15);
|
|
||||||
k1 *= c2;
|
|
||||||
|
|
||||||
h1 ^= k1;
|
|
||||||
h1 = hash_rotl32(h1, 13);
|
|
||||||
h1 = h1 * 5 + 0xe6546b64;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
|
|
||||||
|
|
||||||
uint32_t k1 = 0;
|
|
||||||
|
|
||||||
switch (length & 3) {
|
|
||||||
case 3:
|
|
||||||
k1 ^= tail[2] << 16;
|
|
||||||
[[fallthrough]];
|
|
||||||
case 2:
|
|
||||||
k1 ^= tail[1] << 8;
|
|
||||||
[[fallthrough]];
|
|
||||||
case 1:
|
|
||||||
k1 ^= tail[0];
|
|
||||||
k1 *= c1;
|
|
||||||
k1 = hash_rotl32(k1, 15);
|
|
||||||
k1 *= c2;
|
|
||||||
h1 ^= k1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Finalize with additional bit mixing.
|
|
||||||
h1 ^= length;
|
|
||||||
return hash_fmix32(h1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) {
|
|
||||||
union {
|
|
||||||
double d;
|
|
||||||
uint64_t i;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
|
||||||
if (p_in == 0.0f) {
|
|
||||||
u.d = 0.0;
|
|
||||||
} else if (Math::is_nan(p_in)) {
|
|
||||||
u.d = Math::NaN;
|
|
||||||
} else {
|
|
||||||
u.d = p_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((p_prev << 5) + p_prev) + hash_one_uint64(u.i);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static _FORCE_INLINE_ uint32_t hash_make_uint32_t(T p_in) {
|
|
||||||
union {
|
|
||||||
T t;
|
|
||||||
uint32_t _u32;
|
|
||||||
} _u;
|
|
||||||
_u._u32 = 0;
|
|
||||||
_u.t = p_in;
|
|
||||||
return _u._u32;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) {
|
|
||||||
union {
|
|
||||||
double d;
|
|
||||||
uint64_t i;
|
|
||||||
} u;
|
|
||||||
|
|
||||||
// Normalize +/- 0.0 and NaN values so they hash the same.
|
|
||||||
if (p_in == 0.0f) {
|
|
||||||
u.d = 0.0;
|
|
||||||
} else if (Math::is_nan(p_in)) {
|
|
||||||
u.d = Math::NaN;
|
|
||||||
} else {
|
|
||||||
u.d = p_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((p_prev << 5) + p_prev) + u.i;
|
|
||||||
}
|
|
||||||
|
|
||||||
static _FORCE_INLINE_ uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) {
|
|
||||||
return ((p_prev << 5) + p_prev) ^ p_in;
|
return ((p_prev << 5) + p_prev) ^ p_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static _FORCE_INLINE_ uint64_t hash_make_uint64_t(T p_in) {
|
|
||||||
union {
|
|
||||||
T t;
|
|
||||||
uint64_t _u64;
|
|
||||||
} _u;
|
|
||||||
_u._u64 = 0; // in case p_in is smaller
|
|
||||||
|
|
||||||
_u.t = p_in;
|
|
||||||
return _u._u64;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename, typename = std::void_t<>>
|
template <typename, typename = std::void_t<>>
|
||||||
struct has_hash_method : std::false_type {};
|
struct has_hash_method : std::false_type {};
|
||||||
|
|
||||||
|
|
|
@ -2941,7 +2941,7 @@ uint32_t Variant::recursive_hash(int recursion_count) const {
|
||||||
return hash_one_uint64(reinterpret_cast<const ::RID *>(_data._mem)->get_id());
|
return hash_one_uint64(reinterpret_cast<const ::RID *>(_data._mem)->get_id());
|
||||||
} break;
|
} break;
|
||||||
case OBJECT: {
|
case OBJECT: {
|
||||||
return hash_one_uint64(hash_make_uint64_t(_get_obj().obj));
|
return hash_one_uint64(reinterpret_cast<uint64_t>(_get_obj().obj));
|
||||||
} break;
|
} break;
|
||||||
case STRING_NAME: {
|
case STRING_NAME: {
|
||||||
return reinterpret_cast<const StringName *>(_data._mem)->hash();
|
return reinterpret_cast<const StringName *>(_data._mem)->hash();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue