#pragma once #include "fl/str.h" #include "fl/type_traits.h" #include "fl/int.h" #include "fl/stdint.h" #include "fl/force_inline.h" #include "fl/memfill.h" #include #include "fl/compiler_control.h" namespace fl { template struct vec2; //----------------------------------------------------------------------------- // MurmurHash3 x86 32-bit //----------------------------------------------------------------------------- // Based on the public‐domain implementation by Austin Appleby: // https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp static inline u32 MurmurHash3_x86_32(const void *key, fl::size len, u32 seed = 0) { FL_DISABLE_WARNING_PUSH; FL_DISABLE_WARNING_IMPLICIT_FALLTHROUGH; const fl::u8 *data = static_cast(key); const int nblocks = int(len / 4); u32 h1 = seed; const u32 c1 = 0xcc9e2d51; const u32 c2 = 0x1b873593; // body const u32 *blocks = reinterpret_cast(data); for (int i = 0; i < nblocks; ++i) { u32 k1 = blocks[i]; k1 *= c1; k1 = (k1 << 15) | (k1 >> 17); k1 *= c2; h1 ^= k1; h1 = (h1 << 13) | (h1 >> 19); h1 = h1 * 5 + 0xe6546b64; } // tail const fl::u8 *tail = data + (nblocks * 4); u32 k1 = 0; switch (len & 3) { case 3: k1 ^= u32(tail[2]) << 16; case 2: k1 ^= u32(tail[1]) << 8; case 1: k1 ^= u32(tail[0]); k1 *= c1; k1 = (k1 << 15) | (k1 >> 17); k1 *= c2; h1 ^= k1; } // finalization h1 ^= u32(len); // fmix32 h1 ^= h1 >> 16; h1 *= 0x85ebca6b; h1 ^= h1 >> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >> 16; return h1; FL_DISABLE_WARNING_POP; } //----------------------------------------------------------------------------- // Fast, cheap 32-bit integer hash (Thomas Wang) //----------------------------------------------------------------------------- static inline u32 fast_hash32(u32 x) noexcept { x = (x ^ 61u) ^ (x >> 16); x = x + (x << 3); x = x ^ (x >> 4); x = x * 0x27d4eb2dU; x = x ^ (x >> 15); return x; } // 3) Handy two-word hasher static inline u32 hash_pair(u32 a, u32 b, u32 seed = 0) noexcept { // mix in 'a', then mix in 'b' u32 h = fast_hash32(seed ^ a); return fast_hash32(h ^ b); } static inline u32 fast_hash64(u64 x) noexcept { u32 x1 = static_cast(x & 0x00000000FFFFFFFF); u32 x2 = static_cast(x >> 32); return hash_pair(x1, x2); } //----------------------------------------------------------------------------- // Functor for hashing arbitrary byte‐ranges to a 32‐bit value //----------------------------------------------------------------------------- // https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp template struct Hash { static_assert(fl::is_pod::value, "fl::Hash only supports POD types (integrals, floats, " "etc.), you need to define your own hash."); u32 operator()(const T &key) const noexcept { return MurmurHash3_x86_32(&key, sizeof(T)); } }; template struct FastHash { static_assert(fl::is_pod::value, "fl::FastHash only supports POD types (integrals, floats, " "etc.), you need to define your own hash."); u32 operator()(const T &key) const noexcept { return fast_hash32(key); } }; template struct FastHash> { u32 operator()(const vec2 &key) const noexcept { if (sizeof(T) == sizeof(fl::u8)) { u32 x = static_cast(key.x) + (static_cast(key.y) << 8); return fast_hash32(x); } if (sizeof(T) == sizeof(u16)) { u32 x = static_cast(key.x) + (static_cast(key.y) << 16); return fast_hash32(x); } if (sizeof(T) == sizeof(u32)) { return hash_pair(key.x, key.y); } return MurmurHash3_x86_32(&key, sizeof(T)); } }; template struct Hash { u32 operator()(T *key) const noexcept { if (sizeof(T *) == sizeof(u32)) { u32 key_u = reinterpret_cast(key); return fast_hash32(key_u); } else { return MurmurHash3_x86_32(key, sizeof(T *)); } } }; template struct Hash> { u32 operator()(const vec2 &key) const noexcept { #ifndef __clang__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif T packed[2] = {key.x, key.y}; const void *p = &packed[0]; return MurmurHash3_x86_32(p, sizeof(packed)); #ifndef __clang__ #pragma GCC diagnostic pop #endif } }; template struct Hash> { u32 operator()(const T &key) const noexcept { auto hasher = Hash(); return hasher(key.get()); } }; template struct Hash> { u32 operator()(const fl::WeakPtr &key) const noexcept { fl::uptr val = key.ptr_value(); return MurmurHash3_x86_32(&val, sizeof(fl::uptr)); } }; template<> struct Hash { u32 operator()(const float key) const noexcept { u32 ikey = fl::bit_cast(key); return fast_hash32(ikey); } }; template<> struct Hash { u32 operator()(const double& key) const noexcept { return MurmurHash3_x86_32(&key, sizeof(double)); } }; template<> struct Hash { u32 operator()(const i32 key) const noexcept { u32 ukey = static_cast(key); return fast_hash32(ukey); } }; template<> struct Hash { u32 operator()(const bool key) const noexcept { return fast_hash32(key); } }; template<> struct Hash { u32 operator()(const fl::u8 &key) const noexcept { return fast_hash32(key); } }; template<> struct Hash { u32 operator()(const u16 &key) const noexcept { return fast_hash32(key); } }; template<> struct Hash { u32 operator()(const u32 &key) const noexcept { return fast_hash32(key); } }; template<> struct Hash { u32 operator()(const i8 &key) const noexcept { u8 v = static_cast(key); return fast_hash32(v); } }; template<> struct Hash { u32 operator()(const i16 &key) const noexcept { u16 ukey = static_cast(key); return fast_hash32(ukey); } }; // FASTLED_DEFINE_FAST_HASH(fl::u8) // FASTLED_DEFINE_FAST_HASH(u16) // FASTLED_DEFINE_FAST_HASH(u32) // FASTLED_DEFINE_FAST_HASH(i8) // FASTLED_DEFINE_FAST_HASH(i16) // FASTLED_DEFINE_FAST_HASH(bool) // FASTLED_DEFINE_FAST_HASH(int) //----------------------------------------------------------------------------- // Convenience for std::string → u32 //---------------------------------------------------------------------------- template <> struct Hash { u32 operator()(const fl::string &key) const noexcept { return MurmurHash3_x86_32(key.data(), key.size()); } }; } // namespace fl