BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlc_hashtable.h
Go to the documentation of this file.
1/// @file bdlc_hashtable.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlc_hashtable.h -*-C++-*-
8#ifndef INCLUDED_BDLC_HASHTABLE
9#define INCLUDED_BDLC_HASHTABLE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlc_hashtable bdlc_hashtable
15/// @brief Provide a double-hashed table with utility.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlc
19/// @{
20/// @addtogroup bdlc_hashtable
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlc_hashtable-purpose"> Purpose</a>
25/// * <a href="#bdlc_hashtable-classes"> Classes </a>
26/// * <a href="#bdlc_hashtable-description"> Description </a>
27/// * <a href="#bdlc_hashtable-traditional-hash-algorithm"> Traditional Hash Algorithm </a>
28/// * <a href="#bdlc_hashtable-double-hash-algorithm"> Double-Hash Algorithm </a>
29/// * <a href="#bdlc_hashtable-bucket-type"> Bucket Type </a>
30/// * <a href="#bdlc_hashtable-traits"> Traits </a>
31/// * <a href="#bdlc_hashtable-default-traits"> Default Traits </a>
32/// * <a href="#bdlc_hashtable-hash-functors"> Hash Functors </a>
33/// * <a href="#bdlc_hashtable-default-hash-functors"> Default Hash Functors </a>
34/// * <a href="#bdlc_hashtable-disabling-support-for-remove"> Disabling Support for remove </a>
35/// * <a href="#bdlc_hashtable-usage"> Usage </a>
36/// * <a href="#bdlc_hashtable-example-1-basic-usage"> Example 1: Basic Usage </a>
37///
38/// # Purpose {#bdlc_hashtable-purpose}
39/// Provide a double-hashed table with utility.
40///
41/// # Classes {#bdlc_hashtable-classes}
42///
43/// - bdlc::HashTable : double-hashed table
44/// - bdlc::HashTableDefaultTraits : default traits
45/// - bdlc::HashTableDefaultHash1 : default hash functor 1
46/// - bdlc::HashTableDefaultHash2 : default hash functor 2
47///
48/// @see bdlb_hashutil
49///
50/// # Description {#bdlc_hashtable-description}
51/// This component provides a mechanism, `bdlc::HashTable`, for
52/// efficiently finding elements identified by a parameterized `KEY`. Elements
53/// can also have an associated value by specifying an optional `VALUE` template
54/// parameter. Also, an optional `TRAITS` parameter can be supplied so that
55/// clients can override the default traits of the hash table,
56/// `bdlc::HashTableDefaultTraits`.
57///
58/// The `bdlc::HashTable` class achieves efficient lookup by using a double-hash
59/// algorithm, which will be explained later. Optional `HASH1` and `HASH2`
60/// parameters can be supplied so that clients can override the default hash
61/// functions used by the hash table, `bdlc::HashTableDefaultHash1` and
62/// `bdlc::HashTableDefaultHash2`. Hash functors may also optionally be
63/// specified at construction time, in case the functors contain state (e.g., if
64/// `bsl::function` is used).
65///
66/// The constructor for `bdlc::HashTable` takes a `capacityHint` argument. This
67/// `capacityHint` is used to calculate the capacity of the hash table (i.e.,
68/// the maximum number of elements that can be stored at any one time). Once
69/// constructed, the capacity cannot be changed. The capacity hint can be
70/// either a positive integer or a negative integer. If the capacity hint is
71/// positive, then the capacity of the hash table will be the first available
72/// prime number larger than, or equal to, the capacity hint. Otherwise, the
73/// capacity of the hash table will be the first available prime number smaller
74/// than, or equal to, the capacity hint. The list of available prime numbers
75/// is obtained from an array in the `bdlc_hashtable.cpp` file.
76///
77/// ## Traditional Hash Algorithm {#bdlc_hashtable-traditional-hash-algorithm}
78///
79///
80/// A typical hash table implementation uses only a single hash function to
81/// determine the index in the hash table to store a given element. This
82/// approach results in constant time access if there are no collisions. To
83/// handle cases where there are hash collisions, the hash table needs to
84/// maintain a linked list or tree of elements for each index in the table.
85/// This data structure is illustrated in the diagram below:
86/// @code
87/// Hash Table
88/// ----------
89///
90/// : :
91/// : :
92/// :......:
93/// : :
94/// index - 2 : :
95/// :______:
96/// | |
97/// index - 1 | |
98/// |______| ______ ______ ______
99/// | | | | | | | |
100/// index | | -> | | -> | | -> | | -> NULL
101/// |______| |______| |______| |______|
102/// | |
103/// index + 1 | | element1 element2 element3
104/// |______|
105/// | |
106/// index + 2 | |
107/// |______|
108/// : :
109/// : :
110/// :......:
111/// : :
112/// : :
113/// @endcode
114/// In the diagram above, `element1`, `element2`, and `element3` hash to the
115/// `index`th bucket in the hash table. Because of this collision, they are
116/// maintained in a linked list, which results in linear time complexity.
117///
118/// ## Double-Hash Algorithm {#bdlc_hashtable-double-hash-algorithm}
119///
120///
121/// The double-hash algorithm improves on the traditional algorithm by using a
122/// second hash function to compute an increment value. The index is
123/// incremented by the increment value until an available bucket is found.
124/// This augmented algorithm is illustrated in the following diagrams. Suppose
125/// we have a hash table that is initially empty:
126/// @code
127/// Hash Table
128/// ----------
129///
130/// : :
131/// : :
132/// :......:
133/// : :
134/// index - 2 : :
135/// :______:
136/// | |
137/// index - 1 | |
138/// |______|
139/// | |
140/// index | |
141/// |______|
142/// | |
143/// index + 1 | |
144/// |______|
145/// | |
146/// index + 2 | |
147/// |______|
148/// | |
149/// index + 3 | |
150/// |______|
151/// : :
152/// : :
153/// :......:
154/// : :
155/// : :
156/// @endcode
157/// Now suppose we insert `element1`. The first hash function evaluates to the
158/// `index`th bucket in the hash table:
159/// @code
160/// Hash Table
161/// ----------
162///
163/// : :
164/// : :
165/// :......:
166/// : :
167/// index - 2 : :
168/// :______:
169/// | |
170/// index - 1 | |
171/// |______| ______
172/// | | | |
173/// index | | -> | | element1
174/// |______| |______|
175/// | |
176/// index + 1 | |
177/// |______|
178/// | |
179/// index + 2 | |
180/// |______|
181/// | |
182/// index + 3 | |
183/// |______|
184/// : :
185/// : :
186/// :......:
187/// : :
188/// : :
189/// @endcode
190/// Now suppose we want to insert `element2`, for which the first hash function
191/// also evaluates to the `index`th bucket in the hash table; however, there is
192/// a collision. So, we will calculate an increment using the second hash
193/// function. Suppose the increment value is 3, we will insert `element2` at
194/// `index + 3`:
195/// @code
196/// Hash Table
197/// ----------
198///
199/// : :
200/// : :
201/// :......:
202/// : :
203/// index - 2 : :
204/// :______:
205/// | |
206/// index - 1 | |
207/// |______| ______
208/// | | | |
209/// .---- index | | -> | | element1
210/// | |______| |______|
211/// | | |
212/// | index + 1 | |
213/// | |______|
214/// | | |
215/// | index + 2 | |
216/// | |______| ______
217/// | | | | |
218/// `---> index + 3 | | -> | | element2
219/// |______| |______|
220/// | |
221/// index + 4 | |
222/// |______|
223/// | |
224/// index + 5 | |
225/// |______|
226/// | |
227/// index + 6 | |
228/// |______|
229/// | |
230/// index + 7 | |
231/// |______|
232/// : :
233/// : :
234/// :......:
235/// : :
236/// : :
237/// @endcode
238/// The entry for `element2` is said to be "chained" through node `index`.
239///
240/// Now suppose we want to insert `element3`, for which the first hash function
241/// also evaluates to the `index`th bucket in the hash table. Again, there is a
242/// collision. So, we will calculate an increment using the second hash
243/// function. Suppose the increment value is 5, we will insert `element3` at
244/// `index + 5`:
245/// @code
246/// Hash Table
247/// ----------
248///
249/// : :
250/// : :
251/// :......:
252/// : :
253/// index - 2 : :
254/// :______:
255/// | |
256/// index - 1 | |
257/// |______| ______
258/// | | | |
259/// .-----.---- index | | -> | | element1
260/// | | |______| |______|
261/// | | | |
262/// | | index + 1 | |
263/// | | |______|
264/// | | | |
265/// | | index + 2 | |
266/// | | |______| ______
267/// | | | | | |
268/// | `---> index + 3 | | -> | | element2
269/// | |______| |______|
270/// | | |
271/// | index + 4 | |
272/// | |______| ______
273/// | | | | |
274/// `---------> index + 5 | | -> | | element3
275/// |______| |______|
276/// | |
277/// index + 6 | |
278/// |______|
279/// | |
280/// index + 7 | |
281/// |______|
282/// : :
283/// : :
284/// :......:
285/// : :
286/// : :
287/// @endcode
288/// The entry for `element3` is also "chained" through node `index`.
289///
290/// If there is a collision even after applying the increment, then the
291/// increment can be applied again to form a longer chain, until an available
292/// bucket is found. For example, suppose we want to insert `element4`, for
293/// which the first hash function evaluates to the `index`th bucket. Since
294/// there is a collision, we calculate an increment using the second hash
295/// function. Suppose the increment value is 3, we will get another collision
296/// because `element2` occupies the bucket at `index + 3`. Therefore, we apply
297/// the increment again and we get `index + 3 + 3`, i.e., `index + 6`. This
298/// bucket is empty, so we can store `element4` here:
299/// @code
300/// Hash Table
301/// ----------
302///
303/// : :
304/// : :
305/// :......:
306/// : :
307/// index - 2 : :
308/// :______:
309/// | |
310/// index - 1 | |
311/// |______| ______
312/// | | | |
313/// .-----.---- index | | -> | | element1
314/// | | |______| |______|
315/// | | | |
316/// | | index + 1 | |
317/// | | |______|
318/// | | | |
319/// | | index + 2 | |
320/// | | |______| ______
321/// | | | | | |
322/// | `---> index + 3 | | -> | | element2
323/// | .---- |______| |______|
324/// | | | |
325/// | | index + 4 | |
326/// | | |______| ______
327/// | | | | | |
328/// `-----+---> index + 5 | | -> | | element3
329/// | |______| |______|
330/// | | | | |
331/// `---> index + 6 | | -> | | element4
332/// |______| |______|
333/// | |
334/// index + 7 | |
335/// |______|
336/// : :
337/// : :
338/// :......:
339/// : :
340/// : :
341/// @endcode
342/// The entry for `element4` is chained through nodes `index` and `index + 3`.
343///
344/// If the total number of buckets in the hash table and the increment value
345/// are relatively prime (i.e., their greatest common divisor is 1), then it is
346/// guaranteed that every bucket will be visited before looping back to `index`.
347///
348/// The `bdlc::HashTable` container makes sure that the number of buckets in the
349/// hash table and the increment values are relatively prime. The
350/// `bdlc::HashTable` container also keeps track of the maximum chain length,
351/// number of collisions, and the total chain length, which can be used for
352/// statistical purposes when evaluating different hash functions.
353///
354/// ## Bucket Type {#bdlc_hashtable-bucket-type}
355///
356///
357/// The `bdlc::HashTable` class treats individual buckets as value-semantic
358/// types. The type of the buckets depends on the `KEY` and `VALUE` parameters
359/// used to instantiate the `bdlc::HashTable` template. If the `VALUE`
360/// parameter is `bslmf::Nil`, then the type of the buckets is `KEY`.
361/// Otherwise, the type of the buckets is `bsl::pair<KEY, VALUE>`. For
362/// convenience, we will refer to the bucket type as `Bucket` throughout this
363/// documentation.
364///
365/// The `bdlc::HashTable` class reserves two distinct values from `Bucket`s
366/// value-space to represent a "null" bucket and a "removed" bucket. These
367/// values are determined by the `TRAITS` parameter, which is described in the
368/// next section. Since these two values are reserved for the internal use of
369/// the `bdlc::HashTable` class, the behavior is undefined if one of these
370/// values is inserted into the hash table. Taking these values from the
371/// value-space of `Bucket` allows the storage space required for each bucket to
372/// be as compact as possible.
373///
374/// ## Traits {#bdlc_hashtable-traits}
375///
376///
377/// An optional `TRAITS` parameter can be specified when instantiating the
378/// `bdlc::HashTable` template. This component provides a default traits
379/// implementation, `bdlc::HashTableDefaultTraits`, which will be described
380/// later.
381///
382/// The `TRAITS` parameter allows clients to specify how to load a bucket and
383/// how to compare keys. It also allows clients to classify two distinct values
384/// to represent "null" and "removed" buckets (see "Bucket Type" for more
385/// information about these reserved values).
386///
387/// In the following description, `key1` and `key2` refer to objects of type
388/// `KEY`. `bucket`, `dstBucket`, and `srcBucket` refer to objects of type
389/// `Bucket`.
390///
391/// The following expressions must be supported by the `TRAITS` parameter:
392/// @code
393/// Expression Semantics
394/// ---------- ---------
395/// TRAITS::load(&dstBucket, srcBucket) Load the value of the specified
396/// 'srcBucket' into the specified
397/// 'dstBucket'.
398///
399/// TRAITS::areEqual(key1, key2) Return true if the specified 'key1'
400/// matches the specified 'key2', and
401/// false otherwise.
402///
403/// TRAITS::isNull(bucket) Return true if the specified 'bucket'
404/// has the reserved "null" value, and
405/// false otherwise.
406///
407/// TRAITS::setToNull(&bucket) Load the reserved "null" value into
408/// the specified 'bucket'.
409///
410/// TRAITS::isRemoved(bucket) Return true if the specified 'bucket'
411/// has the reserved "removed" value, and
412/// false otherwise.
413///
414/// TRAITS::setToRemoved(&bucket) Load the reserved "removed" value
415/// into the specified 'bucket'.
416/// @endcode
417///
418/// ### Default Traits {#bdlc_hashtable-default-traits}
419///
420///
421/// The default traits, identified by `bdlc::HashTableDefaultTraits`, can be
422/// used when `KEY` and `VALUE` are either:
423/// * `const char *`
424/// * `bsl::string`
425/// * POD types
426///
427/// The following expressions are implemented as:
428/// @code
429/// Expression Implementation
430/// ---------- --------------
431/// TRAITS::load(&dstBucket, srcBucket) This function is implemented as
432/// '*dstBucket = srcBucket'.
433///
434/// TRAITS::areEqual(key1, key2) If 'KEY' is 'const char*', this
435/// function is implemented as
436/// 'bsl::strcmp(key1, key2)'.
437/// Otherwise, this function is
438/// implemented as 'key1 == key2'.
439/// @endcode
440/// The `isNull`, `setToNull`, `isRemoved`, and `setToRemoved` functions are
441/// implemented by checking for and assigning the appropriate "null" or
442/// "removed" values, respectively. These values are defined in the following
443/// table:
444/// @code
445/// Bucket Type Null Value Removed Value
446/// ----------- ---------- -------------
447/// const char* 0x00000000 address 0xFFFFFFFF address
448///
449/// bsl::string "" "(* REMOVED *)"
450///
451/// All other types All bytes in the footprint All bytes in the footprint
452/// are 0x00 are 0xFF
453/// @endcode
454/// If `Bucket` is of type `bsl::pair<KEY, VALUE>`, then the "null" and
455/// "removed" values are applied to both the `KEY` and the `VALUE`.
456///
457/// Since the default traits may write directly into the footprint of the bucket
458/// (except for `bsl::string`), it is important to note that the `KEY` and
459/// `VALUE` types should be POD types if the default traits are used.
460///
461/// ## Hash Functors {#bdlc_hashtable-hash-functors}
462///
463///
464/// Optional `HASH1` and `HASH2` parameters can be specified when instantiating
465/// the `bdlc::HashTable` template. This component provides a default hash
466/// functors, `bdlc::HashTableDefaultHash1` and `bdlc::HashTableDefaultHash2`,
467/// which will be described later.
468///
469/// The `HASH1` and `HASH2` parameters allow clients to specify hash functor
470/// policies for the first and second hash functions, respectively.
471///
472/// In the following description, `key` refers to an object of type `KEY`, and
473/// `functor` refers to an immutable object of type `HASH1` or `HASH2`.
474///
475/// The following expression must be supported by the supplied `HASH1` and
476/// `HASH2` parameters:
477/// @code
478/// Expression Semantics Return Type
479/// ---------- --------- -----------
480/// functor(&key) Return a hash value for the specified 'key' unsigned int
481/// @endcode
482///
483/// ### Default Hash Functors {#bdlc_hashtable-default-hash-functors}
484///
485///
486/// The default hash functors, identified by `bdlc::HashTableDefaultHash1` and
487/// `bdlc::HashTableDefaultHash2`, can be used when `KEY` is either:
488/// @code
489/// o const char*
490/// o bsl::string
491/// o a POD type
492/// @endcode
493/// The `bdlc::HashTableDefaultHash1` functor is implemented using
494/// `bdlb::HashUtil::hash1` and the `bdlc::HashTableDefaultHash2` functor is
495/// implemented using `bdlb::HashUtil::hash2`.
496///
497/// Note that `bdlb::HashUtil::hash1` and `bdlb::HashUtil::hash2` calculate hash
498/// value from a fixed length block of memory. This block of memory is obtained
499/// based on the following table:
500/// @code
501/// KEY Type Block Data Block Length
502/// -------- ---------- ------------
503/// const char* key bsl::strlen(key)
504///
505/// bsl::string key.data() key.length()
506///
507/// All other types reinterpret_cast<const char *>(&key) sizeof(key)
508/// @endcode
509/// Since the default hash functors use the footprint of the key (except for
510/// `const char*` and `bsl::string`) to compute hash values, it is important to
511/// note that the `KEY` type should be a POD type if the default hash functors
512/// are used.
513///
514/// ## Disabling Support for remove {#bdlc_hashtable-disabling-support-for-remove}
515///
516///
517/// By default (i.e., when using the default traits), the `remove` method can be
518/// used to remove an element from the hash table. However, there are cases
519/// when it is desirable not to allow elements to be removed. This can be
520/// achieved by supplying the `bdlc::HashTable` template with a `TRAITS`
521/// parameter that:
522/// @code
523/// o always returns false for the 'TRAITS::isRemoved(bucket)' expression
524/// o AND does not implemented the 'TRAITS::setToRemoved(&bucket)' expression
525/// @endcode
526/// This effectively describes a trait that does not define a special "removed"
527/// bucket value.
528///
529/// ## Usage {#bdlc_hashtable-usage}
530///
531///
532/// This section illustrates intended use of this component.
533///
534/// ### Example 1: Basic Usage {#bdlc_hashtable-example-1-basic-usage}
535///
536///
537/// The following snippets of code illustrate the usage of this component.
538/// Suppose we wanted to store a table of `int` keys with `double` values. We
539/// will use a capacity hint of 10, default traits, and default hash functors
540/// for demonstration purposes:
541/// @code
542/// #include <bdlc_hashtable.h>
543///
544/// using namespace BloombergLP;
545///
546/// void usageExample()
547/// {
548/// typedef bdlc::HashTable<int, double> TableType;
549///
550/// TableType table(10);
551/// @endcode
552/// Now we can insert elements into this object:
553/// @code
554/// TableType::Handle handles[3];
555///
556/// struct {
557/// int d_key;
558/// double d_value;
559/// } DATA[] = {
560/// { 10, 2.34 },
561/// { 92, 94.2 },
562/// { 236, 9.1 },
563/// };
564///
565/// table.insert(&handles[0], DATA[0].d_key, DATA[0].d_value);
566/// assert(DATA[0].d_key == table.key(handles[0]));
567/// assert(DATA[0].d_value == table.value(handles[0]));
568///
569/// table.insert(&handles[1], DATA[1].d_key, DATA[1].d_value);
570/// assert(DATA[1].d_key == table.key(handles[1]));
571/// assert(DATA[1].d_value == table.value(handles[1]));
572///
573/// table.insert(&handles[2], DATA[2].d_key, DATA[2].d_value);
574/// assert(DATA[2].d_key == table.key(handles[2]));
575/// assert(DATA[2].d_value == table.value(handles[2]));
576/// @endcode
577/// Now we can find elements in this object using the key:
578/// @code
579/// TableType::Handle otherHandles[3];
580///
581/// table.find(&otherHandles[0], DATA[0].d_key);
582/// assert(DATA[0].d_key == table.key(otherHandles[0]));
583/// assert(DATA[0].d_value == table.value(otherHandles[0]));
584///
585/// table.find(&otherHandles[1], DATA[1].d_key);
586/// assert(DATA[1].d_key == table.key(otherHandles[1]));
587/// assert(DATA[1].d_value == table.value(otherHandles[1]));
588///
589/// table.find(&otherHandles[2], DATA[2].d_key);
590/// assert(DATA[2].d_key == table.key(otherHandles[2]));
591/// assert(DATA[2].d_value == table.value(otherHandles[2]));
592/// }
593/// @endcode
594/// @}
595/** @} */
596/** @} */
597
598/** @addtogroup bdl
599 * @{
600 */
601/** @addtogroup bdlc
602 * @{
603 */
604/** @addtogroup bdlc_hashtable
605 * @{
606 */
607
608#include <bdlscm_version.h>
609
610#include <bdlb_hashutil.h>
611
613
614#include <bslma_allocator.h>
616
617#include <bslmf_assert.h>
618#include <bslmf_conditional.h>
619#include <bslmf_issame.h>
622#include <bslmf_nil.h>
623
624#include <bsls_assert.h>
625#include <bsls_platform.h>
626#include <bsls_review.h>
627#include <bsls_types.h>
628
629#include <bsl_algorithm.h>
630#include <bsl_cstring.h>
631#include <bsl_functional.h>
632#include <bsl_string.h>
633#include <bsl_utility.h>
634#include <bsl_vector.h>
635
636#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
637#include <bslmf_if.h>
638#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
639
640
641namespace bdlc {
642
643// FORWARD DECLARATIONS
644struct HashTableDefaultTraits;
645struct HashTableDefaultHash1;
646struct HashTableDefaultHash2;
647
648 // =================================================
649 // class HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>
650 // =================================================
651
652/// This class is a double-hashed table. The `VALUE` template parameter is
653/// optional. The `capacityHint` specified at construction time will be
654/// used to compute the number of buckets (capacity) in this object. Also,
655/// two hash functions may optionally be specified at construction time.
656/// Elements can be inserted using the `insert` method. If the `VALUE`
657/// parameter is not `bslmf::Nil`, then both key and value must be supplied
658/// to the `insert` method. Otherwise, only the key should be supplied.
659/// The `find` method can be used to lookup elements by a specified key.
660/// The optional `TRAITS` parameter can be used to classify "null" and
661/// "removed" values. See the component-level documentation for more
662/// details.
663///
664/// See @ref bdlc_hashtable
665template <class KEY,
666 class VALUE = bslmf::Nil,
667 class TRAITS = HashTableDefaultTraits,
668 class HASH1 = HashTableDefaultHash1,
669 class HASH2 = HashTableDefaultHash2>
671
672 public:
673 // TYPES
674
675 /// Data type to handle elements in the double-hashed table. This value
676 /// is guaranteed to be between 0 and the capacity of the hash table.
678
679 private:
680 // PRIVATE TYPES
681
682 /// Type of the element stored in this object. If the `VALUE` parameter
683 /// is `bslmf::Nil`, then `Bucket` is of type `KEY`, otherwise `Bucket`
684 /// is of type `bsl::pair<KEY, VALUE>`.
686 KEY,
688
689 /// Constructor proxy for `HASH1`.
691
692 /// Constructor proxy for `HASH2`.
694
695 // DATA
696 bsl::vector<Bucket> d_buckets; // array of buckets
697 bsls::Types::Int64 d_capacityHint; // capacity hint
698 Hash1CP d_hashFunctor1; // first hash function
699 Hash2CP d_hashFunctor2; // second hash function
700 bsls::Types::Int64 d_maxChain; // maximum chain length
701 bsls::Types::Int64 d_numCollisions; // number of collisions
702 bsls::Types::Int64 d_numElements; // number of elements
703 bsls::Types::Int64 d_totalChain; // total chain length
704
705 private:
706 // NOT IMPLEMENTED
707 HashTable(const HashTable&);
708 HashTable& operator=(const HashTable&);
709
710 // PRIVATE CLASS METHODS
711
712 /// Return the key from the specified `bucket`. If `bucket` is of type
713 /// `KEY`, then `bucket` is returned. If `bucket` is of type
714 /// `bsl::pair<KEY, VALUE>`, then `bucket.first` is returned.
715 static const KEY& keyFromBucket(const KEY& bucket);
716 static const KEY& keyFromBucket(const bsl::pair<KEY, VALUE>& bucket);
717
718 // PRIVATE MANIPULATORS
719
720 /// Load the specified `element` into the bucket with the specified
721 /// `index`; load a handle to the element in the specified `handle`;
722 /// update chain statistics with the specified `chainLength`.
723 void loadElementAt(Handle *handle,
724 bsls::Types::Int64 index,
725 const Bucket& element,
726 bsls::Types::Int64 chainLength);
727
728 /// Insert the specified `element` into this object; load a handle to
729 /// the element into the specified `handle`. Return true if successful,
730 /// and false otherwise.
731 bool insertElement(Handle *handle, const Bucket& element);
732
733 // PRIVATE ACCESSORS
734
735 /// Implement the double-hash algorithm to find a bucket with the
736 /// specified `key`; load true into the specified `isKeyFound` if an
737 /// element with `key` is found, and false otherwise; load the index of
738 /// the bucket into the specified `index` if an element with `key` is
739 /// found, and the index of the "null" bucket that terminates the chain
740 /// otherwise; load the chain length into the specified `chainLength`;
741 /// load the index of the first "removed" bucket along the chain into
742 /// the specified `removedIndex`, or -1 if no "removed" buckets were found.
743 ///
744 /// \note Note that if the key is not found and there are no "null"
745 /// buckets to terminate the chain, then -1 will be loaded into `index`.
746 void findImp(bool *isKeyFound,
747 bsls::Types::Int64 *index,
748 bsls::Types::Int64 *chainLength,
749 bsls::Types::Int64 *removedIndex,
750 const KEY& key) const;
751
752 public:
753 // TRAITS
755
756 // CREATORS
757
758 /// Create a double-hash table using the specified `capacityHint`.
759 /// Optionally specify a `basicAllocator` used to supply memory. If
760 /// `basicAllocator` is 0, the currently installed default allocator is used.
761 ///
762 /// \pre The behavior is undefined unless `0 != capacityHint`.
763 ///
764 /// \note Note that `capacityHint` can be either a positive integer or a negative
765 /// integer. If `capacityHint` is positive, then the capacity of the
766 /// hash table will be the first available prime number larger than, or
767 /// equal to, `capacityHint`. Otherwise, the capacity of the hash table
768 /// will be the first available prime number smaller than, or equal to,
769 /// `capacityHint`. Also note that `HASH1` will be used as the first
770 /// hash function, and `HASH2` will be used as the second hash
771 /// function.
773 bslma::Allocator *basicAllocator = 0);
774
775 /// Create a double-hash table with the specified `capacityHint`. Use
776 /// the specified `hashFunctor1` as the first hash function; use the
777 /// specified `hashFunctor2` as the second hash function. Optionally
778 /// specify a `basicAllocator` used to supply memory. If
779 /// `basicAllocator` is 0, the currently installed default allocator is used.
780 ///
781 /// \pre The behavior is undefined unless `0 != capacityHint`, and
782 /// `hashFunction1` and `hashFunction2` are valid.
783 ///
784 /// \note Note that `capacityHint` can be either a positive integer or a negative
785 /// integer. If `capacityHint` is positive, then the capacity of the
786 /// hash table will be the first available prime number larger than, or
787 /// equal to, `capacityHint`. Otherwise, the capacity of the hash table
788 /// will be the first available prime number smaller than, or equal to,
789 /// `capacityHint`.
791 const HASH1& hashFunctor1,
792 const HASH2& hashFunctor2,
793 bslma::Allocator *basicAllocator = 0);
794
795 /// Destroy this object.
796 ~HashTable();
797
798 // MANIPULATORS
799
800 /// Insert an element with the specified `key` into this object; load a
801 /// handle to the new element into the specified `handle`. Return true
802 /// if successful, and false otherwise.
803 ///
804 /// \pre The behavior is undefined unless `key` does not evaluate to a "null" or "removed" bucket, as
805 /// defined by the parameterized `TRAITS` (see the component-level documentation for more details).
806 ///
807 /// \note Note that this method will fail to
808 /// compile unless the `VALUE` parameter is `bslmf::Nil`.
809 bool insert(Handle *handle, const KEY& key);
810
811 /// Insert an element with the specified `key` and the specified `value`
812 /// into this object; load a handle to the new element into the
813 /// specified `handle`. Return true if successful, and false otherwise.
814 ///
815 /// \pre The behavior is undefined unless `key` and `value` do not evaluate
816 /// to a "null" or "removed" bucket, as defined by the parameterized
817 /// `TRAITS` (see the component-level documentation for more details).
818 /// This method will fail to compile unless the `VALUE` parameter is not
819 /// `bslmf::Nil`.
820 bool insert(Handle *handle, const KEY& key, const VALUE& value);
821
822 /// Remove the element identified by the specified `handle` from this object.
823 ///
824 /// \pre The behavior is undefined unless `handle` is valid.
825 ///
826 /// \note Note that `handle` will become invalid when this method returns.
827 void remove(const Handle& handle);
828
829 /// Return the reference to the modifiable value of the element
830 /// identified by the specified `handle`.
831 ///
832 /// \pre The behavior is undefined unless `handle` is valid.
833 /// \note Note that this method will fail to
834 /// compile unless the `VALUE` parameter is not `bslmf::Nil`.
835 VALUE& value(const Handle& handle);
836
837 // ACCESSORS
838
839 /// Return the maximum number of elements that can be stored in this object.
840 ///
841 /// \note Note that this value is computed based on the capacity hint
842 /// used upon construction.
844
845 /// Return the capacity hint that was used to determine the capacity of
846 /// this object.
848
849 /// Find an element having the specified `key`; load a handle to the
850 /// element into the specified `handle`. Return true if successful, and
851 /// false otherwise.
852 bool find(Handle *handle, const KEY& key) const;
853
854 /// Return the reference to the non-modifiable key of the element
855 /// identified by the specified `handle`.
856 ///
857 /// \pre The behavior is undefined unless `handle` is valid.
858 const KEY& key(const Handle& handle) const;
859
860 /// Return the maximum chain length encountered by this object.
862
863 /// Return the number of collisions encountered by this object.
865
866 /// Return the number of elements stored in this object.
867 bsls::Types::Int64 size() const;
868
869 /// Return the total chain length encountered by this object.
871
872 /// Return the reference to the non-modifiable value of the element
873 /// identified by the specified `handle`.
874 ///
875 /// \pre The behavior is undefined unless `handle` is valid.
876 /// \note Note that this method will fail to
877 /// compile unless the `VALUE` parameter is not `bslmf::Nil`.
878 const VALUE& value(const Handle& handle) const;
879};
880
881 // =============================
882 // struct HashTableDefaultTraits
883 // =============================
884
885/// Default traits provided by this component. See component-level documentation for more details.
886///
887/// \note Note that this class is not intended to
888/// be used by clients, but the name of this struct must be public so that
889/// clients can explicitly specify this struct when default traits are
890/// needed.
891///
892/// See @ref bdlc_hashtable
894
895 private:
896 // TYPES
897 typedef const char *ConstCharPtr; // Alias for 'const char*'.
898
899 // CONSTANTS
900 static const char REMOVED_KEYWORD[]; // Keyword to be used for removed
901 // objects for 'bsl::string' types.
902
903 // PRIVATE CLASS METHODS
904
905 /// Return `c != t_VALUE`.
906 template <char t_VALUE>
907 static bool isNot(char c);
908
909 public:
910 // CLASS METHODS
911
912 /// Load the specified `srcBucket` into the specified `dstBucket`.
913 template <class BUCKET>
914 static void load(BUCKET *dstBucket, const BUCKET& srcBucket);
915
916 /// Return true if the specified `key1` and the specified `key2` are
917 /// equal, and false otherwise.
918 template <class KEY>
919 static bool areEqual(const KEY& key1, const KEY& key2);
920 static bool areEqual(const ConstCharPtr& key1, const ConstCharPtr& key2);
921
922 /// Return true if the specified `bucket` has a null value, and false
923 /// otherwise.
924 template <class BUCKET>
925 static bool isNull(const BUCKET& bucket);
926 static bool isNull(const bsl::string& bucket);
927 static bool isNull(const ConstCharPtr& bucket);
928 template <class KEY, class VALUE>
929 static bool isNull(const bsl::pair<KEY, VALUE>& bucket);
930
931 /// Load a null value into the specified `bucket`.
932 template <class BUCKET>
933 static void setToNull(BUCKET *bucket);
934 static void setToNull(bsl::string *bucket);
935 static void setToNull(ConstCharPtr *bucket);
936 template <class KEY, class VALUE>
937 static void setToNull(bsl::pair<KEY, VALUE> *bucket);
938
939 /// Return true if the specified `bucket` has a removed value, and false
940 /// otherwise.
941 template <class BUCKET>
942 static bool isRemoved(const BUCKET& bucket);
943 static bool isRemoved(const bsl::string& bucket);
944 static bool isRemoved(const ConstCharPtr& bucket);
945 template <class KEY, class VALUE>
946 static bool isRemoved(const bsl::pair<KEY, VALUE>& bucket);
947
948 /// Load a removed value into the specified `bucket`.
949 template <class BUCKET>
950 static void setToRemoved(BUCKET *bucket);
951 static void setToRemoved(bsl::string *bucket);
952 static void setToRemoved(ConstCharPtr *bucket);
953 template <class KEY, class VALUE>
954 static void setToRemoved(bsl::pair<KEY, VALUE> *bucket);
955};
956
957 // ============================
958 // struct HashTableDefaultHash1
959 // ============================
960
961/// Default hash function provided by this component. See component-level documentation for more details.
962///
963/// \note Note that this class is not intended to
964/// be used by clients, but the name of this struct must be public so that
965/// clients can explicitly specify this struct when default hash function is needed.
966///
967/// \note Note that this functor is implemented using
968/// `bdlb::HashUtil::hash1`.
969///
970/// See @ref bdlc_hashtable
972
973 // TYPES
974 typedef const char *ConstCharPtr; // Alias for 'const char*'.
975
976 // CLASS METHODS
977
978 /// Return the result of `bdlb::HashUtil::hash1` using key data and key
979 /// length. If the specified `key` is not of type `const char*` or
980 /// `bsl::string`, then the footprint and size of the object are used as
981 /// key data and key length, respectively.
982 template <class KEY>
983 unsigned int operator()(const KEY& key) const;
984 unsigned int operator()(const ConstCharPtr& key) const;
985 unsigned int operator()(const bsl::string& key) const;
986};
987
988 // ============================
989 // struct HashTableDefaultHash2
990 // ============================
991
992/// Default hash function provided by this component. See component-level documentation for more details.
993///
994/// \note Note that this class is not intended to
995/// be used by clients, but the name of this struct must be public so that
996/// clients can explicitly specify this struct when default hash function is needed.
997///
998/// \note Note that this functor is implemented using
999/// `bdlb::HashUtil::hash2`.
1000///
1001/// See @ref bdlc_hashtable
1003
1004 // TYPES
1005 typedef const char *ConstCharPtr; // Alias for 'const char*'.
1006
1007 // CLASS METHODS
1008
1009 /// Return the result of `bdlb::HashUtil::hash2` using key data and key
1010 /// length. If the specified `key` is not of type `const char*` or
1011 /// `bsl::string`, then the footprint and size of the object are used as
1012 /// key data and key length, respectively.
1013 template <class KEY>
1014 unsigned int operator()(const KEY& key) const;
1015 unsigned int operator()(const ConstCharPtr& key) const;
1016 unsigned int operator()(const bsl::string& key) const;
1017};
1018
1019// --- Anything below this line is implementation specific. Do not use. ---
1020
1021 // ================================
1022 // private struct HashTable_ImpUtil
1023 // ================================
1024
1025/// Component-private struct. Do not use. Implementation helper functions
1026/// for this component.
1027///
1028/// See @ref bdlc_hashtable
1030
1031 // CLASS DATA
1032 static const unsigned int *PRIME_NUMBERS; // provide access to the
1033 static const int NUM_PRIME_NUMBERS; // array of prime numbers so
1034 // that they can be tested
1035 // in the test driver
1036
1037 // CLASS METHODS
1038
1039 /// Return the hash size based on the specified `hint`.
1040 static unsigned int hashSize(bsls::Types::Int64 hint);
1041};
1042
1043// ============================================================================
1044// INLINE DEFINITIONS
1045// ============================================================================
1046
1047 // -------------------------------------------------
1048 // class HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>
1049 // -------------------------------------------------
1050
1051// PRIVATE CLASS METHODS
1052template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1053inline const KEY&
1055{
1056 return bucket;
1057}
1058
1059template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1060inline const KEY&
1061HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>::keyFromBucket(
1062 const bsl::pair<KEY, VALUE>& bucket)
1063{
1064 return bucket.first;
1065}
1066
1067// PRIVATE MANIPULATORS
1068template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1069void HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>::loadElementAt(
1070 Handle *handle,
1071 bsls::Types::Int64 index,
1072 const Bucket& element,
1073 bsls::Types::Int64 chainLength)
1074{
1075 BSLS_ASSERT(handle);
1076
1077 typedef typename bsl::vector<Bucket>::size_type size_type;
1078 TRAITS::load(&d_buckets[(size_type)index], element);
1079 *handle = index;
1080 ++d_numElements;
1081
1082 if (chainLength) {
1083 d_maxChain = bsl::max(d_maxChain, chainLength);
1084 d_totalChain += chainLength;
1085 ++d_numCollisions;
1086 }
1087}
1088
1089template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1090bool HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>::insertElement(
1091 Handle *handle,
1092 const Bucket& element)
1093{
1094 BSLS_ASSERT(handle);
1095
1096 if (size() == capacity()) {
1097 return false; // RETURN
1098 }
1099
1100 bool isKeyFound;
1101 bsls::Types::Int64 nullIndex, chainLength, removedIndex;
1102
1103 findImp(&isKeyFound, &nullIndex, &chainLength, &removedIndex,
1104 keyFromBucket(element));
1105
1106 if (isKeyFound) {
1107 return false; // RETURN
1108 }
1109
1110 if (-1 != removedIndex) {
1111 loadElementAt(handle, removedIndex, element, chainLength);
1112 }
1113 else {
1114 BSLS_ASSERT(-1 != nullIndex);
1115
1116 loadElementAt(handle, nullIndex, element, chainLength);
1117 }
1118
1119 return true;
1120}
1121
1122// PRIVATE ACCESSORS
1123template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1124void HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>::findImp(
1125 bool *isKeyFound,
1126 bsls::Types::Int64 *index,
1127 bsls::Types::Int64 *chainLength,
1128 bsls::Types::Int64 *removedIndex,
1129 const KEY& key) const
1130{
1131 BSLS_ASSERT(isKeyFound);
1132 BSLS_ASSERT(index);
1133 BSLS_ASSERT(chainLength);
1134 BSLS_ASSERT(removedIndex);
1135
1136 typedef typename bsl::vector<Bucket>::size_type size_type;
1137
1138 *chainLength = 0;
1139 *removedIndex = -1;
1140
1141 unsigned int capacity = static_cast<unsigned int>(d_buckets.size());
1142
1143 bsls::Types::Int64 bucketIndex = d_hashFunctor1.object()(key) % capacity;
1144
1145 if (TRAITS::isNull(d_buckets[(size_type)bucketIndex])) {
1146 *isKeyFound = false;
1147 *index = bucketIndex;
1148 return; // RETURN
1149 }
1150 else if (TRAITS::isRemoved(d_buckets[(size_type)bucketIndex])) {
1151 *removedIndex = bucketIndex;
1152 }
1153 else if (TRAITS::areEqual(keyFromBucket(d_buckets[(size_type)bucketIndex]),
1154 key)) {
1155 *isKeyFound = true;
1156 *index = bucketIndex;
1157 return; // RETURN
1158 }
1159
1160 bsls::Types::Int64 increment = (d_hashFunctor2.object()(key)
1161 % (capacity - 1)) + 1;
1162 // must be between [1, capacity-1]
1163
1164 while (*chainLength < capacity) {
1165 ++*chainLength;
1166 bucketIndex = (bucketIndex + increment) % capacity;
1167
1168 if (TRAITS::isNull(d_buckets[(size_type)bucketIndex])) {
1169 *isKeyFound = false;
1170 *index = bucketIndex;
1171 return; // RETURN
1172 }
1173 else if (TRAITS::isRemoved(d_buckets[(size_type)bucketIndex])) {
1174 if (*removedIndex == -1) {
1175 *removedIndex = bucketIndex;
1176 }
1177 }
1178 else
1179 if (TRAITS::areEqual(keyFromBucket(d_buckets[(size_type)bucketIndex]),
1180 key)) {
1181 *isKeyFound = true;
1182 *index = bucketIndex;
1183 return; // RETURN
1184 }
1185 }
1186
1187 *isKeyFound = false;
1188 *index = -1;
1189}
1190
1191// CREATORS
1192template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1194 bsls::Types::Int64 capacityHint,
1195 bslma::Allocator *basicAllocator)
1196: d_buckets(HashTable_ImpUtil::hashSize(capacityHint),
1197 Bucket(),
1198 basicAllocator)
1199, d_capacityHint(capacityHint)
1200, d_hashFunctor1(basicAllocator)
1201, d_hashFunctor2(basicAllocator)
1202, d_maxChain(0)
1203, d_numCollisions(0)
1204, d_numElements(0)
1205, d_totalChain(0)
1206{
1208
1209 typedef typename bsl::vector<Bucket>::iterator Iterator;
1210
1211 for (Iterator it = d_buckets.begin(); it != d_buckets.end(); ++it) {
1212 TRAITS::setToNull(&(*it));
1213 }
1214}
1215
1216template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1218 bsls::Types::Int64 capacityHint,
1219 const HASH1& hashFunctor1,
1220 const HASH2& hashFunctor2,
1221 bslma::Allocator *basicAllocator)
1222: d_buckets(HashTable_ImpUtil::hashSize(capacityHint),
1223 Bucket(),
1224 basicAllocator)
1225, d_capacityHint(capacityHint)
1226, d_hashFunctor1(hashFunctor1, basicAllocator)
1227, d_hashFunctor2(hashFunctor2, basicAllocator)
1228, d_maxChain(0)
1229, d_numCollisions(0)
1230, d_numElements(0)
1231, d_totalChain(0)
1232{
1234
1235 typedef typename bsl::vector<Bucket>::iterator Iterator;
1236
1237 for (Iterator it = d_buckets.begin(); it != d_buckets.end(); ++it) {
1238 TRAITS::setToNull(&(*it));
1239 }
1240}
1241
1242template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1243inline
1247
1248// MANIPULATORS
1249template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1250inline
1252 const KEY& key)
1253{
1254 BSLS_ASSERT(handle);
1255
1257
1258 return insertElement(handle, key);
1259}
1260
1261template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1262inline
1264 const KEY& key,
1265 const VALUE& value)
1266{
1267 BSLS_ASSERT(handle);
1268
1270
1271 return insertElement(handle, bsl::make_pair(key, value));
1272}
1273
1274template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1275inline
1277{
1278 typedef typename bsl::vector<Bucket>::size_type size_type;
1279
1280 BSLS_ASSERT(!TRAITS::isNull (d_buckets[(size_type)handle]));
1281 BSLS_ASSERT(!TRAITS::isRemoved(d_buckets[(size_type)handle]));
1282
1283 TRAITS::setToRemoved(&d_buckets[(size_type)handle]);
1284 --d_numElements;
1285}
1286
1287template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1288inline
1290{
1291 typedef typename bsl::vector<Bucket>::size_type size_type;
1293
1294 BSLS_ASSERT(!TRAITS::isNull (d_buckets[(size_type)handle]));
1295 BSLS_ASSERT(!TRAITS::isRemoved(d_buckets[(size_type)handle]));
1296
1297 return d_buckets[(size_type)handle].second;
1298}
1299
1300// ACCESSORS
1301template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1302inline
1305{
1306 return d_buckets.size();
1307}
1308
1309template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1310inline
1313{
1314 return d_capacityHint;
1315}
1316
1317template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1318inline
1320 const KEY& key) const
1321{
1322 BSLS_ASSERT(handle);
1323
1324 bool isKeyFound;
1325 bsls::Types::Int64 chainLength, removedIndex;
1326
1327 findImp(&isKeyFound, handle, &chainLength, &removedIndex, key);
1328
1329 return isKeyFound;
1330}
1331
1332template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1333inline
1335 const Handle& handle) const
1336{
1337 typedef typename bsl::vector<Bucket>::size_type size_type;
1338 BSLS_ASSERT(!TRAITS::isNull (d_buckets[(size_type)handle]));
1339 BSLS_ASSERT(!TRAITS::isRemoved(d_buckets[(size_type)handle]));
1340
1341 return keyFromBucket(d_buckets[(size_type)handle]);
1342}
1343
1344template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1345inline
1348{
1349 return d_maxChain;
1350}
1351
1352template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1353inline
1356{
1357 return d_numCollisions;
1358}
1359
1360template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1361inline
1364{
1365 return d_numElements;
1366}
1367
1368template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1369inline
1372{
1373 return d_totalChain;
1374}
1375
1376template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1377inline
1379 const Handle& handle) const
1380{
1381 typedef typename bsl::vector<Bucket>::size_type size_type;
1383
1384 BSLS_ASSERT(!TRAITS::isNull (d_buckets[(size_type)handle]));
1385 BSLS_ASSERT(!TRAITS::isRemoved(d_buckets[(size_type)handle]));
1386
1387 return d_buckets[(size_type)handle].second;
1388}
1389
1390 // -------------------------------------
1391 // private struct HashTableDefaultTraits
1392 // -------------------------------------
1393
1394template <char t_VALUE>
1395inline
1396bool HashTableDefaultTraits::isNot(char c)
1397{
1398 return c != t_VALUE;
1399}
1400
1401template <class BUCKET>
1402inline
1403void HashTableDefaultTraits::load(BUCKET *dstBucket, const BUCKET& srcBucket)
1404{
1405 BSLS_ASSERT(dstBucket);
1406
1407 *dstBucket = srcBucket;
1408}
1409
1410template <class KEY>
1411inline
1412bool HashTableDefaultTraits::areEqual(const KEY& key1, const KEY& key2)
1413{
1414 return key1 == key2;
1415}
1416
1417inline
1418bool HashTableDefaultTraits::areEqual(const ConstCharPtr& key1,
1419 const ConstCharPtr& key2)
1420{
1421 BSLS_ASSERT(key1);
1422 BSLS_ASSERT(key2);
1423
1424 return 0 == bsl::strcmp(key1, key2);
1425}
1426
1427template <class BUCKET>
1428inline
1429bool HashTableDefaultTraits::isNull(const BUCKET& bucket)
1430{
1431 enum {
1433 };
1434
1435 BSLMF_ASSERT(k_IS_POD);
1436
1437 const char null = 0; (void)null; // 'null' not used in some build modes
1438 const char *begin = reinterpret_cast<const char *>(&bucket);
1439 const char *end = begin + sizeof bucket;
1440
1441 return end == bsl::find_if(begin, end, isNot<null>);
1442}
1443
1444inline
1446{
1447 return 0 == bucket.length();
1448}
1449
1450inline
1451bool HashTableDefaultTraits::isNull(const ConstCharPtr& bucket)
1452{
1453 return 0 == bucket;
1454}
1455
1456template <class KEY, class VALUE>
1457inline
1459{
1460 return isNull(bucket.first) && isNull(bucket.second);
1461}
1462
1463template <class BUCKET>
1464inline
1466{
1467 BSLS_ASSERT(bucket);
1468
1469 enum {
1471 };
1472
1473 BSLMF_ASSERT(k_IS_POD);
1474
1475 const char null = 0;
1476 char *begin = reinterpret_cast<char *>(bucket);
1477
1478 bsl::fill_n(begin, sizeof(BUCKET), null);
1479}
1480
1481inline
1483{
1484 BSLS_ASSERT(bucket);
1485
1486 bucket->clear();
1487}
1488
1489inline
1490void HashTableDefaultTraits::setToNull(ConstCharPtr *bucket)
1491{
1492 BSLS_ASSERT(bucket);
1493
1494 *bucket = 0;
1495}
1496
1497template <class KEY, class VALUE>
1498inline
1500{
1501 BSLS_ASSERT(bucket);
1502
1503 setToNull(&bucket->first);
1504 setToNull(&bucket->second);
1505}
1506
1507template <class BUCKET>
1508inline
1509bool HashTableDefaultTraits::isRemoved(const BUCKET& bucket)
1510{
1511 enum {
1513 };
1514
1515 BSLMF_ASSERT(k_IS_POD);
1516
1517 const char removed = (char)0xFF;
1518 const char *begin = reinterpret_cast<const char *>(&bucket);
1519 const char *end = begin + sizeof bucket;
1520
1521 return end == bsl::find_if(begin, end, isNot<removed>);
1522}
1523
1524inline
1526{
1527 return 0 == bsl::strcmp(bucket.c_str(), REMOVED_KEYWORD);
1528}
1529
1530inline
1531bool HashTableDefaultTraits::isRemoved(const ConstCharPtr& bucket)
1532{
1533#if defined(BSLS_PLATFORM_CPU_32_BIT)
1534 const char *removed = reinterpret_cast<const char *>(0xFFFFFFFF);
1535#else
1536 const char *removed = reinterpret_cast<const char *>(0xFFFFFFFFFFFFFFFF);
1537#endif
1538
1539 return removed == bucket;
1540}
1541
1542template <class KEY, class VALUE>
1543inline
1545{
1546 return isRemoved(bucket.first) && isRemoved(bucket.second);
1547}
1548
1549template <class BUCKET>
1550inline
1552{
1553 BSLS_ASSERT(bucket);
1554
1555 enum {
1557 };
1558
1559 BSLMF_ASSERT(k_IS_POD);
1560
1561 const char removed = (char)0xFF;
1562 char *begin = reinterpret_cast<char *>(bucket);
1563
1564 bsl::fill_n(begin, sizeof(BUCKET), removed);
1565}
1566
1567inline
1569{
1570 BSLS_ASSERT(bucket);
1571
1572 *bucket = REMOVED_KEYWORD;
1573}
1574
1575inline
1577{
1578 BSLS_ASSERT(bucket);
1579
1580#if defined(BSLS_PLATFORM_CPU_32_BIT)
1581 const char *removed = reinterpret_cast<const char *>(0xFFFFFFFF);
1582#else
1583 const char *removed = reinterpret_cast<const char *>(0xFFFFFFFFFFFFFFFF);
1584#endif
1585
1586 *bucket = removed;
1587}
1588
1589template <class KEY, class VALUE>
1590inline
1592{
1593 BSLS_ASSERT(bucket);
1594
1595 setToRemoved(&bucket->first);
1596 setToRemoved(&bucket->second);
1597}
1598
1599 // ----------------------------
1600 // struct HashTableDefaultHash1
1601 // ----------------------------
1602
1603template <class KEY>
1604inline
1605unsigned int HashTableDefaultHash1::operator()(const KEY& key) const
1606{
1607 const char *keyData = reinterpret_cast<const char *>(&key);
1608 int keyLength = sizeof key;
1609
1610 return bdlb::HashUtil::hash1(keyData, keyLength);
1611}
1612
1613inline
1615{
1616 const char *keyData = key;
1617 int keyLength = static_cast<int>(bsl::strlen(key));
1618
1619 return bdlb::HashUtil::hash1(keyData, keyLength);
1620}
1621
1622inline
1624{
1625 const char *keyData = key.data();
1626 int keyLength = static_cast<int>(key.length());
1627
1628 return bdlb::HashUtil::hash1(keyData, keyLength);
1629}
1630
1631 // ----------------------------
1632 // struct HashTableDefaultHash2
1633 // ----------------------------
1634
1635template <class KEY>
1636inline
1637unsigned int HashTableDefaultHash2::operator()(const KEY& key) const
1638{
1639 const char *keyData = reinterpret_cast<const char *>(&key);
1640 int keyLength = sizeof key;
1641
1642 return bdlb::HashUtil::hash2(keyData, keyLength);
1643}
1644
1645inline
1647{
1648 const char *keyData = key;
1649 int keyLength = static_cast<int>(bsl::strlen(key));
1650
1651 return bdlb::HashUtil::hash2(keyData, keyLength);
1652}
1653
1654inline
1656{
1657 const char *keyData = key.data();
1658 int keyLength = static_cast<int>(key.length());
1659
1660 return bdlb::HashUtil::hash2(keyData, keyLength);
1661}
1662
1663} // close package namespace
1664
1665
1666#endif
1667
1668// ----------------------------------------------------------------------------
1669// Copyright 2018 Bloomberg Finance L.P.
1670//
1671// Licensed under the Apache License, Version 2.0 (the "License");
1672// you may not use this file except in compliance with the License.
1673// You may obtain a copy of the License at
1674//
1675// http://www.apache.org/licenses/LICENSE-2.0
1676//
1677// Unless required by applicable law or agreed to in writing, software
1678// distributed under the License is distributed on an "AS IS" BASIS,
1679// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1680// See the License for the specific language governing permissions and
1681// limitations under the License.
1682// ----------------------------- END-OF-FILE ----------------------------------
1683
1684/** @} */
1685/** @} */
1686/** @} */
Definition bdlc_hashtable.h:670
bsls::Types::Int64 totalChain() const
Return the total chain length encountered by this object.
Definition bdlc_hashtable.h:1371
~HashTable()
Destroy this object.
Definition bdlc_hashtable.h:1244
bool insert(Handle *handle, const KEY &key)
Definition bdlc_hashtable.h:1251
const KEY & key(const Handle &handle) const
Definition bdlc_hashtable.h:1334
BSLMF_NESTED_TRAIT_DECLARATION(HashTable, bslma::UsesBslmaAllocator)
bsls::Types::Int64 size() const
Return the number of elements stored in this object.
Definition bdlc_hashtable.h:1363
VALUE & value(const Handle &handle)
Definition bdlc_hashtable.h:1289
bsls::Types::Int64 capacity() const
Definition bdlc_hashtable.h:1304
bsls::Types::Int64 capacityHint() const
Definition bdlc_hashtable.h:1312
bsls::Types::Int64 Handle
Definition bdlc_hashtable.h:677
bsls::Types::Int64 maxChain() const
Return the maximum chain length encountered by this object.
Definition bdlc_hashtable.h:1347
void remove(const Handle &handle)
Definition bdlc_hashtable.h:1276
bsls::Types::Int64 numCollisions() const
Return the number of collisions encountered by this object.
Definition bdlc_hashtable.h:1355
bool find(Handle *handle, const KEY &key) const
Definition bdlc_hashtable.h:1319
Definition bslstl_string.h:1252
size_type length() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:7301
const CHAR_TYPE * c_str() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:7405
CHAR_TYPE * data() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:7177
void clear() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6043
Definition bslstl_pair.h:1280
Definition bslstl_vector.h:1120
AllocatorTraits::size_type size_type
Definition bslstl_vector.h:1147
VALUE_TYPE * iterator
Definition bslstl_vector.h:1152
Definition bslalg_constructorproxy.h:376
Definition bslma_allocator.h:545
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
Definition bdlc_bitarray.h:506
static unsigned int hash2(const char *data, int length)
static unsigned int hash1(const char *data, int length)
Definition bdlc_hashtable.h:971
unsigned int operator()(const KEY &key) const
Definition bdlc_hashtable.h:1605
const char * ConstCharPtr
Definition bdlc_hashtable.h:974
Definition bdlc_hashtable.h:1002
unsigned int operator()(const KEY &key) const
Definition bdlc_hashtable.h:1637
const char * ConstCharPtr
Definition bdlc_hashtable.h:1005
Definition bdlc_hashtable.h:893
static void setToRemoved(BUCKET *bucket)
Load a removed value into the specified bucket.
Definition bdlc_hashtable.h:1551
static void setToNull(BUCKET *bucket)
Load a null value into the specified bucket.
Definition bdlc_hashtable.h:1465
static bool areEqual(const KEY &key1, const KEY &key2)
Definition bdlc_hashtable.h:1412
static void load(BUCKET *dstBucket, const BUCKET &srcBucket)
Load the specified srcBucket into the specified dstBucket.
Definition bdlc_hashtable.h:1403
static bool isRemoved(const BUCKET &bucket)
Definition bdlc_hashtable.h:1509
static bool isNull(const BUCKET &bucket)
Definition bdlc_hashtable.h:1429
Definition bdlc_hashtable.h:1029
static const int NUM_PRIME_NUMBERS
Definition bdlc_hashtable.h:1033
static const unsigned int * PRIME_NUMBERS
Definition bdlc_hashtable.h:1032
static unsigned int hashSize(bsls::Types::Int64 hint)
Return the hash size based on the specified hint.
TYPE first
Definition bslstl_pair.h:587
TYPE second
Definition bslstl_pair.h:933
Definition bslmf_conditional.h:123
Definition bslmf_integralconstant.h:261
Definition bslmf_istriviallydefaultconstructible.h:296
Definition bslma_usesbslmaallocator.h:344
Definition bslmf_issame.h:182
Definition bslmf_nil.h:133
long long Int64
Definition bsls_types.h:134