|
BDE 4.39.x Production Release
|
Provide a namespace for hash functions.
Provide a namespace for hash functions.
bsl_functional.h
This component provides a template unary functor, bsl::hash, implementing the std::hash functor. bsl::hash applies a C++ standard compliant, implementation defined, hash function to fundamental types returning the result of such application.
According to the C++ standard the requirements of a standard hash function h are:
size_t value between 0 and numeric_limits<std::size_t>::max().k. For multiple evaluations with the same argument k, the value returned must be always the same.This section illustrates intended usage of this component.
Suppose we already have an array of unique values of type TYPE, for which operator== is defined, and we want to be able to quickly look up whether an element is in the array, without exhaustively applying operator== to all the elements in sequence. The array itself is guaranteed not to change for the duration of our interest in it.
The problem is much simpler than building a general-purpose hash table, because we know how many elements our cross reference will contain in advance, so we will never have to dynamically grow the number of buckets. We do not need to copy the values into our own area, so we don't have to create storage for them, or require that a copy constructor or destructor be available. We only require that they have a transitive, symmetric equivalence operation bool operator== and that a hash function be provided.
We will need a hash function – the hash function is a function that will take as input an object of the type stored in our array, and yield a size_t value that will be very randomized. Ideally, the slightest change in the value of the TYPE object will result in a large change in the value returned by the hash function. In a good hash function, typically half the bits of the return value will change for a 1-bit change in the hashed value. We then use the result of the hash function to index into our array of buckets. Each bucket is simply a pointer to a value in our original array of TYPE objects. We will resolve hash collisions in our array through linear probing, where we will search consecutive buckets following the bucket where the collision occurred, testing occupied buckets for equality with the value we are searching on, and concluding that the value is not in the table if we encounter an empty bucket before we encounter one referring to an equal element.
An important quality of the hash function is that if two values are equivalent, they must yield the same hash value.
First, we define our HashCrossReference template class, with the two type parameters TYPE (the type being referenced) and HASHER, which defaults to bsl::hash<TYPE>. For common types of TYPE such as int, a specialization of bsl::hash is already defined:
Then, In main, we will first use our cross-reference to cross-reference a collection of integer values. We define our array and take its length:
Now, we create our cross-reference hcri and verify it constructed properly. Note that we don't specify the second template parameter HASHER and let it default to bsl::hash<int>, which is already defined by bslstl_hash:
Finally, we use hcri to verify numbers that were and were not in the collection:
We want to specialize bsl::hash for a custom class. We can use the modular hashing system implemented in bslh rather than explicitly specializing bsl::hash. We will re-use the HashCrossReference template class defined in Example 1.
First, we declare Point, a class that allows us to identify a location on a two dimensional Cartesian plane.
Then, we declare operator== as a friend so that we will be able to compare two points.
Next, we declare hashAppend as a friend so that we will be able hash a Point.
Then, we define operator==. Notice how it only checks salient attributes
d_distToOrigin which is not required to determine equality. hashAppend. This method will allow any hashing algorithm to be applied to Point. This is the extent of the work that needs to be done by type creators. They do not need to implement any algorithms, they just need to call out the salient attributes (which have already been determined by operator==) by calling hashAppend on them. Box, that has a Point as one of its salient attributes. operator== and hashAppend as we did before. operator==. This time all of the data members contribute to equality. hashAppend for Box. Notice how as well as calling hashAppend on fundamental types, we can also call it on our user-defined type Point. Calling hashAppend on Point will propagate the hashing algorithm functor hashAlg down to the fundamental types that make up Point, and those types will then be passed into the algorithm functor. Box. We create an array of unique Boxs and take its length: hcrsts and verify that it constructed properly. Note we don't pass a second parameter template argument and let HASHER default to bsl::hash<TYPE>. Since we have not specialized bsl::hash for Box, bsl::hash<TYPE> will attempt to use bslh::hash<> to hash Box. | #define BSLSTL_HASH_DEPRECATED_CPP17 |