microsoft/onnxruntime-extensions
Publicmirrored from https://github.com/microsoft/onnxruntime-extensionsAvailable
cmake/externals/farmhash/dev/farmhashna.cc
169lines · modecode
| 1 | #undef Fetch |
| 2 | #define Fetch Fetch64 |
| 3 | |
| 4 | #undef Rotate |
| 5 | #define Rotate Rotate64 |
| 6 | |
| 7 | #undef Bswap |
| 8 | #define Bswap Bswap64 |
| 9 | |
| 10 | STATIC_INLINE uint64_t ShiftMix(uint64_t val) { |
| 11 | return val ^ (val >> 47); |
| 12 | } |
| 13 | |
| 14 | STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v) { |
| 15 | return Hash128to64(Uint128(u, v)); |
| 16 | } |
| 17 | |
| 18 | STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) { |
| 19 | // Murmur-inspired hashing. |
| 20 | uint64_t a = (u ^ v) * mul; |
| 21 | a ^= (a >> 47); |
| 22 | uint64_t b = (v ^ a) * mul; |
| 23 | b ^= (b >> 47); |
| 24 | b *= mul; |
| 25 | return b; |
| 26 | } |
| 27 | |
| 28 | STATIC_INLINE uint64_t HashLen0to16(const char *s, size_t len) { |
| 29 | if (len >= 8) { |
| 30 | uint64_t mul = k2 + len * 2; |
| 31 | uint64_t a = Fetch(s) + k2; |
| 32 | uint64_t b = Fetch(s + len - 8); |
| 33 | uint64_t c = Rotate(b, 37) * mul + a; |
| 34 | uint64_t d = (Rotate(a, 25) + b) * mul; |
| 35 | return HashLen16(c, d, mul); |
| 36 | } |
| 37 | if (len >= 4) { |
| 38 | uint64_t mul = k2 + len * 2; |
| 39 | uint64_t a = Fetch32(s); |
| 40 | return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul); |
| 41 | } |
| 42 | if (len > 0) { |
| 43 | uint8_t a = s[0]; |
| 44 | uint8_t b = s[len >> 1]; |
| 45 | uint8_t c = s[len - 1]; |
| 46 | uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8); |
| 47 | uint32_t z = len + (static_cast<uint32_t>(c) << 2); |
| 48 | return ShiftMix(y * k2 ^ z * k0) * k2; |
| 49 | } |
| 50 | return k2; |
| 51 | } |
| 52 | |
| 53 | // This probably works well for 16-byte strings as well, but it may be overkill |
| 54 | // in that case. |
| 55 | STATIC_INLINE uint64_t HashLen17to32(const char *s, size_t len) { |
| 56 | uint64_t mul = k2 + len * 2; |
| 57 | uint64_t a = Fetch(s) * k1; |
| 58 | uint64_t b = Fetch(s + 8); |
| 59 | uint64_t c = Fetch(s + len - 8) * mul; |
| 60 | uint64_t d = Fetch(s + len - 16) * k2; |
| 61 | return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, |
| 62 | a + Rotate(b + k2, 18) + c, mul); |
| 63 | } |
| 64 | |
| 65 | // Return a 16-byte hash for 48 bytes. Quick and dirty. |
| 66 | // Callers do best to use "random-looking" values for a and b. |
| 67 | STATIC_INLINE pair<uint64_t, uint64_t> WeakHashLen32WithSeeds( |
| 68 | uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) { |
| 69 | a += w; |
| 70 | b = Rotate(b + a + z, 21); |
| 71 | uint64_t c = a; |
| 72 | a += x; |
| 73 | a += y; |
| 74 | b += Rotate(a, 44); |
| 75 | return make_pair(a + z, b + c); |
| 76 | } |
| 77 | |
| 78 | // Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. |
| 79 | STATIC_INLINE pair<uint64_t, uint64_t> WeakHashLen32WithSeeds( |
| 80 | const char* s, uint64_t a, uint64_t b) { |
| 81 | return WeakHashLen32WithSeeds(Fetch(s), |
| 82 | Fetch(s + 8), |
| 83 | Fetch(s + 16), |
| 84 | Fetch(s + 24), |
| 85 | a, |
| 86 | b); |
| 87 | } |
| 88 | |
| 89 | // Return an 8-byte hash for 33 to 64 bytes. |
| 90 | STATIC_INLINE uint64_t HashLen33to64(const char *s, size_t len) { |
| 91 | uint64_t mul = k2 + len * 2; |
| 92 | uint64_t a = Fetch(s) * k2; |
| 93 | uint64_t b = Fetch(s + 8); |
| 94 | uint64_t c = Fetch(s + len - 8) * mul; |
| 95 | uint64_t d = Fetch(s + len - 16) * k2; |
| 96 | uint64_t y = Rotate(a + b, 43) + Rotate(c, 30) + d; |
| 97 | uint64_t z = HashLen16(y, a + Rotate(b + k2, 18) + c, mul); |
| 98 | uint64_t e = Fetch(s + 16) * mul; |
| 99 | uint64_t f = Fetch(s + 24); |
| 100 | uint64_t g = (y + Fetch(s + len - 32)) * mul; |
| 101 | uint64_t h = (z + Fetch(s + len - 24)) * mul; |
| 102 | return HashLen16(Rotate(e + f, 43) + Rotate(g, 30) + h, |
| 103 | e + Rotate(f + a, 18) + g, mul); |
| 104 | } |
| 105 | |
| 106 | uint64_t Hash64(const char *s, size_t len) { |
| 107 | const uint64_t seed = 81; |
| 108 | if (len <= 32) { |
| 109 | if (len <= 16) { |
| 110 | return HashLen0to16(s, len); |
| 111 | } else { |
| 112 | return HashLen17to32(s, len); |
| 113 | } |
| 114 | } else if (len <= 64) { |
| 115 | return HashLen33to64(s, len); |
| 116 | } |
| 117 | |
| 118 | // For strings over 64 bytes we loop. Internal state consists of |
| 119 | // 56 bytes: v, w, x, y, and z. |
| 120 | uint64_t x = seed; |
| 121 | uint64_t y = seed * k1 + 113; |
| 122 | uint64_t z = ShiftMix(y * k2 + 113) * k2; |
| 123 | pair<uint64_t, uint64_t> v = make_pair(0, 0); |
| 124 | pair<uint64_t, uint64_t> w = make_pair(0, 0); |
| 125 | x = x * k2 + Fetch(s); |
| 126 | |
| 127 | // Set end so that after the loop we have 1 to 64 bytes left to process. |
| 128 | const char* end = s + ((len - 1) / 64) * 64; |
| 129 | const char* last64 = end + ((len - 1) & 63) - 63; |
| 130 | assert(s + len - 64 == last64); |
| 131 | do { |
| 132 | x = Rotate(x + y + v.first + Fetch(s + 8), 37) * k1; |
| 133 | y = Rotate(y + v.second + Fetch(s + 48), 42) * k1; |
| 134 | x ^= w.second; |
| 135 | y += v.first + Fetch(s + 40); |
| 136 | z = Rotate(z + w.first, 33) * k1; |
| 137 | v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); |
| 138 | w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch(s + 16)); |
| 139 | std::swap(z, x); |
| 140 | s += 64; |
| 141 | } while (s != end); |
| 142 | uint64_t mul = k1 + ((z & 0xff) << 1); |
| 143 | // Make s point to the last 64 bytes of input. |
| 144 | s = last64; |
| 145 | w.first += ((len - 1) & 63); |
| 146 | v.first += w.first; |
| 147 | w.first += v.first; |
| 148 | x = Rotate(x + y + v.first + Fetch(s + 8), 37) * mul; |
| 149 | y = Rotate(y + v.second + Fetch(s + 48), 42) * mul; |
| 150 | x ^= w.second * 9; |
| 151 | y += v.first * 9 + Fetch(s + 40); |
| 152 | z = Rotate(z + w.first, 33) * mul; |
| 153 | v = WeakHashLen32WithSeeds(s, v.second * mul, x + w.first); |
| 154 | w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch(s + 16)); |
| 155 | std::swap(z, x); |
| 156 | return HashLen16(HashLen16(v.first, w.first, mul) + ShiftMix(y) * k0 + z, |
| 157 | HashLen16(v.second, w.second, mul) + x, |
| 158 | mul); |
| 159 | } |
| 160 | |
| 161 | uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1); |
| 162 | |
| 163 | uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { |
| 164 | return Hash64WithSeeds(s, len, k2, seed); |
| 165 | } |
| 166 | |
| 167 | uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { |
| 168 | return HashLen16(Hash64(s, len) - seed0, seed1); |
| 169 | } |
| 170 | |