BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslh_hash.h
Go to the documentation of this file.
1/// @file bslh_hash.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslh_hash.h -*-C++-*-
8#ifndef INCLUDED_BSLH_HASH
9#define INCLUDED_BSLH_HASH
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslh_hash bslh_hash
15/// @brief Provide a struct to run `bslh` hash algorithms on supported types.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslh
19/// @{
20/// @addtogroup bslh_hash
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslh_hash-purpose"> Purpose</a>
25/// * <a href="#bslh_hash-classes"> Classes </a>
26/// * <a href="#bslh_hash-description"> Description </a>
27/// * <a href="#bslh_hash-modularity"> Modularity </a>
28/// * <a href="#bslh_hash-hashappend"> hashAppend </a>
29/// * <a href="#bslh_hash-hashing-algorithms"> Hashing Algorithms </a>
30/// * <a href="#bslh_hash-requirements-for-regular-bslh-hashing-algorithms"> Requirements for Regular bslh Hashing Algorithms </a>
31/// * <a href="#bslh_hash-subdivision-invariance"> Subdivision-Invariance </a>
32/// * <a href="#bslh_hash-usage"> Usage </a>
33/// * <a href="#bslh_hash-example-1-keying-a-hash-table-with-a-user-defined-type"> Example 1: Keying a Hash Table with a User-Defined Type </a>
34///
35/// # Purpose {#bslh_hash-purpose}
36/// Provide a struct to run `bslh` hash algorithms on supported types.
37///
38/// # Classes {#bslh_hash-classes}
39///
40/// - bslh::Hash: functor that runs `bslh` hash algorithms on supported types
41///
42/// @see
43///
44/// # Description {#bslh_hash-description}
45/// This component provides a templated `struct`, `bslh::Hash`,
46/// that defines a hash-functor that can be used with standard containers (a
47/// drop in replacement for `bsl::hash`), and which applies the supplied
48/// (template parameter) `HASH_ALGORITHM` to the attributes of the (template
49/// parameter) `TYPE` which have been identified as salient to hashing. The
50/// `bslh::Hash` template parameter `HASH_ALGORITHM` must be a hashing algorithm
51/// that conforms to the requirements outlined below (see {Requirements for
52/// Regular `bslh` Hashing Algorithms}). Note that there are several hashing
53/// algorithms defined within the `bslh` package and some, such as those that
54/// require seeds, will not meet these requirements, meaning they cannot be used
55/// with `bslh::Hash`. A call to `bslh::Hash::operator()` for a (template
56/// parameter) `TYPE` will call the `hashAppend` free function for `TYPE` and
57/// provide `hashAppend` an instance of a hash algorithm in the `bslh` namespace
58/// that will use the (template parameter) `HASH_ALGORITHM` to compute hash
59/// values.
60///
61/// This component also contains `hashAppend` definitions for fundamental types,
62/// which are required by algorithms defined in `bslh`. Clients are expected to
63/// define a free-function `hashAppend` for each of the types they wish to be
64/// hashable (see {`hashAppend`} below). More information can be found in the
65/// package level documentation for `bslh` (internal users can also find
66/// information here {TEAM BDE:USING MODULAR HASHING<GO>})
67///
68/// ## Modularity {#bslh_hash-modularity}
69///
70///
71/// `bslh::Hash` provides a modular system for hashing. This modularity refers
72/// to the decoupling of the various tasks associated with hashing. Using this
73/// system, type implementers can identify attributes of their type that are
74/// salient to hashing, without having to write a hashing algorithm.
75/// Conversely, hashing algorithms can be written independent of types.
76/// Attributes that are salient to hashing are called out on a type using
77/// `hashAppend`. Hashing algorithms are written to operate on the attributes
78/// called out by `hashAppend`. Some default algorithms have been provided in
79/// the `bslh` package. This modularity allows type creators to avoid writing
80/// hashing algorithms, which can save work and avoid bad hashing algorithm
81/// implementations.
82///
83/// ## hashAppend {#bslh_hash-hashappend}
84///
85///
86/// `hashAppend` is the free function that is used to pass attributes that are
87/// salient to hashing into a hashing algorithm. A custom type defined in
88/// another component must define it's own `hashAppend` free function overload
89/// that can be discovered through ADL in order to be hashed using this
90/// facility. A simple implementation of an overload for `hashAppend` might
91/// call `hashAppend` on each of the type's fields that are salient to hashing.
92/// Note that when writing a `hashAppend` function that itself calls
93/// `hashAppend, `using bslh::hashAppend;' must be included as the first line of
94/// code in the function. The using statement ensures that ADL will always be
95/// able to find the `hashAppend` functions defined in this component for
96/// handling fundamental types even when the (template parameter) type
97/// `HASH_ALGORITHM` is not implemented in `bslh`.
98///
99/// A client will thus customize their hashing of any custom `struct`, `class`,
100/// or `union` by providing an appropriate `hashAppend`. In some very rare
101/// cases, a client will want to provide special behavior when hashing
102/// fundamental types such as integral types, pointers, or enums, and this can
103/// be done by providing an appropriate typed `operator()` overload of your own
104/// hash function. Support for doing this is not provided for ther types, or
105/// for `bool`.
106///
107/// Some types may require more subtle implementations for `hashAppend`, such as
108/// types containing C-strings which are salient to hashing. These C-strings
109/// must be passed directly into the (template parameter) type `HASH_ALGORITHM`,
110/// rather than calling `hashAppend` with the pointer as an argument. This
111/// special case exists because calling `hashAppend` with a pointer will hash
112/// the pointer rather than the data that is pointed to.
113///
114/// Within this component, `hashAppend` has been implemented for all of the
115/// fundamental types, and for arrays. When `hashAppend` is reached on a
116/// fundamental type, the hashing algorithm is no longer propagated, and instead
117/// a pointer to the beginning of the type in memory is passed to the algorithm,
118/// along with the length of the type. There are special cases with floating
119/// point numbers and boolean values where the data is tweaked before hashing to
120/// ensure that values that compare equal will be hashed with the same bit-wise
121/// representation. The algorithm will then incorporate the type into its
122/// internal state and return a finalized hash when requested.
123///
124/// ## Hashing Algorithms {#bslh_hash-hashing-algorithms}
125///
126///
127/// There are algorithms implemented in the `bslh` package that can be passed in
128/// and used as template parameters for `bslh::Hash` or other `struct`s like it.
129/// Some of these algorithms, such as `bslh::SpookyHashAlgorithm` or
130/// `bslh::WyHashAlgorithm`, are named for the algorithm they implement. These
131/// named algorithms are intended for use by those who want a specific
132/// algorithm. There are other algorithms, such as
133/// `bslh::DefaultHashAlgorithm`, which wrap an unspecified algorithm and
134/// describe the properties of the wrapped algorithm. The descriptive
135/// algorithms are intended for use by those who need specific properties and
136/// want to be updated to a new algorithm when one is published with
137/// improvements to the desired properties. `bslh::DefaultHashAlgorithm` has
138/// the property of being a good default algorithm, specifically for use in a
139/// hash table.
140///
141/// ## Requirements for Regular bslh Hashing Algorithms {#bslh_hash-requirements-for-regular-bslh-hashing-algorithms}
142///
143///
144/// Users of this modular hashing system are free to write their own hashing
145/// algorithms. In order to plug into `bslh::Hash`, the user-implemented
146/// algorithms must implement the interface shown here:
147/// @code
148/// class SomeHashAlgorithm
149/// {
150/// public:
151/// // TYPES
152/// typedef Uint64 result_type;
153///
154/// // CREATORS
155/// SomeHashAlgorithm();
156///
157/// // MANIPULATORS
158/// void operator()(const void *data, size_t numBytes);
159///
160/// result_type computeHash();
161/// };
162/// @endcode
163/// The `result_type` `typedef` must define the return type of this particular
164/// algorithm. A default constructor (either implicit or explicit) must be
165/// supplied that creates an algorithm functor that is in a usable state. An
166/// `operator()` must be supplied that takes a `const void *` to the data to be
167/// hashed and a `size_t` length of bytes to be hashed. This operator must
168/// operate on all data uniformly, meaning that regardless of whether data is
169/// passed in all at once, or one byte at a time, the result returned by
170/// `computeHash()` will be the same. `computeHash()` will return the final
171/// result of the hashing algorithm, as type `result_type`. `computeHash()` is
172/// allowed to modify the internal state of the algorithm, meaning calling
173/// `computeHash()` more than once may not return the correct value.
174///
175/// ### Subdivision-Invariance {#bslh_hash-subdivision-invariance}
176///
177///
178/// The result produced by the hashing algorithm must be independent of how the
179/// data is subdivided into segments when supplied to `operator()`. More
180/// precisely, for any subdivision of the message `M` of size `S` into `N`
181/// segments `M_i` of size `S_i`, the following must be true:
182///
183/// @code
184/// SomeHashAlgorithm algM;
185/// algM(M, S);
186///
187/// SomeHashAlgorithm algI;
188/// for (int i = 0; i < N; ++i) {
189/// algI(M_i, S_i);
190/// }
191///
192/// assert(algM.computeHash() == algI.computeHash());
193/// @endcode
194///
195/// ## Usage {#bslh_hash-usage}
196///
197///
198/// This section illustrates intended usage of this component.
199///
200/// ### Example 1: Keying a Hash Table with a User-Defined Type {#bslh_hash-example-1-keying-a-hash-table-with-a-user-defined-type}
201///
202///
203/// Suppose we have a value-semantic type, `Box`, that contains attributes that
204/// are salient to hashing as well as attributes that are not salient to
205/// hashing. Some of these attributes are themselves user defined types. We
206/// want to store objects of type `Box` in a hash table, so we need to be able
207/// to produce hash values that represent instances of `Box`. We don't want to
208/// write our own hashing or hash combine algorithm, because we know it is very
209/// difficult and labor-intensive to write a proper hashing algorithm. In order
210/// to hash this `Box`, we will use the modular hashing system supplied in
211/// `bslh`.
212///
213/// First, we define `Point`, a class that allows us to identify a location on a
214/// two dimensional Cartesian plane.
215/// @code
216/// class Point {
217/// // This class is a value-semantic type that represents a two
218/// // dimensional location on a Cartesian plane.
219///
220/// private:
221/// int d_x;
222/// int d_y;
223/// double d_distToOrigin; // This value will be accessed frequently, so we
224/// // cache it rather than recalculate it every
225/// // time.
226///
227/// public:
228/// Point (int x, int y);
229/// // Create a 'Point' having the specified 'x' and 'y' coordinates.
230///
231/// double distanceToOrigin() const;
232/// // Return the distance from the origin (0, 0) to this point.
233///
234/// int getX() const;
235/// // Return the x coordinate of this point.
236///
237/// int getY() const;
238/// // Return the y coordinate of this point.
239/// };
240///
241/// inline
242/// Point::Point(int x, int y)
243/// : d_x(x)
244/// , d_y(y)
245/// {
246/// d_distToOrigin = sqrt(static_cast<double>(d_x * d_x) +
247/// static_cast<double>(d_y * d_y));
248/// }
249///
250/// inline
251/// double Point::distanceToOrigin() const
252/// {
253/// return d_distToOrigin;
254/// }
255///
256/// inline
257/// int Point::getX() const
258/// {
259/// return d_x;
260/// }
261///
262/// inline
263/// int Point::getY() const
264/// {
265/// return d_y;
266/// }
267/// @endcode
268/// Then, we define `operator==`. Notice how it checks only attributes that we
269/// would want to incorporate into the hashed value. Note that attributes that
270/// are salient to hashing tend to be the same as or a subset of the attributes
271/// that are checked in `operator==`.
272/// @code
273/// bool operator==(const Point& lhs, const Point& rhs)
274/// // Return true if the specified 'lhs' and 'rhs' have the same value.
275/// // Two 'Point' objects have the same value if they have the same x and
276/// // y coordinates.
277/// {
278/// return (lhs.getX() == rhs.getX()) && (lhs.getY() == rhs.getY());
279/// }
280/// @endcode
281/// Next, we define `hashAppend`. This function will allow any hashing
282/// algorithm that meets the `bslh` hashing algorithm requirements to be applied
283/// to `Point`. This is the full extent of the work that needs to be done by
284/// type creators. They do not need to implement any algorithms, they just need
285/// to call out the attributes that are salient to hashing by calling
286/// `hashAppend` on them.
287/// @code
288/// template <class HASH_ALGORITHM>
289/// void hashAppend(HASH_ALGORITHM& hashAlg, const Point& point)
290/// // Apply the specified 'hashAlg' to the specified 'point'
291/// {
292/// using bslh::hashAppend;
293/// hashAppend(hashAlg, point.getX());
294/// hashAppend(hashAlg, point.getY());
295/// }
296/// @endcode
297/// Then, we declare another value-semantic type, `Box` that will have a `Point`
298/// as one of its attributes that are salient to hashing.
299/// @code
300/// class Box {
301/// // This class is a value-semantic type that represents a box drawn on
302/// // to a Cartesian plane.
303///
304/// private:
305/// Point d_position;
306/// int d_length;
307/// int d_width;
308///
309/// public:
310/// Box(Point position, int length, int width);
311/// // Create a box having the specified 'length' and 'width', with its
312/// // upper left corner at the specified 'position'
313///
314/// int getLength() const;
315/// // Return the length of this box.
316///
317/// Point getPosition() const;
318/// // Return a 'Point' representing the upper left corner of this box
319/// // on a Cartesian plane
320///
321/// int getWidth() const;
322/// // Return the width of this box.
323/// };
324///
325/// inline
326/// Box::Box(Point position, int length, int width)
327/// : d_position(position)
328/// , d_length(length)
329/// , d_width(width) { }
330///
331/// int Box::getLength() const
332/// {
333/// return d_length;
334/// }
335///
336/// Point Box::getPosition() const
337/// {
338/// return d_position;
339/// }
340///
341/// int Box::getWidth() const
342/// {
343/// return d_width;
344/// }
345/// @endcode
346/// Then, we define `operator==`. This time all of the data members are salient
347/// to equality.
348/// @code
349/// bool operator==(const Box& lhs, const Box& rhs)
350/// // Return true if the specified 'lhs' and 'rhs' have the same value.
351/// // Two 'Box' objects have the same value if they have the same length,
352/// // width, and position.
353/// {
354/// return (lhs.getPosition() == rhs.getPosition()) &&
355/// (lhs.getLength() == rhs.getLength()) &&
356/// (lhs.getWidth() == rhs.getWidth());
357/// }
358/// @endcode
359/// Next, we define `hashAppend` for `Box`. Notice how as well as calling
360/// `hashAppend` on fundamental types, we can also call it with our user defined
361/// type `Point`. Calling `hashAppend` with `Point` will propogate a reference
362/// to the hashing algorithm functor `hashAlg` down to the fundamental types
363/// that make up `Point`, and those types will then be passed into the
364/// referenced algorithm functor.
365/// @code
366/// template <class HASH_ALGORITHM>
367/// void hashAppend(HASH_ALGORITHM& hashAlg, const Box& box)
368/// // Apply the specified 'hashAlg' to the specified 'box'
369/// {
370/// using bslh::hashAppend;
371/// hashAppend(hashAlg, box.getPosition());
372/// hashAppend(hashAlg, box.getLength());
373/// hashAppend(hashAlg, box.getWidth());
374/// }
375/// @endcode
376/// Then, we declare our hash table (implementation elided). We simplify the
377/// problem by requiring the caller to supply an array. Our hash table takes
378/// two type parameters: `TYPE` (the type being referenced) and `HASHER` (a
379/// functor that produces the hash). `HASHER` will default to `bslh::Hash<>`.
380/// @code
381/// template <class TYPE, class HASHER = bslh::Hash<> >
382/// class HashTable {
383/// // This class template implements a hash table providing fast lookup of
384/// // an external, non-owned, array of values of (template parameter)
385/// // 'TYPE'.
386/// //
387/// // The (template parameter) 'TYPE' shall have a transitive, symmetric
388/// // 'operator==' function and it will be hashable using 'bslh::Hash'.
389/// // Note that there is no requirement that it have any kind of creator
390/// // defined.
391/// //
392/// // The 'HASHER' template parameter type must be a functor with a method
393/// // having the following signature:
394/// //..
395/// // size_t operator()(TYPE) const;
396/// // -OR-
397/// // size_t operator()(const TYPE&) const;
398/// //..
399/// // and 'HASHER' shall have a publicly accessible default constructor
400/// // and destructor. Here we use 'bslh::Hash' as our default template
401/// // argument. This allows us to hash any type for which 'hashAppend'
402/// // has been implemented.
403/// //
404/// // Note that this hash table has numerous simplifications because we
405/// // know the size of the array and never have to resize the table.
406///
407/// // DATA
408/// const TYPE *d_values; // Array of values table is to
409/// // hold
410/// size_t d_numValues; // Length of 'd_values'.
411/// const TYPE **d_bucketArray; // Contains ptrs into
412/// // 'd_values'
413/// size_t d_bucketArrayMask; // Will always be '2^N - 1'.
414/// HASHER d_hasher;
415///
416/// private:
417/// // PRIVATE ACCESSORS
418/// bool lookup(size_t *idx,
419/// const TYPE& value,
420/// size_t hashValue) const;
421/// // Look up the specified 'value', having the specified 'hashValue',
422/// // and load its index in 'd_bucketArray' into the specified 'idx'.
423/// // If not found, return the vacant entry in 'd_bucketArray' where
424/// // it should be inserted. Return 'true' if 'value' is found and
425/// // 'false' otherwise.
426///
427/// public:
428/// // CREATORS
429/// HashTable(const TYPE *valuesArray,
430/// size_t numValues);
431/// // Create a hash table referring to the specified 'valuesArray'
432/// // having length of the specified 'numValues'. No value in
433/// // 'valuesArray' shall have the same value as any of the other
434/// // values in 'valuesArray'
435///
436/// ~HashTable();
437/// // Free up memory used by this hash table.
438///
439/// // ACCESSORS
440/// bool contains(const TYPE& value) const;
441/// // Return true if the specified 'value' is found in the table and
442/// // false otherwise.
443/// };
444/// @endcode
445/// Next, we will create an array of boxes that we want to store in our hash
446/// table.
447/// @code
448///
449/// Box boxes[] = { Box(Point(1, 1), 3, 2),
450/// Box(Point(3, 1), 4, 2),
451/// Box(Point(1, 2), 3, 3),
452/// Box(Point(1, 1), 2, 2),
453/// Box(Point(1, 4), 4, 3),
454/// Box(Point(2, 1), 4, 2),
455/// Box(Point(1, 0), 3, 1)};
456/// enum { NUM_BOXES = sizeof boxes / sizeof *boxes };
457///
458/// @endcode
459/// Then, we create our hash table `hashTable`. We pass we use the default
460/// functor which will pick up the `hashAppend` function we created:
461/// @code
462///
463/// HashTable<Box> hashTable(boxes, NUM_BOXES);
464/// @endcode
465/// Now, we verify that each element in our array registers with count:
466/// @code
467/// for ( int i = 0; i < 6; ++i) { ASSERT(hashTable.contains(boxes[i])); }
468/// @endcode
469/// Finally, we verify that futures not in our original array are correctly
470/// identified as not being in the set:
471/// @code
472/// ASSERT(!hashTable.contains(Box(Point(1, 1), 1, 1)));
473/// ASSERT(!hashTable.contains(Box(Point(0, 0), 0, 0)));
474/// ASSERT(!hashTable.contains(Box(Point(3, 3), 3, 3)));
475/// @endcode
476/// @}
477/** @} */
478/** @} */
479
480/** @addtogroup bsl
481 * @{
482 */
483/** @addtogroup bslh
484 * @{
485 */
486/** @addtogroup bslh_hash
487 * @{
488 */
489
490#include <bslscm_version.h>
491
493
494#include <bslmf_enableif.h>
496#include <bslmf_isenum.h>
498#include <bslmf_isintegral.h>
499#include <bslmf_ispointer.h>
500#include <bslmf_issame.h>
503
505#include <bsls_platform.h>
506
507#include <stddef.h> // for 'size_t'
508
509
510namespace bslh {
511
512 // ===========================
513 // class bslh::Hash_AdlWrapper
514 // ===========================
515
516/// This `class` is a wrapper that is useful in the case of `HASH_ALGORITHM`
517/// not being in the `bslh` namespace, which can be problematic for ADL
518/// lookup of `bslh::hashAppend`. Wrapping a hash algorithm in this
519/// wrapper, which is called inline, effectively forwards the algorithm into
520/// the `bslh` namespace.
521///
522/// More detailed explanation:
523///
524/// Normally, we define the free functions `hashAppend` in the same
525/// namespaces as the types they are hashing, so that ADL will find the
526/// function. In cases where this is not possible, such as `std`, we
527/// support defining a `hashAppend` overload in the `bslh` namespace
528/// instead. This wrapper makes sure that `bslh` is an associated namespace
529/// when it is used as the first argument to `hashAppend`, ensuring that
530/// such overloads in `bslh` added outside this component are still found
531/// via ADL. Without this wrapper, in the cases where the hash algorithm is
532/// neither in `bslh` nor in the namespace of the hashed type, ADL then
533/// fails to find the function.
534///
535/// This wrapper solves this problem by forcibly associating the invocation
536/// of `hashAppend`, wherever it may be, with the `bslh` namespace.
537///
538/// See @ref bslh_hash
539template <class HASH_ALGORITHM>
541
542 public:
543 typedef typename HASH_ALGORITHM::result_type result_type;
544
545 private:
546 // DATA
547 HASH_ALGORITHM d_hashAlgorithm; // the wrapped hash algorithm, which may
548 // be in any namespace
549
550 public:
551 // CREATORS
552
553 /// Default construct an instance of the hash algorithm wrapped in this
554 /// wrapper.
556
557 // MANIPULATORS
558
559 /// Forward the call to the identical manipulator of `HASH_ALGORITHM`,
560 /// passing on the specified `input` and `numBytes`.
561 void operator()(const void *input, size_t numBytes);
562
563 /// Forward the call to the identical manipulator of `HASH_ALGORITHM`,
564 /// passing on the specified `input` and `numBytes`.
565 template <class ELEMENT_TYPE>
566 void operator()(const ELEMENT_TYPE *input, size_t numBytes);
567
568 /// Forward the call to the identical manipulator of `HASH_ALGORITHM`
569 /// and cast the return value to 'result_type.
571};
572
573 // ================
574 // class bslh::Hash
575 // ================
576
577/// This struct wraps the (template parameter) type `HASH_ALGORITHM` in an
578/// interface that satisfies the `hash` requirements of the C++11 standard.
579template <class HASH_ALGORITHM = bslh::DefaultHashAlgorithm>
580struct Hash {
581
582 // TYPES
583
584 /// The type of the hash value that will be returned by the
585 /// function-call operator.
586 typedef size_t result_type;
587
588 /// Make the `HASH_ALGORITHM` template parameter available to clients.
589 typedef HASH_ALGORITHM HashAlgorithm;
590
591 // CREATORS
592 Hash() = default;
593 // Create a 'bslh::Hash' object.
594
595 /// Create a `bslh::Hash` object. Note that as `bslh::Hash` is an empty
596 /// (stateless) type, this operation will have no observable effect.
597 Hash(const Hash& original) = default;
598
599 /// Destroy this object.
600 ~Hash() = default;
601
602 // MANIPULATORS
603
604 /// Assign to this object the value of the specified `rhs` object, and
605 /// return a reference providing modifiable access to this object. Note
606 /// that as `bslh::Hash` is an empty (stateless) type, this operation will
607 /// have no observable effect.
608 Hash& operator=(const Hash& rhs) = default;
609
610 // ACCESSORS
611
612 /// Returns a hash value generated by the (template parameter) type
613 /// `HASH_ALGORITHM` for the specified `type`. The value returned by
614 /// the `HASH_ALGORITHM` is cast to `size_t` before returning.
615 template <class TYPE>
616 result_type operator()(const TYPE& type) const;
617
618};
619
620// FREE FUNCTIONS
621
622/// Passes the specified `input` into the specified `hashAlg` to be combined
623/// into the internal state of the algorithm which is used to produce the
624/// resulting hash value. Note that the `enable_if` meta-function is used
625/// to enable this `hashAppend` function for only integral (excluding
626/// `bool`), pointer, and enum types, because these types can all be hashed
627/// as a continuous sequence of bytes. Also note that this function is
628/// defined inline because MS Visual Studio compilers before 2013 require
629/// (some) functions declared using enable_if be in-place inline.
630template <class HASH_ALGORITHM, class TYPE>
631inline
632typename bsl::enable_if<
637>::type
638hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
639{
640 hashAlg(&input, sizeof(input));
641}
642
643/// Passes the specified `input` into the specified `hashAlg` to be combined
644/// into the internal state of the algorithm which is used to produce the
645/// resulting hash value. Note that the `enable_if` meta-function is used
646/// to enable this `hashAppend` function for only floating point (excluding
647/// `long double`) types, because these types need to have +/-0.0 normalized
648/// to 0.0 before they can be hashed as a continuous sequence of bytes.
649/// Also note that this function is defined inline because MS Visual Studio
650/// compilers before 2013 require (some) functions declared using enable_if
651/// be in-place inline.
652template <class HASH_ALGORITHM, class TYPE>
653inline
654typename bsl::enable_if<
657>::type
658hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
659{
660 if (input == 0)
661 input = 0;
662 hashAlg(&input, sizeof(input));
663}
664
665/// Passes the specified `input` into the specified `hashAlg` to be combined
666/// into the internal state of the algorithm which is used to produce the
667/// resulting hash value. Note that the `enable_if` meta-function is used
668/// to enable this `hashAppend` function for only `bool`, because `bool`s
669/// can have multiple `true` representations and need to be normalized
670/// before they can be hashed as a continuous sequence of bytes.
671template <class HASH_ALGORITHM, class TYPE>
673hashAppend(HASH_ALGORITHM& hashAlg, TYPE input);
674
675/// Passes the specified `input` into the specified `hashAlg` to be combined
676/// into the internal state of the algorithm which is used to produce the
677/// resulting hash value. Note that the `enable_if` meta-function is used
678/// to enable this `hashAppend` function for only `long double`, because on
679/// some compilers `long double`s contain garbage and can not be hashed as a
680/// continuous sequence of bytes.
681template <class HASH_ALGORITHM, class TYPE>
683hashAppend(HASH_ALGORITHM& hashAlg, TYPE input);
684
685/// Passes the specified `input` into the specified `hashAlg` to be combined
686/// into the internal state of the algorithm which is used to produce the
687/// resulting hash value. Note that the entire `char` array will be hashed
688/// in only one call to `hashAlg`. Also note that this `hashAppend` exists
689/// because some platforms don't recognize that adding a const qualifier is
690/// a better match for arrays than decaying to a pointer and using the
691/// `hashAppend` function for pointers.
692template <class HASH_ALGORITHM, size_t N>
693void hashAppend(HASH_ALGORITHM& hashAlg, char (&input)[N]);
694
695/// Passes the specified `input` into the specified `hashAlg` to be combined
696/// into the internal state of the algorithm which is used to produce the
697/// resulting hash value. Note that the entire `char` array will be hashed
698/// in only one call to `hashAlg`.
699template <class HASH_ALGORITHM, size_t N>
700void hashAppend(HASH_ALGORITHM& hashAlg, const char (&input)[N]);
701
702/// Passes the specified `input` into the specified `hashAlg` to be combined
703/// into the internal state of the algorithm which is used to produce the
704/// resulting hash value. Note that the elements in `input` will be hashed
705/// one at a time by calling `hashAppend` because the (template parameter)
706/// `TYPE` might not be hashable as a contiguous sequence of bytes. Also
707/// note that this `hashAppend` exists because some platforms don't
708/// recognize that adding a const qualifier is a better match for arrays
709/// than decaying to a pointer and using the `hashAppend` function for
710/// pointers.
711template <class HASH_ALGORITHM, class TYPE, size_t N>
712void hashAppend(HASH_ALGORITHM& hashAlg, TYPE (&input)[N]);
713
714/// Passes the specified `input` into the specified `hashAlg` to be combined
715/// into the internal state of the algorithm which is used to produce the
716/// resulting hash value. Note that the elements in `input` will be hashed
717/// one at a time by calling `hashAppend` because the (template parameter)
718/// `TYPE` might not be hashable as a contiguous sequence of bytes.
719template <class HASH_ALGORITHM, class TYPE, size_t N>
720void hashAppend(HASH_ALGORITHM& hashAlg, const TYPE (&input)[N]);
721
722} // close package namespace
723
724// ============================================================================
725// INLINE DEFINITIONS
726// ============================================================================
727
728 // ---------------------
729 // bslh::Hash_AdlWrapper
730 // ---------------------
731
732// CREATORS
733template <class HASH_ALGORITHM>
734inline
738
739// MANIPULATORS
740template <class HASH_ALGORITHM>
741inline
743 size_t numBytes)
744{
745 d_hashAlgorithm(input, numBytes);
746}
747
748template <class HASH_ALGORITHM>
749template <class ELEMENT_TYPE>
750inline
752 const ELEMENT_TYPE *input,
753 size_t numBytes)
754{
755 d_hashAlgorithm(input, numBytes);
756}
757
758template <class HASH_ALGORITHM>
759inline
762{
763 return d_hashAlgorithm.computeHash();
764}
765
766 // ----------
767 // bslh::Hash
768 // ----------
769
770// ACCESSORS
771template <class HASH_ALGORITHM>
772template <class TYPE>
773inline
776{
778
779 hashAppend(wrapper, key);
780 return static_cast<result_type>(wrapper.computeHash());
781}
782
783template <>
784template <class TYPE>
785inline
788{
789 DefaultHashAlgorithm hashAlg;
790
791 hashAppend(hashAlg, key);
792 return static_cast<result_type>(hashAlg.computeHash());
793}
794
795 // --------------
796 // FREE FUNCTIONS
797 // --------------
798
799// FREE FUNCTIONS
800template <class HASH_ALGORITHM, class TYPE>
801inline
803bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
804{
805 // We need to ensure that any inputs that compare equal produce the same
806 // hash. Any non-zero binary representation of 'input' can be 'true', so
807 // we need to normalize 'input' to ensure that we do not pass two different
808 // binary representations of 'true' true into our hashing algorithm.
809
810 unsigned char normalizedData = !!input;
811
812 hashAlg(static_cast<void *>(&normalizedData), sizeof(normalizedData));
813}
814
815template <class HASH_ALGORITHM, class TYPE>
816inline
818bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
819{
820 if (input == 0.0l){
821 input = 0;
822 }
823
824#if (defined BSLS_PLATFORM_CPU_X86 || defined BSLS_PLATFORM_CPU_X86_64) && \
825 (defined BSLS_PLATFORM_CMP_GNU || defined BSLS_PLATFORM_CMP_CLANG)
826 // This needs to be done to work around issues when compiling with GCC and
827 // Clang on 86 machines. On 64-bit hardware, 'sizeof(long double)' is
828 // advertised as 16 bytes, but only 10 bytes of precision is used. The
829 // remaining 6 bytes are padding.
830 //
831 // For Clang, the final 2 bytes of the padding are zeroed, but the 4 bytes
832 // that proceed the final two appear to be garbage.
833 //
834 //..
835 // Actual Data --+*****************************+
836 // | |
837 // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 87 d8 5c 2b 0 0
838 // | || |
839 // Garbage -------------------------------------+**********+| |
840 // Zeroed --------------------------------------------------+***+
841 //..
842 //
843 // For GCC, the first and last 2 bytes of the padding are zeroed, but the 2
844 // bytes in the middle appear to be garbage.
845 //
846 //..
847 // Garbage -------------------------------------------+****+
848 // Actual Data --+*****************************+ | |
849 // | | | |
850 // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 0 0 5c 2b 0 0
851 // | | | |
852 // Zeroed --------------------------------------+****+------+****+
853 //..
854 //
855 // On 32-bit hardware, 'sizeof(long double)' is advertised as 12 bytes, but
856 // again, only 10 bytes of precision is used. The remaining 2 bytes are
857 // padding.
858 //
859 // For Clang, the 2 bytes of the padding appear to be garbage.
860 //
861 //..
862 // Actual Data --+*****************************+
863 // | |
864 // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 87 d8
865 // | |
866 // Garbage -------------------------------------+****+
867 //..
868 //
869 // For GCC, the 2 bytes of the padding are zeroed.
870 //
871 //..
872 // Actual Data --+*****************************+
873 // | |
874 // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 0 0
875 // | |
876 // Zeroed --------------------------------------+****+
877 //..
878 //
879 // To address all of these issues, we will pass in only 10 bytes for a
880 // 'long double' even if it is longer.
881 #if !defined(BSLS_PLATFORM_CMP_CLANG) && BSLS_PLATFORM_CPU_X86_64
882 // We cant just check 'defined(BSLS_PLATFORM_CMP_GNU)' because Clang
883 // masquerades as GCC. Since we know that to be in this block we must be
884 // using GCC or Clang, we can just check
885 // '!defined(BSLS_PLATFORM_CMP_CLANG)' to get the same result.
886
888 // We need to handle the posibility that somebody has set the GCC
889 // compiler flag that makes 'long double' actually be 128-bit.
890 hashAlg(&input, sizeof(input));
891 return; // RETURN
892 }
893 #endif
894 hashAlg(&input, sizeof(input) > 10 ? 10 : sizeof(input));
895#else
896 hashAlg(&input, sizeof(input));
897#endif
898}
899
900template <class HASH_ALGORITHM, size_t N>
901inline
902void bslh::hashAppend(HASH_ALGORITHM& hashAlg, char (&input)[N])
903{
904 hashAlg(&input, sizeof(char)*N);
905}
906
907template <class HASH_ALGORITHM, size_t N>
908inline
909void bslh::hashAppend(HASH_ALGORITHM& hashAlg, const char (&input)[N])
910{
911 hashAlg(&input, sizeof(char)*N);
912}
913
914template <class HASH_ALGORITHM, class TYPE, size_t N>
915inline
916void bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE (&input)[N])
917{
918
919 for (size_t i = 0; i < N; ++i) {
920 hashAppend(hashAlg, input[i]);
921 }
922}
923
924
925template <class HASH_ALGORITHM, class TYPE, size_t N>
926inline
927void bslh::hashAppend(HASH_ALGORITHM& hashAlg, const TYPE (&input)[N])
928{
929 for (size_t i = 0; i < N; ++i) {
930 hashAppend(hashAlg, input[i]);
931 }
932}
933
934// ============================================================================
935// TYPE TRAITS
936// ============================================================================
937
938// Type traits for STL 'hash'
939//: o 'bsl::hash<TYPE>' is trivially default constructible.
940//: o 'bsl::hash<TYPE>' is trivially copyable.
941//: o 'bsl::hash<TYPE>' is bitwise movable.
942
943namespace bslmf {
944template <class TYPE>
945struct IsBitwiseMoveable<bslh::Hash<TYPE> >
946 : bsl::true_type {};
947} // close namespace bslmf
948
949
950
951
952namespace bsl {
953template <class TYPE>
954struct is_trivially_default_constructible< ::BloombergLP::bslh::Hash<TYPE> >
956{};
957
958template <class TYPE>
959struct is_trivially_copyable< ::BloombergLP::bslh::Hash<TYPE> >
961{};
962} // close namespace bsl
963
964
965
966#endif
967
968// ----------------------------------------------------------------------------
969// Copyright 2017 Bloomberg Finance L.P.
970//
971// Licensed under the Apache License, Version 2.0 (the "License");
972// you may not use this file except in compliance with the License.
973// You may obtain a copy of the License at
974//
975// http://www.apache.org/licenses/LICENSE-2.0
976//
977// Unless required by applicable law or agreed to in writing, software
978// distributed under the License is distributed on an "AS IS" BASIS,
979// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
980// See the License for the specific language governing permissions and
981// limitations under the License.
982// ----------------------------- END-OF-FILE ----------------------------------
983
984/** @} */
985/** @} */
986/** @} */
Definition bslh_defaulthashalgorithm.h:346
result_type computeHash()
Definition bslh_defaulthashalgorithm.h:428
Definition bslh_hash.h:540
HASH_ALGORITHM::result_type result_type
Definition bslh_hash.h:543
result_type computeHash()
Definition bslh_hash.h:761
void operator()(const void *input, size_t numBytes)
Definition bslh_hash.h:742
Hash_AdlWrapper()
Definition bslh_hash.h:735
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlb_printmethods.h:283
Definition bslh_defaulthashalgorithm.h:339
bsl::enable_if<(bsl::is_integral< TYPE >::value||bsl::is_pointer< TYPE >::value||bsl::is_enum< TYPE >::value)&&!bsl::is_same< TYPE, bool >::value >::type hashAppend(HASH_ALGORITHM &hashAlg, TYPE input)
Definition bslh_hash.h:638
Definition bdlbb_blob.h:576
Definition bslmf_enableif.h:525
Definition bslmf_isenum.h:270
Definition bslmf_isfloatingpoint.h:134
Definition bslmf_isintegral.h:130
Definition bslmf_ispointer.h:138
Definition bslmf_issame.h:146
Definition bslmf_istriviallycopyable.h:329
Definition bslmf_istriviallydefaultconstructible.h:293
Definition bslh_hash.h:580
result_type operator()(const TYPE &type) const
Hash()=default
~Hash()=default
Destroy this object.
Hash & operator=(const Hash &rhs)=default
Hash(const Hash &original)=default
size_t result_type
Definition bslh_hash.h:586
HASH_ALGORITHM HashAlgorithm
Make the HASH_ALGORITHM template parameter available to clients.
Definition bslh_hash.h:589
Definition bslmf_isbitwisemoveable.h:718