/*1* Copyright 2012-2015 Samy Al Bahra2* Copyright 2011-2014 AppNexus, Inc.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#ifndef CK_HT_HASH_H27#define CK_HT_HASH_H2829/*30* This is the Murmur hash written by Austin Appleby.31*/3233#include <ck_stdint.h>34#include <ck_string.h>3536//-----------------------------------------------------------------------------37// MurmurHash3 was written by Austin Appleby, and is placed in the public38// domain. The author hereby disclaims copyright to this source code.3940// Note - The x86 and x64 versions do _not_ produce the same results, as the41// algorithms are optimized for their respective platforms. You can still42// compile and run any of them on any platform, but your performance with the43// non-native version will be less than optimal.4445//-----------------------------------------------------------------------------46// Platform-specific functions and macros4748// Microsoft Visual Studio4950#if defined(_MSC_VER)5152#define FORCE_INLINE __forceinline5354#include <stdlib.h>5556#define ROTL32(x,y) _rotl(x,y)57#define ROTL64(x,y) _rotl64(x,y)5859#define BIG_CONSTANT(x) (x)6061// Other compilers6263#else // defined(_MSC_VER)6465#define FORCE_INLINE inline __attribute__((always_inline))6667static inline uint32_t rotl32 ( uint32_t x, int8_t r )68{69return (x << r) | (x >> (32 - r));70}7172static inline uint64_t rotl64 ( uint64_t x, int8_t r )73{74return (x << r) | (x >> (64 - r));75}7677#define ROTL32(x,y) rotl32(x,y)78#define ROTL64(x,y) rotl64(x,y)7980#define BIG_CONSTANT(x) (x##LLU)8182#endif // !defined(_MSC_VER)8384//-----------------------------------------------------------------------------85// Block read - if your platform needs to do endian-swapping or can only86// handle aligned reads, do the conversion here8788FORCE_INLINE static uint32_t getblock ( const uint32_t * p, int i )89{90#ifdef __s390x__91uint32_t res;9293__asm__ (" lrv %0,%1\n"94: "=r" (res) : "Q" (p[i]) : "cc", "mem");95return res;96#else97return p[i];98#endif /* !__s390x__ */99}100101//-----------------------------------------------------------------------------102// Finalization mix - force all bits of a hash block to avalanche103104FORCE_INLINE static uint32_t fmix ( uint32_t h )105{106h ^= h >> 16;107h *= 0x85ebca6b;108h ^= h >> 13;109h *= 0xc2b2ae35;110h ^= h >> 16;111112return h;113}114115//-----------------------------------------------------------------------------116117static inline void MurmurHash3_x86_32 ( const void * key, int len,118uint32_t seed, uint32_t * out )119{120const uint8_t * data = (const uint8_t*)key;121const int nblocks = len / 4;122int i;123124uint32_t h1 = seed;125126uint32_t c1 = 0xcc9e2d51;127uint32_t c2 = 0x1b873593;128129//----------130// body131132const uint32_t * blocks = (const uint32_t *)(const void *)(data + nblocks*4);133134for(i = -nblocks; i; i++)135{136uint32_t k1 = getblock(blocks,i);137138k1 *= c1;139k1 = ROTL32(k1,15);140k1 *= c2;141142h1 ^= k1;143h1 = ROTL32(h1,13);144h1 = h1*5+0xe6546b64;145}146147//----------148// tail149150const uint8_t * tail = (const uint8_t*)(data + nblocks*4);151152uint32_t k1 = 0;153154switch(len & 3)155{156case 3: k1 ^= tail[2] << 16;157/* fall through */158case 2: k1 ^= tail[1] << 8;159/* fall through */160case 1: k1 ^= tail[0];161k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;162};163164//----------165// finalization166167h1 ^= len;168169h1 = fmix(h1);170171*(uint32_t *)out = h1;172}173174static inline uint64_t MurmurHash64A ( const void * key, int len, uint64_t seed )175{176const uint64_t m = BIG_CONSTANT(0xc6a4a7935bd1e995);177const int r = 47;178179uint64_t h = seed ^ (len * m);180181const uint64_t * data = (const uint64_t *)key;182const uint64_t * end = data + (len/8);183184while(data != end)185{186uint64_t k;187188if (!((uintptr_t)data & 0x7))189k = *data++;190else {191memcpy(&k, data, sizeof(k));192data++;193}194195k *= m;196k ^= k >> r;197k *= m;198199h ^= k;200h *= m;201}202203const unsigned char * data2 = (const unsigned char*)data;204205switch(len & 7)206{207case 7: h ^= (uint64_t)(data2[6]) << 48;208/* fall through */209case 6: h ^= (uint64_t)(data2[5]) << 40;210/* fall through */211case 5: h ^= (uint64_t)(data2[4]) << 32;212/* fall through */213case 4: h ^= (uint64_t)(data2[3]) << 24;214/* fall through */215case 3: h ^= (uint64_t)(data2[2]) << 16;216/* fall through */217case 2: h ^= (uint64_t)(data2[1]) << 8;218/* fall through */219case 1: h ^= (uint64_t)(data2[0]);220h *= m;221};222223h ^= h >> r;224h *= m;225h ^= h >> r;226227return h;228}229230231// 64-bit hash for 32-bit platforms232233static inline uint64_t MurmurHash64B ( const void * key, int len, uint64_t seed )234{235const uint32_t m = 0x5bd1e995;236const int r = 24;237238uint32_t h1 = (uint32_t)(seed) ^ len;239uint32_t h2 = (uint32_t)(seed >> 32);240241const uint32_t * data = (const uint32_t *)key;242243while(len >= 8)244{245uint32_t k1 = *data++;246k1 *= m; k1 ^= k1 >> r; k1 *= m;247h1 *= m; h1 ^= k1;248len -= 4;249250uint32_t k2 = *data++;251k2 *= m; k2 ^= k2 >> r; k2 *= m;252h2 *= m; h2 ^= k2;253len -= 4;254}255256if(len >= 4)257{258uint32_t k1 = *data++;259k1 *= m; k1 ^= k1 >> r; k1 *= m;260h1 *= m; h1 ^= k1;261len -= 4;262}263264switch(len)265{266case 3: h2 ^= ((const unsigned char*)data)[2] << 16;267/* fall through */268case 2: h2 ^= ((const unsigned char*)data)[1] << 8;269/* fall through */270case 1: h2 ^= ((const unsigned char*)data)[0];271h2 *= m;272};273274h1 ^= h2 >> 18; h1 *= m;275h2 ^= h1 >> 22; h2 *= m;276h1 ^= h2 >> 17; h1 *= m;277h2 ^= h1 >> 19; h2 *= m;278279uint64_t h = h1;280281h = (h << 32) | h2;282283return h;284}285286#endif /* CK_HT_HASH_H */287288289