X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=blobdiff_plain;f=source%2Fcore%2Fhash.h;h=e2201cf22110280172828fff9021d4e1daa36036;hp=75aba09a57d8e04dfb0a06cdf05f29d90f4c3f4a;hb=HEAD;hpb=95bd04e16acacde19fcfdcc722baf72b06dcdfee diff --git a/source/core/hash.h b/source/core/hash.h index 75aba09..e2201cf 100644 --- a/source/core/hash.h +++ b/source/core/hash.h @@ -1,35 +1,143 @@ #ifndef MSP_CORE_HASH_H_ #define MSP_CORE_HASH_H_ +#include +#include #include -#include "inttypes.h" namespace Msp { +template8)+(N>16)+(N>32)+(N>64)> +struct HashTraits; + +template<> +struct HashTraits<64, 6> +{ + using HashType = uint64_t; + using ResultType = uint64_t; + static constexpr HashType prime = 1099511628211ULL; + static constexpr HashType offset = 14695981039346656037ULL; + static constexpr bool folded = false; +}; + +template<> +struct HashTraits<32, 5> +{ + using HashType = uint32_t; + using ResultType = uint32_t; + static constexpr HashType prime = 16777619; + static constexpr HashType offset = 2166136261U; + static constexpr bool folded = false; +}; + +template +struct HashTraits +{ + using HashType = uint64_t; + using ResultType = uint64_t; + static constexpr bool folded = true; +}; + +template +struct HashTraits +{ + using HashType = uint32_t; + using ResultType = uint32_t; + static constexpr bool folded = true; +}; + +template +struct HashTraits +{ + using HashType = uint32_t; + using ResultType = uint16_t; + static constexpr bool folded = true; +}; + +template +struct HashTraits +{ + using HashType = uint32_t; + using ResultType = uint8_t; + static constexpr bool folded = true; +}; + /** -Computes a 32-bit Fowler-Noll-Vo (FNV-1a) hash. The number of bits can be -limited to less than 32, in which case XOR-folding is used to reduce the hash -size. +Computes a single round of a hash, adding one byte of data. N must be a native +hash size. */ -UInt32 hash32(const void *, unsigned, unsigned = 32); +template +typename HashTraits::ResultType hash_round(typename HashTraits::HashType result, uint8_t byte) +{ + constexpr typename HashTraits::HashType prime = HashTraits::prime; + return (result^byte)*prime; +} /** -Convenience function to compute a 32-bit hash of a string. +Updates a previously computed hash by adding bytes to it. N must be a native +hash size. +*/ +template +typename HashTraits::ResultType hash_update(typename HashTraits::HashType result, const void *data, std::size_t size) +{ + const uint8_t *ptr = static_cast(data); + for(unsigned i=0; i(result, *ptr++); + return result; +} + +template +typename HashTraits::ResultType hash_update(typename HashTraits::HashType result, const std::string &str) +{ return hash_update(result, str.data(), str.size()); } + +// For some reason this causes an ambiguity error without the enable_if. +template +typename std::enable_if::value, typename HashTraits::ResultType>::type hash_update(typename HashTraits::HashType result, const T &obj) +{ return hash_update(result, &obj, sizeof(obj)); } + +/** +Manually folds a hash to a smaller size. +*/ +template +typename std::enable_if::digits, typename HashTraits::ResultType>::type hash_fold(T hash) +{ return (hash>>N ^ hash) & ((T(1)< +typename std::enable_if::digits, typename HashTraits::ResultType>::type hash_fold(T hash) +{ return hash; } + +/** +Computes an N-bit Fowler-Noll-Vo (FNV-1a) hash. If N is not a native hash +size, the next larger native hash is computed and XOR-folding is applied to +the result. + +http://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function +http://www.isthe.com/chongo/tech/comp/fnv/index.html */ -inline unsigned hash32(const std::string &s, unsigned b = 32) -{ return hash32(s.data(), s.size(), b); } +template +typename HashTraits::ResultType hash(const void *data, std::size_t size) +{ + constexpr unsigned hash_bits = std::numeric_limits::HashType>::digits; + typename HashTraits::HashType result = hash_update(HashTraits::offset, data, size); + if(HashTraits::folded) + result = hash_fold(result); + return result; +} /** -Computes a 64-bit Fowler-Noll-Vo (FNV-1a) hash. Note that even if bits is -limited to 32 or less, this does not produce the same result as hash32. +Convenience function to compute an N-bit hash of a string. */ -UInt64 hash64(const void *, unsigned, unsigned = 64); +template +typename HashTraits::ResultType hash(const std::string &str) +{ return hash(str.data(), str.size()); } /** -Convenience function to compute a 64-bit hash of a string. +Convenience function to compute an N-bit hash of any object. The entire object +representation is hashed, including any padding bytes. */ -inline UInt64 hash64(const std::string &s, unsigned b = 64) -{ return hash64(s.data(), s.size(), b); } +template +typename HashTraits::ResultType hash(const T &obj) +{ return hash(&obj, sizeof(obj)); } } // namespace Msp