libmoost
/home/mhx/git/github/libmoost/include/moost/hash/murmur3.hpp
Go to the documentation of this file.
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