Quick Links: |
Provide an implementation of the WyHash algorithm final v3. More...
Namespaces | |
namespace | bslh |
bslh::WyHashIncrementalAlgorithm | functor implementing the WyHash algorithm |
bslh::WyHashIncrementalAlgorithm
implements the WyHash algorithm by Wang Yi et al (see implementation file for full list of authors) with modifications. This algorithm is known to be very fast yet have good avalanche behavior. m1
and m2
such that hash(m1) == hash(m2)
. Because of the limited sized output (only 2**64 possibilities) and the fast execution time of the algorithm, it is probable to find two such values searching only about sqrt(2**64) == 2**32
inputs, which wont take long. bslh_hash
|Subdivision-Invariance). operator==
, and we want a fast way to find out if values are contained in the array. We can create a HashTable
data structure that is capable of looking up values in O(1) time. TYPE
that are salient to hashing into the hashing algorithm, and then return the hash that is produced. buckets
. Each bucket
is simply a pointer to a value in our original array of TYPE
objects. HashTable
template class, with the two type parameters: TYPE
(the type being referenced) and HASHER
(a functor that produces the hash). template <class TYPE, class HASHER> class HashTable {
class template
implements a hash table providing fast lookup of an external, non-owned, array of values of (template parameter) TYPE
. TYPE
shall have a transitive, symmetric operator==
function. There is no requirement that it have any kind of creator defined. HASHER
template parameter type must be a functor with a method having the following signature: size_t operator()(TYPE) const; -OR- size_t operator()(const TYPE&) const;
HASHER
shall have a publicly accessible default constructor and destructor. // DATA const TYPE *d_values; // Array of values table is to // hold size_t d_numValues; // Length of 'd_values'. const TYPE **d_bucketArray; // Contains ptrs into 'd_values' size_t d_bucketArrayMask; // Will always be '2^N - 1'. HASHER d_hasher; // User supplied hashing algorithm private: // PRIVATE ACCESSORS bool lookup(size_t *idx, const TYPE& value, size_t hashValue) const; // Look up the specified 'value', having the specified 'hashValue', // and load its index in 'd_bucketArray' into the specified 'idx'. // If not found, return the vacant entry in 'd_bucketArray' where // it should be inserted. Return 'true' if 'value' is found and // 'false' otherwise. public: // CREATORS HashTable(const TYPE *valuesArray, size_t numValues); // Create a hash table referring to the specified 'valuesArray' // having length of the specified 'numValues'. No value in // 'valuesArray' shall have the same value as any of the other // values in 'valuesArray' ~HashTable(); // Free up memory used by this hash table. // ACCESSORS bool contains(const TYPE& value) const; // Return true if the specified 'value' is found in the table and // false otherwise. }; // PRIVATE ACCESSORS template <class TYPE, class HASHER> bool HashTable<TYPE, HASHER>::lookup(size_t *idx, const TYPE& value, size_t hashValue) const { const TYPE *ptr; for (*idx = hashValue & d_bucketArrayMask; (ptr = d_bucketArray[*idx]); *idx = (*idx + 1) & d_bucketArrayMask) { if (value == *ptr) { return true; // RETURN } } // value was not found in table return false; } // CREATORS template <class TYPE, class HASHER> HashTable<TYPE, HASHER>::HashTable(const TYPE *valuesArray, size_t numValues) : d_values(valuesArray) , d_numValues(numValues) , d_hasher() { size_t bucketArrayLength = 4; while (bucketArrayLength < numValues * 4) { bucketArrayLength *= 2; } d_bucketArrayMask = bucketArrayLength - 1; d_bucketArray = new const TYPE *[bucketArrayLength]; memset(d_bucketArray, 0, bucketArrayLength * sizeof(TYPE *)); for (unsigned i = 0; i < numValues; ++i) { const TYPE& value = d_values[i]; size_t idx; const bool found = lookup(&idx, value, d_hasher(value)); BSLS_ASSERT_OPT(!found); (void) found; d_bucketArray[idx] = &d_values[i]; } } template <class TYPE, class HASHER> HashTable<TYPE, HASHER>::~HashTable() { delete [] d_bucketArray; } // ACCESSORS template <class TYPE, class HASHER> bool HashTable<TYPE, HASHER>::contains(const TYPE& value) const { size_t idx; return lookup(&idx, value, d_hasher(value)); }
Future
class, which holds a c-string name
, char callMonth
, and short callYear
. class Future {
class
identifies a future contract. It tracks the name, call month and year of the contract it represents, and allows equality comparison. // DATA const char *d_name; // held, not owned const char d_callMonth; const short d_callYear; public: // CREATORS Future(const char *name, const char callMonth, const short callYear) : d_name(name), d_callMonth(callMonth), d_callYear(callYear) // Create a 'Future' object out of the specified 'name', // 'callMonth', and 'callYear'. {} Future() : d_name(""), d_callMonth('\0'), d_callYear(0) // Create a 'Future' with default values. {} // ACCESSORS const char * getMonth() const // Return the month that this future expires. { return &d_callMonth; } const char * getName() const // Return the name of this future { return d_name; } const short * getYear() const // Return the year that this future expires { return &d_callYear; } bool operator==(const Future& rhs) const // Compare this to the specified 'other' object and return true if // they are equal { return (!strcmp(d_name, rhs.d_name)) && d_callMonth == rhs.d_callMonth && d_callYear == rhs.d_callYear; } }; bool operator!=(const Future& lhs, const Future& rhs) // Compare compare the specified 'lhs' and 'rhs' objects and return // true if they are not equal { return !(lhs == rhs); }
Future
. We are going to use the SpookyHashAlgorithm
because it is a fast, general purpose hashing algorithm that will provide an easy way to combine the attributes of Future
objects that are salient to hashing into one reasonable hash that will distribute the items evenly throughout the hash table. struct HashFuture { // This struct is a functor that will apply the 'SpookyHashAlgorithm' // to objects of type 'Future'. bsls::Types::Uint64 d_seed; HashFuture() { // Generate random bits in 'd_seed' based on the time of day in // nanoseconds. bsls::Types::Int64 nano = bsls::SystemTime::nowMonotonicClock().totalNanoseconds(); const int iterations = static_cast<int>(nano & 7) + 1; for (int ii = 0; ii < iterations; ++ii) { nano *= bsls::SystemTime::nowMonotonicClock(). totalNanoseconds(); nano += nano >> 32; } BSLMF_ASSERT(sizeof(d_seed) <= sizeof(nano)); memcpy(&d_seed, &nano, sizeof(d_seed)); } // MANIPULATOR size_t operator()(const Future& future) const // Return the hash of the of the specified 'future'. Note that // this uses the 'SpookyHashAlgorithm' to quickly combine the // attributes of 'Future' objects that are salient to hashing into // a hash suitable for a hash table. { bslh::WyHashIncrementalAlgorithm hash(d_seed); hash(future.getName(), strlen(future.getName())); hash(future.getMonth(), sizeof(char)); hash(future.getYear(), sizeof(short)); return static_cast<size_t>(hash.computeHash()); } };