Merge branch 'directory-operation' of https://github.com/friendy-su/fio
[fio.git] / hash.h
CommitLineData
bdc7211e
JA
1#ifndef _LINUX_HASH_H
2#define _LINUX_HASH_H
daaa166f 3
dadf66c5 4#include <inttypes.h>
daaa166f 5#include "arch/arch.h"
db83b0ab 6#include "compiler/compiler.h"
daaa166f 7
bdc7211e
JA
8/* Fast hashing routine for a long.
9 (C) 2002 William Lee Irwin III, IBM */
10
11/*
2078c136
JA
12 * Although a random odd number will do, it turns out that the golden
13 * ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice
14 * properties.
15 *
16 * These are the negative, (1 - phi) = (phi^2) = (3 - sqrt(5))/2.
17 * (See Knuth vol 3, section 6.4, exercise 9.)
18 */
19#define GOLDEN_RATIO_32 0x61C88647
20#define GOLDEN_RATIO_64 0x61C8864680B583EBull
a5a4fdfd 21
1bd4cb6b 22static inline unsigned long __hash_long(uint64_t val)
bdc7211e 23{
1bd4cb6b 24 uint64_t hash = val;
bdc7211e
JA
25
26#if BITS_PER_LONG == 64
2078c136
JA
27 hash *= GOLDEN_RATIO_64;
28#else
bdc7211e 29 /* Sigh, gcc can't optimise this alone like it does for 32 bits. */
1bd4cb6b 30 uint64_t n = hash;
bdc7211e
JA
31 n <<= 18;
32 hash -= n;
33 n <<= 33;
34 hash -= n;
35 n <<= 3;
36 hash += n;
37 n <<= 3;
38 hash -= n;
39 n <<= 4;
40 hash += n;
41 n <<= 2;
42 hash += n;
bdc7211e
JA
43#endif
44
ed1860cd
JA
45 return hash;
46}
47
48static inline unsigned long hash_long(unsigned long val, unsigned int bits)
49{
bdc7211e 50 /* High bits are more random, so use them. */
ed1860cd 51 return __hash_long(val) >> (BITS_PER_LONG - bits);
bdc7211e 52}
a5a4fdfd
JA
53
54static inline uint64_t __hash_u64(uint64_t val)
55{
2078c136 56 return val * GOLDEN_RATIO_64;
a5a4fdfd 57}
bdc7211e
JA
58
59static inline unsigned long hash_ptr(void *ptr, unsigned int bits)
60{
e43606c2 61 return hash_long((uintptr_t)ptr, bits);
bdc7211e 62}
dadf66c5
JA
63
64/*
65 * Bob Jenkins jhash
66 */
67
2078c136 68#define JHASH_INITVAL GOLDEN_RATIO_32
dadf66c5
JA
69
70static inline uint32_t rol32(uint32_t word, uint32_t shift)
71{
72 return (word << shift) | (word >> (32 - shift));
73}
74
75/* __jhash_mix -- mix 3 32-bit values reversibly. */
76#define __jhash_mix(a, b, c) \
77{ \
78 a -= c; a ^= rol32(c, 4); c += b; \
79 b -= a; b ^= rol32(a, 6); a += c; \
80 c -= b; c ^= rol32(b, 8); b += a; \
81 a -= c; a ^= rol32(c, 16); c += b; \
82 b -= a; b ^= rol32(a, 19); a += c; \
83 c -= b; c ^= rol32(b, 4); b += a; \
84}
85
86/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
87#define __jhash_final(a, b, c) \
88{ \
89 c ^= b; c -= rol32(b, 14); \
90 a ^= c; a -= rol32(c, 11); \
91 b ^= a; b -= rol32(a, 25); \
92 c ^= b; c -= rol32(b, 16); \
93 a ^= c; a -= rol32(c, 4); \
94 b ^= a; b -= rol32(a, 14); \
95 c ^= b; c -= rol32(b, 24); \
96}
97
98static inline uint32_t jhash(const void *key, uint32_t length, uint32_t initval)
99{
100 const uint8_t *k = key;
101 uint32_t a, b, c;
102
103 /* Set up the internal state */
104 a = b = c = JHASH_INITVAL + length + initval;
105
106 /* All but the last block: affect some 32 bits of (a,b,c) */
107 while (length > 12) {
108 a += *k;
109 b += *(k + 4);
110 c += *(k + 8);
111 __jhash_mix(a, b, c);
112 length -= 12;
113 k += 12;
114 }
115
116 /* Last block: affect all 32 bits of (c) */
117 /* All the case statements fall through */
118 switch (length) {
87933e32
JA
119 case 12: c += (uint32_t) k[11] << 24; fio_fallthrough;
120 case 11: c += (uint32_t) k[10] << 16; fio_fallthrough;
121 case 10: c += (uint32_t) k[9] << 8; fio_fallthrough;
122 case 9: c += k[8]; fio_fallthrough;
123 case 8: b += (uint32_t) k[7] << 24; fio_fallthrough;
124 case 7: b += (uint32_t) k[6] << 16; fio_fallthrough;
125 case 6: b += (uint32_t) k[5] << 8; fio_fallthrough;
126 case 5: b += k[4]; fio_fallthrough;
127 case 4: a += (uint32_t) k[3] << 24; fio_fallthrough;
128 case 3: a += (uint32_t) k[2] << 16; fio_fallthrough;
129 case 2: a += (uint32_t) k[1] << 8; fio_fallthrough;
dadf66c5
JA
130 case 1: a += k[0];
131 __jhash_final(a, b, c);
87933e32 132 fio_fallthrough;
dadf66c5
JA
133 case 0: /* Nothing left to add */
134 break;
135 }
136
137 return c;
138}
139
bdc7211e 140#endif /* _LINUX_HASH_H */