BDE 4.14.0 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 // NOT IMPLEMENTED
706 HashTable(const HashTable&);
707 HashTable& operator=(const HashTable&);
708
709 // PRIVATE CLASS METHODS
710
711 /// Return the key from the specified `bucket`. If `bucket` is of type
712 /// `KEY`, then `bucket` is returned. If `bucket` is of type
713 /// `bsl::pair<KEY, VALUE>`, then `bucket.first` is returned.
714 static const KEY& keyFromBucket(const KEY& bucket);
715 static const KEY& keyFromBucket(const bsl::pair<KEY, VALUE>& bucket);
716
717 // PRIVATE MANIPULATORS
718
719 /// Load the specified `element` into the bucket with the specified
720 /// `index`; load a handle to the element in the specified `handle`;
721 /// update chain statistics with the specified `chainLength`.
722 void loadElementAt(Handle *handle,
723 bsls::Types::Int64 index,
724 const Bucket& element,
725 bsls::Types::Int64 chainLength);
726
727 /// Insert the specified `element` into this object; load a handle to
728 /// the element into the specified `handle`. Return true if successful,
729 /// and false otherwise.
730 bool insertElement(Handle *handle, const Bucket& element);
731
732 // PRIVATE ACCESSORS
733
734 /// Implement the double-hash algorithm to find a bucket with the
735 /// specified `key`; load true into the specified `isKeyFound` if an
736 /// element with `key` is found, and false otherwise; load the index of
737 /// the bucket into the specified `index` if an element with `key` is
738 /// found, and the index of the "null" bucket that terminates the chain
739 /// otherwise; load the chain length into the specified `chainLength`;
740 /// load the index of the first "removed" bucket along the chain into
741 /// the specified `removedIndex`, or -1 if no "removed" buckets were
742 /// found. Note that if the key is not found and there are no "null"
743 /// buckets to terminate the chain, then -1 will be loaded into `index`.
744 void findImp(bool *isKeyFound,
745 bsls::Types::Int64 *index,
746 bsls::Types::Int64 *chainLength,
747 bsls::Types::Int64 *removedIndex,
748 const KEY& key) const;
749
750 public:
751 // TRAITS
753
754 // CREATORS
755
756 /// Create a double-hash table using the specified `capacityHint`.
757 /// Optionally specify a `basicAllocator` used to supply memory. If
758 /// `basicAllocator` is 0, the currently installed default allocator is
759 /// used. The behavior is undefined unless `0 != capacityHint`. Note
760 /// that `capacityHint` can be either a positive integer or a negative
761 /// integer. If `capacityHint` is positive, then the capacity of the
762 /// hash table will be the first available prime number larger than, or
763 /// equal to, `capacityHint`. Otherwise, the capacity of the hash table
764 /// will be the first available prime number smaller than, or equal to,
765 /// `capacityHint`. Also note that `HASH1` will be used as the first
766 /// hash function, and `HASH2` will be used as the second hash
767 /// function.
769 bslma::Allocator *basicAllocator = 0);
770
771 /// Create a double-hash table with the specified `capacityHint`. Use
772 /// the specified `hashFunctor1` as the first hash function; use the
773 /// specified `hashFunctor2` as the second hash function. Optionally
774 /// specify a `basicAllocator` used to supply memory. If
775 /// `basicAllocator` is 0, the currently installed default allocator is
776 /// used. The behavior is undefined unless `0 != capacityHint`, and
777 /// `hashFunction1` and `hashFunction2` are valid. Note that
778 /// `capacityHint` can be either a positive integer or a negative
779 /// integer. If `capacityHint` is positive, then the capacity of the
780 /// hash table will be the first available prime number larger than, or
781 /// equal to, `capacityHint`. Otherwise, the capacity of the hash table
782 /// will be the first available prime number smaller than, or equal to,
783 /// `capacityHint`.
785 const HASH1& hashFunctor1,
786 const HASH2& hashFunctor2,
787 bslma::Allocator *basicAllocator = 0);
788
789 /// Destroy this object.
790 ~HashTable();
791
792 // MANIPULATORS
793
794 /// Insert an element with the specified `key` into this object; load a
795 /// handle to the new element into the specified `handle`. Return true
796 /// if successful, and false otherwise. The behavior is undefined
797 /// unless `key` does not evaluate to a "null" or "removed" bucket, as
798 /// defined by the parameterized `TRAITS` (see the component-level
799 /// documentation for more details). Note that this method will fail to
800 /// compile unless the `VALUE` parameter is `bslmf::Nil`.
801 bool insert(Handle *handle, const KEY& key);
802
803 /// Insert an element with the specified `key` and the specified `value`
804 /// into this object; load a handle to the new element into the
805 /// specified `handle`. Return true if successful, and false otherwise.
806 /// The behavior is undefined unless `key` and `value` do not evaluate
807 /// to a "null" or "removed" bucket, as defined by the parameterized
808 /// `TRAITS` (see the component-level documentation for more details).
809 /// This method will fail to compile unless the `VALUE` parameter is not
810 /// `bslmf::Nil`.
811 bool insert(Handle *handle, const KEY& key, const VALUE& value);
812
813 /// Remove the element identified by the specified `handle` from this
814 /// object. The behavior is undefined unless `handle` is valid. Note
815 /// that `handle` will become invalid when this method returns.
816 void remove(const Handle& handle);
817
818 /// Return the reference to the modifiable value of the element
819 /// identified by the specified `handle`. The behavior is undefined
820 /// unless `handle` is valid. Note that this method will fail to
821 /// compile unless the `VALUE` parameter is not `bslmf::Nil`.
822 VALUE& value(const Handle& handle);
823
824 // ACCESSORS
825
826 /// Return the maximum number of elements that can be stored in this
827 /// object. Note that this value is computed based on the capacity hint
828 /// used upon construction.
830
831 /// Return the capacity hint that was used to determine the capacity of
832 /// this object.
834
835 /// Find an element having the specified `key`; load a handle to the
836 /// element into the specified `handle`. Return true if successful, and
837 /// false otherwise.
838 bool find(Handle *handle, const KEY& key) const;
839
840 /// Return the reference to the non-modifiable key of the element
841 /// identified by the specified `handle`. The behavior is undefined
842 /// unless `handle` is valid.
843 const KEY& key(const Handle& handle) const;
844
845 /// Return the maximum chain length encountered by this object.
847
848 /// Return the number of collisions encountered by this object.
850
851 /// Return the number of elements stored in this object.
852 bsls::Types::Int64 size() const;
853
854 /// Return the total chain length encountered by this object.
856
857 /// Return the reference to the non-modifiable value of the element
858 /// identified by the specified `handle`. The behavior is undefined
859 /// unless `handle` is valid. Note that this method will fail to
860 /// compile unless the `VALUE` parameter is not `bslmf::Nil`.
861 const VALUE& value(const Handle& handle) const;
862};
863
864 // =============================
865 // struct HashTableDefaultTraits
866 // =============================
867
868/// Default traits provided by this component. See component-level
869/// documentation for more details. Note that this class is not intended to
870/// be used by clients, but the name of this struct must be public so that
871/// clients can explicitly specify this struct when default traits are
872/// needed.
874
875 private:
876 // TYPES
877 typedef const char *ConstCharPtr; // Alias for 'const char*'.
878
879 // CONSTANTS
880 static const char REMOVED_KEYWORD[]; // Keyword to be used for removed
881 // objects for 'bsl::string' types.
882
883 // PRIVATE CLASS METHODS
884
885 /// Return `c != t_VALUE`.
886 template <char t_VALUE>
887 static bool isNot(char c);
888
889 public:
890 // CLASS METHODS
891
892 /// Load the specified `srcBucket` into the specified `dstBucket`.
893 template <class BUCKET>
894 static void load(BUCKET *dstBucket, const BUCKET& srcBucket);
895
896 /// Return true if the specified `key1` and the specified `key2` are
897 /// equal, and false otherwise.
898 template <class KEY>
899 static bool areEqual(const KEY& key1, const KEY& key2);
900 static bool areEqual(const ConstCharPtr& key1, const ConstCharPtr& key2);
901
902 /// Return true if the specified `bucket` has a null value, and false
903 /// otherwise.
904 template <class BUCKET>
905 static bool isNull(const BUCKET& bucket);
906 static bool isNull(const bsl::string& bucket);
907 static bool isNull(const ConstCharPtr& bucket);
908 template <class KEY, class VALUE>
909 static bool isNull(const bsl::pair<KEY, VALUE>& bucket);
910
911 /// Load a null value into the specified `bucket`.
912 template <class BUCKET>
913 static void setToNull(BUCKET *bucket);
914 static void setToNull(bsl::string *bucket);
915 static void setToNull(ConstCharPtr *bucket);
916 template <class KEY, class VALUE>
917 static void setToNull(bsl::pair<KEY, VALUE> *bucket);
918
919 /// Return true if the specified `bucket` has a removed value, and false
920 /// otherwise.
921 template <class BUCKET>
922 static bool isRemoved(const BUCKET& bucket);
923 static bool isRemoved(const bsl::string& bucket);
924 static bool isRemoved(const ConstCharPtr& bucket);
925 template <class KEY, class VALUE>
926 static bool isRemoved(const bsl::pair<KEY, VALUE>& bucket);
927
928 /// Load a removed value into the specified `bucket`.
929 template <class BUCKET>
930 static void setToRemoved(BUCKET *bucket);
931 static void setToRemoved(bsl::string *bucket);
932 static void setToRemoved(ConstCharPtr *bucket);
933 template <class KEY, class VALUE>
934 static void setToRemoved(bsl::pair<KEY, VALUE> *bucket);
935};
936
937 // ============================
938 // struct HashTableDefaultHash1
939 // ============================
940
941/// Default hash function provided by this component. See component-level
942/// documentation for more details. Note that this class is not intended to
943/// be used by clients, but the name of this struct must be public so that
944/// clients can explicitly specify this struct when default hash function is
945/// needed. Note that this functor is implemented using
946/// `bdlb::HashUtil::hash1`.
948
949 // TYPES
950 typedef const char *ConstCharPtr; // Alias for 'const char*'.
951
952 // CLASS METHODS
953
954 /// Return the result of `bdlb::HashUtil::hash1` using key data and key
955 /// length. If the specified `key` is not of type `const char*` or
956 /// `bsl::string`, then the footprint and size of the object are used as
957 /// key data and key length, respectively.
958 template <class KEY>
959 unsigned int operator()(const KEY& key) const;
960 unsigned int operator()(const ConstCharPtr& key) const;
961 unsigned int operator()(const bsl::string& key) const;
962};
963
964 // ============================
965 // struct HashTableDefaultHash2
966 // ============================
967
968/// Default hash function provided by this component. See component-level
969/// documentation for more details. Note that this class is not intended to
970/// be used by clients, but the name of this struct must be public so that
971/// clients can explicitly specify this struct when default hash function is
972/// needed. Note that this functor is implemented using
973/// `bdlb::HashUtil::hash2`.
975
976 // TYPES
977 typedef const char *ConstCharPtr; // Alias for 'const char*'.
978
979 // CLASS METHODS
980
981 /// Return the result of `bdlb::HashUtil::hash2` using key data and key
982 /// length. If the specified `key` is not of type `const char*` or
983 /// `bsl::string`, then the footprint and size of the object are used as
984 /// key data and key length, respectively.
985 template <class KEY>
986 unsigned int operator()(const KEY& key) const;
987 unsigned int operator()(const ConstCharPtr& key) const;
988 unsigned int operator()(const bsl::string& key) const;
989};
990
991// --- Anything below this line is implementation specific. Do not use. ---
992
993 // ================================
994 // private struct HashTable_ImpUtil
995 // ================================
996
997/// Component-private struct. Do not use. Implementation helper functions
998/// for this component.
1000
1001 // CLASS DATA
1002 static const unsigned int *PRIME_NUMBERS; // provide access to the
1003 static const int NUM_PRIME_NUMBERS; // array of prime numbers so
1004 // that they can be tested
1005 // in the test driver
1006
1007 // CLASS METHODS
1008
1009 /// Return the hash size based on the specified `hint`.
1010 static unsigned int hashSize(bsls::Types::Int64 hint);
1011};
1012
1013// ============================================================================
1014// INLINE DEFINITIONS
1015// ============================================================================
1016
1017 // -------------------------------------------------
1018 // class HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>
1019 // -------------------------------------------------
1020
1021// PRIVATE CLASS METHODS
1022template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1023inline const KEY&
1025{
1026 return bucket;
1027}
1028
1029template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1030inline const KEY&
1031HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>::keyFromBucket(
1032 const bsl::pair<KEY, VALUE>& bucket)
1033{
1034 return bucket.first;
1035}
1036
1037// PRIVATE MANIPULATORS
1038template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1039void HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>::loadElementAt(
1040 Handle *handle,
1041 bsls::Types::Int64 index,
1042 const Bucket& element,
1043 bsls::Types::Int64 chainLength)
1044{
1045 BSLS_ASSERT(handle);
1046
1047 typedef typename bsl::vector<Bucket>::size_type size_type;
1048 TRAITS::load(&d_buckets[(size_type)index], element);
1049 *handle = index;
1050 ++d_numElements;
1051
1052 if (chainLength) {
1053 d_maxChain = bsl::max(d_maxChain, chainLength);
1054 d_totalChain += chainLength;
1055 ++d_numCollisions;
1056 }
1057}
1058
1059template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1060bool HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>::insertElement(
1061 Handle *handle,
1062 const Bucket& element)
1063{
1064 BSLS_ASSERT(handle);
1065
1066 if (size() == capacity()) {
1067 return false; // RETURN
1068 }
1069
1070 bool isKeyFound;
1071 bsls::Types::Int64 nullIndex, chainLength, removedIndex;
1072
1073 findImp(&isKeyFound, &nullIndex, &chainLength, &removedIndex,
1074 keyFromBucket(element));
1075
1076 if (isKeyFound) {
1077 return false; // RETURN
1078 }
1079
1080 if (-1 != removedIndex) {
1081 loadElementAt(handle, removedIndex, element, chainLength);
1082 }
1083 else {
1084 BSLS_ASSERT(-1 != nullIndex);
1085
1086 loadElementAt(handle, nullIndex, element, chainLength);
1087 }
1088
1089 return true;
1090}
1091
1092// PRIVATE ACCESSORS
1093template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1094void HashTable<KEY, VALUE, TRAITS, HASH1, HASH2>::findImp(
1095 bool *isKeyFound,
1096 bsls::Types::Int64 *index,
1097 bsls::Types::Int64 *chainLength,
1098 bsls::Types::Int64 *removedIndex,
1099 const KEY& key) const
1100{
1101 BSLS_ASSERT(isKeyFound);
1102 BSLS_ASSERT(index);
1103 BSLS_ASSERT(chainLength);
1104 BSLS_ASSERT(removedIndex);
1105
1106 typedef typename bsl::vector<Bucket>::size_type size_type;
1107
1108 *chainLength = 0;
1109 *removedIndex = -1;
1110
1111 unsigned int capacity = static_cast<unsigned int>(d_buckets.size());
1112
1113 bsls::Types::Int64 bucketIndex = d_hashFunctor1.object()(key) % capacity;
1114
1115 if (TRAITS::isNull(d_buckets[(size_type)bucketIndex])) {
1116 *isKeyFound = false;
1117 *index = bucketIndex;
1118 return; // RETURN
1119 }
1120 else if (TRAITS::isRemoved(d_buckets[(size_type)bucketIndex])) {
1121 *removedIndex = bucketIndex;
1122 }
1123 else if (TRAITS::areEqual(keyFromBucket(d_buckets[(size_type)bucketIndex]),
1124 key)) {
1125 *isKeyFound = true;
1126 *index = bucketIndex;
1127 return; // RETURN
1128 }
1129
1130 bsls::Types::Int64 increment = (d_hashFunctor2.object()(key)
1131 % (capacity - 1)) + 1;
1132 // must be between [1, capacity-1]
1133
1134 while (*chainLength < capacity) {
1135 ++*chainLength;
1136 bucketIndex = (bucketIndex + increment) % capacity;
1137
1138 if (TRAITS::isNull(d_buckets[(size_type)bucketIndex])) {
1139 *isKeyFound = false;
1140 *index = bucketIndex;
1141 return; // RETURN
1142 }
1143 else if (TRAITS::isRemoved(d_buckets[(size_type)bucketIndex])) {
1144 if (*removedIndex == -1) {
1145 *removedIndex = bucketIndex;
1146 }
1147 }
1148 else
1149 if (TRAITS::areEqual(keyFromBucket(d_buckets[(size_type)bucketIndex]),
1150 key)) {
1151 *isKeyFound = true;
1152 *index = bucketIndex;
1153 return; // RETURN
1154 }
1155 }
1156
1157 *isKeyFound = false;
1158 *index = -1;
1159}
1160
1161// CREATORS
1162template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1164 bsls::Types::Int64 capacityHint,
1165 bslma::Allocator *basicAllocator)
1166: d_buckets(HashTable_ImpUtil::hashSize(capacityHint),
1167 Bucket(),
1168 basicAllocator)
1169, d_capacityHint(capacityHint)
1170, d_hashFunctor1(basicAllocator)
1171, d_hashFunctor2(basicAllocator)
1172, d_maxChain(0)
1173, d_numCollisions(0)
1174, d_numElements(0)
1175, d_totalChain(0)
1176{
1178
1179 typedef typename bsl::vector<Bucket>::iterator Iterator;
1180
1181 for (Iterator it = d_buckets.begin(); it != d_buckets.end(); ++it) {
1182 TRAITS::setToNull(&(*it));
1183 }
1184}
1185
1186template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1188 bsls::Types::Int64 capacityHint,
1189 const HASH1& hashFunctor1,
1190 const HASH2& hashFunctor2,
1191 bslma::Allocator *basicAllocator)
1192: d_buckets(HashTable_ImpUtil::hashSize(capacityHint),
1193 Bucket(),
1194 basicAllocator)
1195, d_capacityHint(capacityHint)
1196, d_hashFunctor1(hashFunctor1, basicAllocator)
1197, d_hashFunctor2(hashFunctor2, basicAllocator)
1198, d_maxChain(0)
1199, d_numCollisions(0)
1200, d_numElements(0)
1201, d_totalChain(0)
1202{
1204
1205 typedef typename bsl::vector<Bucket>::iterator Iterator;
1206
1207 for (Iterator it = d_buckets.begin(); it != d_buckets.end(); ++it) {
1208 TRAITS::setToNull(&(*it));
1209 }
1210}
1211
1212template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1213inline
1217
1218// MANIPULATORS
1219template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1220inline
1222 const KEY& key)
1223{
1224 BSLS_ASSERT(handle);
1225
1227
1228 return insertElement(handle, key);
1229}
1230
1231template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1232inline
1234 const KEY& key,
1235 const VALUE& value)
1236{
1237 BSLS_ASSERT(handle);
1238
1240
1241 return insertElement(handle, bsl::make_pair(key, value));
1242}
1243
1244template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1245inline
1247{
1248 typedef typename bsl::vector<Bucket>::size_type size_type;
1249
1250 BSLS_ASSERT(!TRAITS::isNull (d_buckets[(size_type)handle]));
1251 BSLS_ASSERT(!TRAITS::isRemoved(d_buckets[(size_type)handle]));
1252
1253 TRAITS::setToRemoved(&d_buckets[(size_type)handle]);
1254 --d_numElements;
1255}
1256
1257template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1258inline
1260{
1261 typedef typename bsl::vector<Bucket>::size_type size_type;
1263
1264 BSLS_ASSERT(!TRAITS::isNull (d_buckets[(size_type)handle]));
1265 BSLS_ASSERT(!TRAITS::isRemoved(d_buckets[(size_type)handle]));
1266
1267 return d_buckets[(size_type)handle].second;
1268}
1269
1270// ACCESSORS
1271template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1272inline
1275{
1276 return d_buckets.size();
1277}
1278
1279template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1280inline
1283{
1284 return d_capacityHint;
1285}
1286
1287template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1288inline
1290 const KEY& key) const
1291{
1292 BSLS_ASSERT(handle);
1293
1294 bool isKeyFound;
1295 bsls::Types::Int64 chainLength, removedIndex;
1296
1297 findImp(&isKeyFound, handle, &chainLength, &removedIndex, key);
1298
1299 return isKeyFound;
1300}
1301
1302template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1303inline
1305 const Handle& handle) const
1306{
1307 typedef typename bsl::vector<Bucket>::size_type size_type;
1308 BSLS_ASSERT(!TRAITS::isNull (d_buckets[(size_type)handle]));
1309 BSLS_ASSERT(!TRAITS::isRemoved(d_buckets[(size_type)handle]));
1310
1311 return keyFromBucket(d_buckets[(size_type)handle]);
1312}
1313
1314template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1315inline
1318{
1319 return d_maxChain;
1320}
1321
1322template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1323inline
1326{
1327 return d_numCollisions;
1328}
1329
1330template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1331inline
1334{
1335 return d_numElements;
1336}
1337
1338template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1339inline
1342{
1343 return d_totalChain;
1344}
1345
1346template <class KEY, class VALUE, class TRAITS, class HASH1, class HASH2>
1347inline
1349 const Handle& handle) const
1350{
1351 typedef typename bsl::vector<Bucket>::size_type size_type;
1353
1354 BSLS_ASSERT(!TRAITS::isNull (d_buckets[(size_type)handle]));
1355 BSLS_ASSERT(!TRAITS::isRemoved(d_buckets[(size_type)handle]));
1356
1357 return d_buckets[(size_type)handle].second;
1358}
1359
1360 // -------------------------------------
1361 // private struct HashTableDefaultTraits
1362 // -------------------------------------
1363
1364template <char t_VALUE>
1365inline
1366bool HashTableDefaultTraits::isNot(char c)
1367{
1368 return c != t_VALUE;
1369}
1370
1371template <class BUCKET>
1372inline
1373void HashTableDefaultTraits::load(BUCKET *dstBucket, const BUCKET& srcBucket)
1374{
1375 BSLS_ASSERT(dstBucket);
1376
1377 *dstBucket = srcBucket;
1378}
1379
1380template <class KEY>
1381inline
1382bool HashTableDefaultTraits::areEqual(const KEY& key1, const KEY& key2)
1383{
1384 return key1 == key2;
1385}
1386
1387inline
1388bool HashTableDefaultTraits::areEqual(const ConstCharPtr& key1,
1389 const ConstCharPtr& key2)
1390{
1391 BSLS_ASSERT(key1);
1392 BSLS_ASSERT(key2);
1393
1394 return 0 == bsl::strcmp(key1, key2);
1395}
1396
1397template <class BUCKET>
1398inline
1399bool HashTableDefaultTraits::isNull(const BUCKET& bucket)
1400{
1401 enum {
1403 };
1404
1405 BSLMF_ASSERT(k_IS_POD);
1406
1407 const char null = 0; (void)null; // 'null' not used in some build modes
1408 const char *begin = reinterpret_cast<const char *>(&bucket);
1409 const char *end = begin + sizeof bucket;
1410
1411 return end == bsl::find_if(begin, end, isNot<null>);
1412}
1413
1414inline
1416{
1417 return 0 == bucket.length();
1418}
1419
1420inline
1421bool HashTableDefaultTraits::isNull(const ConstCharPtr& bucket)
1422{
1423 return 0 == bucket;
1424}
1425
1426template <class KEY, class VALUE>
1427inline
1429{
1430 return isNull(bucket.first) && isNull(bucket.second);
1431}
1432
1433template <class BUCKET>
1434inline
1436{
1437 BSLS_ASSERT(bucket);
1438
1439 enum {
1441 };
1442
1443 BSLMF_ASSERT(k_IS_POD);
1444
1445 const char null = 0;
1446 char *begin = reinterpret_cast<char *>(bucket);
1447
1448 bsl::fill_n(begin, sizeof(BUCKET), null);
1449}
1450
1451inline
1453{
1454 BSLS_ASSERT(bucket);
1455
1456 bucket->clear();
1457}
1458
1459inline
1460void HashTableDefaultTraits::setToNull(ConstCharPtr *bucket)
1461{
1462 BSLS_ASSERT(bucket);
1463
1464 *bucket = 0;
1465}
1466
1467template <class KEY, class VALUE>
1468inline
1470{
1471 BSLS_ASSERT(bucket);
1472
1473 setToNull(&bucket->first);
1474 setToNull(&bucket->second);
1475}
1476
1477template <class BUCKET>
1478inline
1479bool HashTableDefaultTraits::isRemoved(const BUCKET& bucket)
1480{
1481 enum {
1483 };
1484
1485 BSLMF_ASSERT(k_IS_POD);
1486
1487 const char removed = (char)0xFF;
1488 const char *begin = reinterpret_cast<const char *>(&bucket);
1489 const char *end = begin + sizeof bucket;
1490
1491 return end == bsl::find_if(begin, end, isNot<removed>);
1492}
1493
1494inline
1496{
1497 return 0 == bsl::strcmp(bucket.c_str(), REMOVED_KEYWORD);
1498}
1499
1500inline
1501bool HashTableDefaultTraits::isRemoved(const ConstCharPtr& bucket)
1502{
1503#if defined(BSLS_PLATFORM_CPU_32_BIT)
1504 const char *removed = reinterpret_cast<const char *>(0xFFFFFFFF);
1505#else
1506 const char *removed = reinterpret_cast<const char *>(0xFFFFFFFFFFFFFFFF);
1507#endif
1508
1509 return removed == bucket;
1510}
1511
1512template <class KEY, class VALUE>
1513inline
1515{
1516 return isRemoved(bucket.first) && isRemoved(bucket.second);
1517}
1518
1519template <class BUCKET>
1520inline
1522{
1523 BSLS_ASSERT(bucket);
1524
1525 enum {
1527 };
1528
1529 BSLMF_ASSERT(k_IS_POD);
1530
1531 const char removed = (char)0xFF;
1532 char *begin = reinterpret_cast<char *>(bucket);
1533
1534 bsl::fill_n(begin, sizeof(BUCKET), removed);
1535}
1536
1537inline
1539{
1540 BSLS_ASSERT(bucket);
1541
1542 *bucket = REMOVED_KEYWORD;
1543}
1544
1545inline
1547{
1548 BSLS_ASSERT(bucket);
1549
1550#if defined(BSLS_PLATFORM_CPU_32_BIT)
1551 const char *removed = reinterpret_cast<const char *>(0xFFFFFFFF);
1552#else
1553 const char *removed = reinterpret_cast<const char *>(0xFFFFFFFFFFFFFFFF);
1554#endif
1555
1556 *bucket = removed;
1557}
1558
1559template <class KEY, class VALUE>
1560inline
1562{
1563 BSLS_ASSERT(bucket);
1564
1565 setToRemoved(&bucket->first);
1566 setToRemoved(&bucket->second);
1567}
1568
1569 // ----------------------------
1570 // struct HashTableDefaultHash1
1571 // ----------------------------
1572
1573template <class KEY>
1574inline
1575unsigned int HashTableDefaultHash1::operator()(const KEY& key) const
1576{
1577 const char *keyData = reinterpret_cast<const char *>(&key);
1578 int keyLength = sizeof key;
1579
1580 return bdlb::HashUtil::hash1(keyData, keyLength);
1581}
1582
1583inline
1585{
1586 const char *keyData = key;
1587 int keyLength = static_cast<int>(bsl::strlen(key));
1588
1589 return bdlb::HashUtil::hash1(keyData, keyLength);
1590}
1591
1592inline
1594{
1595 const char *keyData = key.data();
1596 int keyLength = static_cast<int>(key.length());
1597
1598 return bdlb::HashUtil::hash1(keyData, keyLength);
1599}
1600
1601 // ----------------------------
1602 // struct HashTableDefaultHash2
1603 // ----------------------------
1604
1605template <class KEY>
1606inline
1607unsigned int HashTableDefaultHash2::operator()(const KEY& key) const
1608{
1609 const char *keyData = reinterpret_cast<const char *>(&key);
1610 int keyLength = sizeof key;
1611
1612 return bdlb::HashUtil::hash2(keyData, keyLength);
1613}
1614
1615inline
1617{
1618 const char *keyData = key;
1619 int keyLength = static_cast<int>(bsl::strlen(key));
1620
1621 return bdlb::HashUtil::hash2(keyData, keyLength);
1622}
1623
1624inline
1626{
1627 const char *keyData = key.data();
1628 int keyLength = static_cast<int>(key.length());
1629
1630 return bdlb::HashUtil::hash2(keyData, keyLength);
1631}
1632
1633} // close package namespace
1634
1635
1636#endif
1637
1638// ----------------------------------------------------------------------------
1639// Copyright 2018 Bloomberg Finance L.P.
1640//
1641// Licensed under the Apache License, Version 2.0 (the "License");
1642// you may not use this file except in compliance with the License.
1643// You may obtain a copy of the License at
1644//
1645// http://www.apache.org/licenses/LICENSE-2.0
1646//
1647// Unless required by applicable law or agreed to in writing, software
1648// distributed under the License is distributed on an "AS IS" BASIS,
1649// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1650// See the License for the specific language governing permissions and
1651// limitations under the License.
1652// ----------------------------- END-OF-FILE ----------------------------------
1653
1654/** @} */
1655/** @} */
1656/** @} */
Definition bdlc_hashtable.h:670
bsls::Types::Int64 totalChain() const
Return the total chain length encountered by this object.
Definition bdlc_hashtable.h:1341
~HashTable()
Destroy this object.
Definition bdlc_hashtable.h:1214
bool insert(Handle *handle, const KEY &key)
Definition bdlc_hashtable.h:1221
const KEY & key(const Handle &handle) const
Definition bdlc_hashtable.h:1304
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:1333
VALUE & value(const Handle &handle)
Definition bdlc_hashtable.h:1259
bsls::Types::Int64 capacity() const
Definition bdlc_hashtable.h:1274
bsls::Types::Int64 capacityHint() const
Definition bdlc_hashtable.h:1282
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:1317
void remove(const Handle &handle)
Definition bdlc_hashtable.h:1246
bsls::Types::Int64 numCollisions() const
Return the number of collisions encountered by this object.
Definition bdlc_hashtable.h:1325
bool find(Handle *handle, const KEY &key) const
Definition bdlc_hashtable.h:1289
Definition bslstl_string.h:1281
size_type length() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6601
const CHAR_TYPE * c_str() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6705
CHAR_TYPE * data() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6477
void clear() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:5430
Definition bslstl_pair.h:1210
Definition bslstl_vector.h:1025
AllocatorTraits::size_type size_type
Definition bslstl_vector.h:1052
VALUE_TYPE * iterator
Definition bslstl_vector.h:1057
Definition bslalg_constructorproxy.h:368
Definition bslma_allocator.h:457
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
Definition bdlc_bitarray.h:503
static unsigned int hash2(const char *data, int length)
static unsigned int hash1(const char *data, int length)
Definition bdlc_hashtable.h:947
unsigned int operator()(const KEY &key) const
Definition bdlc_hashtable.h:1575
const char * ConstCharPtr
Definition bdlc_hashtable.h:950
Definition bdlc_hashtable.h:974
unsigned int operator()(const KEY &key) const
Definition bdlc_hashtable.h:1607
const char * ConstCharPtr
Definition bdlc_hashtable.h:977
Definition bdlc_hashtable.h:873
static void setToRemoved(BUCKET *bucket)
Load a removed value into the specified bucket.
Definition bdlc_hashtable.h:1521
static void setToNull(BUCKET *bucket)
Load a null value into the specified bucket.
Definition bdlc_hashtable.h:1435
static bool areEqual(const KEY &key1, const KEY &key2)
Definition bdlc_hashtable.h:1382
static void load(BUCKET *dstBucket, const BUCKET &srcBucket)
Load the specified srcBucket into the specified dstBucket.
Definition bdlc_hashtable.h:1373
static bool isRemoved(const BUCKET &bucket)
Definition bdlc_hashtable.h:1479
static bool isNull(const BUCKET &bucket)
Definition bdlc_hashtable.h:1399
Definition bdlc_hashtable.h:999
static const int NUM_PRIME_NUMBERS
Definition bdlc_hashtable.h:1003
static const unsigned int * PRIME_NUMBERS
Definition bdlc_hashtable.h:1002
static unsigned int hashSize(bsls::Types::Int64 hint)
Return the hash size based on the specified hint.
TYPE first
Definition bslstl_pair.h:605
TYPE second
Definition bslstl_pair.h:908
Definition bslmf_conditional.h:120
Definition bslmf_integralconstant.h:244
Definition bslmf_istriviallydefaultconstructible.h:293
Definition bslma_usesbslmaallocator.h:343
Definition bslmf_issame.h:181
This struct is empty and represents a nil type.
Definition bslmf_nil.h:131
long long Int64
Definition bsls_types.h:132