diff options
author | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-25 01:05:00 +0000 |
---|---|---|
committer | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-25 01:05:00 +0000 |
commit | e7a765c9ad82e7c52661ebd143f30ef827e1f7cb (patch) | |
tree | 13cf24c597e9c47494dbda8f18bff2dfa182d3be /cc/hash_pair.h | |
parent | 3f4771d08156c8d19b28c6802186acec29c56e16 (diff) | |
download | chromium_src-e7a765c9ad82e7c52661ebd143f30ef827e1f7cb.zip chromium_src-e7a765c9ad82e7c52661ebd143f30ef827e1f7cb.tar.gz chromium_src-e7a765c9ad82e7c52661ebd143f30ef827e1f7cb.tar.bz2 |
Add methods for hashing pairs of integer values.
This will allow us to create hash_maps that are keyed off of std::pair objects
holding two integer values.
When both integers are at most 32-bits we can use 64-bit multiplication to
efficiently find the hash code. When one of the integers is 64-bit, then
we split the two values in the pair into 4 32-bit integers.
References to the algorithms used are contained in comments within the code.
These algorithms are similar to the hash function recently added to WebKit
in https://bugs.webkit.org/show_bug.cgi?id=96022, however since our hash codes
are of type size_t (theirs are unsigned) which is 64 bits large on some
platforms, we can be more efficient and not have to reduce the hash code to 32
bits on some platforms.
Tested by cc_unittests: HashPairTest.IntegerPairs.
BUG=149870
Review URL: https://chromiumcodereview.appspot.com/10911330
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158479 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/hash_pair.h')
-rw-r--r-- | cc/hash_pair.h | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/cc/hash_pair.h b/cc/hash_pair.h new file mode 100644 index 0000000..d4b0c16 --- /dev/null +++ b/cc/hash_pair.h @@ -0,0 +1,150 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Defines methods for hashing a pair of integers. + +#ifndef CC_HASH_PAIR_H_ +#define CC_HASH_PAIR_H_ + +#include "base/hash_tables.h" + +#if defined(COMPILER_MSVC) + +#define DEFINE_PAIR_HASH_FUNCTION_START(type1, type2) \ + template<> \ + inline std::size_t hash_value<std::pair<type1, type2> >( \ + const std::pair<type1, type2>& value) + +#define DEFINE_PAIR_HASH_FUNCTION_END() + +#elif defined(COMPILER_GCC) + +#define DEFINE_PAIR_HASH_FUNCTION_START(type1, type2) \ + template<> \ + struct hash<std::pair<type1, type2> > { \ + std::size_t operator()(std::pair<type1, type2> value) const + +#define DEFINE_PAIR_HASH_FUNCTION_END() \ + }; + +#else +#error define DEFINE_PAIR_HASH_FUNCTION_START for your compiler +#endif // COMPILER + +namespace BASE_HASH_NAMESPACE { + +// Implement hashing for pairs of at-most 32 bit integer values. +// When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using +// multiply-add hashing. This algorithm, as described in +// Theorem 4.3.3 of the thesis "Über die Komplexität der Multiplikation in +// eingeschränkten Branchingprogrammmodellen" by Woelfel, is: +// +// h32(x32, y32) = (h64(x32, y32) * randOdd64 + rand16 * 2^16) % 2^64 / 2^32 + +#define DEFINE_32BIT_PAIR_HASH(type1, type2) \ + DEFINE_PAIR_HASH_FUNCTION_START(type1, type2) { \ + uint64 first = value.first; \ + uint32 second = value.second; \ + uint64 hash64 = (first << 32) | second; \ + \ + if (sizeof(std::size_t) >= sizeof(uint64)) \ + return static_cast<std::size_t>(hash64); \ + \ + uint64 oddRandom = 481046412LL << 32 | 1025306954LL; \ + uint32 shiftRandom = 10121U << 16; \ + \ + hash64 = hash64 * oddRandom + shiftRandom; \ + std::size_t highBits = static_cast<std::size_t>( \ + hash64 >> (sizeof(uint64) - sizeof(std::size_t))); \ + return highBits; \ + } \ + DEFINE_PAIR_HASH_FUNCTION_END(); + +DEFINE_32BIT_PAIR_HASH(short, short); +DEFINE_32BIT_PAIR_HASH(short, unsigned short); +DEFINE_32BIT_PAIR_HASH(short, int); +DEFINE_32BIT_PAIR_HASH(short, unsigned); +DEFINE_32BIT_PAIR_HASH(unsigned short, short); +DEFINE_32BIT_PAIR_HASH(unsigned short, unsigned short); +DEFINE_32BIT_PAIR_HASH(unsigned short, int); +DEFINE_32BIT_PAIR_HASH(unsigned short, unsigned); +DEFINE_32BIT_PAIR_HASH(int, short); +DEFINE_32BIT_PAIR_HASH(int, unsigned short); +DEFINE_32BIT_PAIR_HASH(int, int); +DEFINE_32BIT_PAIR_HASH(int, unsigned); +DEFINE_32BIT_PAIR_HASH(unsigned, short); +DEFINE_32BIT_PAIR_HASH(unsigned, unsigned short); +DEFINE_32BIT_PAIR_HASH(unsigned, int); +DEFINE_32BIT_PAIR_HASH(unsigned, unsigned); + +#undef DEFINE_32BIT_PAIR_HASH + +// Implement hashing for pairs of up-to 64-bit integer values. +// We use the compound integer hash method to produce a 64-bit hash code, by +// breaking the two 64-bit inputs into 4 32-bit values: +// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000 +// Then we reduce our result to 32 bits if required, similar to above. + +#define DEFINE_64BIT_PAIR_HASH(type1, type2) \ + DEFINE_PAIR_HASH_FUNCTION_START(type1, type2) { \ + uint32 shortRandom1 = 842304669U; \ + uint32 shortRandom2 = 619063811U; \ + uint32 shortRandom3 = 937041849U; \ + uint32 shortRandom4 = 3309708029U; \ + \ + uint64 value1 = value.first; \ + uint64 value2 = value.second; \ + uint32 value1a = static_cast<uint32>(value1 & 0xffffffff); \ + uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff); \ + uint32 value2a = static_cast<uint32>(value2 & 0xffffffff); \ + uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff); \ + \ + uint64 product1 = static_cast<uint64>(value1a) * shortRandom1; \ + uint64 product2 = static_cast<uint64>(value1b) * shortRandom2; \ + uint64 product3 = static_cast<uint64>(value2a) * shortRandom3; \ + uint64 product4 = static_cast<uint64>(value2b) * shortRandom4; \ + \ + uint64 hash64 = product1 + product2 + product3 + product4; \ + \ + if (sizeof(std::size_t) >= sizeof(uint64)) \ + return static_cast<std::size_t>(hash64); \ + \ + uint64 oddRandom = 1578233944LL << 32 | 194370989LL; \ + uint32 shiftRandom = 20591U << 16; \ + \ + hash64 = hash64 * oddRandom + shiftRandom; \ + std::size_t highBits = static_cast<std::size_t>( \ + hash64 >> (sizeof(uint64) - sizeof(std::size_t))); \ + return highBits; \ + } \ + DEFINE_PAIR_HASH_FUNCTION_END(); + +DEFINE_64BIT_PAIR_HASH(short, int64); +DEFINE_64BIT_PAIR_HASH(short, uint64); +DEFINE_64BIT_PAIR_HASH(unsigned short, int64); +DEFINE_64BIT_PAIR_HASH(unsigned short, uint64); +DEFINE_64BIT_PAIR_HASH(int, int64); +DEFINE_64BIT_PAIR_HASH(int, uint64); +DEFINE_64BIT_PAIR_HASH(unsigned, int64); +DEFINE_64BIT_PAIR_HASH(unsigned, uint64); +DEFINE_64BIT_PAIR_HASH(int64, short); +DEFINE_64BIT_PAIR_HASH(int64, unsigned short); +DEFINE_64BIT_PAIR_HASH(int64, int); +DEFINE_64BIT_PAIR_HASH(int64, unsigned); +DEFINE_64BIT_PAIR_HASH(int64, int64); +DEFINE_64BIT_PAIR_HASH(int64, uint64); +DEFINE_64BIT_PAIR_HASH(uint64, short); +DEFINE_64BIT_PAIR_HASH(uint64, unsigned short); +DEFINE_64BIT_PAIR_HASH(uint64, int); +DEFINE_64BIT_PAIR_HASH(uint64, unsigned); +DEFINE_64BIT_PAIR_HASH(uint64, int64); +DEFINE_64BIT_PAIR_HASH(uint64, uint64); + +#undef DEFINE_64BIT_PAIR_HASH +} + +#undef DEFINE_PAIR_HASH_FUNCTION_START +#undef DEFINE_PAIR_HASH_FUNCTION_END + +#endif // CC_HASH_PAIR_H_ |