aoc-2025/libguf/guf_hash.h
2025-12-23 21:13:41 +01:00

83 lines
2.8 KiB
C
Executable File

/*
is parametrized: no (but recieves GUF_HASH_32_BIT from guf_common.h to set guf_hash_size_t depending on platform)
*/
#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 uint_least32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint_least32_t hash); // FNV-1a (32 bit)
GUF_HASH_KWRDS uint_least64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint_least64_t hash); // FNV-1a (64 bit)
#ifdef GUF_HASH_32_BIT
typedef uint_least32_t guf_hash_size_t;
#define GUF_HASH_INIT GUF_HASH32_INIT
#define GUF_HASH_MAX GUF_UINT32_MAX
static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, guf_hash_size_t hash) {
return guf_hash32(data, num_bytes, hash);
}
#else
typedef uint_least64_t guf_hash_size_t;
#define GUF_HASH_INIT GUF_HASH64_INIT
#define GUF_HASH_MAX GUF_UINT64_MAX
static inline guf_hash_size_t guf_hash(const void *data, ptrdiff_t num_bytes, guf_hash_size_t hash) {
return guf_hash64(data, num_bytes, hash);
}
#endif
#endif
#if defined(GUF_HASH_IMPL) || defined(GUF_HASH_IMPL_STATIC)
#include "guf_assert.h"
GUF_HASH_KWRDS uint_least32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint_least32_t hash)
{
hash = GUF_UWRAP_32(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 uint_least32_t FNV_32_PRIME = UINT32_C(16777619);
for (ptrdiff_t i = 0; i < num_bytes; ++i) {
hash = GUF_UWRAP_32(1u * hash ^ data_bytes[i]);
hash = GUF_UWRAP_32(1u * hash * FNV_32_PRIME);
}
return hash;
}
GUF_HASH_KWRDS uint_least64_t guf_hash64(const void *data, ptrdiff_t num_bytes, uint_least64_t hash)
{
hash = GUF_UWRAP_64(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 uint_least64_t FNV_64_PRIME = UINT64_C(1099511628211);
for (ptrdiff_t i = 0; i < num_bytes; ++i) {
hash = GUF_UWRAP_64(1u * hash ^ data_bytes[i]);
hash = GUF_UWRAP_64(1u * 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