Created
May 22, 2026 23:32
-
-
Save tralamazza/3edacc7612427aec5958c4dd66670f94 to your computer and use it in GitHub Desktop.
xxHash32 progressive: length-dispatched unkeyed 32-bit hash optimized for small inputs on embedded (Cortex-M)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef XXHASH_PROGRESSIVE_H | |
| #define XXHASH_PROGRESSIVE_H | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #define XXHP_PRIME32_1 UINT32_C(0x9e3779b1) | |
| #define XXHP_PRIME32_2 UINT32_C(0x85ebca77) | |
| #define XXHP_PRIME32_3 UINT32_C(0xc2b2ae3d) | |
| #define XXHP_PRIME32_4 UINT32_C(0x27d4eb2f) | |
| #define XXHP_PRIME32_5 UINT32_C(0x165667b1) | |
| #define XXHP_TINY_MAX 31u | |
| #define XXHP_MEDIUM_MAX 127u | |
| static uint32_t xxhp_rotl32(uint32_t x, unsigned r) { | |
| return (x << r) | (x >> (32u - r)); | |
| } | |
| static uint32_t xxhp_readle32(const uint8_t *p) { | |
| return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | | |
| ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); | |
| } | |
| static uint32_t xxhp_round(uint32_t acc, uint32_t input) { | |
| acc += input * XXHP_PRIME32_2; | |
| acc = xxhp_rotl32(acc, 13); | |
| acc *= XXHP_PRIME32_1; | |
| return acc; | |
| } | |
| static uint32_t xxhp_avalanche(uint32_t x) { | |
| x ^= x >> 15; | |
| x *= XXHP_PRIME32_2; | |
| x ^= x >> 13; | |
| x *= XXHP_PRIME32_3; | |
| x ^= x >> 16; | |
| return x; | |
| } | |
| static uint32_t xxhp_tiny(const uint8_t *p, size_t len, uint32_t seed) { | |
| const uint8_t *end = p + len; | |
| uint32_t h32 = seed + XXHP_PRIME32_5; | |
| h32 += (uint32_t)len; | |
| while (p + 4 <= end) { | |
| h32 += xxhp_readle32(p) * XXHP_PRIME32_3; | |
| h32 = xxhp_rotl32(h32, 17) * XXHP_PRIME32_4; | |
| p += 4; | |
| } | |
| while (p < end) { | |
| h32 += (uint32_t)*p * XXHP_PRIME32_5; | |
| h32 = xxhp_rotl32(h32, 11) * XXHP_PRIME32_1; | |
| p++; | |
| } | |
| return xxhp_avalanche(h32); | |
| } | |
| static uint32_t xxhp_large(const uint8_t *p, size_t len, uint32_t seed) { | |
| const uint8_t *end = p + len; | |
| const uint8_t *limit; | |
| uint32_t h32; | |
| uint32_t v1, v2, v3, v4; | |
| if (len >= 16u) { | |
| limit = end - 16u; | |
| v1 = seed + XXHP_PRIME32_1 + XXHP_PRIME32_2; | |
| v2 = seed + XXHP_PRIME32_2; | |
| v3 = seed; | |
| v4 = seed - XXHP_PRIME32_1; | |
| do { | |
| v1 = xxhp_round(v1, xxhp_readle32(p)); | |
| v2 = xxhp_round(v2, xxhp_readle32(p + 4)); | |
| v3 = xxhp_round(v3, xxhp_readle32(p + 8)); | |
| v4 = xxhp_round(v4, xxhp_readle32(p + 12)); | |
| p += 16; | |
| } while (p <= limit); | |
| h32 = xxhp_rotl32(v1, 1) + xxhp_rotl32(v2, 7) + | |
| xxhp_rotl32(v3, 12) + xxhp_rotl32(v4, 18); | |
| } else { | |
| h32 = seed + XXHP_PRIME32_5; | |
| } | |
| h32 += (uint32_t)len; | |
| while (p + 4 <= end) { | |
| h32 += xxhp_readle32(p) * XXHP_PRIME32_3; | |
| h32 = xxhp_rotl32(h32, 17) * XXHP_PRIME32_4; | |
| p += 4; | |
| } | |
| while (p < end) { | |
| h32 += (uint32_t)*p * XXHP_PRIME32_5; | |
| h32 = xxhp_rotl32(h32, 11) * XXHP_PRIME32_1; | |
| p++; | |
| } | |
| return xxhp_avalanche(h32); | |
| } | |
| static uint32_t xxhp_medium(const uint8_t *p, size_t len, uint32_t seed) { | |
| const uint8_t *end = p + len; | |
| const uint8_t *limit = end - 16u; | |
| uint32_t h32; | |
| uint32_t v1 = seed + XXHP_PRIME32_1 + XXHP_PRIME32_2; | |
| uint32_t v2 = seed + XXHP_PRIME32_2; | |
| uint32_t v3 = seed; | |
| uint32_t v4 = seed - XXHP_PRIME32_1; | |
| do { | |
| v1 = xxhp_round(v1, xxhp_readle32(p)); | |
| v2 = xxhp_round(v2, xxhp_readle32(p + 4)); | |
| v3 = xxhp_round(v3, xxhp_readle32(p + 8)); | |
| v4 = xxhp_round(v4, xxhp_readle32(p + 12)); | |
| p += 16; | |
| } while (p <= limit); | |
| h32 = xxhp_rotl32(v1, 1) + xxhp_rotl32(v2, 7) + | |
| xxhp_rotl32(v3, 12) + xxhp_rotl32(v4, 18); | |
| h32 += (uint32_t)len; | |
| while (p + 4 <= end) { | |
| h32 += xxhp_readle32(p) * XXHP_PRIME32_3; | |
| h32 = xxhp_rotl32(h32, 17) * XXHP_PRIME32_4; | |
| p += 4; | |
| } | |
| while (p < end) { | |
| h32 += (uint32_t)*p * XXHP_PRIME32_5; | |
| h32 = xxhp_rotl32(h32, 11) * XXHP_PRIME32_1; | |
| p++; | |
| } | |
| return xxhp_avalanche(h32); | |
| } | |
| static uint32_t xxh32_progressive(const void *input, size_t len, uint32_t seed) { | |
| if (len == 0u) return seed + XXHP_PRIME32_5; | |
| if (len <= XXHP_TINY_MAX) return xxhp_tiny((const uint8_t *)input, len, seed); | |
| if (len <= XXHP_MEDIUM_MAX) return xxhp_medium((const uint8_t *)input, len, seed); | |
| return xxhp_large((const uint8_t *)input, len, seed); | |
| } | |
| #endif /* XXHASH_PROGRESSIVE_H */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment