X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=blobdiff_plain;f=source%2Fcore%2Fhash.h;h=85ee5dd74c046a4cdbc3b793cfd07d22dca2132f;hp=d696cae5b63542e65d6718f1012d0606b9f55833;hb=HEAD;hpb=062b200b08ec5998c4c02326e1e7b4e71fe4a5c6 diff --git a/source/core/hash.h b/source/core/hash.h index d696cae..e2201cf 100644 --- a/source/core/hash.h +++ b/source/core/hash.h @@ -1,41 +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. */ -inline unsigned hash32(const std::string &s, unsigned b = 32) -{ return hash32(s.data(), s.size(), b); } +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)); } /** -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. +Manually folds a hash to a smaller size. */ -UInt64 hash64(const void *, unsigned, unsigned = 64); +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; } /** -Convenience function to compute a 64-bit hash of a string. +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 UInt64 hash64(const std::string &s, unsigned b = 64) -{ return hash64(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; +} -inline UInt32 fold32(UInt64 hash) -{ return hash^(hash>>32); } +/** +Convenience function to compute an N-bit hash of a string. +*/ +template +typename HashTraits::ResultType hash(const std::string &str) +{ return hash(str.data(), str.size()); } -inline UInt16 fold16(UInt64 hash) -{ return hash^(hash>>16)^(hash>>32)^(hash>>48); } +/** +Convenience function to compute an N-bit hash of any object. The entire object +representation is hashed, including any padding bytes. +*/ +template +typename HashTraits::ResultType hash(const T &obj) +{ return hash(&obj, sizeof(obj)); } } // namespace Msp