#if defined(GUF_HASH_IMPL_STATIC) #define GUF_HASH_KWRDS static #else #define GUF_HASH_KWRDS #endif #ifndef GUF_HASH_H #define GUF_HASH_H #include "guf_common.h" /* FNV-1a (32-bit and 64-bit) hash functions. Generally, you should always call csr_hash with GUF_HASH_INIT as the hash argument, unless you want to create "chains" of hashes. cf. http://www.isthe.com/chongo/tech/comp/fnv/ (last retrieved: 2023-11-30) */ #define GUF_HASH32_INIT UINT32_C(2166136261) #define GUF_HASH64_INIT UINT64_C(14695981039346656037) GUF_HASH_KWRDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash); // FNV-1a (32 bit) GUF_HASH_KWRDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash); // FNV-1a (64 bit) #ifdef GUF_HASH_32_BIT typedef uint32_t guf_hash_size_t; #define GUF_HASH_INIT GUF_HASH32_INIT #define GUF_HASH_MAX UINT32_MAX static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, uint32_t hash) { return guf_hash32(data, num_bytes, hash); } #else typedef uint64_t guf_hash_size_t; #define GUF_HASH_INIT GUF_HASH64_INIT #define GUF_HASH_MAX UINT64_MAX static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, uint64_t hash) { return guf_hash64(data, num_bytes, hash); } #endif // Calculate a mod pow2 (with pow2 being a power of two != 0) static inline uint32_t guf_mod_pow2_u32(uint32_t a, uint32_t pow2) {return a & (pow2 - 1);} static inline uint64_t guf_mod_pow2_u64(uint64_t a, uint64_t pow2) {return a & (pow2 - 1);} static inline guf_hash_size_t guf_mod_pow2_hash(guf_hash_size_t a, guf_hash_size_t pow2) {return a & (pow2 - 1);} #endif #if defined(GUF_HASH_IMPL) || defined(GUF_HASH_IMPL_STATIC) #include "guf_assert.h" GUF_HASH_KWRDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash) { GUF_ASSERT_RELEASE(data); GUF_ASSERT_RELEASE(num_bytes >= 0); const unsigned char *data_bytes = (const unsigned char*)data; // This does not break strict-aliasing rules I think... const uint32_t FNV_32_PRIME = 16777619ul; for (ptrdiff_t i = 0; i < num_bytes; ++i) { hash ^= data_bytes[i]; hash *= FNV_32_PRIME; } return hash; } GUF_HASH_KWRDS uint64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint64_t hash) { GUF_ASSERT_RELEASE(data); GUF_ASSERT_RELEASE(num_bytes >= 0); const unsigned char *data_bytes = (const unsigned char*)data; // This does not break strict-aliasing rules I think... const uint64_t FNV_64_PRIME = 1099511628211ull; for (ptrdiff_t i = 0; i < num_bytes; ++i) { hash ^= data_bytes[i]; hash *= FNV_64_PRIME; } return hash; } #undef GUF_HASH_IMPL #undef GUF_HASH_IMPL_STATIC #endif /* endif GUF_IMPL/GUF_IMPL_STATIC */ #undef GUF_HASH_KWRDS