// // SpookyHash: a 128-bit noncryptographic hash function // By Bob Jenkins, public domain // Oct 31 2010: alpha, framework + SpookyHash::Mix appears right // Oct 31 2011: alpha again, Mix only good to 2^^69 but rest appears right // Dec 31 2011: beta, improved Mix, tested it for 2-bit deltas // Feb 2 2012: production, same bits as beta // Feb 5 2012: adjusted definitions of uint* to be more portable // Mar 30 2012: 3 bytes/cycle, not 4. Alpha was 4 but wasn't thorough enough. // August 5 2012: SpookyV2 (different results) // // Up to 3 bytes/cycle for long messages. Reasonably fast for short messages. // All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit. // // This was developed for and tested on 64-bit x86-compatible processors. // It assumes the processor is little-endian. There is a macro // controlling whether unaligned reads are allowed (by default they are). // This should be an equally good hash on big-endian machines, but it will // compute different results on them than on little-endian machines. // // Google's CityHash has similar specs to SpookyHash, and CityHash is faster // on new Intel boxes. MD4 and MD5 also have similar specs, but they are orders // of magnitude slower. CRCs are two or more times slower, but unlike // SpookyHash, they have nice math for combining the CRCs of pieces to form // the CRCs of wholes. There are also cryptographic hashes, but those are even // slower than MD5. // #pragma once #include #include #include #include class SpookyHash { public: // A hash is two uint64's. // using HashValue = std::pair; // // SpookyHash: hash a single message in one call, produce 128-bit output // static void ChainHash128( const void *message, // message to hash size_t length, // length of message in bytes uint64_t *hash1, // input seed0, output hash0 uint64_t *hash2); // input seed1, output hash1 static inline HashValue QkHash128(const void *message, size_t len) { uint64_t hash1 = 0; uint64_t hash2 = 0; ChainHash128(message, len, &hash1, &hash2); return std::make_pair(hash1, hash2); } static inline HashValue QkHash128(std::string_view v) { uint64_t hash1 = 0; uint64_t hash2 = 0; ChainHash128(v.data(), v.size(), &hash1, &hash2); return std::make_pair(hash1, hash2); } static inline uint64_t QkHash64(const void *message, size_t len) { uint64_t hash1 = 0; uint64_t hash2 = 0; ChainHash128(message, len, &hash1, &hash2); return hash1; } static inline uint64_t QkHash64(std::string_view v) { uint64_t hash1 = 0; uint64_t hash2 = 0; ChainHash128(v.data(), v.size(), &hash1, &hash2); return hash1; } };