Feature #12142 » city.patch
| st.c | ||
|---|---|---|
| st_data_t never ATTRIBUTE_UNUSED) { | ||
| return st_general_values(tab, values, size); | ||
| } | ||
| /* | ||
| * hash_32 - 32 bit Fowler/Noll/Vo FNV-1a hash code | ||
| * | ||
| * @(#) $Hash32: Revision: 1.1 $ | ||
| * @(#) $Hash32: Id: hash_32a.c,v 1.1 2003/10/03 20:38:53 chongo Exp $ | ||
| * @(#) $Hash32: Source: /usr/local/src/cmd/fnv/RCS/hash_32a.c,v $ | ||
| * | ||
| *** | ||
| * | ||
| * Fowler/Noll/Vo hash | ||
| * | ||
| * The basis of this hash algorithm was taken from an idea sent | ||
| * as reviewer comments to the IEEE POSIX P1003.2 committee by: | ||
| * | ||
| * Phong Vo (http://www.research.att.com/info/kpv/) | ||
| * Glenn Fowler (http://www.research.att.com/~gsf/) | ||
| * | ||
| * In a subsequent ballot round: | ||
| * | ||
| * Landon Curt Noll (http://www.isthe.com/chongo/) | ||
| * | ||
| * improved on their algorithm. Some people tried this hash | ||
| * and found that it worked rather well. In an EMail message | ||
| * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash. | ||
| * | ||
| * FNV hashes are designed to be fast while maintaining a low | ||
| * collision rate. The FNV speed allows one to quickly hash lots | ||
| * of data while maintaining a reasonable collision rate. See: | ||
| * | ||
| * http://www.isthe.com/chongo/tech/comp/fnv/index.html | ||
| * | ||
| * for more details as well as other forms of the FNV hash. | ||
| *** | ||
| * | ||
| * To use the recommended 32 bit FNV-1a hash, pass FNV1_32A_INIT as the | ||
| * Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_str(). | ||
| * | ||
| *** | ||
| * | ||
| * Please do not copyright this code. This code is in the public domain. | ||
| * | ||
| * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
| * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO | ||
| * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
| * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF | ||
| * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
| * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
| * PERFORMANCE OF THIS SOFTWARE. | ||
| * | ||
| * By: | ||
| * chongo <Landon Curt Noll> /\oo/\ | ||
| * http://www.isthe.com/chongo/ | ||
| * | ||
| * Share and Enjoy! :-) | ||
| */ | ||
| /* | ||
| * 32 bit FNV-1 and FNV-1a non-zero initial basis | ||
| * | ||
| * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets: | ||
| * | ||
| * chongo <Landon Curt Noll> /\../\ | ||
| * | ||
| * NOTE: The \'s above are not back-slashing escape characters. | ||
| * They are literal ASCII backslash 0x5c characters. | ||
| * | ||
| * NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition. | ||
| */ | ||
| #define FNV1_32A_INIT 0x811c9dc5 | ||
| /* Copyright (c) 2011 Google, Inc. | ||
| | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
| | ||
| The above copyright notice and this permission notice shall be included in | ||
| all copies or substantial portions of the Software. | ||
| | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| THE SOFTWARE. | ||
| | ||
| CityHash, by Geoff Pike and Jyrki Alakuijala | ||
| | ||
| This file provides CityHash64() and related functions. | ||
| | ||
| It's probably possible to create even faster hash functions by | ||
| writing a program that systematically explores some of the space of | ||
| possible hash functions, by using SIMD instructions, or by | ||
| compromising on hash quality. */ | ||
| static inline uint64_t Uint128Low64(uint64_t x, uint64_t y) { return x; } | ||
| static inline uint64_t Uint128High64(uint64_t x, uint64_t y) { return y; } | ||
| /* Hash 128 input bits down to 64 bits of output. This is intended to | ||
| be a reasonably good hash function. */ | ||
| static inline uint64_t | ||
| Hash128to64(uint64_t first, uint64_t second) { | ||
| /* Murmur-inspired hashing. */ | ||
| const uint64_t kMul = 0x9ddfea08eb382d69ULL; | ||
| uint64_t b, a = (Uint128Low64(first, second) ^ Uint128High64(first, second)) * kMul; | ||
| a ^= (a >> 47); | ||
| b = (Uint128High64(first, second) ^ a) * kMul; | ||
| b ^= (b >> 47); | ||
| b *= kMul; | ||
| return b; | ||
| } | ||
| static uint64_t | ||
| UNALIGNED_LOAD64(const char *p) { | ||
| uint64_t result; | ||
| | ||
| memcpy(&result, p, sizeof(result)); | ||
| return result; | ||
| } | ||
| /* | ||
| * 32 bit magic FNV-1a prime | ||
| */ | ||
| #define FNV_32_PRIME 0x01000193 | ||
| static uint32_t | ||
| UNALIGNED_LOAD32(const char *p) { | ||
| uint32_t result; | ||
| | ||
| memcpy(&result, p, sizeof(result)); | ||
| return result; | ||
| } | ||
| #ifdef ST_USE_FNV1 | ||
| static st_index_t | ||
| strhash(st_data_t arg) | ||
| { | ||
| register const char *string = (const char *)arg; | ||
| register st_index_t hval = FNV1_32A_INIT; | ||
| #ifndef __BIG_ENDIAN__ | ||
| /* | ||
| * FNV-1a hash each octet in the buffer | ||
| */ | ||
| while (*string) { | ||
| /* xor the bottom with the current octet */ | ||
| hval ^= (unsigned int)*string++; | ||
| #define uint32_in_expected_order(x) (x) | ||
| #define uint64_in_expected_order(x) (x) | ||
| /* multiply by the 32 bit FNV magic prime mod 2^32 */ | ||
| hval *= FNV_32_PRIME; | ||
| } | ||
| return hval; | ||
| } | ||
| #else | ||
| #if !defined(UNALIGNED_WORD_ACCESS) && defined(__GNUC__) && __GNUC__ >= 6 | ||
| # define UNALIGNED_WORD_ACCESS 0 | ||
| #endif | ||
| #ifdef _MSC_VER | ||
| #include <stdlib.h> | ||
| #define bswap_32(x) _byteswap_ulong(x) | ||
| #define bswap_64(x) _byteswap_uint64_t(x) | ||
| #ifndef UNALIGNED_WORD_ACCESS | ||
| # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ | ||
| defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \ | ||
| defined(__powerpc64__) || \ | ||
| defined(__mc68020__) | ||
| # define UNALIGNED_WORD_ACCESS 1 | ||
| # endif | ||
| #endif | ||
| #ifndef UNALIGNED_WORD_ACCESS | ||
| # define UNALIGNED_WORD_ACCESS 0 | ||
| #endif | ||
| #elif defined(__APPLE__) | ||
| /* Mac OS X / Darwin features: */ | ||
| #include <libkern/OSByteOrder.h> | ||
| #define bswap_32(x) OSSwapInt32(x) | ||
| #define bswap_64(x) OSSwapInt64(x) | ||
| /* MurmurHash described in http://murmurhash.googlepages.com/ */ | ||
| #ifndef MURMUR | ||
| #define MURMUR 2 | ||
| #else | ||
| #include <byteswap.h> | ||
| #endif | ||
| #define MurmurMagic_1 (st_index_t)0xc6a4a793 | ||
| #define MurmurMagic_2 (st_index_t)0x5bd1e995 | ||
| #if MURMUR == 1 | ||
| #define MurmurMagic MurmurMagic_1 | ||
| #elif MURMUR == 2 | ||
| #if SIZEOF_ST_INDEX_T > 4 | ||
| #define MurmurMagic ((MurmurMagic_1 << 32) | MurmurMagic_2) | ||
| #define uint32_in_expected_order(x) (bswap_32(x)) | ||
| #define uint64_in_expected_order(x) (bswap_64(x)) | ||
| #endif /* __BIG_ENDIAN__ */ | ||
| #if !defined(LIKELY) | ||
| #if defined(__GNUC__) || defined(__INTEL_COMPILER) | ||
| #define LIKELY(x) (__builtin_expect(!!(x), 1)) | ||
| #else | ||
| #define MurmurMagic MurmurMagic_2 | ||
| #define LIKELY(x) (x) | ||
| #endif | ||
| #endif | ||
| static inline st_index_t | ||
| murmur(st_index_t h, st_index_t k, int r) | ||
| { | ||
| const st_index_t m = MurmurMagic; | ||
| #if MURMUR == 1 | ||
| h += k; | ||
| h *= m; | ||
| h ^= h >> r; | ||
| #elif MURMUR == 2 | ||
| k *= m; | ||
| k ^= k >> r; | ||
| k *= m; | ||
| h *= m; | ||
| h ^= k; | ||
| #endif | ||
| return h; | ||
| static uint64_t | ||
| Fetch64(const char *p) { | ||
| return uint64_in_expected_order(UNALIGNED_LOAD64(p)); | ||
| } | ||
| static inline st_index_t | ||
| murmur_finish(st_index_t h) | ||
| { | ||
| #if MURMUR == 1 | ||
| h = murmur(h, 0, 10); | ||
| h = murmur(h, 0, 17); | ||
| #elif MURMUR == 2 | ||
| h ^= h >> 13; | ||
| h *= MurmurMagic; | ||
| h ^= h >> 15; | ||
| #endif | ||
| return h; | ||
| static uint32_t | ||
| Fetch32(const char *p) { | ||
| return uint32_in_expected_order(UNALIGNED_LOAD32(p)); | ||
| } | ||
| #define murmur_step(h, k) murmur((h), (k), 16) | ||
| /* Some primes between 2^63 and 2^64 for various uses. */ | ||
| static const uint64_t k0 = 0xc3a5c85c97cb3127ULL; | ||
| static const uint64_t k1 = 0xb492b66fbe98f273ULL; | ||
| static const uint64_t k2 = 0x9ae16a3b2f90404fULL; | ||
| static const uint64_t k3 = 0xc949d7c7509e6557ULL; | ||
| #if MURMUR == 1 | ||
| #define murmur1(h) murmur_step((h), 16) | ||
| #else | ||
| #define murmur1(h) murmur_step((h), 24) | ||
| #endif | ||
| st_index_t | ||
| st_hash(const void *ptr, size_t len, st_index_t h) | ||
| { | ||
| const char *data = ptr; | ||
| st_index_t t = 0; | ||
| h += 0xdeadbeef; | ||
| #define data_at(n) (st_index_t)((unsigned char)data[(n)]) | ||
| #define UNALIGNED_ADD_4 UNALIGNED_ADD(2); UNALIGNED_ADD(1); UNALIGNED_ADD(0) | ||
| #if SIZEOF_ST_INDEX_T > 4 | ||
| #define UNALIGNED_ADD_8 UNALIGNED_ADD(6); UNALIGNED_ADD(5); UNALIGNED_ADD(4); UNALIGNED_ADD(3); UNALIGNED_ADD_4 | ||
| #if SIZEOF_ST_INDEX_T > 8 | ||
| #define UNALIGNED_ADD_16 UNALIGNED_ADD(14); UNALIGNED_ADD(13); UNALIGNED_ADD(12); UNALIGNED_ADD(11); \ | ||
| UNALIGNED_ADD(10); UNALIGNED_ADD(9); UNALIGNED_ADD(8); UNALIGNED_ADD(7); UNALIGNED_ADD_8 | ||
| #define UNALIGNED_ADD_ALL UNALIGNED_ADD_16 | ||
| #endif | ||
| #define UNALIGNED_ADD_ALL UNALIGNED_ADD_8 | ||
| #else | ||
| #define UNALIGNED_ADD_ALL UNALIGNED_ADD_4 | ||
| #endif | ||
| if (len >= sizeof(st_index_t)) { | ||
| #if !UNALIGNED_WORD_ACCESS | ||
| int align = (int)((st_data_t)data % sizeof(st_index_t)); | ||
| if (align) { | ||
| st_index_t d = 0; | ||
| int sl, sr, pack; | ||
| switch (align) { | ||
| #ifdef WORDS_BIGENDIAN | ||
| # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \ | ||
| t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 2) | ||
| #else | ||
| # define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \ | ||
| t |= data_at(n) << CHAR_BIT*(n) | ||
| #endif | ||
| UNALIGNED_ADD_ALL; | ||
| #undef UNALIGNED_ADD | ||
| } | ||
| #ifdef WORDS_BIGENDIAN | ||
| t >>= (CHAR_BIT * align) - CHAR_BIT; | ||
| #else | ||
| t <<= (CHAR_BIT * align); | ||
| #endif | ||
| data += sizeof(st_index_t)-align; | ||
| len -= sizeof(st_index_t)-align; | ||
| /* Bitwise right rotate. Normally this will compile to a single | ||
| instruction, especially if the shift is a manifest constant. */ | ||
| static uint64_t | ||
| Rotate(uint64_t val, int shift) { | ||
| /* Avoid shifting by 64: doing so yields an undefined result. */ | ||
| return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); | ||
| } | ||
| sl = CHAR_BIT * (SIZEOF_ST_INDEX_T-align); | ||
| sr = CHAR_BIT * align; | ||
| /* Equivalent to Rotate(), but requires the second arg to be non-zero. | ||
| On x86-64, and probably others, it's possible for this to compile | ||
| to a single instruction if both args are already in registers. */ | ||
| static uint64_t | ||
| RotateByAtLeast1(uint64_t val, int shift) { | ||
| return (val >> shift) | (val << (64 - shift)); | ||
| } | ||
| while (len >= sizeof(st_index_t)) { | ||
| d = *(st_index_t *)data; | ||
| #ifdef WORDS_BIGENDIAN | ||
| t = (t << sr) | (d >> sl); | ||
| #else | ||
| t = (t >> sr) | (d << sl); | ||
| #endif | ||
| h = murmur_step(h, t); | ||
| t = d; | ||
| data += sizeof(st_index_t); | ||
| len -= sizeof(st_index_t); | ||
| } | ||
| static uint64_t | ||
| ShiftMix(uint64_t val) { | ||
| return val ^ (val >> 47); | ||
| } | ||
| pack = len < (size_t)align ? (int)len : align; | ||
| d = 0; | ||
| switch (pack) { | ||
| #ifdef WORDS_BIGENDIAN | ||
| # define UNALIGNED_ADD(n) case (n) + 1: \ | ||
| d |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1) | ||
| #else | ||
| # define UNALIGNED_ADD(n) case (n) + 1: \ | ||
| d |= data_at(n) << CHAR_BIT*(n) | ||
| #endif | ||
| UNALIGNED_ADD_ALL; | ||
| #undef UNALIGNED_ADD | ||
| } | ||
| #ifdef WORDS_BIGENDIAN | ||
| t = (t << sr) | (d >> sl); | ||
| #else | ||
| t = (t >> sr) | (d << sl); | ||
| #endif | ||
| static uint64_t | ||
| HashLen16(uint64_t u, uint64_t v) { | ||
| return Hash128to64(u, v); | ||
| } | ||
| #if MURMUR == 2 | ||
| if (len < (size_t)align) goto skip_tail; | ||
| #endif | ||
| h = murmur_step(h, t); | ||
| data += pack; | ||
| len -= pack; | ||
| } | ||
| else | ||
| #endif | ||
| { | ||
| do { | ||
| h = murmur_step(h, *(st_index_t *)data); | ||
| data += sizeof(st_index_t); | ||
| len -= sizeof(st_index_t); | ||
| } while (len >= sizeof(st_index_t)); | ||
| static uint64_t | ||
| HashLen0to16(const char *s, size_t len) { | ||
| if (len > 8) { | ||
| uint64_t a = Fetch64(s); | ||
| uint64_t b = Fetch64(s + len - 8); | ||
| return HashLen16(a, RotateByAtLeast1(b + len, len)) ^ b; | ||
| } | ||
| if (len >= 4) { | ||
| uint64_t a = Fetch32(s); | ||
| return HashLen16(len + (a << 3), Fetch32(s + len - 4)); | ||
| } | ||
| if (len > 0) { | ||
| uint8_t a = s[0]; | ||
| uint8_t b = s[len >> 1]; | ||
| uint8_t c = s[len - 1]; | ||
| uint32_t y = ((uint32_t)(a) + (uint32_t)(b) << 8); | ||
| uint32_t z = len + ((uint32_t)(c) << 2); | ||
| return ShiftMix(y * k2 ^ z * k3) * k2; | ||
| } | ||
| return k2; | ||
| } | ||
| /* This probably works well for 16-byte strings as well, but it may be | ||
| overkill in that case. */ | ||
| static uint64_t | ||
| HashLen17to32(const char *s, size_t len) { | ||
| uint64_t a = Fetch64(s) * k1; | ||
| uint64_t b = Fetch64(s + 8); | ||
| uint64_t c = Fetch64(s + len - 8) * k2; | ||
| uint64_t d = Fetch64(s + len - 16) * k0; | ||
| return HashLen16(Rotate(a - b, 43) + Rotate(c, 30) + d, | ||
| a + Rotate(b ^ k3, 20) - c + len); | ||
| } | ||
| typedef struct pair64 {uint64_t first, second;} pair64; | ||
| /* Return a 16-byte hash for 48 bytes. Quick and dirty. | ||
| Callers do best to use "random-looking" values for a and b. */ | ||
| static pair64 | ||
| WeakHashLen32WithSeeds0(uint64_t w, uint64_t x, uint64_t y, uint64_t z, | ||
| uint64_t a, uint64_t b) { | ||
| pair64 res; | ||
| uint64_t c; | ||
| a += w; | ||
| b = Rotate(b + a + z, 21); | ||
| c = a; | ||
| a += x; | ||
| a += y; | ||
| b += Rotate(a, 44); | ||
| res.first = a + z; res.second = b + c; | ||
| return res; | ||
| } | ||
| /* Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. */ | ||
| static pair64 | ||
| WeakHashLen32WithSeeds(const char* s, uint64_t a, uint64_t b) { | ||
| return WeakHashLen32WithSeeds0(Fetch64(s), | ||
| Fetch64(s + 8), | ||
| Fetch64(s + 16), | ||
| Fetch64(s + 24), | ||
| a, | ||
| b); | ||
| } | ||
| /* Return an 8-byte hash for 33 to 64 bytes. */ | ||
| static uint64_t | ||
| HashLen33to64(const char *s, size_t len) { | ||
| uint64_t z = Fetch64(s + 24); | ||
| uint64_t a = Fetch64(s) + (len + Fetch64(s + len - 16)) * k0; | ||
| uint64_t b = Rotate(a + z, 52); | ||
| uint64_t c = Rotate(a, 37); | ||
| uint64_t vf, vs, wf, ws, r; | ||
| | ||
| a += Fetch64(s + 8); | ||
| c += Rotate(a, 7); | ||
| a += Fetch64(s + 16); | ||
| vf = a + z; | ||
| vs = b + Rotate(a, 31) + c; | ||
| a = Fetch64(s + 16) + Fetch64(s + len - 32); | ||
| z = Fetch64(s + len - 8); | ||
| b = Rotate(a + z, 52); | ||
| c = Rotate(a, 37); | ||
| a += Fetch64(s + len - 24); | ||
| c += Rotate(a, 7); | ||
| a += Fetch64(s + len - 16); | ||
| wf = a + z; | ||
| ws = b + Rotate(a, 31) + c; | ||
| r = ShiftMix((vf + ws) * k2 + (wf + vs) * k0); | ||
| return ShiftMix(r * k0 + vs) * k2; | ||
| } | ||
| static uint64_t | ||
| CityHash64(const char *s, size_t len) { | ||
| uint64_t x, y, z, t; | ||
| pair64 v, w; | ||
| if (len <= 32) { | ||
| if (len <= 16) { | ||
| return HashLen0to16(s, len); | ||
| } else { | ||
| return HashLen17to32(s, len); | ||
| } | ||
| } else if (len <= 64) { | ||
| return HashLen33to64(s, len); | ||
| } | ||
| | ||
| /* For strings over 64 bytes we hash the end first, and then as we | ||
| loop we keep 56 bytes of state: v, w, x, y, and z. */ | ||
| x = Fetch64(s + len - 40); | ||
| y = Fetch64(s + len - 16) + Fetch64(s + len - 56); | ||
| z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24)); | ||
| v = WeakHashLen32WithSeeds(s + len - 64, len, z); | ||
| w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x); | ||
| x = x * k1 + Fetch64(s); | ||
| | ||
| /* Decrease len to the nearest multiple of 64, and operate on | ||
| 64-byte chunks. */ | ||
| len = (len - 1) & ~(size_t)(63); | ||
| do { | ||
| x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1; | ||
| y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1; | ||
| x ^= w.second; | ||
| y += v.first + Fetch64(s + 40); | ||
| z = Rotate(z + w.first, 33) * k1; | ||
| v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); | ||
| w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16)); | ||
| t = x; x = z; z = t; | ||
| s += 64; | ||
| len -= 64; | ||
| } while (len != 0); | ||
| return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z, | ||
| HashLen16(v.second, w.second) + x); | ||
| } | ||
| t = 0; | ||
| switch (len) { | ||
| #ifdef WORDS_BIGENDIAN | ||
| # define UNALIGNED_ADD(n) case (n) + 1: \ | ||
| t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1) | ||
| #else | ||
| # define UNALIGNED_ADD(n) case (n) + 1: \ | ||
| t |= data_at(n) << CHAR_BIT*(n) | ||
| #endif | ||
| UNALIGNED_ADD_ALL; | ||
| #undef UNALIGNED_ADD | ||
| #if MURMUR == 1 | ||
| h = murmur_step(h, t); | ||
| #elif MURMUR == 2 | ||
| # if !UNALIGNED_WORD_ACCESS | ||
| skip_tail: | ||
| # endif | ||
| h ^= t; | ||
| h *= MurmurMagic; | ||
| #endif | ||
| } | ||
| return murmur_finish(h); | ||
| static uint64_t | ||
| CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { | ||
| return HashLen16(CityHash64(s, len) - seed0, seed1); | ||
| } | ||
| static uint64_t | ||
| CityHash64WithSeed(const char *s, size_t len, uint64_t seed) { | ||
| return CityHash64WithSeeds(s, len, k2, seed); | ||
| } | ||
| st_index_t | ||
| st_hash_uint32(st_index_t h, uint32_t i) | ||
| { | ||
| return murmur_step(h + i, 16); | ||
| st_hash(const void *ptr, size_t len, st_index_t h) { | ||
| return CityHash64WithSeed(ptr, len, h); | ||
| } | ||
| static st_index_t | ||
| strhash(st_data_t arg) { | ||
| const char *string = (const char *)arg; | ||
| return CityHash64(string, strlen(string)); | ||
| } | ||
| st_index_t | ||
| st_hash_uint(st_index_t h, st_index_t i) | ||
| { | ||
| st_index_t v = 0; | ||
| h += i; | ||
| #ifdef WORDS_BIGENDIAN | ||
| #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8 | ||
| v = murmur1(v + (h >> 12*8)); | ||
| #endif | ||
| #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8 | ||
| v = murmur1(v + (h >> 8*8)); | ||
| #endif | ||
| #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8 | ||
| v = murmur1(v + (h >> 4*8)); | ||
| #endif | ||
| #endif | ||
| v = murmur1(v + h); | ||
| #ifndef WORDS_BIGENDIAN | ||
| #if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8 | ||
| v = murmur1(v + (h >> 4*8)); | ||
| #endif | ||
| #if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8 | ||
| v = murmur1(v + (h >> 8*8)); | ||
| #endif | ||
| #if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8 | ||
| v = murmur1(v + (h >> 12*8)); | ||
| #endif | ||
| #endif | ||
| return v; | ||
| st_hash_uint(st_index_t h, st_index_t i) { | ||
| return CityHash64WithSeed((const char *) &i, sizeof (st_index_t), h); | ||
| } | ||
| st_index_t | ||
| st_hash_end(st_index_t h) | ||
| { | ||
| h = murmur_step(h, 10); | ||
| h = murmur_step(h, 17); | ||
| st_hash_end(st_index_t h) { | ||
| return h; | ||
| } | ||
| #undef st_hash_start | ||
| st_index_t | ||
| st_hash_start(st_index_t h) | ||
| { | ||
| st_hash_start(st_index_t h) { | ||
| return h; | ||
| } | ||
| static st_index_t | ||
| strhash(st_data_t arg) | ||
| { | ||
| register const char *string = (const char *)arg; | ||
| return st_hash(string, strlen(string), FNV1_32A_INIT); | ||
| } | ||
| #endif | ||
| /* | ||
| * 32 bit FNV-1 and FNV-1a non-zero initial basis | ||
| * | ||
| * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets: | ||
| * | ||
| * chongo <Landon Curt Noll> /\../\ | ||
| * | ||
| * NOTE: The \'s above are not back-slashing escape characters. | ||
| * They are literal ASCII backslash 0x5c characters. | ||
| * | ||
| * NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition. | ||
| */ | ||
| #define FNV1_32A_INIT 0x811c9dc5 | ||
| /* | ||
| * 32 bit magic FNV-1a prime | ||
| */ | ||
| #define FNV_32_PRIME 0x01000193 | ||
| int | ||
| st_locale_insensitive_strcasecmp(const char *s1, const char *s2) | ||