X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FHash.h;h=566bad05afed814ec77e4698711d250ff518f643;hb=1137f4b872d19547b2f76874174034ff94060cc0;hp=e1c526e29518c2afe2512efa0330ec7dee5adccd;hpb=ff25e3b55ba9380c0eb2bc2b3c6b6397e2ba663b;p=folly.git diff --git a/folly/Hash.h b/folly/Hash.h index e1c526e2..566bad05 100644 --- a/folly/Hash.h +++ b/folly/Hash.h @@ -1,5 +1,5 @@ /* - * Copyright 2012 Facebook, Inc. + * Copyright 2015 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,10 @@ #include #include #include +#include -#include "folly/SpookyHash.h" +#include +#include /* * Various hashing functions. @@ -31,39 +33,72 @@ namespace folly { namespace hash { // This is a general-purpose way to create a single hash from multiple -// hashable objects. It relies on std::hash being available for all -// relevant types and combines those hashes in an order-dependent way -// to yield a new hash. +// hashable objects. hash_combine_generic takes a class Hasher implementing +// hash; hash_combine uses a default hasher StdHasher that uses std::hash. +// hash_combine_generic hashes each argument and combines those hashes in +// an order-dependent way to yield a new hash. -// Never used, but gcc demands it. -inline size_t hash_combine() { - return 0; -} // This is the Hash128to64 function from Google's cityhash (available // under the MIT License). We use it to reduce multiple 64 bit hashes // into a single hash. -inline size_t hash_128_to_64(const size_t upper, const size_t lower) { +inline uint64_t hash_128_to_64(const uint64_t upper, const uint64_t lower) { // Murmur-inspired hashing. - const size_t kMul = 0x9ddfea08eb382d69ULL; - size_t a = (lower ^ upper) * kMul; + const uint64_t kMul = 0x9ddfea08eb382d69ULL; + uint64_t a = (lower ^ upper) * kMul; a ^= (a >> 47); - size_t b = (upper ^ a) * kMul; + uint64_t b = (upper ^ a) * kMul; b ^= (b >> 47); b *= kMul; return b; } -template -size_t hash_combine(const T& t, const Ts&... ts) { - size_t seed = std::hash()(t); +// Never used, but gcc demands it. +template +inline size_t hash_combine_generic() { + return 0; +} + +template < + class Iter, + class Hash = std::hash::value_type>> +uint64_t hash_range(Iter begin, + Iter end, + uint64_t hash = 0, + Hash hasher = Hash()) { + for (; begin != end; ++begin) { + hash = hash_128_to_64(hash, hasher(*begin)); + } + return hash; +} + +template +size_t hash_combine_generic(const T& t, const Ts&... ts) { + size_t seed = Hasher::hash(t); if (sizeof...(ts) == 0) { return seed; } - size_t remainder = hash_combine(ts...); + size_t remainder = hash_combine_generic(ts...); return hash_128_to_64(seed, remainder); } +// Simply uses std::hash to hash. Note that std::hash is not guaranteed +// to be a very good hash function; provided std::hash doesn't collide on +// the individual inputs, you are fine, but that won't be true for, say, +// strings or pairs +class StdHasher { + public: + template + static size_t hash(const T& t) { + return std::hash()(t); + } +}; + +template +size_t hash_combine(const T& t, const Ts&... ts) { + return hash_combine_generic(t, ts...); +} + ////////////////////////////////////////////////////////////////////// /* @@ -168,7 +203,7 @@ inline uint32_t jenkins_rev_unmix32(uint32_t key) { * http://www.isthe.com/chongo/tech/comp/fnv/ */ -const uint32_t FNV_32_HASH_START = 216613626UL; +const uint32_t FNV_32_HASH_START = 2166136261UL; const uint64_t FNV_64_HASH_START = 14695981039346656037ULL; inline uint32_t fnv32(const char* s, @@ -182,11 +217,11 @@ inline uint32_t fnv32(const char* s, } inline uint32_t fnv32_buf(const void* buf, - int n, + size_t n, uint32_t hash = FNV_32_HASH_START) { const char* char_buf = reinterpret_cast(buf); - for (int i = 0; i < n; ++i) { + for (size_t i = 0; i < n; ++i) { hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); hash ^= char_buf[i]; @@ -196,7 +231,7 @@ inline uint32_t fnv32_buf(const void* buf, } inline uint32_t fnv32(const std::string& str, - uint64_t hash = FNV_32_HASH_START) { + uint32_t hash = FNV_32_HASH_START) { return fnv32_buf(str.data(), str.size(), hash); } @@ -211,11 +246,11 @@ inline uint64_t fnv64(const char* s, } inline uint64_t fnv64_buf(const void* buf, - int n, + size_t n, uint64_t hash = FNV_64_HASH_START) { const char* char_buf = reinterpret_cast(buf); - for (int i = 0; i < n; ++i) { + for (size_t i = 0; i < n; ++i) { hash += (hash << 1) + (hash << 4) + (hash << 5) + (hash << 7) + (hash << 8) + (hash << 40); hash ^= char_buf[i]; @@ -234,11 +269,11 @@ inline uint64_t fnv64(const std::string& str, #define get16bits(d) (*((const uint16_t*) (d))) -inline uint32_t hsieh_hash32_buf(const void* buf, int len) { +inline uint32_t hsieh_hash32_buf(const void* buf, size_t len) { const char* s = reinterpret_cast(buf); - uint32_t hash = len; + uint32_t hash = static_cast(len); uint32_t tmp; - int rem; + size_t rem; if (len <= 0 || buf == 0) { return 0; @@ -303,6 +338,13 @@ inline uint32_t hsieh_hash32_str(const std::string& str) { template struct hasher; +struct Hash { + template + size_t operator()(const T& v) const { + return hasher()(v); + } +}; + template<> struct hasher { size_t operator()(int32_t key) const { return hash::jenkins_rev_mix32(uint32_t(key)); @@ -327,6 +369,26 @@ template<> struct hasher { } }; +// recursion +template +struct TupleHasher { + size_t operator()(std::tuple const& key) const { + return hash::hash_combine( + TupleHasher()(key), + std::get(key)); + } +}; + +// base +template +struct TupleHasher<0, Ts...> { + size_t operator()(std::tuple const& key) const { + // we could do std::hash here directly, but hash_combine hides all the + // ugly templating implicitly + return hash::hash_combine(std::get<0>(key)); + } +}; + } // namespace folly // Custom hash functions. @@ -334,12 +396,24 @@ namespace std { // Hash function for pairs. Requires default hash functions for both // items in the pair. template - class hash > { + struct hash > { public: size_t operator()(const std::pair& x) const { return folly::hash::hash_combine(x.first, x.second); } }; + + // Hash function for tuples. Requires default hash functions for all types. + template + struct hash> { + size_t operator()(std::tuple const& key) const { + folly::TupleHasher< + std::tuple_size>::value - 1, // start index + Ts...> hasher; + + return hasher(key); + } + }; } // namespace std #endif