libguf/src/guf_hash.h
2025-01-30 13:29:14 +01:00

61 lines
2.0 KiB
C

#ifndef GUF_HASH_H
#define GUF_HASH_H
#include "guf_common.h"
#include "guf_assert.h"
// #define GUF_USE_32_BIT_HASH /* Define GUF_USE_32_BIT_HASH to make guflib use 32 bit hashes */
/*
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 2166136261ul
#define GUF_HASH64_INIT 14695981039346656037ull
static inline 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 (size_t i = 0; i < (size_t)num_bytes; ++i) {
hash ^= data_bytes[i];
hash *= FNV_32_PRIME;
}
return hash;
}
static inline 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 (size_t i = 0; i < (size_t)num_bytes; ++i) {
hash ^= data_bytes[i];
hash *= FNV_64_PRIME;
}
return hash;
}
#ifdef GUF_HASH_USE_32_BIT
typedef uint32_t guf_hash_size_t;
#define GUF_HASH_INIT GUF_HASH32_INIT
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);
}
#define GUF_HASH_MAX UINT32_MAX
#else
typedef uint64_t guf_hash_size_t;
#define GUF_HASH_INIT GUF_HASH64_INIT
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);
}
#define GUF_HASH_MAX UINT64_MAX
#endif
#endif