tommyhash.h
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-2-Clause
2// Copyright (C) 2010 Andrea Mazzoleni
3
39#ifndef TOMMY_HASH_H
40#define TOMMY_HASH_H
41
42#include "tommytypes.h"
43#include <string.h> /* for strlen */
44
45/******************************************************************************/
46/* hash */
47
67TOMMY_API tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len);
68
88TOMMY_API tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len);
89
107tommy_inline tommy_uint32_t tommy_strhash_u32(tommy_uint32_t init_val, const void* void_key)
108{
109 return tommy_hash_u32(init_val, void_key, strlen(tommy_cast(const char*, void_key)));
110}
111
129tommy_inline tommy_uint64_t tommy_strhash_u64(tommy_uint64_t init_val, const void* void_key)
130{
131 return tommy_hash_u64(init_val, void_key, strlen(tommy_cast(const char*, void_key)));
132}
133
142{
143 key -= key << 6;
144 key ^= key >> 17;
145 key -= key << 9;
146 key ^= key << 4;
147 key -= key << 3;
148 key ^= key << 10;
149 key ^= key >> 15;
150
151 return key;
152}
153
162{
163 key = ~key + (key << 21);
164 key = key ^ (key >> 24);
165 key = key + (key << 3) + (key << 8);
166 key = key ^ (key >> 14);
167 key = key + (key << 2) + (key << 4);
168 key = key ^ (key >> 28);
169 key = key + (key << 31);
170
171 return key;
172}
173
184{
185 key ^= key >> 16;
186 key *= 0x85ebca6bU;
187 key ^= key >> 13;
188 key *= 0xc2b2ae35U;
189 key ^= key >> 16;
190
191 return key;
192}
193
205{
206 key ^= key >> 30;
207 key *= 0xbf58476d1ce4e5b9ULL;
208 key ^= key >> 27;
209 key *= 0x94d049bb133111ebULL;
210 key ^= key >> 31;
211
212 return key;
213}
214
215/******************************************************************************/
216/* multiplication */
217
224#if defined(_MSC_VER) && defined(_M_X64)
225/*
226 * MSVC x64 does not support inline assembly, so use its full-product intrinsic.
227 */
228#pragma intrinsic(_umul128)
229tommy_inline void tommy_mum(tommy_uint64_t* A, tommy_uint64_t* B)
230{
231 tommy_uint64_t high;
232 tommy_uint64_t low = _umul128(*A, *B, &high);
233 *A = low;
234 *B = high;
235}
236#elif defined(_MSC_VER) && defined(_M_ARM64)
237#pragma intrinsic(__umulh)
238tommy_inline void tommy_mum(tommy_uint64_t* A, tommy_uint64_t* B)
239{
240 tommy_uint64_t a = *A;
241 tommy_uint64_t b = *B;
242 *A = a * b;
243 *B = __umulh(a, b);
244}
245#elif defined(__x86_64__) && (defined(__GNUC__) || defined(__clang__))
249tommy_inline void tommy_mum(tommy_uint64_t* A, tommy_uint64_t* B)
250{
251 tommy_uint64_t a = *A;
252 tommy_uint64_t b = *B;
253 tommy_uint64_t low, high;
254
255 /* require a register to avoid Clang spilling the operand before mulq */
256 __asm__ (
257 "mulq %3"
258 : "=a" (low), "=d" (high)
259 : "a" (a), "r" (b)
260 : "cc"
261 );
262
263 *A = low;
264 *B = high;
265}
266#elif defined(__SIZEOF_INT128__)
267tommy_inline void tommy_mum(tommy_uint64_t* A, tommy_uint64_t* B)
268{
269 __uint128_t product = (__uint128_t)*A * *B;
270 *A = product;
271 *B = product >> 64;
272}
273#elif defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__))
274/*
275 * Keep this after __SIZEOF_INT128__ because the assembly path failed optimized
276 * hash tests on Apple clang 21.0.0. See https://github.com/amadvance/snapraid/issues/43.
277 */
278tommy_inline void tommy_mum(tommy_uint64_t* A, tommy_uint64_t* B)
279{
280 tommy_uint64_t a = *A;
281 tommy_uint64_t b = *B;
282 tommy_uint64_t low = a * b;
283 tommy_uint64_t high;
284 __asm__ (
285 "umulh %0, %1, %2"
286 : "=r" (high)
287 : "r" (a), "r" (b)
288 );
289 *A = low;
290 *B = high;
291}
292#else
293tommy_inline void tommy_mum(tommy_uint64_t* A, tommy_uint64_t* B)
294{
295 tommy_uint64_t a = *A;
296 tommy_uint64_t b = *B;
298 tommy_uint64_t a_hi = a >> 32;
300 tommy_uint64_t b_hi = b >> 32;
301 tommy_uint64_t p0 = a_lo * b_lo;
302 tommy_uint64_t p1 = a_lo * b_hi;
303 tommy_uint64_t p2 = a_hi * b_lo;
304 tommy_uint64_t p3 = a_hi * b_hi;
305
306 /* retain the carry from the middle words in the high half */
307 tommy_uint64_t middle = p1 + (p0 >> 32) + (tommy_uint32_t)p2;
308 tommy_uint64_t low = (middle << 32) | (tommy_uint32_t)p0;
309 tommy_uint64_t high = p3 + (middle >> 32) + (p2 >> 32);
310 *A = low;
311 *B = high;
312}
313#endif
314
315#endif
316
void tommy_mum(tommy_uint64_t *A, tommy_uint64_t *B)
Multiplies two 64-bit unsigned numbers to obtain the full 128-bit product.
Definition: tommyhash.h:293
tommy_uint64_t tommy_strhash_u64(tommy_uint64_t init_val, const void *void_key)
String hash function with a 64-bit result.
Definition: tommyhash.h:129
tommy_uint32_t tommy_strhash_u32(tommy_uint32_t init_val, const void *void_key)
String hash function with a 32-bit result.
Definition: tommyhash.h:107
TOMMY_API tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void *void_key, tommy_size_t key_len)
Hash function with a 64-bit result.
tommy_uint64_t tommy_inthash_u64(tommy_uint64_t key)
Reversible 64-bit integer hash function.
Definition: tommyhash.h:161
TOMMY_API tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void *void_key, tommy_size_t key_len)
Hash function with a 32-bit result.
tommy_uint32_t tommy_mulhash_u32(tommy_uint32_t key)
Reversible 32-bit integer hash function using multiplications.
Definition: tommyhash.h:183
tommy_uint32_t tommy_inthash_u32(tommy_uint32_t key)
Reversible 32-bit integer hash function.
Definition: tommyhash.h:141
tommy_uint64_t tommy_mulhash_u64(tommy_uint64_t key)
Reversible 64-bit integer hash function using multiplications.
Definition: tommyhash.h:204
Generic types.
uint64_t tommy_uint64_t
Generic uint64_t type.
Definition: tommytypes.h:35
uint32_t tommy_uint32_t
Generic uint32_t type.
Definition: tommytypes.h:34
uint64_t tommy_size_t
Generic size_t type.
Definition: tommytypes.h:40