libmoost
|
00001 /* vim:set ts=3 sw=3 sts=3 et: */ 00030 #ifndef MOOST_HASH_MURMUR3_HPP 00031 #define MOOST_HASH_MURMUR3_HPP 00032 00033 #include <vector> 00034 00035 #include <boost/cstdint.hpp> 00036 #include <boost/static_assert.hpp> 00037 #include <boost/type_traits/is_pod.hpp> 00038 00039 namespace moost { namespace hash { 00040 00055 class murmur3 00056 { 00057 private: 00058 static uint32_t fmix(uint32_t h) 00059 { 00060 h ^= h >> 16; 00061 h *= 0x85ebca6b; 00062 h ^= h >> 13; 00063 h *= 0xc2b2ae35; 00064 h ^= h >> 16; 00065 00066 return h; 00067 } 00068 00069 static uint32_t getblock(const uint32_t *p, int i) 00070 { 00071 return p[i]; 00072 } 00073 00074 static uint32_t rotl32 (uint32_t x, int8_t r) 00075 { 00076 return (x << r) | (x >> (32 - r)); 00077 } 00078 00079 public: 00080 static uint32_t compute32(const void *key, size_t len, uint32_t seed) 00081 { 00082 const uint8_t *data = reinterpret_cast<const uint8_t *>(key); 00083 const int nblocks = len/4; 00084 00085 uint32_t h1 = seed; 00086 00087 const uint32_t c1 = 0xcc9e2d51; 00088 const uint32_t c2 = 0x1b873593; 00089 00090 //---------- 00091 // body 00092 00093 const uint32_t *blocks = reinterpret_cast<const uint32_t *>(data + nblocks*4); 00094 00095 for(int i = -nblocks; i; i++) 00096 { 00097 uint32_t k1 = getblock(blocks, i); 00098 00099 k1 *= c1; 00100 k1 = rotl32(k1, 15); 00101 k1 *= c2; 00102 00103 h1 ^= k1; 00104 h1 = rotl32(h1, 13); 00105 h1 = h1*5+0xe6546b64; 00106 } 00107 00108 //---------- 00109 // tail 00110 00111 const uint8_t *tail = reinterpret_cast<const uint8_t*>(data + nblocks*4); 00112 00113 uint32_t k1 = 0; 00114 00115 switch (len & 3) 00116 { 00117 case 3: k1 ^= tail[2] << 16; 00118 case 2: k1 ^= tail[1] << 8; 00119 case 1: k1 ^= tail[0]; 00120 k1 *= c1; k1 = rotl32(k1, 15); k1 *= c2; h1 ^= k1; 00121 } 00122 00123 //---------- 00124 // finalization 00125 00126 h1 ^= len; 00127 00128 return fmix(h1); 00129 } 00130 00131 template <typename T> 00132 static uint32_t compute32(const T& key, uint32_t seed) 00133 { 00134 BOOST_STATIC_ASSERT(boost::is_pod<T>::value); 00135 return compute32(&key, sizeof(key), seed); 00136 } 00137 00138 static uint32_t compute32(const std::string& key, uint32_t seed) 00139 { 00140 return compute32(key.data(), key.size(), seed); 00141 } 00142 00143 template <typename T> 00144 static uint32_t compute32(const std::vector<T>& key, uint32_t seed) 00145 { 00146 BOOST_STATIC_ASSERT(boost::is_pod<T>::value); 00147 return compute32(&key[0], sizeof(T)*key.size(), seed); 00148 } 00149 00150 template <typename T, unsigned Seed = 0U> 00151 struct hash32 00152 { 00153 size_t operator() (const T& key) const 00154 { 00155 return compute32(key, Seed); 00156 } 00157 }; 00158 }; 00159 00160 }} 00161 00162 #endif