BDE 4.39.x 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.
579///
580/// See @ref bslh_hash
581template <class HASH_ALGORITHM = bslh::DefaultHashAlgorithm>
582struct Hash {
583
584 // TYPES
585
586 /// The type of the hash value that will be returned by the
587 /// function-call operator.
588 typedef size_t result_type;
589
590 /// Make the `HASH_ALGORITHM` template parameter available to clients.
591 typedef HASH_ALGORITHM HashAlgorithm;
592
593 // CREATORS
594 Hash() = default;
595 // Create a 'bslh::Hash' object.
596
597 /// Create a `bslh::Hash` object.
598 /// \note Note that as `bslh::Hash` is an empty
599 /// (stateless) type, this operation will have no observable effect.
600 Hash(const Hash& original) = default;
601
602 /// Destroy this object.
603 ~Hash() = default;
604
605 // MANIPULATORS
606
607 /// Assign to this object the value of the specified `rhs` object, and
608 /// return a reference providing modifiable access to this object.
609 ///
610 /// \note Note that as `bslh::Hash` is an empty (stateless) type, this operation will
611 /// have no observable effect.
612 Hash& operator=(const Hash& rhs) = default;
613
614 // ACCESSORS
615
616 /// Returns a hash value generated by the (template parameter) type
617 /// `HASH_ALGORITHM` for the specified `type`. The value returned by
618 /// the `HASH_ALGORITHM` is cast to `size_t` before returning.
619 template <class TYPE>
620 result_type operator()(const TYPE& type) const;
621
622};
623
624// FREE FUNCTIONS
625
626/// Passes the specified `input` into the specified `hashAlg` to be combined
627/// into the internal state of the algorithm which is used to produce the resulting hash value.
628///
629/// \note Note that the `enable_if` meta-function is used
630/// to enable this `hashAppend` function for only integral (excluding
631/// `bool`), pointer, and enum types, because these types can all be hashed
632/// as a continuous sequence of bytes. Also note that this function is
633/// defined inline because MS Visual Studio compilers before 2013 require
634/// (some) functions declared using enable_if be in-place inline.
635template <class HASH_ALGORITHM, class TYPE>
636inline
637typename bsl::enable_if<
642>::type
643hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
644{
645 hashAlg(&input, sizeof(input));
646}
647
648/// Passes the specified `input` into the specified `hashAlg` to be combined
649/// into the internal state of the algorithm which is used to produce the resulting hash value.
650///
651/// \note Note that the `enable_if` meta-function is used
652/// to enable this `hashAppend` function for only floating point (excluding
653/// `long double`) types, because these types need to have +/-0.0 normalized
654/// to 0.0 before they can be hashed as a continuous sequence of bytes.
655/// Also note that this function is defined inline because MS Visual Studio
656/// compilers before 2013 require (some) functions declared using enable_if
657/// be in-place inline.
658template <class HASH_ALGORITHM, class TYPE>
659inline
660typename bsl::enable_if<
663>::type
664hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
665{
666 if (input == 0)
667 input = 0;
668 hashAlg(&input, sizeof(input));
669}
670
671/// Passes the specified `input` into the specified `hashAlg` to be combined
672/// into the internal state of the algorithm which is used to produce the resulting hash value.
673///
674/// \note Note that the `enable_if` meta-function is used
675/// to enable this `hashAppend` function for only `bool`, because `bool`s
676/// can have multiple `true` representations and need to be normalized
677/// before they can be hashed as a continuous sequence of bytes.
678template <class HASH_ALGORITHM, class TYPE>
680hashAppend(HASH_ALGORITHM& hashAlg, TYPE input);
681
682/// Passes the specified `input` into the specified `hashAlg` to be combined
683/// into the internal state of the algorithm which is used to produce the resulting hash value.
684///
685/// \note Note that the `enable_if` meta-function is used
686/// to enable this `hashAppend` function for only `long double`, because on
687/// some compilers `long double`s contain garbage and can not be hashed as a
688/// continuous sequence of bytes.
689template <class HASH_ALGORITHM, class TYPE>
691hashAppend(HASH_ALGORITHM& hashAlg, TYPE input);
692
693/// Passes the specified `input` into the specified `hashAlg` to be combined
694/// into the internal state of the algorithm which is used to produce the resulting hash value.
695///
696/// \note Note that the entire `char` array will be hashed
697/// in only one call to `hashAlg`. Also note that this `hashAppend` exists
698/// because some platforms don't recognize that adding a const qualifier is
699/// a better match for arrays than decaying to a pointer and using the
700/// `hashAppend` function for pointers.
701template <class HASH_ALGORITHM, size_t N>
702void hashAppend(HASH_ALGORITHM& hashAlg, char (&input)[N]);
703
704/// Passes the specified `input` into the specified `hashAlg` to be combined
705/// into the internal state of the algorithm which is used to produce the resulting hash value.
706///
707/// \note Note that the entire `char` array will be hashed
708/// in only one call to `hashAlg`.
709template <class HASH_ALGORITHM, size_t N>
710void hashAppend(HASH_ALGORITHM& hashAlg, const char (&input)[N]);
711
712/// Passes the specified `input` into the specified `hashAlg` to be combined
713/// into the internal state of the algorithm which is used to produce the resulting hash value.
714///
715/// \note Note that the elements in `input` will be hashed
716/// one at a time by calling `hashAppend` because the (template parameter)
717/// `TYPE` might not be hashable as a contiguous sequence of bytes. Also
718/// note that this `hashAppend` exists because some platforms don't
719/// recognize that adding a const qualifier is a better match for arrays
720/// than decaying to a pointer and using the `hashAppend` function for
721/// pointers.
722template <class HASH_ALGORITHM, class TYPE, size_t N>
723void hashAppend(HASH_ALGORITHM& hashAlg, TYPE (&input)[N]);
724
725/// Passes the specified `input` into the specified `hashAlg` to be combined
726/// into the internal state of the algorithm which is used to produce the resulting hash value.
727///
728/// \note Note that the elements in `input` will be hashed
729/// one at a time by calling `hashAppend` because the (template parameter)
730/// `TYPE` might not be hashable as a contiguous sequence of bytes.
731template <class HASH_ALGORITHM, class TYPE, size_t N>
732void hashAppend(HASH_ALGORITHM& hashAlg, const TYPE (&input)[N]);
733
734} // close package namespace
735
736// ============================================================================
737// INLINE DEFINITIONS
738// ============================================================================
739
740 // ---------------------
741 // bslh::Hash_AdlWrapper
742 // ---------------------
743
744// CREATORS
745template <class HASH_ALGORITHM>
746inline
750
751// MANIPULATORS
752template <class HASH_ALGORITHM>
753inline
755 size_t numBytes)
756{
757 d_hashAlgorithm(input, numBytes);
758}
759
760template <class HASH_ALGORITHM>
761template <class ELEMENT_TYPE>
762inline
764 const ELEMENT_TYPE *input,
765 size_t numBytes)
766{
767 d_hashAlgorithm(input, numBytes);
768}
769
770template <class HASH_ALGORITHM>
771inline
774{
775 return d_hashAlgorithm.computeHash();
776}
777
778 // ----------
779 // bslh::Hash
780 // ----------
781
782// ACCESSORS
783template <class HASH_ALGORITHM>
784template <class TYPE>
785inline
788{
790
791 hashAppend(wrapper, key);
792 return static_cast<result_type>(wrapper.computeHash());
793}
794
795template <>
796template <class TYPE>
797inline
800{
801 DefaultHashAlgorithm hashAlg;
802
803 hashAppend(hashAlg, key);
804 return static_cast<result_type>(hashAlg.computeHash());
805}
806
807 // --------------
808 // FREE FUNCTIONS
809 // --------------
810
811// FREE FUNCTIONS
812template <class HASH_ALGORITHM, class TYPE>
813inline
815bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
816{
817 // We need to ensure that any inputs that compare equal produce the same
818 // hash. Any non-zero binary representation of 'input' can be 'true', so
819 // we need to normalize 'input' to ensure that we do not pass two different
820 // binary representations of 'true' true into our hashing algorithm.
821
822 unsigned char normalizedData = !!input;
823
824 hashAlg(static_cast<void *>(&normalizedData), sizeof(normalizedData));
825}
826
827template <class HASH_ALGORITHM, class TYPE>
828inline
830bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE input)
831{
832 if (input == 0.0l){
833 input = 0;
834 }
835
836#if (defined BSLS_PLATFORM_CPU_X86 || defined BSLS_PLATFORM_CPU_X86_64) && \
837 (defined BSLS_PLATFORM_CMP_GNU || defined BSLS_PLATFORM_CMP_CLANG)
838 // This needs to be done to work around issues when compiling with GCC and
839 // Clang on 86 machines. On 64-bit hardware, 'sizeof(long double)' is
840 // advertised as 16 bytes, but only 10 bytes of precision is used. The
841 // remaining 6 bytes are padding.
842 //
843 // For Clang, the final 2 bytes of the padding are zeroed, but the 4 bytes
844 // that proceed the final two appear to be garbage.
845 //
846 //..
847 // Actual Data --+*****************************+
848 // | |
849 // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 87 d8 5c 2b 0 0
850 // | || |
851 // Garbage -------------------------------------+**********+| |
852 // Zeroed --------------------------------------------------+***+
853 //..
854 //
855 // For GCC, the first and last 2 bytes of the padding are zeroed, but the 2
856 // bytes in the middle appear to be garbage.
857 //
858 //..
859 // Garbage -------------------------------------------+****+
860 // Actual Data --+*****************************+ | |
861 // | | | |
862 // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 0 0 5c 2b 0 0
863 // | | | |
864 // Zeroed --------------------------------------+****+------+****+
865 //..
866 //
867 // On 32-bit hardware, 'sizeof(long double)' is advertised as 12 bytes, but
868 // again, only 10 bytes of precision is used. The remaining 2 bytes are
869 // padding.
870 //
871 // For Clang, the 2 bytes of the padding appear to be garbage.
872 //
873 //..
874 // Actual Data --+*****************************+
875 // | |
876 // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 87 d8
877 // | |
878 // Garbage -------------------------------------+****+
879 //..
880 //
881 // For GCC, the 2 bytes of the padding are zeroed.
882 //
883 //..
884 // Actual Data --+*****************************+
885 // | |
886 // Actual long double: 5d e9 79 a9 c2 82 bb ef 2b 40 0 0
887 // | |
888 // Zeroed --------------------------------------+****+
889 //..
890 //
891 // To address all of these issues, we will pass in only 10 bytes for a
892 // 'long double' even if it is longer.
893 #if !defined(BSLS_PLATFORM_CMP_CLANG) && BSLS_PLATFORM_CPU_X86_64
894 // We cant just check 'defined(BSLS_PLATFORM_CMP_GNU)' because Clang
895 // masquerades as GCC. Since we know that to be in this block we must be
896 // using GCC or Clang, we can just check
897 // '!defined(BSLS_PLATFORM_CMP_CLANG)' to get the same result.
898
900 // We need to handle the posibility that somebody has set the GCC
901 // compiler flag that makes 'long double' actually be 128-bit.
902 hashAlg(&input, sizeof(input));
903 return; // RETURN
904 }
905 #endif
906 hashAlg(&input, sizeof(input) > 10 ? 10 : sizeof(input));
907#else
908 hashAlg(&input, sizeof(input));
909#endif
910}
911
912template <class HASH_ALGORITHM, size_t N>
913inline
914void bslh::hashAppend(HASH_ALGORITHM& hashAlg, char (&input)[N])
915{
916 hashAlg(&input, sizeof(char)*N);
917}
918
919template <class HASH_ALGORITHM, size_t N>
920inline
921void bslh::hashAppend(HASH_ALGORITHM& hashAlg, const char (&input)[N])
922{
923 hashAlg(&input, sizeof(char)*N);
924}
925
926template <class HASH_ALGORITHM, class TYPE, size_t N>
927inline
928void bslh::hashAppend(HASH_ALGORITHM& hashAlg, TYPE (&input)[N])
929{
930
931 for (size_t i = 0; i < N; ++i) {
932 hashAppend(hashAlg, input[i]);
933 }
934}
935
936
937template <class HASH_ALGORITHM, class TYPE, size_t N>
938inline
939void bslh::hashAppend(HASH_ALGORITHM& hashAlg, const TYPE (&input)[N])
940{
941 for (size_t i = 0; i < N; ++i) {
942 hashAppend(hashAlg, input[i]);
943 }
944}
945
946// ============================================================================
947// TYPE TRAITS
948// ============================================================================
949
950// Type traits for STL 'hash'
951//: o 'bsl::hash<TYPE>' is trivially default constructible.
952//: o 'bsl::hash<TYPE>' is trivially copyable.
953//: o 'bsl::hash<TYPE>' is bitwise movable.
954
955namespace bslmf {
956template <class TYPE>
957struct IsBitwiseMoveable<bslh::Hash<TYPE> >
958 : bsl::true_type {};
959} // close namespace bslmf
960
961
962
963
964namespace bsl {
965template <class TYPE>
966struct is_trivially_default_constructible< ::BloombergLP::bslh::Hash<TYPE> >
968{};
969
970template <class TYPE>
971struct is_trivially_copyable< ::BloombergLP::bslh::Hash<TYPE> >
973{};
974} // close namespace bsl
975
976
977
978#endif
979
980// ----------------------------------------------------------------------------
981// Copyright 2017 Bloomberg Finance L.P.
982//
983// Licensed under the Apache License, Version 2.0 (the "License");
984// you may not use this file except in compliance with the License.
985// You may obtain a copy of the License at
986//
987// http://www.apache.org/licenses/LICENSE-2.0
988//
989// Unless required by applicable law or agreed to in writing, software
990// distributed under the License is distributed on an "AS IS" BASIS,
991// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
992// See the License for the specific language governing permissions and
993// limitations under the License.
994// ----------------------------- END-OF-FILE ----------------------------------
995
996/** @} */
997/** @} */
998/** @} */
Definition bslh_defaulthashalgorithm.h:346
result_type computeHash()
Definition bslh_defaulthashalgorithm.h:431
Definition bslh_hash.h:540
HASH_ALGORITHM::result_type result_type
Definition bslh_hash.h:543
result_type computeHash()
Definition bslh_hash.h:773
void operator()(const void *input, size_t numBytes)
Definition bslh_hash.h:754
Hash_AdlWrapper()
Definition bslh_hash.h:747
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlat_valuetypefunctions.h:939
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:643
Definition bdlbb_blob.h:579
Definition bslmf_enableif.h:530
Definition bslmf_isenum.h:272
Definition bslmf_isfloatingpoint.h:144
Definition bslmf_isintegral.h:140
Definition bslmf_ispointer.h:138
Definition bslmf_issame.h:146
Definition bslmf_istriviallycopyable.h:324
Definition bslmf_istriviallydefaultconstructible.h:296
Definition bslh_hash.h:582
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:588
HASH_ALGORITHM HashAlgorithm
Make the HASH_ALGORITHM template parameter available to clients.
Definition bslh_hash.h:591
Definition bslmf_isbitwisemoveable.h:718