120 lines
2.9 KiB
C
120 lines
2.9 KiB
C
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#ifndef NULL
|
|
# define NULL ((void *)0)
|
|
#endif /* NULL */
|
|
|
|
/* xxHash implementation */
|
|
|
|
#define XXH3_PRIME64_1 0x9E3779B185EBCA87ULL
|
|
#define XXH3_PRIME64_2 0xC2B2AE3D27D4EB4FULL
|
|
#define XXH3_PRIME64_3 0x165667B19E3779F9ULL
|
|
#define XXH3_PRIME64_4 0x85EBCA77C2B2AE63ULL
|
|
#define XXH3_PRIME64_5 0x27D4EB2F165667C5ULL
|
|
|
|
#define xxh3_rotl64(x, r) ((x << r) | (x >> (64 - r)))
|
|
|
|
#define xxh3_avalanche(h) \
|
|
(h) ^= (h) >> 37; \
|
|
(h) *= XXH3_PRIME64_3; \
|
|
(h) ^= (h) >> 32
|
|
|
|
#define xxh3_mix16B(input, seed) \
|
|
(*(const uint64_t *)(input) + seed) * (*(const uint64_t *)(input + 8) + seed) + XXH3_PRIME64_1
|
|
|
|
static uint64_t xxhash3(const void *data, const uint64_t data_size, uint64_t seed) {
|
|
uint64_t h64, k1;
|
|
|
|
if (!data || data_size == 0)
|
|
return 0;
|
|
|
|
if (seed == 0)
|
|
seed = data_size;
|
|
|
|
const uint8_t *input = (const uint8_t *)data;
|
|
const uint8_t *end = input + data_size;
|
|
|
|
if (data_size >= 16) {
|
|
h64 = seed * XXH3_PRIME64_1;
|
|
|
|
do {
|
|
h64 += xxh3_mix16B(input, seed);
|
|
input += 16;
|
|
} while (input <= end - 16);
|
|
|
|
xxh3_avalanche(h64);
|
|
} else
|
|
h64 = data_size + XXH3_PRIME64_5;
|
|
|
|
h64 += data_size;
|
|
|
|
while (input + 8 <= end) {
|
|
k1 = *(const uint64_t *)input;
|
|
k1 *= XXH3_PRIME64_2;
|
|
k1 = xxh3_rotl64(k1, 31);
|
|
k1 *= XXH3_PRIME64_1;
|
|
h64 ^= k1;
|
|
h64 = xxh3_rotl64(h64, 27) * XXH3_PRIME64_1 + XXH3_PRIME64_4;
|
|
input += 8;
|
|
}
|
|
|
|
while (input < end) {
|
|
h64 ^= (uint64_t)(*input) * (uint64_t)XXH3_PRIME64_5;
|
|
h64 = xxh3_rotl64(h64, 11) * XXH3_PRIME64_1;
|
|
++input;
|
|
}
|
|
|
|
xxh3_avalanche(h64);
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
h64 = (h64 >> 56) | ((h64 >> 40) & 0x000000000000FF00ULL) |
|
|
((h64 >> 24) & 0x0000000000FF0000ULL) | ((h64 >> 8) & 0x00000000FF000000ULL) |
|
|
((h64 << 8) & 0x000000FF00000000ULL) | ((h64 << 24) & 0x0000FF0000000000ULL) |
|
|
((h64 << 40) & 0x00FF000000000000ULL) | ((h64 << 56) & 0xFF00000000000000ULL);
|
|
#endif /* __BIG_ENDIAN__ */
|
|
|
|
return h64;
|
|
}
|
|
|
|
static uint64_t fnv1a(const void *src, const uint64_t length) {
|
|
const uint8_t *data = (const uint8_t *)src;
|
|
uint64_t h = 14695981039346656037ULL;
|
|
|
|
for (uint64_t idx = 0; idx < length; ++idx) {
|
|
h ^= data[idx];
|
|
h *= 1099511628211ULL;
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
static char *uppstr(char *src) {
|
|
if (!src)
|
|
return NULL;
|
|
|
|
while (*src) {
|
|
*src = (char)toupper((unsigned char)*src);
|
|
++src;
|
|
}
|
|
|
|
return src;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
if (argc < 3) {
|
|
fprintf(stderr, "Usage: %s <name> <string>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
uppstr(argv[1]);
|
|
|
|
printf("#define %s_HASH %luULL /* %s */\n",
|
|
argv[1],
|
|
xxhash3(argv[2], strlen(argv[2]), fnv1a(argv[2], strlen(argv[2]))),
|
|
argv[2]);
|
|
|
|
return 0;
|
|
}
|