Sat Apr 30 06:33:16 2016  Vladimir Makarov  <vmakarov@redhat.com>

	* st.c (Uint128Low64, Uint128High64, Hash128to64): New.
	(UNALIGNED_LOAD64): New.
	(UNALIGNED_LOAD32, uint32_in_expected_order): New
	(uint64_in_expected_order, bswap_32, bswap_64, LIKELY, Fetch64):
	New.
	(Fetch32, k0, k1, k2, k3, Rotate, RotateByAtLeast1, ShiftMix):
	New.
	(HashLen16, HashLen0to16, HashLen17to32, pair64): New.
	(WeakHashLen32WithSeeds0, WeakHashLen32WithSeeds, HashLen33to64):
	New.
	(CityHash64, CityHash64WithSeeds, CityHash64WithSeed): New.
	(UNALIGNED_WORD_ACCESS,MurmurMagic_1, MurmurMagic_2, MurmurMagic):
	Remove.
	(murmur, murmur_finish, murmur_step): Remove.
	(UNALIGNED_ADD_4, UNALIGNED_ADD_8, UNALIGNED_ADD_16): Remove.
	(UNALIGNED_ADD_ALL, UNALIGNED_ADD, st_hash_uint32): Remove.
	(strhash, st_hash, st_hash_uint, st_hash_end, st_hash_start):
	Redefine.

diff --git a/st.c b/st.c
index 65811fc..fe15ffd 100644
--- a/st.c
+++ b/st.c
@@ -1603,362 +1603,341 @@ st_values_check(st_table *tab, st_data_t *values, st_index_t size,
 		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)
