75 lines
2.4 KiB
C
75 lines
2.4 KiB
C
#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)
|
|
*/
|
|
|
|
#ifdef GUF_IMPL_STATIC
|
|
#define GUF_FN_KEYWORDS static
|
|
#else
|
|
#define GUF_FN_KEYWORDS
|
|
#endif
|
|
|
|
#define GUF_HASH32_INIT UINT32_C(2166136261)
|
|
#define GUF_HASH64_INIT UINT64_C(14695981039346656037)
|
|
|
|
GUF_FN_KEYWORDS uint32_t guf_hash32(const void *data, ptrdiff_t num_bytes, uint32_t hash); // FNV-1a (32 bit)
|
|
GUF_FN_KEYWORDS 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
|
|
|
|
#endif
|
|
|
|
#if defined(GUF_IMPL) || defined(GUF_IMPL_STATIC)
|
|
#include "guf_assert.h"
|
|
|
|
GUF_FN_KEYWORDS 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_FN_KEYWORDS 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_IMPL
|
|
#undef GUF_IMPL_STATIC
|
|
#endif /* endif GUF_IMPL/GUF_IMPL_STATIC */
|
|
|
|
#undef GUF_FN_KEYWORDS
|