/* This file is a part of MIR project. Copyright (C) 2018-2021 Vladimir Makarov . */ /* Simple high-quality multiplicative hash passing demerphq-smhsher, faster than spooky, city, or xxhash for strings less 100 bytes. Hash for the same key can be different on different architectures. To get machine-independent hash, use mir_hash_strict which is about 1.5 times slower than mir_hash. */ #ifndef __MIR_HASH__ #define __MIR_HASH__ #include #include #if defined(__x86_64__) || defined(__i386__) || defined(__PPC64__) || defined(__s390__) \ || defined(__m32c__) || defined(cris) || defined(__CR16__) || defined(__vax__) \ || defined(__m68k__) || defined(__aarch64__) || defined(_M_AMD64) || defined(_M_IX86) #define MIR_HASH_UNALIGNED_ACCESS 1 #else #define MIR_HASH_UNALIGNED_ACCESS 0 #endif #if (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || defined(_MSC_VER) #define MIR_LITTLE_ENDIAN 1 #else #define MIR_LITTLE_ENDIAN 0 #endif static inline uint64_t mir_get_key_part (const uint8_t *v, size_t len, int relax_p) { size_t i, start = 0; uint64_t tail = 0; if (relax_p || MIR_LITTLE_ENDIAN) { #if MIR_HASH_UNALIGNED_ACCESS if (len == sizeof (uint64_t)) return *(uint64_t *) v; if (len >= sizeof (uint32_t)) { tail = (uint64_t) * (uint32_t *) v << 32; start = 4; } #endif } for (i = start; i < len; i++) tail = (tail >> 8) | ((uint64_t) v[i] << 56); return tail; } static const uint64_t p1 = 0X65862b62bdf5ef4d, p2 = 0X288eea216831e6a7; static inline uint64_t mir_mum (uint64_t v, uint64_t c, int relax_p) { if (relax_p) { #if defined(__SIZEOF_INT128__) __uint128_t r = (__uint128_t) v * (__uint128_t) c; return (uint64_t) (r >> 64) + (uint64_t) r; #endif } uint64_t v1 = v >> 32, v2 = (uint32_t) v, c1 = c >> 32, c2 = (uint32_t) c, rm = v2 * c1 + v1 * c2; return v1 * c1 + (rm >> 32) + v2 * c2 + (rm << 32); } static inline uint64_t mir_round (uint64_t state, uint64_t v, int relax_p) { state ^= mir_mum (v, p1, relax_p); return state ^ mir_mum (state, p2, relax_p); } static inline uint64_t mir_hash_1 (const void *key, size_t len, uint64_t seed, int relax_p) { const uint8_t *v = (const uint8_t *) key; uint64_t r = seed + len; for (; len >= 16; len -= 16, v += 16) { r ^= mir_mum (mir_get_key_part (v, 8, relax_p), p1, relax_p); r ^= mir_mum (mir_get_key_part (v + 8, 8, relax_p), p2, relax_p); r ^= mir_mum (r, p1, relax_p); } if (len >= 8) { r ^= mir_mum (mir_get_key_part (v, 8, relax_p), p1, relax_p); len -= 8, v += 8; } if (len != 0) r ^= mir_mum (mir_get_key_part (v, len, relax_p), p2, relax_p); return mir_round (r, r, relax_p); } static inline uint64_t mir_hash (const void *key, size_t len, uint64_t seed) { return mir_hash_1 (key, len, seed, 1); } static inline uint64_t mir_hash_strict (const void *key, size_t len, uint64_t seed) { return mir_hash_1 (key, len, seed, 0); } static inline uint64_t mir_hash_init (uint64_t seed) { return seed; } static inline uint64_t mir_hash_step (uint64_t h, uint64_t key) { return mir_round (h, key, 1); } static inline uint64_t mir_hash_finish (uint64_t h) { return mir_round (h, h, 1); } static inline uint64_t mir_hash64 (uint64_t key, uint64_t seed) { return mir_hash_finish (mir_hash_step (mir_hash_init (seed), key)); } #endif