BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslstl_hashtable.h
Go to the documentation of this file.
1/// @file bslstl_hashtable.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslstl_hashtable.h -*-C++-*-
8#ifndef INCLUDED_BSLSTL_HASHTABLE
9#define INCLUDED_BSLSTL_HASHTABLE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslstl_hashtable bslstl_hashtable
15/// @brief Provide a hash-container with support for duplicate values.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslstl
19/// @{
20/// @addtogroup bslstl_hashtable
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslstl_hashtable-purpose"> Purpose</a>
25/// * <a href="#bslstl_hashtable-classes"> Classes </a>
26/// * <a href="#bslstl_hashtable-description"> Description </a>
27/// * <a href="#bslstl_hashtable-requirements-on-key_config"> Requirements on KEY_CONFIG </a>
28/// * <a href="#bslstl_hashtable-memory-allocation"> Memory Allocation </a>
29/// * <a href="#bslstl_hashtable-bslma-style-allocators"> bslma-Style Allocators </a>
30/// * <a href="#bslstl_hashtable-exception-safety"> Exception Safety </a>
31/// * <a href="#bslstl_hashtable-internal-data-structure"> Internal Data Structure </a>
32/// * <a href="#bslstl_hashtable-usage"> Usage </a>
33/// * <a href="#bslstl_hashtable-example-1-implementing-a-hashed-set-container"> Example 1: Implementing a Hashed Set Container </a>
34/// * <a href="#bslstl_hashtable-example-2-implementing-a-hashed-map-container"> Example 2: Implementing a Hashed Map Container </a>
35/// * <a href="#bslstl_hashtable-example-3-implementing-a-hashed-multi-map-container"> Example 3: Implementing a Hashed Multi-Map Container </a>
36/// * <a href="#bslstl_hashtable-example-4-implementing-a-custom-container"> Example 4: Implementing a Custom Container </a>
37///
38/// # Purpose {#bslstl_hashtable-purpose}
39/// Provide a hash-container with support for duplicate values.
40///
41/// # Classes {#bslstl_hashtable-classes}
42///
43/// - bslstl::HashTable : hashed-table container for user-supplied object types
44///
45/// @see package bos+stdhdrs in the bos package group
46///
47/// # Description {#bslstl_hashtable-description}
48/// This component defines a single class template, `HashTable`,
49/// implementing a value-semantic container that can be used to easily implement
50/// the four `unordered` containers specified by the C++11 standard.
51///
52/// An instantiation of `HashTable` is an allocator-aware, value-semantic type
53/// whose salient attributes are its size (number of keys) and the ordered
54/// sequence of keys the `HashTable` contains. If `HashTable` is instantiated
55/// with a key type that is not itself value-semantic, then it will not retain
56/// all of its value-semantic qualities. In particular, if the key type cannot
57/// be tested for equality, then a HashTable containing that type cannot be
58/// tested for equality. It is even possible to instantiate `HashTable` with a
59/// key type that does not have a copy-constructor, in which case the
60/// `HashTable` will not be copyable.
61///
62/// ## Requirements on KEY_CONFIG {#bslstl_hashtable-requirements-on-key_config}
63///
64///
65/// The elements stored in a `HashTable` and the key by which they are indexed
66/// are defined by a `KEY_CONFIG` template type parameter. The user-supplied
67/// `KEY_CONFIG` type must provide two type aliases named `ValueType` and
68/// `KeyType` that name the type of element stored and its associated key type
69/// respectively. In addition, a `KEY_CONFIG` class shall provide a static
70/// member function which may be called as if it had the following signature:
71/// @code
72/// /// Return a reference offering non-modifiable access to the key for the
73/// /// specified `value`.
74/// static const KeyType& extractKey(const ValueType& value);
75/// @endcode
76/// Optionally, the `KEY_CONFIG` class might provide an `extractKey` function
77/// with the alternative signature:
78/// @code
79/// /// Return a reference to the key for the specified `value`.
80/// static KeyType& extractKey(ValueType& value);
81/// @endcode
82/// This alternative signature is necessary to support the rare case that a hash
83/// function or comparator used to configure the `HashTable` template below take
84/// their arguments by non-`const` reference. This is subject to additional
85/// constraints that these functions may not modify the passed arguments, and is
86/// inherently a fragile interface and not recommended. It is supported only
87/// for C++ Standard conformance.
88///
89/// A `HashTable` is a "Value-Semantic Type" (see @ref bsldoc_glossary ) only if
90/// the configured `ValueType` is value-semantic. It is possible to instantiate
91/// a `HashTable` configured with a `ValueType` that does not provide a full
92/// `HashTable` of value-semantic operations, but then some methods of the
93/// container may not be instantiable. The following terminology, adopted from
94/// the C++11 standard, is used in the function documentation of `HashTable` to
95/// describe a function's requirements for the `KEY` template parameter. These
96/// terms are also defined in [utility.arg.requirements] (section 17.6.3.1 of
97/// the C++11 standard). Note that, in the context of a `HashTable`
98/// instantiation, the requirements apply specifically to the `HashTable`s
99/// element type, `ValueType`.
100///
101/// Legend
102/// ------
103/// `X` - denotes an allocator-aware container type (e.g., `unordered_set`)
104/// `T` - `value_type` associated with `X`
105/// `A` - type of the allocator used by `X`
106/// `m` - lvalue of type `A` (allocator)
107/// `p` - address (`T *`) of uninitialized storage for a `T` within an `X`
108/// `rv` - rvalue of type (non-`const`) `T`
109/// `v` - rvalue or lvalue of type (possibly `const`) `T`
110/// `args` - 0 or more arguments
111///
112/// The following terms are used to more precisely specify the requirements on
113/// template parameter types in function-level documentation.
114///
115/// *default-insertable*: `T` has a default constructor. More precisely, `T`
116/// is `default-insertable` into `X` means that the following expression is
117/// well-formed:
118///
119/// `allocator_traits<A>::construct(m, p)`
120///
121/// *move-insertable*: `T` provides a constructor that takes an rvalue of type
122/// (non-`const`) `T`. More precisely, `T` is `move-insertable` into `X`
123/// means that the following expression is well-formed:
124///
125/// `allocator_traits<A>::construct(m, p, rv)`
126///
127/// *copy-insertable*: `T` provides a constructor that takes an lvalue or
128/// rvalue of type (possibly `const`) `T`. More precisely, `T` is
129/// `copy-insertable` into `X` means that the following expression is
130/// well-formed:
131///
132/// `allocator_traits<A>::construct(m, p, v)`
133///
134/// *move-assignable*: `T` provides an assignment operator that takes an rvalue
135/// of type (non-`const`) `T`.
136///
137/// *copy-assignable*: `T` provides an assignment operator that takes an lvalue
138/// or rvalue of type (possibly `const`) `T`.
139///
140/// *emplace-constructible*: `T` is `emplace-constructible` into `X` from
141/// `args` means that the following expression is well-formed:
142///
143/// `allocator_traits<A>::construct(m, p, args)`
144///
145/// *erasable*: `T` provides a destructor. More precisely, `T` is `erasable`
146/// from `X` means that the following expression is well-formed:
147///
148/// `allocator_traits<A>::destroy(m, p)`
149///
150/// *equality-comparable*: The type provides an equality-comparison operator
151/// that defines an equivalence relationship and is both reflexive and
152/// transitive.
153///
154/// ## Memory Allocation {#bslstl_hashtable-memory-allocation}
155///
156///
157/// The type supplied as a HashTable's `ALLOCATOR` template parameter determines
158/// how that HashTable will allocate memory. The `HashTable` template supports
159/// allocators meeting the requirements of the C++ standard allocator
160/// requirements ([allocator.requirements], C++11 17.6.3.5); in addition it
161/// supports scoped-allocators derived from the `bslma::Allocator` memory
162/// allocation protocol. Clients intending to use `bslma` style allocators
163/// should use the template's default `ALLOCATOR` type: The default type for the
164/// `ALLOCATOR` template parameter, `bsl::allocator`, provides a C++11
165/// standard-compatible adapter for a `bslma::Allocator` object.
166///
167/// ### bslma-Style Allocators {#bslstl_hashtable-bslma-style-allocators}
168///
169///
170/// If the parameterized `ALLOCATOR` type of an `HashTable` instantiation is
171/// `bsl::allocator`, then objects of that HashTable type will conform to the
172/// standard behavior of a `bslma`-allocator-enabled type. Such a HashTable
173/// accepts an optional `bslma::Allocator` argument at construction. If the
174/// address of a `bslma::Allocator` object is explicitly supplied at
175/// construction, it will be used to supply memory for the HashTable throughout
176/// its lifetime; otherwise, the HashTable will use the default allocator
177/// installed at the time of the HashTable's construction (see @ref bslma_default ).
178/// In addition to directly allocating memory from the indicated
179/// `bslma::Allocator`, a HashTable supplies that allocator's address to the
180/// constructors of contained objects of the configured `ValueType` with the
181/// `bslalg::TypeTraitUsesBslmaAllocator` trait.
182///
183/// ## Exception Safety {#bslstl_hashtable-exception-safety}
184///
185///
186/// The operations of a `HashTable` provide the strong exception guarantee (see
187/// @ref bsldoc_glossary ) except in the presence of a hash-functor or
188/// equality-comparator that throws exceptions. If either the hash-functor or
189/// equality-comparator throws an exception from a non-`const` method,
190/// `HashTable` provides only the basic exception guarantee, and the operation
191/// will leave the container in a valid but unspecified (potentially empty)
192/// state.
193///
194/// ## Internal Data Structure {#bslstl_hashtable-internal-data-structure}
195///
196///
197/// This implementation of a hash-table uses a single bidirectional list, to
198/// hold all the elements stored in the container, and the elements in this list
199/// are indexed by a dynamic array of buckets, each of which holds a pointer to
200/// the first and last element in the linked-list whose adjusted hash-values are
201/// equal to that bucket's index.
202///
203/// As we do not cache the hashed value, if any hash function throws we will
204/// either do nothing and allow the exception to propagate, or, if some change
205/// of state has already been made, clear the whole container to provide the
206/// basic exception guarantee. There are similar concerns for the `COMPARATOR`
207/// predicate.
208///
209/// ## Usage {#bslstl_hashtable-usage}
210///
211///
212/// This section illustrates intended use of this component. The
213/// `bslstl::HashTable` class template provides a common foundation for
214/// implementing the four standard unordered containers:
215/// * `bsl::unordered_map`
216/// * `bsl::unordered_multiset`
217/// * `bsl::unordered_multimap`
218/// * `bsl::unordered_set`
219/// This and the subsequent examples in this component use the
220/// `bslstl::HashTable` class to implement several model container classes, each
221/// providing a small but representative sub-set of the functionality of one of
222/// the standard unordered containers.
223///
224/// ## Example 1: Implementing a Hashed Set Container {#bslstl_hashtable-example-1-implementing-a-hashed-set-container}
225///
226///
227/// Suppose we wish to implement, `MyHashedSet`, a greatly abbreviated version
228/// of `bsl::unordered_set`. The `bslstl::HashTable` class template can be used
229/// as the basis of that implementation.
230///
231/// First, we define `UseEntireValueAsKey`, a class template we can use to
232/// configure `bslstl::HashTable` to use its entire elements as keys for its
233/// hasher, a policy suitable for a set container. (Later, in {Example 2}, we
234/// will define `UseFirstValueOfPairAsKey` for use in a map container. Note
235/// that, in practice, developers can use the existing classes in
236/// @ref bslstl_unorderedmapkeyconfiguration and
237/// @ref bslstl_unorderedsetkeyconfiguration .)
238/// @code
239/// // ==========================
240/// // struct UseEntireValueAsKey
241/// // ==========================
242///
243/// // This `struct` provides a namespace for types and methods that define
244/// // the policy by which the key value of a hashed container (i.e., the
245/// // value passed to the hasher) is extracted from the objects stored in
246/// // the hashed container (the `value` type).
247/// template <class VALUE_TYPE>
248/// struct UseEntireValueAsKey {
249///
250/// /// Alias for `VALUE_TYPE`, the type stored in the hashed container.
251/// typedef VALUE_TYPE ValueType;
252///
253/// /// Alias for the type passed to the hasher by the hashed container.
254/// /// In this policy, that type is `ValueType`.
255/// typedef ValueType KeyType;
256///
257/// /// Return the key value for the specified `value`. In this policy,
258/// /// that is `value` itself.
259/// static const KeyType& extractKey(const ValueType& value);
260/// };
261///
262/// // --------------------------
263/// // struct UseEntireValueAsKey
264/// // --------------------------
265///
266/// template <class VALUE_TYPE>
267/// inline
268/// const typename UseEntireValueAsKey<VALUE_TYPE>::KeyType&
269/// UseEntireValueAsKey<VALUE_TYPE>::extractKey(
270/// const ValueType& value)
271/// {
272/// return value;
273/// }
274/// @endcode
275/// Next, we define our `MyHashedSet` class template with an instance of
276/// `bslstl::HashTable` (configured using `UseEntireValueAsKey`) as its sole
277/// data member. We provide `insert` method, to allow us to populate these
278/// sets, and the `find` method to allow us to examine those elements. We also
279/// provide `size` and @ref bucket_count accessor methods to let us check the inner
280/// workings of our class.
281///
282/// Note that the standard classes define aliases for the templated parameters
283/// and other types. In the interest of brevity, this model class (and the
284/// classes in the subsequent examples) do not define such aliases except where
285/// strictly needed for the example.
286/// @code
287/// // =================
288/// // class MyHashedSet
289/// // =================
290///
291/// template <class KEY,
292/// class HASHF = bsl::hash< KEY>,
293/// class EQUAL = bsl::equal_to< KEY>,
294/// class ALLOCATOR = bsl::allocator<KEY> >
295/// class MyHashedSet
296/// {
297/// private:
298/// // PRIVATE TYPES
299/// typedef bsl::allocator_traits<ALLOCATOR> AllocatorTraits;
300/// typedef typename AllocatorTraits::difference_type difference_type;
301/// typedef BloombergLP::bslstl::HashTableIterator<
302/// const KEY, difference_type> iterator;
303///
304/// typedef UseEntireValueAsKey<KEY> HashKey;
305///
306/// typedef BloombergLP::bslstl::HashTable<HashKey,
307/// HASHF,
308/// EQUAL,
309/// ALLOCATOR> ImpHashTable;
310///
311///
312/// // DATA
313/// ImpHashTable d_impl;
314///
315/// public:
316/// // TYPES
317/// typedef typename AllocatorTraits::size_type size_type;
318/// typedef iterator const_iterator;
319///
320/// // CREATORS
321///
322/// /// Create an empty `MyHashedSet` object having a maximum load
323/// /// factor of 1. Optionally specify at least `initialNumBuckets` in
324/// /// this container's initial array of buckets. If
325/// /// `initialNumBuckets` is not supplied, an implementation defined
326/// /// value is used. Optionally specify a `hash` used to generate the
327/// /// hash values associated to the keys extracted from the values
328/// /// contained in this object. If `hash` is not supplied, a
329/// /// default-constructed object of type `HASHF` is used. Optionally
330/// /// specify a key-equality functor `keyEqual` used to verify that
331/// /// two key values are the same. If `keyEqual` is not supplied, a
332/// /// default-constructed object of type `EQUAL` is used. Optionally
333/// /// specify an `allocator` used to supply memory. If `allocator` is
334/// /// not supplied, a default-constructed object of the (template
335/// /// parameter) type `ALLOCATOR` is used. If the `ALLOCATOR` is
336/// /// `bsl::allocator` (the default), then `allocator` shall be
337/// /// convertible to `bslma::Allocator *`. If the `ALLOCATOR` is
338/// /// `bsl::allocator` and `allocator` is not supplied, the currently
339/// /// installed default allocator is used to supply memory.
340/// explicit MyHashedSet(size_type initialNumBuckets = 0,
341/// const HASHF& hash = HASHF(),
342/// const EQUAL& keyEqual = EQUAL(),
343/// const ALLOCATOR& allocator = ALLOCATOR());
344///
345/// /// Destroy this object.
346/// //! ~MyHashedSet() = default;
347///
348/// // MANIPULATORS
349///
350/// /// Insert the specified `value` into this set if the `value` does
351/// /// not already exist in this set; otherwise, this method has no
352/// /// effect. Return a pair whose `first` member is an iterator
353/// /// providing non-modifiable access to the (possibly newly inserted)
354/// /// `KEY` object having `value` (according to `EQUAL`) and whose
355/// /// `second` member is `true` if a new element was inserted, and
356/// /// `false` if `value` was already present.
357/// bsl::pair<const_iterator, bool> insert(const KEY& value);
358///
359/// // ACCESSORS
360///
361/// /// Return the number of buckets in this set.
362/// size_type bucket_count() const;
363///
364/// /// Return an iterator providing non-modifiable access to the
365/// /// past-the-end element (in the sequence of `KEY` objects)
366/// /// maintained by this set.
367/// const_iterator cend() const;
368///
369/// /// Return an iterator providing non-modifiable access to the `KEY`
370/// /// object in this set having the specified `value`, if such an
371/// /// entry exists, and the iterator returned by the `cend` method
372/// /// otherwise.
373/// const_iterator find(const KEY& value) const;
374///
375/// /// Return the number of elements in this set.
376/// size_type size() const;
377/// };
378/// @endcode
379/// Next, we implement the methods of `MyHashedSet`. In many cases, the
380/// implementations consist mainly in forwarding arguments to and returning
381/// values from the underlying `bslstl::HashTable`.
382/// @code
383/// // =================
384/// // class MyHashedSet
385/// // =================
386///
387/// // CREATORS
388/// template <class KEY, class HASHF, class EQUAL, class ALLOCATOR>
389/// inline
390/// MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::MyHashedSet(
391/// size_type initialNumBuckets,
392/// const HASHF& hash,
393/// const EQUAL& keyEqual,
394/// const ALLOCATOR& allocator)
395/// : d_impl(hash, keyEqual, initialNumBuckets, allocator)
396/// {
397/// }
398/// @endcode
399/// Note that the `insertIfMissing` method of `bslstl::HashTable` provides the
400/// semantics needed for adding values (unique values only) to sets.
401/// @code
402/// // MANIPULATORS
403/// template <class KEY, class HASHF, class EQUAL, class ALLOCATOR>
404/// inline
405/// bsl::pair<typename MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::iterator,
406/// bool> MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::insert(
407/// const KEY& value)
408/// {
409/// typedef bsl::pair<iterator, bool> ResultType;
410///
411/// bool isInsertedFlag = false;
412/// bslalg::BidirectionalLink *result = d_impl.insertIfMissing(
413/// &isInsertedFlag,
414/// value);
415/// return ResultType(iterator(result), isInsertedFlag);
416/// }
417///
418/// // ACCESSORS
419/// template <class KEY, class HASHF, class EQUAL, class ALLOCATOR>
420/// inline
421/// typename MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::size_type
422/// MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::bucket_count() const
423/// {
424/// return d_impl.numBuckets();
425/// }
426///
427/// template <class KEY, class HASHF, class EQUAL, class ALLOCATOR>
428/// inline
429/// typename MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::const_iterator
430/// MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::cend() const
431/// {
432/// return const_iterator();
433/// }
434///
435/// template <class KEY, class HASHF, class EQUAL, class ALLOCATOR>
436/// inline
437/// typename MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::const_iterator
438/// MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::find(const KEY& key)
439/// const
440/// {
441/// return const_iterator(d_impl.find(key));
442/// }
443///
444/// template <class KEY, class HASHF, class EQUAL, class ALLOCATOR>
445/// inline
446/// typename MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::size_type
447/// MyHashedSet<KEY, HASHF, EQUAL, ALLOCATOR>::size() const
448/// {
449/// return d_impl.size();
450/// }
451/// @endcode
452/// Finally, we create `mhs`, an instance of `MyHashedSet`, exercise it, and
453/// confirm that it behaves as expected.
454/// @code
455/// MyHashedSet<int> mhs;
456/// assert( 0 == mhs.size());
457/// assert( 1 == mhs.bucket_count());
458/// @endcode
459/// Notice that the newly created set is empty and has a single bucket.
460///
461/// Inserting a value (10) succeeds the first time but correctly fails on the
462/// second attempt.
463/// @code
464/// bsl::pair<MyHashedSet<int>::const_iterator, bool> status;
465///
466/// status = mhs.insert(10);
467/// assert( 1 == mhs.size());
468/// assert(10 == *status.first);
469/// assert(true == status.second);
470///
471/// status = mhs.insert(10);
472/// assert( 1 == mhs.size());
473/// assert(10 == *status.first);
474/// assert(false == status.second);
475/// @endcode
476/// We can insert a different value (20) and thereby increase the set size to 2.
477/// @code
478/// status = mhs.insert(20);
479/// assert( 2 == mhs.size());
480/// assert(20 == *status.first);
481/// assert(true == status.second);
482/// @endcode
483/// Each of the inserted values (10, 20) can be found in the set.
484/// @code
485/// MyHashedSet<int>::const_iterator itr, end = mhs.cend();
486///
487/// itr = mhs.find(10);
488/// assert(end != itr);
489/// assert(10 == *itr);
490///
491/// itr = mhs.find(20);
492/// assert(end != itr);
493/// assert(20 == *itr);
494/// @endcode
495/// However, a value known to absent from the set (0), is correctly reported as
496/// not there.
497/// @code
498/// itr = mhs.find(0);
499/// assert(end == itr);
500/// @endcode
501///
502/// ## Example 2: Implementing a Hashed Map Container {#bslstl_hashtable-example-2-implementing-a-hashed-map-container}
503///
504///
505/// Suppose we wish to implement, `MyHashedMap`, a greatly abbreviated version
506/// of `bsl::unordered_map`. As with `MyHashedSet` (see {Example 1}), the
507/// `bslstl::HashTable` class template can be used as the basis of our
508/// implementation.
509///
510/// First, we define `UseFirstValueOfPairAsKey`, a class template we can use to
511/// configure `bslstl::HashTable` to use the `first` member of each element,
512/// each a `bsl::pair`, as the key-value for hashing. Note that, in practice,
513/// developers can use class defined in @ref bslstl_unorderedmapkeyconfiguration .
514/// @code
515/// // ===============================
516/// // struct UseFirstValueOfPairAsKey
517/// // ===============================
518///
519/// template <class VALUE_TYPE>
520/// struct UseFirstValueOfPairAsKey {
521/// // This 'struct' provides a namespace for types and methods that define
522/// // the policy by which the key value of a hashed container (i.e., the
523/// // value passed to the hasher) is extracted from the objects stored in
524/// // the hashed container (the 'value' type).
525///
526/// typedef VALUE_TYPE ValueType;
527/// // Alias for 'VALUE_TYPE', the type stored in the hashed container.
528/// // For this policy 'ValueType' must define a public member named
529/// // 'first' of type 'first_type'.
530///
531/// typedef typename ValueType::first_type KeyType;
532/// // Alias for the type passed to the hasher by the hashed container.
533/// // In this policy, that type is the type of the 'first' element of
534/// // 'ValueType'.
535///
536/// static const KeyType& extractKey(const ValueType& value);
537/// // Return the key value for the specified 'value'. In this policy,
538/// // that is the value of the 'first' member of 'value'.
539/// };
540///
541/// // -------------------------------
542/// // struct UseFirstValueOfPairAsKey
543/// // -------------------------------
544///
545/// template <class VALUE_TYPE>
546/// inline
547/// const typename UseFirstValueOfPairAsKey<VALUE_TYPE>::KeyType&
548/// UseFirstValueOfPairAsKey<VALUE_TYPE>::extractKey(
549/// const ValueType& value)
550/// {
551/// return value.first;
552/// }
553/// @endcode
554/// Next, we define our `MyHashedMap` class template with an instance of
555/// `bslstl::HashTable` (configured using `UseFirstValueOfPairAsKey`) as its
556/// sole data member. In this example, we choose to implement `operator[]`
557/// (corresponding to the signature method of `bsl::unordered_map`) to allow us
558/// to populate our maps and to examine their elements.
559/// @code
560/// // =================
561/// // class MyHashedMap
562/// // =================
563///
564/// template <class KEY,
565/// class VALUE,
566/// class HASHF = bsl::hash< KEY>,
567/// class EQUAL = bsl::equal_to< KEY>,
568/// class ALLOCATOR = bsl::allocator<KEY> >
569/// class MyHashedMap
570/// {
571/// private:
572/// // PRIVATE TYPES
573/// typedef bsl::allocator_traits<ALLOCATOR> AllocatorTraits;
574///
575/// typedef UseFirstValueOfPairAsKey<bsl::pair<const KEY, VALUE> > HashKey;
576/// typedef BloombergLP::bslstl::HashTable<HashKey,
577/// HASHF,
578/// EQUAL,
579/// ALLOCATOR> ImpHashTable;
580///
581/// // DATA
582/// ImpHashTable d_impl;
583///
584/// public:
585/// // TYPES
586/// typedef typename AllocatorTraits::size_type size_type;
587///
588/// // CREATORS
589/// explicit MyHashedMap(size_type initialNumBuckets = 0,
590/// const HASHF& hash = HASHF(),
591/// const EQUAL& keyEqual = EQUAL(),
592/// const ALLOCATOR& allocator = ALLOCATOR());
593/// // Create an empty 'MyHashedMap' object having a maximum load factor
594/// // of 1. Optionally specify at least 'initialNumBuckets' in this
595/// // container's initial array of buckets. If 'initialNumBuckets' is not
596/// // supplied, one empty bucket shall be used and no memory allocated.
597/// // Optionally specify 'hash' to generate the hash values associated
598/// // with the key-value pairs contained in this unordered map. If 'hash'
599/// // is not supplied, a default-constructed object of (template
600/// // parameter) 'HASHF' is used. Optionally specify a key-equality
601/// // functor 'keyEqual' used to determine whether two keys have the same
602/// // value. If 'keyEqual' is not supplied, a default-constructed object
603/// // of (template parameter) 'EQUAL' is used. Optionally specify an
604/// // 'allocator' used to supply memory. If 'allocator' is not supplied,
605/// // a default-constructed object of the (template parameter) type
606/// // 'ALLOCATOR' is used. If 'ALLOCATOR' is 'bsl::allocator' (the
607/// // default), then 'allocator' shall be convertible to
608/// // 'bslma::Allocator *'. If 'ALLOCATOR' is 'bsl::allocator' and
609/// // 'allocator' is not supplied, the currently installed default
610/// // allocator is used to supply memory. Note that more than
611/// // 'initialNumBuckets' buckets may be created in order to preserve the
612/// // bucket allocation strategy of the hash-table (but never fewer).
613///
614/// //! ~MyHashedMap() = default;
615/// // Destroy this object.
616///
617/// // MANIPULATORS
618/// VALUE& operator[](const KEY& key);
619/// // Return a reference providing modifiable access to the
620/// // mapped-value associated with the specified 'key' in this
621/// // unordered map; if this unordered map does not already contain a
622/// // 'value_type' object with 'key', first insert a new 'value_type'
623/// // object having 'key' and a default-constructed 'VALUE' object.
624/// // Note that this method requires that the (template parameter)
625/// // type 'KEY' is "copy-constructible" and the (template parameter)
626/// // 'VALUE' is "default-constructible".
627/// };
628/// @endcode
629/// Then, we implement the methods `MyHashedMap`. The construct need merely
630/// forward its arguments to the constructor of `d_impl`,
631/// @code
632/// // =================
633/// // class MyHashedMap
634/// // =================
635///
636/// // CREATORS
637/// template <class KEY,
638/// class VALUE,
639/// class HASHF,
640/// class EQUAL,
641/// class ALLOCATOR>
642/// inline
643/// MyHashedMap<KEY, VALUE, HASHF, EQUAL, ALLOCATOR>::MyHashedMap(
644/// size_type initialNumBuckets,
645/// const HASHF& hash,
646/// const EQUAL& keyEqual,
647/// const ALLOCATOR& allocator)
648/// : d_impl(hash, keyEqual, initialNumBuckets, allocator)
649/// {
650/// }
651/// @endcode
652/// As with `MyHashedSet`, the `insertIfMissing` method of `bslstl::HashTable`
653/// provides the semantics we need: an element is inserted only if no such
654/// element (no element with the same key) in the container, and a reference to
655/// that element (`node`) is returned. Here, we use `node` to obtain and return
656/// a reference offering modifiable access to the `second` member of the
657/// (possibly newly added) element. Note that the @ref static_cast from
658/// `HashTableLink *` to `HashTableNode *` is valid because the nodes derive
659/// from the link type (see @ref bslalg_bidirectionallink and
660/// @ref bslalg_hashtableimputil ).
661/// @code
662/// // MANIPULATORS
663/// template <class KEY,
664/// class VALUE,
665/// class HASHF,
666/// class EQUAL,
667/// class ALLOCATOR>
668/// inline
669/// VALUE& MyHashedMap<KEY, VALUE, HASHF, EQUAL, ALLOCATOR>::operator[](
670/// const KEY& key)
671/// {
672/// typedef typename HashTable::NodeType HashTableNode;
673/// typedef BloombergLP::bslalg::BidirectionalLink HashTableLink;
674///
675/// HashTableLink *node = d_impl.insertIfMissing(key);
676/// return static_cast<HashTableNode *>(node)->value().second;
677/// }
678/// @endcode
679/// Finally, we create `mhm`, an instance of `MyHashedMap`, exercise it, and
680/// confirm that it behaves as expected. We can add an element (with key value
681/// of 0).
682/// @code
683/// MyHashedMap<int, double> mhm;
684///
685/// mhm[0] = 1.234;
686/// assert(1.234 == mhm[0]);
687/// @endcode
688/// We can change the value of the element with key value 0.
689/// @code
690/// mhm[0] = 4.321;
691/// assert(4.321 == mhm[0]);
692/// @endcode
693/// We can add a new element (key value 1), without changing the previously
694/// existing element (key value 0).
695/// @code
696/// mhm[1] = 5.768;
697/// assert(5.768 == mhm[1]);
698/// assert(4.321 == mhm[0]);
699/// @endcode
700/// Accessing a non-existing element (key value 2) creates that element and
701/// populates it with the default value of the mapped value (0.0).
702/// @code
703/// assert(0.000 == mhm[2]);
704/// @endcode
705///
706/// ## Example 3: Implementing a Hashed Multi-Map Container {#bslstl_hashtable-example-3-implementing-a-hashed-multi-map-container}
707///
708///
709/// Suppose we wish to implement, `MyHashedMultiMap`, a greatly abbreviated
710/// version of `bsl::unordered_multimap`. As with `MyHashedSet` and
711/// `MyHashedMap` (see {Example 1}, and {Example 2}, respectively), the
712/// `bslstl::HashTable` class template can be used as the basis of our
713/// implementation.
714///
715/// First, we need a class template to configure `bslstl::HashTable` to extract
716/// key values in manner appropriate for maps. The previously defined
717/// `UseFirstValueOfPairAsKey` class template (see {Example 2}) suits perfectly.
718///
719/// Next, we define our `MyHashedMultiMap` class template with an instance of
720/// `bslstl::HashTable` (configured using `UseFirstValueOfPairAsKey`) as its
721/// sole data member. In this example, we choose to implement an `insert`
722/// method to populate our container, and an @ref equal_range method (a signature
723/// method of the multi containers) to provide access to those elements.
724/// @code
725/// // ======================
726/// // class MyHashedMultiMap
727/// // ======================
728///
729/// template <class KEY,
730/// class VALUE,
731/// class HASHF = bsl::hash< KEY>,
732/// class EQUAL = bsl::equal_to< KEY>,
733/// class ALLOCATOR = bsl::allocator<KEY> >
734/// class MyHashedMultiMap
735/// {
736/// private:
737/// // PRIVATE TYPES
738/// typedef bsl::pair<const KEY, VALUE> value_type;
739/// typedef bsl::allocator_traits<ALLOCATOR> AllocatorTraits;
740/// typedef typename AllocatorTraits::difference_type difference_type;
741///
742/// typedef UseFirstValueOfPairAsKey<bsl::pair<const KEY, VALUE> > HashKey;
743/// typedef BloombergLP::bslstl::HashTable<HashKey,
744/// HASHF,
745/// EQUAL,
746/// ALLOCATOR> ImpHashTable;
747///
748/// // DATA
749/// ImpHashTable d_impl;
750///
751/// public:
752/// // TYPES
753/// typedef typename AllocatorTraits::size_type size_type;
754/// typedef BloombergLP::bslstl::HashTableIterator<
755/// value_type, difference_type> iterator;
756/// typedef BloombergLP::bslstl::HashTableIterator<
757/// const value_type, difference_type> const_iterator;
758///
759/// // CREATORS
760/// explicit MyHashedMultiMap(
761/// size_type initialNumBuckets = 0,
762/// const HASHF& hash = HASHF(),
763/// const EQUAL& keyEqual = EQUAL(),
764/// const ALLOCATOR& allocator = ALLOCATOR());
765/// // Create an empty 'MyHashedMultiMap' object having a maximum load
766/// // factor of 1. Optionally specify at least 'initialNumBuckets' in
767/// // this container's initial array of buckets. If 'initialNumBuckets'
768/// // is not supplied, an implementation defined value is used.
769/// // Optionally specify a 'hash', a hash-functor used to generate the
770/// // hash values associated to the key-value pairs contained in this
771/// // object. If 'hash' is not supplied, a default-constructed object of
772/// // (template parameter) 'HASHF' type is used. Optionally specify a
773/// // key-equality functor 'keyEqual' used to verify that two key values
774/// // are the same. If 'keyEqual' is not supplied, a default-constructed
775/// // object of (template parameter) 'EQUAL' type is used. Optionally
776/// // specify an 'allocator' used to supply memory. If 'allocator' is not
777/// // supplied, a default-constructed object of the (template parameter)
778/// // 'ALLOCATOR' type is used. If 'ALLOCATOR' is 'bsl::allocator' (the
779/// // default), then 'allocator' shall be convertible to
780/// // 'bslma::Allocator *'. If the 'ALLOCATOR' is 'bsl::allocator' and
781/// // 'allocator' is not supplied, the currently installed default
782/// // allocator is used to supply memory.
783///
784/// //! ~MyHashedMultiMap() = default;
785/// // Destroy this object.
786///
787/// // MANIPULATORS
788/// template <class SOURCE_TYPE>
789/// iterator insert(const SOURCE_TYPE& value);
790/// // Insert the specified 'value' into this multi-map, and return an
791/// // iterator to the newly inserted element. Note that this method
792/// // requires that the (class template parameter) types 'KEY' and
793/// // 'VALUE' types both be "copy-constructible", and that the
794/// // (function template parameter) 'SOURCE_TYPE' be convertible to
795/// // the (class template parameter) 'VALUE' type.
796///
797/// // ACCESSORS
798/// bsl::pair<const_iterator, const_iterator> equal_range(const KEY& key)
799/// const;
800/// // Return a pair of iterators providing non-modifiable access to
801/// // the sequence of 'value_type' objects in this container matching
802/// // the specified 'key', where the first iterator is positioned at
803/// // the start of the sequence and the second iterator is positioned
804/// // one past the end of the sequence. If this container contains no
805/// // 'value_type' objects matching 'key', then the two returned
806/// // iterators will have the same value.
807/// };
808/// @endcode
809/// Then, we implement the methods `MyHashedMultiMap`. The construct need
810/// merely forward its arguments to the constructor of `d_impl`,
811/// @code
812/// // ======================
813/// // class MyHashedMultiMap
814/// // ======================
815///
816/// // CREATORS
817/// template <class KEY,
818/// class VALUE,
819/// class HASHF,
820/// class EQUAL,
821/// class ALLOCATOR>
822/// inline
823/// MyHashedMultiMap<KEY, VALUE, HASHF, EQUAL, ALLOCATOR>::MyHashedMultiMap(
824/// size_type initialNumBuckets,
825/// const HASHF& hash,
826/// const EQUAL& keyEqual,
827/// const ALLOCATOR& allocator)
828/// : d_impl(hash, keyEqual, initialNumBuckets, allocator)
829/// {
830/// }
831/// @endcode
832/// Note that here we forgo use of the `insertIfMissing` method and use the
833/// `insert` method of `bslstl::HashTable`. This method supports the semantics
834/// of the multi containers: there can be more than one element with the same
835/// key value.
836/// @code
837/// // MANIPULATORS
838/// template <class KEY,
839/// class VALUE,
840/// class HASHF,
841/// class EQUAL,
842/// class ALLOCATOR>
843/// template <class SOURCE_TYPE>
844/// inline
845/// typename MyHashedMultiMap<KEY, VALUE, HASHF, EQUAL, ALLOCATOR>::iterator
846/// MyHashedMultiMap<KEY, VALUE, HASHF, EQUAL, ALLOCATOR>::insert(
847/// const SOURCE_TYPE& value)
848/// {
849/// return iterator(d_impl.insert(value));
850/// }
851/// @endcode
852/// The @ref equal_range method need only convert the values returned by the
853/// `findRange` method to the types expected by the caller.
854/// @code
855/// // ACCESSORS
856/// template <class KEY,
857/// class VALUE,
858/// class HASHF,
859/// class EQUAL,
860/// class ALLOCATOR>
861/// bsl::pair<typename MyHashedMultiMap<KEY,
862/// VALUE,
863/// HASHF,
864/// EQUAL,
865/// ALLOCATOR>::const_iterator,
866/// typename MyHashedMultiMap<KEY,
867/// VALUE,
868/// HASHF,
869/// EQUAL, ALLOCATOR>::const_iterator>
870/// MyHashedMultiMap<KEY, VALUE, HASHF, EQUAL, ALLOCATOR>::equal_range(
871/// const KEY& key) const
872/// {
873/// typedef bsl::pair<const_iterator, const_iterator> ResultType;
874/// typedef BloombergLP::bslalg::BidirectionalLink HashTableLink;
875///
876/// HashTableLink *first;
877/// HashTableLink *last;
878/// d_impl.findRange(&first, &last, key);
879/// return ResultType(const_iterator(first), const_iterator(last));
880/// }
881/// @endcode
882/// Finally, we create `mhmm`, an instance of `MyHashedMultiMap`, exercise it,
883/// and confirm that it behaves as expected.
884///
885/// We define several aliases to make our code more concise.
886/// @code
887/// typedef MyHashedMultiMap<int, double>::iterator Iterator;
888/// typedef MyHashedMultiMap<int, double>::const_iterator ConstIterator;
889/// typedef bsl::pair<ConstIterator, ConstIterator> ConstRange;
890/// @endcode
891/// Searching for an element (key value 10) in a newly created, empty container
892/// correctly shows the absence of any such element.
893/// @code
894/// MyHashedMultiMap<int, double> mhmm;
895///
896/// ConstRange range;
897/// range = mhmm.equal_range(10);
898/// assert(range.first == range.second);
899/// @endcode
900/// We can insert a value (the pair 10, 100.00) into the container...
901/// @code
902/// bsl::pair<const int, double> value(10, 100.00);
903///
904/// Iterator itr;
905///
906/// itr = mhmm.insert(value);
907/// assert(value == *itr);
908/// @endcode
909/// ... and we can do so again.
910/// @code
911/// itr = mhmm.insert(value);
912/// assert(value == *itr);
913/// @endcode
914/// We can now find elements with the key value of 10.
915/// @code
916/// range = mhmm.equal_range(10);
917/// assert(range.first != range.second);
918/// @endcode
919/// As expected, there are two such elements, and both are identical in key
920/// value (10) and mapped value (100.00).
921/// @code
922/// int count = 0;
923/// for (ConstIterator cur = range.first,
924/// end = range.second;
925/// end != cur; ++cur, ++count) {
926/// assert(value == *cur);
927/// }
928/// assert(2 == count);
929/// @endcode
930/// }
931///
932/// ## Example 4: Implementing a Custom Container {#bslstl_hashtable-example-4-implementing-a-custom-container}
933///
934///
935/// Although the `bslstl::HashTable` class was created to be a common
936/// implementation for the standard unordered classes, this class can also be
937/// used in its own right to address other user problems.
938///
939/// Suppose that we wish to retain a record of sales orders, that each record is
940/// characterized by several integer attributes, and that we must be able to
941/// find records based on *any* of those attributes. We can use
942/// `bslstl::HashTable` to implement a custom container supporting multiple
943/// key-values.
944///
945/// First, we define `MySalesRecord`, our record class:
946/// @code
947/// enum { MAX_DESCRIPTION_SIZE = 16 };
948///
949/// typedef struct MySalesRecord {
950/// int orderNumber; // unique
951/// int customerId; // no constraint
952/// int vendorId; // no constraint
953/// char description[MAX_DESCRIPTION_SIZE]; // ASCII string
954/// } MySalesRecord;
955/// @endcode
956/// Notice that only each `orderNumber` is unique. We expect multiple sales to
957/// any given customer (`customerId`) and multiple sales by any given vendor
958/// (`vendorId`).
959///
960/// We will use a `bslstl::HashTable` object (a hashtable) to save record values
961/// based on the unique `orderNumber`, and two auxiliary hashtables to provide
962/// map `customerId` and `vendorId` values to the addresses of the records in
963/// the first `bslstl::HashTable` object. Note that this implementation relies
964/// on the fact that nodes in our hashtables remain stable until they are
965/// removed and that in this application we do *not* allow the removal (or
966/// modification) of records once they are inserted.
967///
968/// To configure these hashtables, we will need several policy objects to
969/// extract relevant portions the `MySalesRecord` objects for hashing.
970///
971/// Next, define `UseOrderNumberAsKey`, a policy class for the hashtable holding
972/// the sales record objects. Note that the `ValueType` is `MySalesRecord` and
973/// that the `extractKey` method selects the `orderNumber` attribute:
974/// @code
975/// // ==========================
976/// // struct UseOrderNumberAsKey
977/// // ==========================
978///
979/// struct UseOrderNumberAsKey {
980/// // This 'struct' provides a namespace for types and methods that define
981/// // the policy by which the key value of a hashed container (i.e., the
982/// // value passed to the hasher) is extracted from the objects stored in
983/// // the hashed container (the 'value' type).
984///
985/// typedef MySalesRecord ValueType;
986/// // Alias for 'MySalesRecord', the type stored in the first
987/// // hashtable.
988///
989/// typedef int KeyType;
990/// // Alias for the type passed to the hasher by the hashed container.
991/// // In this policy, the value passed to the hasher is the
992/// // 'orderNumber' attribute, an 'int' type.
993///
994/// static const KeyType& extractKey(const ValueType& value);
995/// // Return the key value for the specified 'value'. In this policy,
996/// // that is the 'orderNumber' attribute of 'value'.
997/// };
998///
999/// // --------------------------
1000/// // struct UseOrderNumberAsKey
1001/// // --------------------------
1002///
1003/// inline
1004/// const UseOrderNumberAsKey::KeyType&
1005/// UseOrderNumberAsKey::extractKey(const ValueType& value)
1006/// {
1007/// return value.orderNumber;
1008/// }
1009/// @endcode
1010/// Then, we define `UseCustomerIdAsKey`, the policy class for the hashtable
1011/// that will multiply map `customerId` to the addresses of records in the first
1012/// hashtable. Note that in this policy class the `ValueType` is
1013/// `const MySalesRecord *`.
1014/// @code
1015/// // =========================
1016/// // struct UseCustomerIdAsKey
1017/// // =========================
1018///
1019/// /// This `struct` provides a namespace for types and methods that define
1020/// /// the policy by which the key value of a hashed container (i.e., the
1021/// /// value passed to the hasher) is extracted from the objects stored in
1022/// /// the hashed container (the `value` type).
1023/// struct UseCustomerIdAsKey {
1024///
1025/// typedef const MySalesRecord *ValueType;
1026/// // Alias for 'const MySalesRecord *', the type stored in second
1027/// // hashtable, a pointer to the record stored in the first
1028/// // hashtable.
1029///
1030/// typedef int KeyType;
1031/// // Alias for the type passed to the hasher by the hashed container.
1032/// // In this policy, the value passed to the hasher is the
1033/// // 'orderNumber' attribute, an 'int' type.
1034///
1035/// static const KeyType& extractKey(const ValueType& value);
1036/// // Return the key value for the specified 'value'. In this policy,
1037/// // that is the 'customerId' attribute of 'value'.
1038/// };
1039///
1040/// // -------------------------
1041/// // struct UseCustomerIdAsKey
1042/// // -------------------------
1043///
1044/// inline
1045/// const UseCustomerIdAsKey::KeyType&
1046/// UseCustomerIdAsKey::extractKey(const ValueType& value)
1047/// {
1048/// return value->customerId;
1049/// }
1050/// @endcode
1051/// Notice that, since the values in the second hashtable are addresses, the
1052/// key-value is extracted by reference. This second hashtable allows what
1053/// map-like semantics, *without* having to store key-values; those reside in
1054/// the records in the first hashtable.
1055///
1056/// The `UseVendorIdAsKey` class, the policy class for the hashtable providing
1057/// an index by `vendorId`, is almost a near clone of `UseCustomerIdAsKey`. It
1058/// is shown for completeness:
1059/// @code
1060/// // =======================
1061/// // struct UseVendorIdAsKey
1062/// // ========================
1063///
1064/// /// This `struct` provides a namespace for types and methods that define
1065/// /// the policy by which the key value of a hashed container (i.e., the
1066/// /// value passed to the hasher) is extracted from the objects stored in
1067/// /// the hashed container (the `value` type).
1068/// struct UseVendorIdAsKey {
1069///
1070/// typedef const MySalesRecord *ValueType;
1071/// // Alias for 'const MySalesRecord *', the type stored in second
1072/// // hashtable, a pointer to the record stored in the first
1073/// // hashtable.
1074///
1075/// typedef int KeyType;
1076/// // Alias for the type passed to the hasher by the hashed container.
1077/// // In this policy, the value passed to the hasher is the
1078/// // 'vendorId' attribute, an 'int' type.
1079///
1080/// static const KeyType& extractKey(const ValueType& value);
1081/// // Return the key value for the specified 'value'. In this policy,
1082/// // that is the 'vendorId' attribute of 'value'.
1083/// };
1084///
1085/// // -----------------------
1086/// // struct UseVendorIdAsKey
1087/// // -----------------------
1088///
1089/// inline
1090/// const UseVendorIdAsKey::KeyType&
1091/// UseVendorIdAsKey::extractKey(const ValueType& value)
1092/// {
1093/// return value->vendorId;
1094/// }
1095/// @endcode
1096/// Next, we define `MySalesRecordContainer`, our customized container:
1097/// @code
1098/// // ----------------------------
1099/// // class MySalesRecordContainer
1100/// // ----------------------------
1101///
1102/// class MySalesRecordContainer
1103/// {
1104/// private:
1105/// // PRIVATE TYPES
1106/// typedef BloombergLP::bslstl::HashTable<
1107/// UseOrderNumberAsKey,
1108/// bsl::hash< UseOrderNumberAsKey::KeyType>,
1109/// bsl::equal_to<UseOrderNumberAsKey::KeyType> >
1110/// RecordsByOrderNumber;
1111/// typedef bsl::allocator_traits<
1112/// bsl::allocator<UseOrderNumberAsKey::ValueType> > AllocatorTraits;
1113/// typedef AllocatorTraits::difference_type difference_type;
1114/// @endcode
1115/// The `ItrByOrderNumber` type is used to provide access to the elements of the
1116/// first hash table, the one that stores the records.
1117/// @code
1118///
1119/// typedef BloombergLP::bslstl::HashTableIterator<const MySalesRecord,
1120/// difference_type>
1121/// ItrByOrderNumber;
1122/// @endcode
1123/// The `ItrPtrById` type is used to provide access to the elements of the other
1124/// hashtables, the ones that store pointers into the first hashtable.
1125/// @code
1126/// typedef BloombergLP::bslstl::HashTableIterator<const MySalesRecord *,
1127/// difference_type>
1128/// ItrPtrById;
1129/// @endcode
1130/// If we were to provide iterators of type `ItrPtrById` to our users,
1131/// dereferencing the iterator would provide a `MySalesRecord` pointer, which
1132/// would then have to be dereferences. Instead, we use `ItrPtrById` to define
1133/// `ItrById` in which accessors have been overridden to provide that extra
1134/// dereference implicitly.
1135/// @code
1136/// class ItrById : public ItrPtrById
1137/// {
1138/// public:
1139/// // CREATORS
1140/// explicit ItrById(bslalg::BidirectionalLink *node)
1141/// : ItrPtrById(node)
1142/// {
1143/// }
1144///
1145/// // ACCESSORS
1146/// const MySalesRecord& operator*() const
1147/// {
1148/// return *ItrPtrById::operator*();
1149/// }
1150///
1151/// const MySalesRecord *operator->() const
1152/// {
1153/// return &(*ItrPtrById::operator*());
1154/// }
1155/// };
1156///
1157/// typedef BloombergLP::bslstl::HashTable<
1158/// UseCustomerIdAsKey,
1159/// bsl::hash< UseCustomerIdAsKey::KeyType>,
1160/// bsl::equal_to<UseCustomerIdAsKey::KeyType> >
1161/// RecordsPtrsByCustomerId;
1162/// typedef BloombergLP::bslstl::HashTable<
1163/// UseVendorIdAsKey,
1164/// bsl::hash< UseVendorIdAsKey::KeyType>,
1165/// bsl::equal_to<UseVendorIdAsKey::KeyType> >
1166/// RecordsPtrsByVendorId;
1167/// // DATA
1168/// RecordsByOrderNumber d_recordsByOrderNumber;
1169/// RecordsPtrsByCustomerId d_recordptrsByCustomerId;
1170/// RecordsPtrsByVendorId d_recordptrsByVendorId;
1171///
1172/// public:
1173/// // PUBLIC TYPES
1174/// typedef ItrByOrderNumber ConstItrByOrderNumber;
1175/// typedef ItrById ConstItrById;
1176///
1177/// // CREATORS
1178/// explicit MySalesRecordContainer(bslma::Allocator *basicAllocator = 0);
1179/// // Create an empty 'MySalesRecordContainer' object. If
1180/// // 'basicAllocator' is 0, the currently installed default allocator
1181/// // is used.
1182///
1183/// //! ~MySalesRecordContainer() = default;
1184/// // Destroy this object.
1185///
1186/// // MANIPULATORS
1187/// bsl::pair<ConstItrByOrderNumber, bool> insert(
1188/// const MySalesRecord& value);
1189/// // Insert the specified 'value' into this set if the 'value' does
1190/// // not already exist in this set; otherwise, this method has no
1191/// // effect. Return a pair whose 'first' member is an iterator
1192/// // providing non-modifiable access to the (possibly newly inserted)
1193/// // 'MySalesRecord' object having 'value' and whose 'second' member
1194/// // is 'true' if a new element was inserted, and 'false' if 'value'
1195/// // was already present.
1196///
1197/// // ACCESSORS
1198/// ConstItrByOrderNumber cend() const;
1199/// // Return an iterator providing non-modifiable access to the
1200/// // past-the-end element (in the sequence of 'MySalesRecord'
1201/// // objects) maintained by this set.
1202///
1203/// ConstItrByOrderNumber findByOrderNumber(int value) const;
1204/// // Return an iterator providing non-modifiable access to the
1205/// // 'MySalesRecord' object in this set having the specified 'value',
1206/// // if such an entry exists, and the iterator returned by the 'cend'
1207/// // method otherwise.
1208/// @endcode
1209/// Notice that this interface provides map-like semantics for finding records.
1210/// We need only specify the `orderNumber` attribute of the record of interest;
1211/// however, the return value is set-like: we get access to the record, not the
1212/// more complicated key-value/record pair that a map would have provided.
1213///
1214/// Internally, the hash table need only store the records themselves. A map
1215/// would have had to manage key-value/record pairs, where the key-value would
1216/// be a copy of part of the record.
1217/// @code
1218/// bsl::pair<ConstItrById, ConstItrById> findByCustomerId(int value)
1219/// const;
1220/// // Return a pair of iterators providing non-modifiable access to
1221/// // the sequence of 'MySalesRecord' objects in this container having
1222/// // a 'customerId' attribute equal to the specified 'value' where
1223/// // the first iterator is positioned at the start of the sequence
1224/// // and the second iterator is positioned one past the end of the
1225/// // sequence. If this container has no such objects, then the two
1226/// // iterators will be equal.
1227///
1228/// bsl::pair<ConstItrById, ConstItrById> findByVendorId(int value) const;
1229/// // Return a pair of iterators providing non-modifiable access to
1230/// // the sequence of 'MySalesRecord' objects in this container having
1231/// // a 'vendorId' attribute equal to the specified 'value' where the
1232/// // first iterator is positioned at the start of the sequence and
1233/// // the second iterator is positioned one past the end of the
1234/// // sequence. If this container has no such objects, then the two
1235/// // iterators will be equal.
1236/// };
1237/// @endcode
1238/// Then, we implement the methods of `MySalesRecordContainer`, our customized
1239/// container:
1240/// @code
1241/// // ----------------------------
1242/// // class MySalesRecordContainer
1243/// // ----------------------------
1244///
1245/// // CREATORS
1246/// inline
1247/// MySalesRecordContainer::MySalesRecordContainer(
1248/// bslma::Allocator *basicAllocator)
1249/// : d_recordsByOrderNumber(basicAllocator)
1250/// , d_recordptrsByCustomerId(basicAllocator)
1251/// , d_recordptrsByVendorId(basicAllocator)
1252/// {
1253/// }
1254///
1255/// // MANIPULATORS
1256/// inline
1257/// bsl::pair<MySalesRecordContainer::ConstItrByOrderNumber, bool>
1258/// MySalesRecordContainer::insert(const MySalesRecord& value)
1259/// {
1260/// // Insert into internal container that will own the record.
1261///
1262/// bool isInsertedFlag = false;
1263/// BloombergLP::bslalg::BidirectionalLink *result =
1264/// d_recordsByOrderNumber.insertIfMissing(&isInsertedFlag, value);
1265///
1266/// // Index by other record attributes
1267///
1268/// RecordsByOrderNumber::NodeType *nodePtr =
1269/// static_cast<RecordsByOrderNumber::NodeType *>(result);
1270///
1271/// d_recordptrsByCustomerId.insert(&nodePtr->value());
1272/// d_recordptrsByVendorId.insert(&nodePtr->value());
1273///
1274/// // Return of insertion.
1275///
1276/// return bsl::pair<ConstItrByOrderNumber, bool>(
1277/// ConstItrByOrderNumber(result),
1278/// isInsertedFlag);
1279/// }
1280///
1281/// // ACCESSORS
1282/// inline
1283/// MySalesRecordContainer::ConstItrByOrderNumber
1284/// MySalesRecordContainer::cend() const
1285/// {
1286/// return ConstItrByOrderNumber();
1287/// }
1288///
1289/// inline
1290/// MySalesRecordContainer::ConstItrByOrderNumber
1291/// MySalesRecordContainer::findByOrderNumber(int value) const
1292/// {
1293/// return ConstItrByOrderNumber(d_recordsByOrderNumber.find(value));
1294/// }
1295///
1296/// inline
1297/// bsl::pair<MySalesRecordContainer::ConstItrById,
1298/// MySalesRecordContainer::ConstItrById>
1299/// MySalesRecordContainer::findByCustomerId(int value) const
1300/// {
1301/// typedef BloombergLP::bslalg::BidirectionalLink HashTableLink;
1302///
1303/// HashTableLink *first;
1304/// HashTableLink *last;
1305/// d_recordptrsByCustomerId.findRange(&first, &last, value);
1306///
1307/// return bsl::pair<ConstItrById, ConstItrById>(ConstItrById(first),
1308/// ConstItrById(last));
1309/// }
1310///
1311/// inline
1312/// bsl::pair<MySalesRecordContainer::ConstItrById,
1313/// MySalesRecordContainer::ConstItrById>
1314/// MySalesRecordContainer::findByVendorId(int value) const
1315/// {
1316/// typedef BloombergLP::bslalg::BidirectionalLink HashTableLink;
1317///
1318/// HashTableLink *first;
1319/// HashTableLink *last;
1320/// d_recordptrsByVendorId.findRange(&first, &last, value);
1321///
1322/// return bsl::pair<ConstItrById, ConstItrById>(ConstItrById(first),
1323/// ConstItrById(last));
1324/// }
1325/// @endcode
1326/// Now, create an empty container and load it with some sample data.
1327/// @code
1328/// MySalesRecordContainer msrc;
1329///
1330/// const MySalesRecord DATA[] = {
1331/// { 1000, 100, 10, "hello" },
1332/// { 1001, 100, 20, "world" },
1333/// { 1002, 200, 10, "how" },
1334/// { 1003, 200, 20, "are" },
1335/// { 1004, 100, 10, "you" },
1336/// { 1005, 100, 20, "today" }
1337/// };
1338/// const int numDATA = sizeof DATA / sizeof *DATA;
1339///
1340/// printf("Insert sales records into container.\n");
1341///
1342/// for (int i = 0; i < numDATA; ++i) {
1343/// const int orderNumber = DATA[i].orderNumber;
1344/// const int customerId = DATA[i].customerId;
1345/// const int vendorId = DATA[i].vendorId;
1346/// const char *description = DATA[i].description;
1347///
1348/// printf("%d: %d %d %s\n",
1349/// orderNumber, customerId, vendorId, description);
1350///
1351/// typedef MySalesRecordContainer::ConstItrByOrderNumber MyConstItr;
1352/// typedef bsl::pair<MyConstItr, bool> InsertResult;
1353///
1354/// const InsertResult status = msrc.insert(DATA[i]);
1355/// assert(msrc.cend() != status.first);
1356/// assert(true == status.second);
1357/// }
1358/// @endcode
1359/// We find on standard output:
1360/// @code
1361/// Insert sales records into container.
1362/// 1000: 100 10 hello
1363/// 1001: 100 20 world
1364/// 1002: 200 10 how
1365/// 1003: 200 20 are
1366/// 1004: 100 10 you
1367/// 1005: 100 20 today
1368/// @endcode
1369/// We can search our container by order number and find the expected records.
1370/// @code
1371/// printf("Find sales records by order number.\n");
1372/// for (int i = 0; i < numDATA; ++i) {
1373/// const int orderNumber = DATA[i].orderNumber;
1374/// const int customerId = DATA[i].customerId;
1375/// const int vendorId = DATA[i].vendorId;
1376/// const char *description = DATA[i].description;
1377///
1378/// printf("%d: %d %d %s\n",
1379/// orderNumber, customerId, vendorId, description);
1380///
1381/// MySalesRecordContainer::ConstItrByOrderNumber itr =
1382/// msrc.findByOrderNumber(orderNumber);
1383/// assert(msrc.cend() != itr);
1384/// assert(orderNumber == itr->orderNumber);
1385/// assert(customerId == itr->customerId);
1386/// assert(vendorId == itr->vendorId);
1387/// assert(0 == strcmp(description, itr->description));
1388/// }
1389/// @endcode
1390/// We find on standard output:
1391/// @code
1392/// Find sales records by order number.
1393/// 1000: 100 10 hello
1394/// 1001: 100 20 world
1395/// 1002: 200 10 how
1396/// 1003: 200 20 are
1397/// 1004: 100 10 you
1398/// 1005: 100 20 today
1399/// @endcode
1400/// We can search our container by customer identifier and find the expected
1401/// records.
1402/// @code
1403/// printf("Find sales records by customer identifier.\n");
1404///
1405/// typedef MySalesRecordContainer::ConstItrById MyConstItrById;
1406///
1407/// for (int customerId = 100; customerId <= 200; customerId += 100) {
1408/// bsl::pair<MyConstItrById, MyConstItrById> result =
1409/// msrc.findByCustomerId(customerId);
1410/// typedef bsl::iterator_traits<
1411/// MyConstItrById>::difference_type CountType;
1412/// const CountType count = bsl::distance(result.first, result.second);
1413/// printf("customerId %d, count %d\n", customerId, count);
1414///
1415/// for (MySalesRecordContainer::ConstItrById itr = result.first,
1416/// end = result.second;
1417/// end != itr; ++itr) {
1418/// printf("\t\t%d %d %d %s\n",
1419/// itr->orderNumber,
1420/// itr->customerId,
1421/// itr->vendorId,
1422/// itr->description);
1423/// }
1424/// }
1425/// @endcode
1426/// We find on standard output:
1427/// @code
1428/// Find sales records by customer identifier.
1429/// customerId 100, count 4
1430/// 1005 100 20 today
1431/// 1004 100 10 you
1432/// 1001 100 20 world
1433/// 1000 100 10 hello
1434/// customerId 200, count 2
1435/// 1003 200 20 are
1436/// 1002 200 10 how
1437/// @endcode
1438/// Lastly, we can search our container by vendor identifier and find the
1439/// expected records.
1440/// @code
1441/// printf("Find sales records by vendor identifier.\n");
1442///
1443/// typedef MySalesRecordContainer::ConstItrById MyConstItrById;
1444///
1445/// for (int vendorId = 10; vendorId <= 20; vendorId += 10) {
1446/// bsl::pair<MyConstItrById, MyConstItrById> result =
1447/// msrc.findByVendorId(vendorId);
1448/// typedef bsl::iterator_traits<
1449/// MyConstItrById>::difference_type CountType;
1450/// const CountType count = bsl::distance(result.first, result.second);
1451///
1452/// printf("vendorId %d, count %d\n", vendorId, count);
1453///
1454/// for (MySalesRecordContainer::ConstItrById itr = result.first,
1455/// end = result.second;
1456/// end != itr; ++itr) {
1457/// printf("\t\t%d %d %d %s\n",
1458/// (*itr).orderNumber,
1459/// (*itr).customerId,
1460/// (*itr).vendorId,
1461/// (*itr).description);
1462/// }
1463/// }
1464/// @endcode
1465/// We find on standard output:
1466/// @code
1467/// Find sales records by vendor identifier.
1468/// vendorId 10, count 3
1469/// 1004 100 10 you
1470/// 1002 200 10 how
1471/// 1000 100 10 hello
1472/// vendorId 20, count 3
1473/// 1005 100 20 today
1474/// 1003 200 20 are
1475/// 1001 100 20 world
1476/// @endcode
1477/// @}
1478/** @} */
1479/** @} */
1480
1481/** @addtogroup bsl
1482 * @{
1483 */
1484/** @addtogroup bslstl
1485 * @{
1486 */
1487/** @addtogroup bslstl_hashtable
1488 * @{
1489 */
1490
1491#include <bslscm_version.h>
1492
1494
1497#include <bslalg_functoradapter.h>
1498#include <bslalg_hashtableanchor.h>
1499#include <bslalg_hashtablebucket.h>
1501
1502#include <bslma_allocatortraits.h>
1503#include <bslma_allocatorutil.h>
1504#include <bslma_destructorguard.h>
1505#include <bslma_bslallocator.h>
1507
1509#include <bslmf_assert.h>
1510#include <bslmf_conditional.h>
1511#include <bslmf_enableif.h>
1513#include <bslmf_isfunction.h>
1514#include <bslmf_ispointer.h>
1516#include <bslmf_movableref.h>
1517#include <bslmf_util.h> // 'forward(V)'
1518
1519#include <bsls_assert.h>
1520#include <bsls_bslexceptionutil.h>
1521#include <bsls_compilerfeatures.h>
1522#include <bsls_objectbuffer.h>
1523#include <bsls_performancehint.h>
1524#include <bsls_platform.h>
1525#include <bsls_util.h> // 'forward<T>(V)'
1526
1527#include <algorithm> // for fill_n, max, swap (C++03)
1528#include <cstddef> // for 'size_t'
1529#include <cstring> // for 'memset'
1530#include <limits> // for numeric_limits
1531#if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR)
1532#include <tuple> // for forward_as_tuple (C++11)
1533#endif
1534#include <utility> // for swap (C++17)
1535
1536#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
1537#include <bsls_nativestd.h>
1538#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
1539
1540#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1541// Include version that can be compiled with C++03
1542// Generated on Thu Oct 21 10:11:37 2021
1543// Command line: sim_cpp11_features.pl bslstl_hashtable.h
1544# define COMPILING_BSLSTL_HASHTABLE_H
1545# include <bslstl_hashtable_cpp03.h>
1546# undef COMPILING_BSLSTL_HASHTABLE_H
1547#else
1548
1549
1550
1551namespace bslstl {
1552
1553template <class KEY_CONFIG,
1554 class HASHER,
1555 class COMPARATOR,
1557class HashTable;
1558
1559template <class FACTORY>
1560class HashTable_ArrayProctor;
1561
1562template <class FACTORY>
1563class HashTable_NodeProctor;
1564
1565template <class FUNCTOR>
1566class HashTable_ComparatorWrapper;
1567
1568template <class FUNCTOR>
1569class HashTable_ComparatorWrapper<const FUNCTOR>;
1570
1571template <class FUNCTOR>
1572class HashTable_ComparatorWrapper<FUNCTOR &>;
1573
1574template <class FUNCTOR>
1575class HashTable_HashWrapper;
1576
1577template <class FUNCTOR>
1578class HashTable_HashWrapper<const FUNCTOR>;
1579
1580template <class FUNCTOR>
1581class HashTable_HashWrapper<FUNCTOR &>;
1582
1583struct HashTable_ImpDetails;
1584struct HashTable_Util;
1585
1586 // ======================
1587 // class CallableVariable
1588 // ======================
1589
1590/// This metafunction returns a `type` that is an alias for `CALLABLE`
1591/// unless that is a function type, in which case it is an alias for
1592/// `CALLABLE &`. This should be used to declare variables of an arbitrary
1593/// callable type, typically a template type parameter, that may turn out to
1594/// be a function type. Note that this metafunction is necessary as the C++
1595/// language does not allow variables of function type, nor may functions
1596/// return a function type.
1597template <class CALLABLE>
1599
1600 // TYPES
1601 typedef typename bsl::conditional<
1604 CALLABLE>::type type;
1605};
1606
1607 // ===========================
1608 // class HashTable_HashWrapper
1609 // ===========================
1610
1611/// This class provides a wrapper around a functor satisfying the `Hash`
1612/// requirements (@ref bslstl_hash ) such that the function call operator is
1613/// always declared as `const` qualified.
1614///
1615/// TBD Provide an optimization for the case of an empty base functor, where
1616/// we can safely const_cast want calling the base class operator.
1617///
1618/// Note that we would only one class, not two, with C++11 variadic
1619/// templates and perfect forwarding, and we could also easily detect
1620/// whether or not `FUNCTOR` provided a const-qualified `operator()`.
1621///
1622/// See @ref bslstl_hashtable
1623template <class FUNCTOR>
1625
1626 private:
1627 mutable FUNCTOR d_functor;
1628
1629 public:
1630 // CREATORS
1631
1632 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that
1633 /// has its default value.
1635
1636 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that is
1637 /// a copy of the specified `fn`.
1638 explicit HashTable_HashWrapper(const FUNCTOR& fn);
1639
1640 // MANIPULATORS
1641
1642 /// Exchange the value of this object with the specified `other` object.
1643 void swap(HashTable_HashWrapper &other);
1644
1645 // ACCESSORS
1646
1647 /// Call the wrapped `functor` with the specified `arg` and return the
1648 /// result. Note that `ARG_TYPE` will typically be deduced as a `const`
1649 /// type.
1650 template <class ARG_TYPE>
1651 std::size_t operator()(ARG_TYPE& arg) const;
1652
1653 /// Return a reference providing non-modifiable access to the hash
1654 /// functor wrapped by this object.
1655 const FUNCTOR& functor() const;
1656};
1657
1658/// This partial specialization handles `const` qualified functors, that may
1659/// not be stored as a `mutable` member in the primary template. The need
1660/// to wrap such functors diminishes greatly, as there is no need to play
1661/// mutable tricks to invoke the function call operator. An alternative to
1662/// providing this specialization would be to skip the wrapper entirely if
1663/// using a `const` qualified functor in a `HashTable`. Note that this type
1664/// has a `const` qualified data member, so is neither assignable nor
1665/// swappable.
1666template <class FUNCTOR>
1667class HashTable_HashWrapper<const FUNCTOR> {
1668
1669 private:
1670 const FUNCTOR d_functor;
1671
1672 public:
1673 // CREATORS
1674
1675 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that
1676 /// has its default value.
1678
1679 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that is
1680 /// a copy of the specified `fn`.
1681 explicit HashTable_HashWrapper(const FUNCTOR& fn);
1682
1683 // ACCESSORS
1684
1685 /// Call the wrapped `functor` with the specified `arg` and return the
1686 /// result. Note that `ARG_TYPE` will typically be deduced as a `const`
1687 /// type.
1688 template <class ARG_TYPE>
1689 std::size_t operator()(ARG_TYPE& arg) const;
1690
1691 /// Return a reference providing non-modifiable access to the hash
1692 /// functor wrapped by this object.
1693 const FUNCTOR& functor() const;
1694};
1695
1696/// This partial specialization handles `const` qualified functors, that may
1697/// not be stored as a `mutable` member in the primary template. Note that
1698/// the `FUNCTOR` type itself may be `const`-qualified, so this one partial
1699/// template specialization also handles `const FUNCTOR&` references. In
1700/// order to correctly parse with the reference-binding rules, we drop the
1701/// `const` in front of many of the references to `FUNCTOR` seen in the
1702/// primary template definition. Note that this type has a reference data
1703/// member, so is not default constructible, assignable or swappable.
1704template <class FUNCTOR>
1705class HashTable_HashWrapper<FUNCTOR &> {
1706
1707 private:
1708 FUNCTOR& d_functor;
1709
1710 public:
1711 // CREATORS
1712
1713 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that is
1714 /// a copy of the specified `fn`.
1715 explicit HashTable_HashWrapper(FUNCTOR& fn);
1716
1717 // ACCESSORS
1718
1719 /// Call the wrapped `functor` with the specified `arg` and return the
1720 /// result. Note that `ARG_TYPE` will typically be deduced as a `const`
1721 /// type.
1722 template <class ARG_TYPE>
1723 std::size_t operator()(ARG_TYPE& arg) const;
1724
1725 /// Return a reference providing non-modifiable access to the hash
1726 /// functor wrapped by this object.
1727 FUNCTOR& functor() const;
1728};
1729
1730/// Swap the functor wrapped by the specified `a` object with the functor
1731/// wrapped by the specified `b` object.
1732template <class FUNCTOR>
1735
1736 // =================================
1737 // class HashTable_ComparatorWrapper
1738 // =================================
1739
1740/// This class provides a wrapper around a functor that can compare two
1741/// values and return a `bool`, so that the function call operator is always
1742/// declared as `const` qualified.
1743///
1744/// TBD Provide an optimization for the case of an empty base functor, where
1745/// we can safely const_cast want calling the base class operator.
1746///
1747/// See @ref bslstl_hashtable
1748template <class FUNCTOR>
1750
1751 private:
1752 mutable FUNCTOR d_functor;
1753
1754 public:
1755 // CREATORS
1756
1757 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1758 /// that has its default value.
1760
1761 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1762 /// that is a copy of the specified `fn`.
1763 explicit HashTable_ComparatorWrapper(const FUNCTOR& fn);
1764
1765 // MANIPULATORS
1766
1767 /// Exchange the value of this object with the specified `other` object.
1768 void swap(HashTable_ComparatorWrapper &other);
1769
1770 // ACCESSORS
1771
1772 /// Call the wrapped `functor` with the specified `arg1` and `arg2` (in
1773 /// that order) and return the result. Note that `ARGn_TYPE` will
1774 /// typically be deduced as a `const` type.
1775 template <class ARG1_TYPE, class ARG2_TYPE>
1776 bool operator()(ARG1_TYPE& arg1, ARG2_TYPE& arg2) const;
1777
1778 /// Return a reference providing non-modifiable access to the hash
1779 /// functor wrapped by this object.
1780 const FUNCTOR& functor() const;
1781};
1782
1783/// This partial specialization handles `const` qualified functors, that may
1784/// not be stored as a `mutable` member in the primary template. The need
1785/// to wrap such functors diminishes greatly, as there is no need to play
1786/// mutable tricks to invoke the function call operator. An alternative to
1787/// providing this specialization would be to skip the wrapper entirely if
1788/// using a `const` qualified functor in a `HashTable`. Note that this type
1789/// has a `const` qualified data member, so is neither assignable nor
1790/// swappable.
1791template <class FUNCTOR>
1792class HashTable_ComparatorWrapper<const FUNCTOR> {
1793
1794 private:
1795 const FUNCTOR d_functor;
1796
1797 public:
1798 // CREATORS
1799
1800 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1801 /// that has its default value.
1803
1804 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1805 /// that is a copy of the specified `fn`.
1806 explicit HashTable_ComparatorWrapper(const FUNCTOR& fn);
1807
1808 // ACCESSORS
1809
1810 /// Call the wrapped `functor` with the specified `arg1` and `arg2` (in
1811 /// that order) and return the result. Note that `ARGn_TYPE` will
1812 /// typically be deduced as a `const` type.
1813 template <class ARG1_TYPE, class ARG2_TYPE>
1814 bool operator()(ARG1_TYPE& arg1, ARG2_TYPE& arg2) const;
1815
1816 /// Return a reference providing non-modifiable access to the hash
1817 /// functor wrapped by this object.
1818 const FUNCTOR& functor() const;
1819};
1820
1821/// This partial specialization handles `const` qualified functors, that may
1822/// not be stored as a `mutable` member in the primary template. Note that
1823/// the `FUNCTOR` type itself may be `const`-qualified, so this one partial
1824/// template specialization also handles `const FUNCTOR&` references. In
1825/// order to correctly parse with the reference-binding rules, we drop the
1826/// `const` in front of many of the references to `FUNCTOR` seen in the
1827/// primary template definition. Note that this type has a reference data
1828/// member, so is not default constructible, assignable or swappable.
1829template <class FUNCTOR>
1831
1832 private:
1833 FUNCTOR& d_functor;
1834
1835 public:
1836 // CREATORS
1837
1838 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1839 /// that is a copy of the specified `fn`.
1840 explicit HashTable_ComparatorWrapper(FUNCTOR& fn);
1841
1842 // ACCESSORS
1843
1844 /// Call the wrapped `functor` with the specified `arg1` and `arg2` (in
1845 /// that order) and return the result. Note that `ARGn_TYPE` will
1846 /// typically be deduced as a `const` type.
1847 template <class ARG1_TYPE, class ARG2_TYPE>
1848 bool operator()(ARG1_TYPE& arg1, ARG2_TYPE& arg2) const;
1849
1850 /// Return a reference providing non-modifiable access to the hash
1851 /// functor wrapped by this object.
1852 FUNCTOR& functor() const;
1853};
1854
1855/// Swap the functor wrapped by the specified `lhs` object with the functor
1856/// wrapped by the specified `rhs` object.
1857template <class FUNCTOR>
1860
1861 // ===============
1862 // class HashTable
1863 // ===============
1864
1865template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
1867
1868/// This class template implements a value-semantic container type holding
1869/// an unordered sequence of (possibly duplicate) elements, that can be
1870/// rapidly accessed using their key, with the constraint on the container
1871/// that elements whose keys compare equal according to the specified
1872/// `COMPARATOR` will be stored in a stable, contiguous sequence within the
1873/// container. The value type and key type of the elements maintained by a
1874/// `HashTable` are determined by aliases provided through the (template
1875/// parameter) type `KEY_CONFIG`. Elements in a `HashTable` are stored in
1876/// "nodes" that are allocated using an allocator of the specified
1877/// `ALLOCATOR` type (rebound to the node type), and elements are
1878/// constructed directly in the node using the allocator as described in the
1879/// C++11 standard under the allocator-aware container requirements in
1880/// ([container.requirements.general], C++11 23.2.1). The (template
1881/// parameter) types `HASHER` and `COMPARATOR` shall be `copy-constructible`
1882/// function-objects. `HASHER` shall support a function call operator
1883/// compatible with the following statements:
1884/// @code
1885/// HASHER hash;
1886/// KEY_CONFIG::KeyType key;
1887/// std::size_t result = hash(key);
1888/// @endcode
1889/// where the definition of the called function meets the requirements of a
1890/// hash function, as specified in @ref bslstl_hash . `COMPARATOR` shall
1891/// support the a function call operator compatible with the following
1892/// statements:
1893/// @code
1894/// COMPARATOR compare;
1895/// KEY_CONFIG::KeyType key1, key2;
1896/// bool result = compare(key1, key2);
1897/// @endcode
1898/// where the definition of the called function defines an equivalence
1899/// relationship on keys that is both reflexive and transitive. The
1900/// `HASHER` and `COMPARATOR` attributes of this class are further
1901/// constrained, such for any two objects whose keys compare equal by the
1902/// comparator, shall produce the same value from the hasher.
1903///
1904/// This class:
1905/// * supports a complete set of *value-semantic* operations
1906/// - except for `bdex` serialization
1907/// * is *exception-neutral* (agnostic except for the `at` method)
1908/// * is *alias-safe*
1909/// * is `const` *thread-safe*
1910/// For terminology see @ref bsldoc_glossary .
1911///
1912/// See @ref bslstl_hashtable
1913template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
1915
1916 public:
1917 // TYPES
1918 typedef ALLOCATOR AllocatorType;
1919 typedef ::bsl::allocator_traits<AllocatorType> AllocatorTraits;
1920 typedef typename KEY_CONFIG::KeyType KeyType;
1921 typedef typename KEY_CONFIG::ValueType ValueType;
1925
1926 private:
1927 // PRIVATE TYPES
1928 typedef
1931
1932 /// This typedef is a convenient alias for the utility associated with
1933 /// movable references.
1935
1936 // CONSISTENCY CHECKS
1937
1938 // Assert consistency checks against Machiavellian users, specializing an
1939 // allocator for a specific type to have different propagation traits to
1940 // the primary template.
1941
1942 typedef typename AllocatorTraits::template rebind_traits<NodeType>
1943 ReboundTraits;
1944
1946 ReboundTraits::propagate_on_container_copy_assignment::value ==
1947 AllocatorTraits::propagate_on_container_copy_assignment::value);
1948
1950 ReboundTraits::propagate_on_container_move_assignment::value ==
1951 AllocatorTraits::propagate_on_container_move_assignment::value);
1952
1953 BSLMF_ASSERT(ReboundTraits::propagate_on_container_swap::value ==
1954 AllocatorTraits::propagate_on_container_swap::value);
1955
1956 private:
1957 // DATA
1958 ImplParameters d_parameters; // policies governing table behavior
1960 d_anchor; // list root and bucket array
1961 SizeType d_size; // number of elements in this table
1962 SizeType d_capacity; // max number of elements before a
1963 // rehash is required (computed from
1964 // 'd_maxLoadFactor')
1965 float d_maxLoadFactor; // maximum permitted load factor
1966
1967 private:
1968 // PRIVATE MANIPULATORS
1969
1970 /// Copy the sequence of elements from the list starting at the
1971 /// specified `cursor` and having `size` elements. Allocate a bucket
1972 /// array sufficiently large to store `size` elements while respecting
1973 /// the `maxLoadFactor`, and index the copied list into that new array
1974 /// of hash buckets. This hash table then takes ownership of the list
1975 /// and bucket array. Note that this method is intended to be called
1976 /// from copy constructors, which will have assigned some initial values
1977 /// for the `size` and other attributes that may not be consistent with
1978 /// the class invariants until after this method is called.
1979 void copyDataStructure(bslalg::BidirectionalLink *cursor);
1980
1981 /// Recreate the sequence of elements from the list starting at the
1982 /// specified `cursor` and having (member) `d_size` elements, ensuring
1983 /// that each `ValueType` object in the source list is move-inserted
1984 /// into the new sequence. Allocate a bucket array sufficiently large
1985 /// to store `d_size` elements, while respecting the `maxLoadFactor`,
1986 /// and index the new list into that new array of hash buckets. This
1987 /// hash table then takes ownership of the list and bucket array. Note
1988 /// that this method is intended to be called from move constructors
1989 /// (where the source and target allocators do not match), which will
1990 /// have assigned some initial values for the `size` and other
1991 /// attributes that may not be consistent with the class invariants
1992 /// until after this method completes. If an exception is thrown during
1993 /// this operation, this object is left in a valid but unspecified
1994 /// state; it is the caller's responsibility, however, to ensure the
1995 /// source hash-table is in a valid state if an exception is thrown
1996 void moveDataStructure(bslalg::BidirectionalLink *cursor);
1997
1998 /// Efficiently exchange the value, functors, and allocator of this
1999 /// object with those of the specified `other` object. This method
2000 /// provides the no-throw exception-safety guarantee.
2001 void quickSwapExchangeAllocators(HashTable *other);
2002
2003 /// Efficiently exchange the value and functors this object with those
2004 /// of the specified `other` object. This method provides the no-throw
2005 /// exception-safety guarantee. The behavior is undefined unless this
2006 /// object was created with the same allocator as `other`.
2007 void quickSwapRetainAllocators(HashTable *other);
2008
2009 /// Re-organize this hash-table to have exactly the specified
2010 /// `newNumBuckets`, which will then be able to store the specified
2011 /// `capacity` number of elements without exceeding the `maxLoadFactor`.
2012 /// This operation provides the strong exception guarantee (see
2013 /// @ref bsldoc_glossary ) unless the `hasher` throws, in which case this
2014 /// operation provides the basic exception guarantee, leaving the
2015 /// hash-table in a valid, but otherwise unspecified (and potentially
2016 /// empty), state. The behavior is undefined unless
2017 /// `size / newNumBuckets <= maxLoadFactor`. Note that the caller is
2018 /// responsible for correctly computing the `capacity` supported by the
2019 /// new number of buckets. This allows for a minor optimization where
2020 /// the value is computed only once per rehash.
2021 void rehashIntoExactlyNumBuckets(SizeType newNumBuckets,
2022 SizeType capacity);
2023
2024 /// Erase all the nodes in this hash-table, and deallocate their memory
2025 /// via the supplied node-factory. Destroy the array of buckets owned
2026 /// by this hash-table. If `d_anchor.bucketAddress()` is the default
2027 /// bucket address (`HashTable_ImpDetails::defaultBucketAddress`), then
2028 /// this hash-table does not own its array of buckets, and it will not
2029 /// be destroyed.
2030 void removeAllAndDeallocate();
2031
2032 /// Erase all the nodes in this table and deallocate their memory via
2033 /// the node factory, without performing the necessary bookkeeping to
2034 /// reflect such change. Note that this (private) method explicitly
2035 /// leaves the HashTable in an inconsistent state, and is expected to be
2036 /// useful when the anchor of this hash table is about to be overwritten
2037 /// with a new value, or when the hash table is going out of scope and
2038 /// the extra bookkeeping is not necessary.
2039 void removeAllImp();
2040
2041 // PRIVATE ACCESSORS
2042
2043 /// Return the address of the first node in this hash table having a key
2044 /// that compares equal (according to this hash-table's `comparator`) to
2045 /// the specified `key`. The behavior is undefined unless the specified
2046 /// `hashValue` is the hash code for the `key` according to the `hasher`
2047 /// functor of this hash table. Note that this function's
2048 /// implementation relies on the supplied `hashValue` rather than
2049 /// recomputing it, eliminating some redundant computation for the
2050 /// public methods.
2051 template <class DEDUCED_KEY>
2052 bslalg::BidirectionalLink *find(DEDUCED_KEY& key,
2053 std::size_t hashValue) const;
2054
2055 /// Return the address of the bucket at the specified `bucketIndex` in
2056 /// bucket array of this hash table. The behavior is undefined unless
2057 /// `bucketIndex < this->numBuckets()`.
2058 bslalg::HashTableBucket *getBucketAddress(SizeType bucketIndex) const;
2059
2060 /// Return the hash code for the element stored in the specified `node`
2061 /// using a copy of the hash functor supplied at construction. The
2062 /// behavior is undefined unless `node` points to a list-node of type
2063 /// `bslalg::BidirectionalNode<KEY_CONFIG::ValueType>`.
2064 std::size_t hashCodeForNode(bslalg::BidirectionalLink *node) const;
2065
2066 public:
2067 // CREATORS
2068
2069 /// Create an empty hash-table. Optionally specify a `basicAllocator`
2070 /// used to supply memory. If `basicAllocator` is not supplied, a
2071 /// default-constructed object of the (template parameter) type
2072 /// `ALLOCATOR` is used. If the type `ALLOCATOR` is `bsl::allocator`
2073 /// and `basicAllocator` is not supplied, the currently installed
2074 /// default allocator is used to supply memory. Use 1.0 for the
2075 /// `maxLoadFactor`. Use a default constructed object of the (template
2076 /// parameter) type `HASHER` and a default constructed object of the
2077 /// (template parameter) type `COMPARATOR` to organize elements in the
2078 /// table. No memory is allocated unless the `HASHER` or `COMPARATOR`
2079 /// types allocate memory in their default constructor. Note that a
2080 /// `bslma::Allocator *` can be supplied for `basicAllocator` if the
2081 /// type `ALLOCATOR` is `bsl::allocator` (the default).
2082 explicit HashTable(const ALLOCATOR& basicAllocator = ALLOCATOR());
2083
2084 /// Create an empty hash-table using the specified `hash` and `compare`
2085 /// functors to organize elements in the table, which will initially
2086 /// have at least the specified `initialNumBuckets` and a
2087 /// `maxLoadFactor` of the specified `initialMaxLoadFactor`. Optionally
2088 /// specify a `basicAllocator` used to supply memory. If
2089 /// `basicAllocator` is not supplied, a default-constructed object of
2090 /// the (template parameter) type `ALLOCATOR` is used. If the type
2091 /// `ALLOCATOR` is `bsl::allocator` and `basicAllocator` is not
2092 /// supplied, the currently installed default allocator is used to
2093 /// supply memory. If this constructor tries to allocate a number of
2094 /// buckets larger than can be represented by this hash-table's
2095 /// `SizeType`, a `std::length_error` exception is thrown. The behavior
2096 /// is undefined unless `0 < initialMaxLoadFactor`. Note that more than
2097 /// `initialNumBuckets` buckets may be created in order to preserve the
2098 /// bucket allocation strategy of the hash-table (but never fewer).
2099 /// Also note that a `bslma::Allocator *` can be supplied for
2100 /// `basicAllocator` if the type `ALLOCATOR` is `bsl::allocator` (the
2101 /// default).
2102 HashTable(const HASHER& hash,
2103 const COMPARATOR& compare,
2104 SizeType initialNumBuckets,
2105 float initialMaxLoadFactor,
2106 const ALLOCATOR& basicAllocator = ALLOCATOR());
2107
2108 /// Create a hash-table having the same value (and `maxLoadFactor`) as
2109 /// the specified `original` object. Use a copy of `original.hasher()`
2110 /// and a copy of `original.comparator()` to organize elements in this
2111 /// hash-table. Use the allocator returned by
2112 /// 'bsl::allocator_traits<ALLOCATOR>::
2113 /// select_on_container_copy_construction(original.allocator())'
2114 /// to allocate memory. This method requires that the `ValueType`
2115 /// defined by the (template parameter) type `KEY_CONFIG` be
2116 /// `copy-insertable` into this hash-table (see '{Requirements on
2117 /// `KEY_CONFIG`}). Note that this hash-table may have fewer buckets
2118 /// than `original`, and a correspondingly higher `loadFactor`, so long
2119 /// as `maxLoadFactor` is not exceeded. Also note that the created hash
2120 /// table may have a different `numBuckets` than `original`, and a
2121 /// correspondingly different `loadFactor`, as long as `maxLoadFactor`
2122 /// is not exceeded.
2123 HashTable(const HashTable& original);
2124
2125 /// Create a hash-table having the same value (and `maxLoadFactor`) as
2126 /// the specified `original` object by moving (in constant time) the
2127 /// contents of `original` to the new hash-table. Use a copy of
2128 /// `original.hasher()` and a copy of `original.comparator()` to
2129 /// organize elements in this hash-table. The allocator associated with
2130 /// `original` is propagated for use in the newly created hash-table.
2131 /// `original` is left in a valid but unspecified state.
2132 HashTable(BloombergLP::bslmf::MovableRef<HashTable> original);
2133
2134 /// Create a hash-table having the same value (and `maxLoadFactor`) as
2135 /// the specified `original` object that uses the specified
2136 /// `basicAllocator` to supply memory. Use a copy of
2137 /// `original.hasher()` and a copy of `original.comparator()` to
2138 /// organize elements in this hash-table. This method requires that the
2139 /// `ValueType` defined by the (template parameter) type `KEY_CONFIG` be
2140 /// `move-insertable` into this hash-table. Note that this hash-table
2141 /// may have a different `numBuckets` than `original`, and a
2142 /// correspondingly different `loadFactor`, as long as `maxLoadFactor`
2143 /// is not exceeded.
2144 HashTable(const HashTable& original, const ALLOCATOR& basicAllocator);
2145
2146 /// Create a hash table having the same value (and `maxLoadFactor`) as
2147 /// the specified `original` object that uses the specified
2148 /// `basicAllocator` to supply memory. The contents of `original` are
2149 /// moved (in constant time) to the new hash-table if
2150 /// `basicAllocator == original.get_allocator()`, and are move-inserted
2151 /// (in linear time) using `basicAllocator` otherwise. `original` is
2152 /// left in a valid but unspecified state. Use a copy of
2153 /// `original.hasher()` and a copy of `original.comparator()` to
2154 /// organize elements in this hash-table. This method requires that the
2155 /// `ValueType` defined by the (template parameter) type `KEY_CONFIG` be
2156 /// `move-insertable` into this hash-table. Note that this hash-table
2157 /// may have a different `numBuckets` than `original`, and a
2158 /// correspondingly different `loadFactor`, as long as `maxLoadFactor`
2159 /// is not exceeded. Also note that a `bslma::Allocator *` can be
2160 /// supplied for `basicAllocator` if the (template parameter)
2161 /// `ALLOCATOR` is `bsl::allocator` (the default).
2162 HashTable(BloombergLP::bslmf::MovableRef<HashTable> original,
2163 const ALLOCATOR& basicAllocator);
2164
2165 /// Destroy this object.
2166 ~HashTable();
2167
2168 // MANIPULATORS
2169
2170 /// Assign to this object the value, hasher, comparator and
2171 /// `maxLoadFactor` of the specified `rhs` object, propagate to this
2172 /// object the allocator of `rhs` if the `ALLOCATOR` type has trait
2173 /// `propagate_on_container_copy_assignment`, and return a reference
2174 /// providing modifiable access to this object. This method requires
2175 /// that the `ValueType` defined by the (template parameter) type
2176 /// `KEY_CONFIG` be `copy-assignable` and `copy-insertable` into this
2177 /// hash-table (see {Requirements on `KEY_CONFIG`}). This method
2178 /// requires that the (template parameter) types `HASHER` and
2179 /// `COMPARATOR` be `copy-constructible` and `copy-assignable`. Note
2180 /// that these requirements are modeled after the unordered container
2181 /// requirements table in the C++11 standard, which is imprecise on this
2182 /// operation; these requirements might simplify in the future, if the
2183 /// standard is updated.
2184 HashTable& operator=(const HashTable& rhs);
2185
2186 /// Assign to this object the value, hasher, comparator, and
2187 /// `maxLoadFactor` of the specified `rhs` object, propagate to this
2188 /// object the allocator of `rhs` if the `ALLOCATOR` type has trait
2189 /// `propagate_on_container_move_assignment`, and return a reference
2190 /// providing modifiable access to this object. If this hash-table and
2191 /// `rhs` use the same allocator (after considering the aforementioned
2192 /// trait), all of the contents of `rhs` are moved to this hash-table in
2193 /// constant time; otherwise, all elements in this hash table are either
2194 /// destroyed or move-assigned to and each additional element in `rhs`
2195 /// is move-inserted into this hash-table. `rhs` is left in a valid but
2196 /// unspecified state. This method requires that the `ValueType`
2197 /// defined by the (template parameter) type `KEY_CONFIG` be both
2198 /// `move-assignable` and `move-insertable` into this hash-table (see
2199 /// {Requirements on `KEY_CONFIG`}).
2200 HashTable& operator=(BloombergLP::bslmf::MovableRef<HashTable> rhs);
2201
2202#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
2203 /// Insert into this hash-table a newly-created `ValueType` object,
2204 /// constructed by forwarding the specified (variable number of)
2205 /// `arguments` to the corresponding constructor of `ValueType`, and
2206 /// return the address of the newly inserted node. If a key equivalent
2207 /// to that of the newly-created object already exists in this
2208 /// hash-table, then insert the newly-created object immediately before
2209 /// the first such element. Additional buckets are allocated, as
2210 /// needed, to preserve the invariant `loadFactor <= maxLoadFactor`. If
2211 /// this function tries to allocate a number of buckets larger than can
2212 /// be represented by this hash-table's `SizeType`, a
2213 /// `std::length_error` exception is thrown. This method requires that
2214 /// the `ValueType` defined in the (template parameter) type
2215 /// `KEY_CONFIG` be `emplace-constructible` into this hash-table from
2216 /// `arguments` (see {Requirements on `KEY_CONFIG`});
2217 template <class... Args>
2218 bslalg::BidirectionalLink *emplace(Args&&... arguments);
2219
2220 /// Insert into this hash-table a newly-created `ValueType` object,
2221 /// constructed by forwarding the specified (variable number of)
2222 /// `arguments` to the corresponding constructor of `ValueType`
2223 /// (immediately preceding the specified `hint` if `hint` is not null
2224 /// and the key of the node pointed to by `hint` is equivalent to that
2225 /// of the newly-created object), and return the address of the newly
2226 /// inserted node. If `hint` is null or the key of the node pointed to
2227 /// by `hint` is not equivalent to that of the newly created object, and
2228 /// a key equivalent to that of the newly-created object already exists
2229 /// in this hash-table, then insert the newly-created object immediately
2230 /// before the first such element. Additional buckets will be
2231 /// allocated, as needed, to preserve the invariant
2232 /// `loadFactor <= maxLoadFactor`. If this function tries to allocate a
2233 /// number of buckets larger than can be represented by this hash
2234 /// table's `SizeType`, a `std::length_error` exception is thrown. This
2235 /// method requires that `ValueType` defined in the (template parameter)
2236 /// type `KEY_CONFIG` be `emplace-constructible` into this hash-table
2237 /// from `arguments` (see {Requirements on `KEY_CONFIG`}). The behavior
2238 /// is undefined unless `hint` is either null or points to a node in
2239 /// this hash table.
2240 template <class... Args>
2243 Args&&... arguments);
2244
2245 /// Insert into this hash-table a newly-created `ValueType` object,
2246 /// constructed by forwarding the specified (variable number of)
2247 /// `arguments` to the corresponding constructor of `ValueType`, if a
2248 /// key equivalent to that of the newly-created object does not already
2249 /// exist in this hash-table. Return the address of the (possibly newly
2250 /// created and inserted) element in this hash table whose key is
2251 /// equivalent to that of an object created from `arguments`. Load
2252 /// `true` into the specified `isInsertedFlag` if a new value was
2253 /// inserted, and `false` if an equivalent key was already present. If
2254 /// this hash-table contains more than one element with an equivalent
2255 /// key, return the first such element (from the contiguous sequence of
2256 /// elements having a matching key). Additional buckets are allocated,
2257 /// as needed, to preserve the invariant `loadFactor <= maxLoadFactor`.
2258 /// If this function tries to allocate a number of buckets larger than
2259 /// can be represented by this hash-table's `SizeType`, a
2260 /// `std::length_error` exception is thrown. This method requires that
2261 /// the `ValueType` defined in the (template parameter) type
2262 /// `KEY_CONFIG` be `emplace-constructible` into this hash-table from
2263 /// `arguments` (see {Requirements on `KEY_CONFIG`});
2264 template <class... Args>
2266 Args&&... arguments);
2267#endif
2268
2269 /// Insert into this hash-table a newly-created `ValueType` object,
2270 /// constructed by forwarding the specified `key` and a
2271 /// default-constructed object of the type `ValueType::second_type`, to
2272 /// the corresponding constructor of `ValueType`, if `key` does not
2273 /// already exist in this hash-table. Return the address of the
2274 /// (possibly newly created and inserted) element in this hash-table
2275 /// whose key is equivalent to `key`. If this hash-table contains more
2276 /// than one element with the supplied `key`, return the first such
2277 /// element (from the contiguous sequence of elements having a matching
2278 /// key). Additional buckets are allocated, as needed, to preserve the
2279 /// invariant `loadFactor <= maxLoadFactor`. If this function tries to
2280 /// allocate a number of buckets larger than can be represented by this
2281 /// hash table's `SizeType`, a `std::length_error` exception is thrown.
2282 /// This method requires that the `ValueType` defined in the (template
2283 /// parameter) type `KEY_CONFIG` be `emplace-constructible` into this
2284 /// hash-table from a `pair` of arguments representing the key and
2285 /// value, respectively (see {Requirements on `KEY_CONFIG`});
2289
2290 /// Insert the specified `value` into this hash-table if a key
2291 /// equivalent to that of `value` does not already exist in this
2292 /// hash-table. Return the address of the (possibly newly inserted)
2293 /// element in this hash-table whose key is equivalent to that of
2294 /// `value`. If this hash-table contains more than one element with a
2295 /// matching key, return the first such element (from the contiguous
2296 /// sequence of elements having a matching key). Additional buckets are
2297 /// allocated, as needed, to preserve the invariant
2298 /// `loadFactor <= maxLoadFactor`. If this function tries to allocate a
2299 /// number of buckets larger than can be represented by this
2300 /// hash-table's `SizeType`, a `std::length_error` exception is thrown.
2301 /// This method requires that the `ValueType` defined in the (template
2302 /// parameter) type `KEY_CONFIG` be `copy-insertable` into this
2303 /// hash-table (see {Requirements on `KEY_CONFIG`});
2305 bool *isInsertedFlag,
2306 const ValueType& value);
2307
2308 /// Insert the specified `value` into this hash-table if a key
2309 /// equivalent to that of `value` does not already exist in this
2310 /// hash-table. Return the address of the (possibly newly inserted)
2311 /// element in this hash-table whose key is equivalent to that of
2312 /// `value`. `value` is left in a valid but unspecified state. If this
2313 /// hash-table contains more than one element with a matching key,
2314 /// return the first such element (from the contiguous sequence of
2315 /// elements having a matching key). Additional buckets are allocated,
2316 /// as needed, to preserve the invariant `loadFactor <= maxLoadFactor`.
2317 /// If this function tries to allocate a number of buckets larger than
2318 /// can be represented by this hash-table's `SizeType`, a
2319 /// `std::length_error` exception is thrown. This method requires that
2320 /// the `ValueType` defined in the (template parameter) type
2321 /// `KEY_CONFIG` be `move-insertable` into this hash-table (see
2322 /// {Requirements on `KEY_CONFIG`});
2324 bool *isInsertedFlag,
2326
2327 /// Insert into this hash-table a `ValueType` object created from the
2328 /// specified `value` if a key equivalent to that of such an object does
2329 /// not already exist in this hash-table. Return the address of the
2330 /// (possibly newly inserted) element in this hash-table whose key is
2331 /// equivalent to that of the object created from `value`. Load `true`
2332 /// into the specified `isInsertedFlag` if a new value was inserted, and
2333 /// `false` if an equivalent key was already present. If this
2334 /// hash-table contains more than one element with an equivalent key,
2335 /// return the first such element (from the contiguous sequence of
2336 /// elements having a matching key). Additional buckets are allocated,
2337 /// as needed, to preserve the invariant `loadFactor <= maxLoadFactor`.
2338 /// If this function tries to allocate a number of buckets larger than
2339 /// can be represented by this hash-table's `SizeType`, a
2340 /// `std::length_error` exception is thrown. This method requires that
2341 /// the `ValueType` defined in the (template parameter) type
2342 /// `KEY_CONFIG` be `move-insertable` into this hash-table (see
2343 /// {Requirements on `KEY_CONFIG`}) and the (template parameter) type
2344 /// `SOURCE_TYPE` be implicitly convertible to `ValueType`.
2345 template <class SOURCE_TYPE>
2348 bool *isInsertedFlag,
2349 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value);
2350
2351 /// Insert into this hash-table a `ValueType` object created from the
2352 /// specified `value` and return the address of the newly inserted node.
2353 /// If a key equivalent to that of the newly-created object already
2354 /// exists in this hash-table, then insert the new object immediately
2355 /// before the first such element. Additional buckets are allocated, as
2356 /// needed, to preserve the invariant `loadFactor <= maxLoadFactor`. If
2357 /// this function tries to allocate a number of buckets larger than can
2358 /// be represented by this hash-table's `SizeType`, a
2359 /// `std::length_error` exception is thrown. This method requires that
2360 /// the `ValueType` defined in the (template parameter) type
2361 /// `KEY_CONFIG` be `move-insertable` into this hash-table (see
2362 /// {Requirements on `KEY_CONFIG`}) and the (template parameter) type
2363 /// `SOURCE_TYPE` be implicitly convertible to `ValueType`. Note that
2364 /// this method is deprecated is provided only to ensure backward
2365 /// compatibility with existing clients; use the `emplace` method
2366 /// instead.
2367 template <class SOURCE_TYPE>
2369 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value);
2370
2371 /// Insert into this hash-table a `ValueType` object created from the
2372 /// specified `value` (immediately preceding the specified `hint` if
2373 /// `hint` is not null and the key of the node pointed to by `hint` is
2374 /// equivalent to that of the newly-created object), and return the
2375 /// address of the newly inserted node. If `hint` is null or the key of
2376 /// the node pointed to by `hint` is not equivalent to that of the newly
2377 /// created object, and a key equivalent to that of the newly-created
2378 /// object already exists in this hash-table, then insert the
2379 /// newly-created object immediately before the first such element.
2380 /// Additional buckets will be allocated, as needed, to preserve the
2381 /// invariant `loadFactor <= maxLoadFactor`. If this function tries to
2382 /// allocate a number of buckets larger than can be represented by this
2383 /// hash-table's `SizeType`, a `std::length_error` exception is thrown.
2384 /// This method requires that `ValueType` defined in the (template
2385 /// parameter) type `KEY_CONFIG` be `move-insertable` into this
2386 /// hash-table (see {Requirements on `KEY_CONFIG`}) and the (template
2387 /// parameter) type `SOURCE_TYPE` be implicitly convertible to
2388 /// `ValueType`. Note that this method is deprecated and is provided
2389 /// only to ensure backward compatibility with existing clients; use the
2390 /// `emplaceWithHint` method instead.
2391 template <class SOURCE_TYPE>
2393 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value,
2395
2396#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
2397 /// If a key equivalent to the specified `key` already exists in this
2398 /// hash-table, assign the specified `obj` to the value associated with
2399 /// that key, load `false` into the specified `isInsertedFlag` and
2400 /// return a pointer to the existing entry. Otherwise, insert into this
2401 /// hash-table a newly-created `value_type` object, constructed from
2402 /// `key` and `obj`, load `true` into `isInsertedFlag`, and return a
2403 /// pointer to the newly-created entry. Use the optionally specified
2404 /// `hint` as a starting place for the search for the existing key.
2405 template <class KEY_ARG, class BDE_OTHER_TYPE>
2407 bool *isInsertedFlag,
2410 BDE_OTHER_TYPE&& obj);
2411#endif
2412
2413 /// Re-organize this hash-table to have at least the specified
2414 /// `newNumBuckets`, preserving the invariant
2415 /// `loadFactor <= maxLoadFactor`. If this function tries to allocate a
2416 /// number of buckets larger than can be represented by this hash
2417 /// table's `SizeType`, a `std::length_error` exception is thrown. This
2418 /// operation provides the strong exception guarantee (see
2419 /// @ref bsldoc_glossary ) unless the `hasher` throws, in which case this
2420 /// operation provides the basic exception guarantee, leaving the
2421 /// hash-table in a valid, but otherwise unspecified (and potentially
2422 /// empty), state. Note that more buckets than requested may be
2423 /// allocated in order to preserve the bucket allocation strategy of the
2424 /// hash table (but never fewer).
2425 void rehashForNumBuckets(SizeType newNumBuckets);
2426
2427 /// Remove the specified `node` from this hash-table, and return the
2428 /// address of the node immediately after `node` in this hash-table
2429 /// (prior to its removal), or a null pointer value if `node` is the
2430 /// last node in the table. This method invalidates only iterators and
2431 /// references to the removed node and previously saved values of the
2432 /// `end()` iterator, and preserves the relative order of the nodes not
2433 /// removed. The behavior is undefined unless `node` refers to a node
2434 /// in this hash-table.
2436
2437 /// Remove all the elements from this hash-table. Note that this
2438 /// hash-table is empty after this call, but allocated memory may be
2439 /// retained for future use. The destructor of each (non-trivial)
2440 /// element that is remove shall be run.
2441 void removeAll();
2442
2443 /// Re-organize this hash-table to have a sufficient number of buckets
2444 /// to accommodate at least the specified `numElements` without
2445 /// exceeding the `maxLoadFactor`, and ensure that there are sufficient
2446 /// nodes pre-allocated in this object's node pool. If this function
2447 /// tries to allocate a number of buckets larger than can be represented
2448 /// by this hash table's `SizeType`, a `std::length_error` exception is
2449 /// thrown. This operation provides the strong exception guarantee (see
2450 /// @ref bsldoc_glossary ) unless the `hasher` throws, in which case this
2451 /// operation provides the basic exception guarantee, leaving the
2452 /// hash-table in a valid, but otherwise unspecified (and potentially
2453 /// empty), state.
2454 void reserveForNumElements(SizeType numElements);
2455
2456 /// Set the maximum load factor permitted by this hash table to the
2457 /// specified `newMaxLoadFactor`, where load factor is the statistical
2458 /// mean number of elements per bucket. If 'newMaxLoadFactor <
2459 /// loadFactor', allocate at least enough buckets to re-establish the
2460 /// invariant `loadFactor <= maxLoadFactor`. If this function tries to
2461 /// allocate a number of buckets larger than can be represented by this
2462 /// hash table's `SizeType`, a `std::length_error` exception is thrown.
2463 /// The behavior is undefined unless `0 < maxLoadFactor`.
2464 void setMaxLoadFactor(float newMaxLoadFactor);
2465
2466 /// Exchange the value of this object, its `comparator` functor, its
2467 /// `hasher` functor, and its `maxLoadFactor` with those of the
2468 /// specified `other` object. Additionally, if
2469 /// `bslstl::AllocatorTraits<ALLOCATOR>::propagate_on_container_swap` is
2470 /// `true`, then exchange the allocator of this object with that of the
2471 /// `other` object, and do not modify either allocator otherwise. This
2472 /// method provides the no-throw exception-safety guarantee unless any
2473 /// of the `comparator` or `hasher` functors throw when swapped, leaving
2474 /// both objects in a safely destructible, but otherwise unusable,
2475 /// state. The operation guarantees `O[1]` complexity. The behavior is
2476 /// undefined unless either this object has an allocator that compares
2477 /// equal to the allocator of `other`, or the trait
2478 /// `bslstl::AllocatorTraits<ALLOCATOR>::propagate_on_container_swap` is
2479 /// `true`.
2480 void swap(HashTable& other);
2481
2482#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
2483 /// If a key equivalent to the specified `key` already exists in this
2484 /// hash-table, load `false` into the specified `isInsertedFlag` and
2485 /// return a pointer to the existing entry. Otherwise, insert into this
2486 /// hash-table a newly-created `value_type` object, constructed from
2487 /// `key` and the specified `args`, load `true` into `isInsertedFlag`
2488 /// and return a pointer to the newly created entry. Use the optionally
2489 /// specified `hint` as a starting place for the search for the existing
2490 /// key.
2491 template <class... ARGS>
2493 bool *isInsertedFlag,
2495 const KeyType& key,
2496 ARGS&&... args);
2497
2498 /// If a key equivalent to the specified `key` already exists in this
2499 /// hash-table, load `false` into the specified `isInsertedFlag` and
2500 /// return a pointer to the existing entry. Otherwise, insert into this
2501 /// hash-table a newly-created `value_type` object, constructed from
2502 /// `std::forward<KEY>(key)` and the specified `args`, load `true` into
2503 /// `isInsertedFlag` and return a pointer to the newly created entry.
2504 /// Use the optionally specified `hint` as a starting place for the
2505 /// search for the existing key.
2506 template <class... ARGS>
2508 bool *isInsertedFlag,
2511 ARGS&&... args);
2512
2513
2514 /// If a key equivalent to the specified `key` already exists in this
2515 /// hash-table, load `false` into the specified `isInsertedFlag` and
2516 /// return a pointer to the existing entry. Otherwise, insert into this
2517 /// hash-table a newly-created `value_type` object, constructed from
2518 /// `key` and the specified `args`, load `true` into `isInsertedFlag`
2519 /// and return a pointer to the newly created entry. Use the optionally
2520 /// specified `hint` as a starting place for the search for the existing
2521 /// key.
2522 ///
2523 /// Note: implemented inline due to Sun CC compilation error.
2524 template <class LOOKUP_KEY, class... ARGS>
2525 typename bsl::enable_if<
2526 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2527 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value,
2529 bool *isInsertedFlag,
2531 LOOKUP_KEY&& key,
2532 ARGS&&... args)
2533 {
2534 typedef bslalg::HashTableImpUtil ImpUtil;
2535
2536 const LOOKUP_KEY& lvalue = key;
2537 const std::size_t hashCode = this->d_parameters.hashCodeForKey(lvalue);
2538
2539 // Use the hint, if we can
2540 if (!hint
2541 || !d_parameters.comparator()(
2542 lvalue,
2543 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
2544
2545 hint = bslalg::HashTableImpUtil::findTransparent<KEY_CONFIG>(
2546 d_anchor,
2547 lvalue,
2548 d_parameters.comparator(),
2549 hashCode);
2550 }
2551
2552 // If the key exists, we're done
2553 if (hint) {
2554 *isInsertedFlag = false;
2555 return hint; // RETURN
2556 }
2557
2558 if (d_size >= d_capacity) {
2559 this->rehashForNumBuckets(numBuckets() * 2);
2560 }
2561
2562 // Make a new node
2563 #if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR)
2564 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
2565 std::piecewise_construct,
2566 std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key)),
2567 std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...));
2568 #else
2569 typedef typename ValueType::second_type MappedType;
2570
2571 // TBD: make 'this->allocator()' return the allocator by reference with
2572 // modifiable access rather than by value.
2573
2574 AllocatorType alloc = this->allocator();
2575
2576 bsls::ObjectBuffer<MappedType> defaultMapped;
2577 AllocatorTraits::construct(alloc, defaultMapped.address(),
2578 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
2579 bslma::DestructorGuard<MappedType> mGuard(defaultMapped.address());
2580
2581 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
2582 BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key),
2583 defaultMapped.object());
2584 #endif
2585
2586 // Add it to the hash table
2588 nodeProctor(&d_parameters.nodeFactory(), hint);
2589 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
2590 nodeProctor.release();
2591 ++d_size;
2592
2593 *isInsertedFlag = true;
2594 return hint;
2595 }
2596#endif
2597
2598 // ACCESSORS
2599
2600 /// Return a copy of the allocator used to construct this hash table.
2601 /// Note that this is not the allocator used to allocate elements for
2602 /// this hash table, which is instead a copy of that allocator rebound
2603 /// to allocate the nodes used by the internal data structure of this
2604 /// hash table.
2605 ALLOCATOR allocator() const;
2606
2607 /// Return a reference offering non-modifiable access to the
2608 /// `HashTableBucket` at the specified `index` position in the array of
2609 /// buckets of this table. The behavior is undefined unless 'index <
2610 /// numBuckets()'.
2612
2613 /// Return the index of the bucket that would contain all the elements
2614 /// having the specified `key`.
2615 SizeType bucketIndexForKey(const KeyType& key) const;
2616
2617 /// Return a reference providing non-modifiable access to the
2618 /// key-equality comparison functor used by this hash table.
2619 const COMPARATOR& comparator() const;
2620
2621 /// Return the number elements contained in the bucket at the specified
2622 /// `index`. Note that this operation has linear run-time complexity
2623 /// with respect to the number of elements in the indexed bucket.
2625
2626 /// Return the address of the first element in this hash table, or a
2627 /// null pointer value if this hash table is empty.
2629
2630 /// Return the address of a link whose key is equivalent to the
2631 /// specified `key` (according to this hash-table's `comparator`), and a
2632 /// null pointer value if no such link exists. If this hash-table
2633 /// contains more than one element having the supplied `key`, return the
2634 /// first such element (from the contiguous sequence of elements having
2635 /// the same key). The behavior is undefined unless `key` is equivalent
2636 /// to the elements of at most one equivalent-key group.
2637 template <class LOOKUP_KEY>
2638 typename bsl::enable_if<
2639 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2640 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value,
2642 find(const LOOKUP_KEY& key) const
2643 {
2644 return bslalg::HashTableImpUtil::findTransparent<KEY_CONFIG>(
2645 d_anchor,
2646 key,
2647 d_parameters.comparator(),
2648 d_parameters.hashCodeForKey(key));
2649 }
2650
2651 /// Return the address of a link whose key has the same value as the
2652 /// specified `key` (according to this hash-table's `comparator`), and a
2653 /// null pointer value if no such link exists. If this hash-table
2654 /// contains more than one element having the supplied `key`, return the
2655 /// first such element (from the contiguous sequence of elements having
2656 /// the same key).
2657 bslalg::BidirectionalLink *find(const KeyType& key) const;
2658
2659 /// Return the address of the first node after any nodes holding a value
2660 /// having the same key as the specified `first` node (according to this
2661 /// hash-table's `comparator`), and a null pointer value if all nodes
2662 /// following `first` hold values with the same key as `first`. The
2663 /// behavior is undefined unless `first` is a link in this hash-table.
2664 /// Note that this hash-table ensures all elements having the same key
2665 /// form a contiguous sequence.
2667 bslalg::BidirectionalLink *first) const;
2668
2669 /// Load into the specified `first` and `last` pointers the respective
2670 /// addresses of the first and last link (in the list of elements owned
2671 /// by this hash table) where the contained elements have a key that is
2672 /// equivalent to the specified `key` using the `comparator` of this
2673 /// hash-table, and null pointer values if there are no elements
2674 /// matching `key`. The behavior is undefined unless `key` is
2675 /// equivalent to the elements of at most one equivalent-key group.
2676 /// Note that the output values will form a closed range, where both
2677 /// `first` and `last` point to links satisfying the predicate (rather
2678 /// than a semi-open range where `last` would point to the element
2679 /// following the range). Also note that this hash-table ensures all
2680 /// elements having the same key form a contiguous sequence.
2681 ///
2682 /// Note: implemented inline due to Sun CC compilation error.
2683 template <class LOOKUP_KEY>
2684 typename bsl::enable_if<
2685 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2686 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value,
2687 void>::type
2690 const LOOKUP_KEY& key) const
2691 {
2692 BSLS_ASSERT_SAFE(first);
2693 BSLS_ASSERT_SAFE(last);
2694
2695 *first = this->find(key);
2696 *last = *first ? this->findEndOfRange(*first) : 0;
2697 }
2698
2699 /// Load into the specified `first` and `last` pointers the respective
2700 /// addresses of the first and last link (in the list of elements owned
2701 /// by this hash table) where the contained elements have a key that
2702 /// compares equal to the specified `key` using the `comparator` of this
2703 /// hash-table, and null pointer values if there are no elements
2704 /// matching `key`. Note that the output values will form a closed
2705 /// range, where both `first` and `last` point to links satisfying the
2706 /// predicate (rather than a semi-open range where `last` would point to
2707 /// the element following the range). Also note that this hash-table
2708 /// ensures all elements having the same key form a contiguous sequence.
2711 const KeyType& key) const;
2712
2713 /// Return `true` if the specified `other` has the same value as this
2714 /// object, and `false` otherwise. Two `HashTable` objects have the
2715 /// same value if they have the same number of elements, and for every
2716 /// subset of elements in this object having keys that compare equal
2717 /// (according to that hash table's `comparator`), a corresponding
2718 /// subset of elements exists in the `other` object, having the same
2719 /// number of elements, where, for some permutation of the subset in
2720 /// this object, every element in that subset compares equal (using
2721 /// `operator==`) to the corresponding element in the `other` subset.
2722 /// The behavior is undefined unless both the `hasher` and `comparator`
2723 /// of this object and the `other` return the same value for every valid
2724 /// input. Note that this method requires that the `ValueType` of the
2725 /// parameterized `KEY_CONFIG` be "equality-comparable" (see
2726 /// {Requirements on `KEY_CONFIG`}).
2727 bool hasSameValue(const HashTable& other) const;
2728
2729 /// Return a reference providing non-modifiable access to the hash
2730 /// functor used by this hash-table.
2731 const HASHER& hasher() const;
2732
2733 /// Return the current load factor for this table. The load factor is
2734 /// the statistical mean number of elements per bucket.
2735 float loadFactor() const;
2736
2737 /// Return the maximum load factor permitted by this hash table object,
2738 /// where the load factor is the statistical mean number of elements per
2739 /// bucket. Note that this hash table will enforce the maximum load
2740 /// factor by rehashing into a larger array of buckets on any any
2741 /// insertion operation where a successful insertion would exceed the
2742 /// maximum load factor. The maximum load factor may actually be less
2743 /// than the current load factor if the maximum load factor has been
2744 /// reset, but no insert operations have yet occurred.
2745 float maxLoadFactor() const;
2746
2747 /// Return a theoretical upper bound on the largest number of buckets
2748 /// that this hash-table could possibly have. Note that there is no
2749 /// guarantee that the hash-table can successfully maintain that number
2750 /// of buckets, or even close to that number of buckets without running
2751 /// out of resources.
2752 SizeType maxNumBuckets() const;
2753
2754 /// Return a theoretical upper bound on the largest number of elements
2755 /// that this hash-table could possibly hold. Note that there is no
2756 /// guarantee that the hash-table can successfully grow to the returned
2757 /// size, or even close to that size without running out of resources.
2758 SizeType maxSize() const;
2759
2760 /// Return the number of buckets contained in this hash table.
2761 SizeType numBuckets() const;
2762
2763 /// Return the number of elements this hash table can hold without
2764 /// requiring a rehash operation in order to respect the
2765 /// `maxLoadFactor`.
2766 SizeType rehashThreshold() const;
2767
2768 /// Return the number of elements in this hash table.
2769 SizeType size() const;
2770};
2771
2772/// Swap both the value, the hasher, the comparator, and the `maxLoadFactor`
2773/// of the specified `x` object with the value, the hasher, the comparator,
2774/// and the `maxLoadFactor` of the specified `y` object. Additionally, if
2775/// `bslstl::AllocatorTraits<ALLOCATOR>::propagate_on_container_swap` is
2776/// `true`, then exchange the allocator of `x` with that of `y`, and do not
2777/// modify either allocator otherwise. This method guarantees `O[1]`
2778/// complexity if `x` and `y` have the same allocator or if the allocators
2779/// propagate on swap, otherwise this operation will typically pay the cost
2780/// of two copy constructors, which may in turn throw. If the allocators
2781/// are the same or propagate, then this method provides the no-throw
2782/// exception-safety guarantee unless the `swap` function of the hasher or
2783/// comparator throw. Otherwise this method offers only the basic exception
2784/// safety guarantee.
2785template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
2788
2789/// Return `true` if the specified `lhs` and `rhs` objects have the same
2790/// value, and `false` otherwise. Two `HashTable` objects have the same
2791/// value if they have the same number of elements, and for every subset of
2792/// elements in `lhs` having keys that compare equal (according to that hash
2793/// table's `comparator`), a corresponding subset of elements exists in
2794/// `rhs`, having the same number of elements, where, for some permutation
2795/// of the `lhs` subset, every element in that subset compares equal (using
2796/// `operator==`) to the corresponding element in the `rhs` subset. The
2797/// behavior is undefined unless both the `hasher` and `comparator` of `lhs`
2798/// and `rhs` return the same value for every valid input. Note that this
2799/// method requires that the `ValueType` of the parameterized `KEY_CONFIG`
2800/// be "equality-comparable" (see {Requirements on `KEY_CONFIG`}).
2801template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
2802bool operator==(
2805
2806/// Return `true` if the specified `lhs` and `rhs` objects do not have the
2807/// same value, and `false` otherwise. Two `HashTable` objects do not have
2808/// the same value if they do not have the same number of elements, or if,
2809/// for any key found in `lhs`, the subset of elements having that key
2810/// (according to the hash-table's `comparator`) in `lhs` either (1) does
2811/// not have the same number of elements as the subset of elements having
2812/// that key in `rhs`, or (2) there exists no permutation of the `lhs`
2813/// subset where each element compares equal (using `operator==`) to the
2814/// corresponding element in the `rhs` subset. The behavior is undefined
2815/// unless both the `hasher` and `comparator` of `lhs` and `rhs` return the
2816/// same value for every valid input. Note that this method requires that
2817/// the `ValueType` of the parameterized `KEY_CONFIG` be
2818/// "equality-comparable" (see {Requirements on `KEY_CONFIG`}).
2819template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
2820bool operator!=(
2823
2824 // ============================
2825 // class HashTable_ArrayProctor
2826 // ============================
2827
2828/// This class probably already exists in `bslalg`
2829///
2830/// See @ref bslstl_hashtable
2831template <class FACTORY>
2833
2834 private:
2835 // DATA
2836 FACTORY *d_factory_p;
2837 bslalg::HashTableAnchor *d_anchor_p;
2838
2839 private:
2840 // NOT IMPLEMENTED
2843
2844 public:
2845 // CREATORS
2846
2847 /// Create a `HashTable_ArrayProctor` managing the hash-table data
2848 /// structure owned by the specified `anchor` that was created using the
2849 /// specified `factory`.
2850 HashTable_ArrayProctor(FACTORY *factory,
2851 bslalg::HashTableAnchor *anchor);
2852
2853 /// Destroy the hash-table data structure managed by this proctor and
2854 /// reclaim all of its resources, unless there was a call to `release`
2855 /// this proctor.
2857
2858 // MANIPULATORS
2859
2860 /// Release from management the object currently managed by this
2861 /// proctor. If no object is currently being managed, this method has
2862 /// no effect.
2863 void release();
2864};
2865
2866 // ===========================
2867 // class HashTable_NodeProctor
2868 // ===========================
2869
2870/// This class implements a proctor that, unless its `release` method has
2871/// previously been invoked, automatically deallocates a managed list of
2872/// nodes upon destruction by recursively invoking the `deleteNode` method
2873/// of a supplied factory on each node. The (template parameter) type
2874/// `FACTORY` shall be provide a member function that can be called as if it
2875/// had the following signature:
2876/// @code
2877/// void deleteNode(bslalg::BidirectionalLink *node);
2878/// @endcode
2879///
2880/// See @ref bslstl_hashtable
2881template <class FACTORY>
2883
2884 private:
2885 // DATA
2886 FACTORY *d_factory_p;
2887 bslalg::BidirectionalLink *d_node_p;
2888
2889 private:
2890 // NOT IMPLEMENTED
2893
2894 public:
2895 // CREATORS
2896
2897 /// Create a new node-proctor that conditionally manages the specified
2898 /// `node` (if non-zero), and that uses the specified `factory` to
2899 /// destroy the node (unless released) upon its destruction. The
2900 /// behavior is undefined unless `node` was created by the `factory`.
2901 HashTable_NodeProctor(FACTORY *factory,
2903
2904 /// Destroy this node proctor, and delete the node that it manages (if
2905 /// any) by invoking the `deleteNode` method of the factory supplied at
2906 /// construction. If no node is currently being managed, this method
2907 /// has no effect.
2909
2910 // MANIPULATORS
2911
2912 /// Release from management the node currently managed by this proctor.
2913 /// If no object is currently being managed, this method has no effect.
2914 void release();
2915};
2916
2917 // ==========================
2918 // class HashTable_ImpDetails
2919 // ==========================
2920
2921/// This utility `struct` provides a namespace for functions that are useful
2922/// when implementing a hash table.
2924
2925 // CLASS METHODS
2926
2927 /// Return the address of a statically initialized empty bucket that can
2928 /// be shared as the (un-owned) bucket array by all empty hash tables.
2930
2931 /// Return the suggested number of buckets to index a linked list that
2932 /// can hold as many as the specified `minElements` without exceeding
2933 /// the specified `maxLoadFactor`, and supporting at least the specified
2934 /// number of `requestedBuckets`. Set the specified `*capacity` to the
2935 /// maximum length of linked list that the returned number of buckets
2936 /// could index without exceeding the `maxLoadFactor`. The behavior is
2937 /// undefined unless `0 < maxLoadFactor`, `0 < minElements` and
2938 /// `0 < requestedBuckets`.
2939 static size_t growBucketsForLoadFactor(size_t *capacity,
2940 size_t minElements,
2941 size_t requestedBuckets,
2942 double maxLoadFactor);
2943
2944 /// Return that address of an allocator that can be used to allocate
2945 /// temporary storage, but that is neither the default nor global
2946 /// allocator. Note that this function is intended to support detailed
2947 /// checks in `SAFE_2` builds, that may need additional storage for the
2948 /// evaluation of a validity check on a large data structure, but that
2949 /// should not change the expected values computed for regular allocator
2950 /// usage of the component as validated by the test driver.
2952
2953 /// Return the next prime number greater-than or equal to the specified
2954 /// `n` in the increasing sequence of primes chosen to disperse hash
2955 /// codes across buckets as uniformly as possible. Throw a
2956 /// `std::length_error` exception if `n` is greater than the last prime
2957 /// number in the sequence. Note that, typically, prime numbers in the
2958 /// sequence have increasing values that reflect a growth factor (e.g.,
2959 /// each value in the sequence may be, approximately, two times the
2960 /// preceding value).
2961 static size_t nextPrime(size_t n);
2962};
2963
2964 // ====================
2965 // class HashTable_Util
2966 // ====================
2967
2968/// This utility `struct` provide utilities for initializing and destroying
2969/// bucket lists in anchors that are managed by a `HashTable`. They cannot
2970/// migrate down to `bslalg::HashTableImpUtil` as they rely on the standard
2971/// library @ref bslma_allocatortraits for their implementation.
2973
2974 // CLASS METHODS
2975
2976 /// Assert that the passed argument (the specified `ptr`) is not a null
2977 /// pointer value. Note that this utility is necessary as the
2978 /// `HashTable` class template may be instantiated with function
2979 /// pointers for the hasher or comparator policies, but there is no easy
2980 /// way to assert in general that the value of a generic type passed to
2981 /// a function is not a null pointer value.
2982 template <class TYPE>
2983 static void assertNotNullPointer(TYPE&);
2984 template <class TYPE>
2985 static void assertNotNullPointer(TYPE * const& ptr);
2986 template <class TYPE>
2987 static void assertNotNullPointer(TYPE * & ptr);
2988
2989 /// Destroy the specified `data` array of the specified length
2990 /// `bucketArraySize`, that was allocated by the specified `allocator`.
2991 template<class ALLOCATOR>
2993 std::size_t bucketArraySize,
2994 const ALLOCATOR& allocator);
2995
2996 /// Load into the specified `anchor` a (contiguous) array of buckets of
2997 /// the specified `bucketArraySize` using memory supplied by the
2998 /// specified `allocator`. The behavior is undefined unless
2999 /// `0 < bucketArraySize` and `0 == anchor->bucketArraySize()`. Note
3000 /// that this operation has no effect on `anchor->listRootAddress()`.
3001 template<class ALLOCATOR>
3002 static void initAnchor(bslalg::HashTableAnchor *anchor,
3003 std::size_t bucketArraySize,
3004 const ALLOCATOR& allocator);
3005};
3006
3007 // ==============================
3008 // class HashTable_ImplParameters
3009 // ==============================
3010
3011 // It looks like the 'CallableVariable' adaptation would be more
3012 // appropriately addressed as part of the 'bslalg::FunctorAdapter' wrapper
3013 // than intrusively in this component, and in similar ways by any other
3014 // container trying to support the full range of standard conforming
3015 // functors. Given that our intent is to support standard predicates, it
3016 // may be appropriate to handle calling non-'const' 'operator()' overloads
3017 // (via a 'mutable' member) too.
3018
3019template <class HASHER>
3021 : bslalg::FunctorAdapter<HashTable_HashWrapper<
3022 typename CallableVariable<HASHER>::type> >
3023{
3024};
3025
3026template <class COMPARATOR>
3028 : bslalg::FunctorAdapter<HashTable_ComparatorWrapper<
3029 typename CallableVariable<COMPARATOR>::type> >
3030{
3031};
3032
3033/// This class holds all the parameterized parts of a `HashTable` class,
3034/// efficiently exploiting the empty base optimization without adding
3035/// unforeseen namespace associations to the `HashTable` class itself due to
3036/// the structural inheritance.
3037template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3039 : private HashTable_BaseHasher<HASHER>::Type
3040 , private HashTable_Comparator<COMPARATOR>::Type
3041{
3042
3043 // PRIVATE TYPES
3044 typedef typename HashTable_BaseHasher<HASHER>::Type BaseHasher;
3045 typedef typename HashTable_Comparator<COMPARATOR>::Type BaseComparator;
3046
3047 /// This typedef is a convenient alias for the utility associated with
3048 /// movable references.
3050
3051 // typedefs stolen from HashTable
3052 typedef ALLOCATOR AllocatorType;
3053 typedef ::bsl::allocator_traits<AllocatorType> AllocatorTraits;
3054 typedef typename KEY_CONFIG::ValueType ValueType;
3056
3057 public:
3058 // PUBLIC TYPES
3060 typedef typename HashTableType::AllocatorTraits::
3061 template rebind_traits<NodeType> ReboundTraits;
3062 typedef typename ReboundTraits::allocator_type NodeAllocator;
3063
3064 typedef
3067
3068 private:
3069 // DATA
3070 NodeFactory d_nodeFactory; // nested 'struct's have public data by
3071 // convention, but should always be
3072 // accessed through the public methods.
3073
3074 private:
3075 // NOT IMPLEMENTED
3076
3077 /// = delete;
3080
3081 public:
3082 // CREATORS
3083
3084 /// Create a `HashTable_ImplParameters` object having default
3085 /// constructed `HASHER` and `COMPARATOR` functors, and using the
3086 /// specified `allocator` to provide a `BidirectionalNodePool`.
3087 explicit HashTable_ImplParameters(const ALLOCATOR& allocator);
3088
3089 /// Create a `HashTable_ImplParameters` object having the specified
3090 /// `hash` and `compare` functors, and using the specified `allocator`
3091 /// to provide a `BidirectionalNodePool`.
3092 HashTable_ImplParameters(const HASHER& hash,
3093 const COMPARATOR& compare,
3094 const ALLOCATOR& allocator);
3095
3096 /// Create a `HashTable_ImplParameters` object having the same `hasher`
3097 /// and `comparator` attributes as the specified `original`, and
3098 /// providing a `BidirectionalNodePool` using the specified `allocator`.
3100 const ALLOCATOR& allocator);
3101
3102 /// Create a `HashTable_ImplParameters` object with a copy of the
3103 /// `hasher` and `comparator` attributes associated with the specified
3104 /// `original` parameters object, and adopting all outstanding memory
3105 /// allocations and the allocator associated with `original`. Note that
3106 /// `original` is left in a valid but unspecified state.
3109
3110 // MANIPULATORS
3111
3112 /// Return a reference offering modifiable access to the `nodeFactory`
3113 /// owned by this object.
3115
3116 /// Efficiently exchange the value, functor, and allocator of this
3117 /// object with those of the specified `other` object. This method
3118 /// provides the no-throw exception-safety guarantee.
3120
3121 /// Efficiently exchange the value and functors this object with those
3122 /// of the specified `other` object. This method provides the no-throw
3123 /// exception-safety guarantee. The behavior is undefined unless this
3124 /// object was created with the same allocator as `other`.
3126
3127 // ACCESSORS
3128
3129 /// Return a reference offering non-modifiable access to the
3130 /// `comparator` functor owned by this object.
3131 const BaseComparator& comparator() const;
3132
3133 /// Return the hash code for the specified `key` using a copy of the
3134 /// hash functor supplied at construction. Note that this function is
3135 /// provided as a common way to resolve `const_cast` issues in the case
3136 /// that the stored hash functor has a function call operator that is
3137 /// not declared as `const`.
3138 template <class DEDUCED_KEY>
3139 std::size_t hashCodeForKey(DEDUCED_KEY& key) const;
3140
3141 /// Return a reference offering non-modifiable access to the `hasher`
3142 /// functor owned by this object.
3143 const BaseHasher& hasher() const;
3144
3145 /// Return a reference offering non-modifiable access to the
3146 /// `nodeFactory` owned by this object.
3147 const NodeFactory& nodeFactory() const;
3148
3149 /// Return a reference offering non-modifiable access to the
3150 /// `comparator` functor owned by this object.
3151 const COMPARATOR& originalComparator() const;
3152
3153 /// Return a reference offering non-modifiable access to the `hasher`
3154 /// functor owned by this object.
3155 const HASHER& originalHasher() const;
3156};
3157
3158// ============================================================================
3159// TEMPLATE AND INLINE FUNCTION DEFINITIONS
3160// ============================================================================
3161
3162 // ---------------------------
3163 // class HashTable_HashWrapper
3164 // ---------------------------
3165
3166template <class FUNCTOR>
3167inline
3172
3173template <class FUNCTOR>
3174inline
3176: d_functor(fn)
3177{
3178}
3179
3180template <class FUNCTOR>
3181template <class ARG_TYPE>
3182inline
3183std::size_t
3185{
3186 return d_functor(arg);
3187}
3188
3189template <class FUNCTOR>
3190inline
3192{
3193 return d_functor;
3194}
3195
3196template <class FUNCTOR>
3197inline
3199{
3200 using std::swap;
3201 swap(d_functor, other.d_functor);
3202}
3203
3204 // 'const FUNCTOR' partial specialization
3205
3206template <class FUNCTOR>
3207inline
3209: d_functor()
3210{
3211}
3212
3213template <class FUNCTOR>
3214inline
3216: d_functor(fn)
3217{
3218}
3219
3220template <class FUNCTOR>
3221template <class ARG_TYPE>
3222inline
3223std::size_t
3225{
3226 return d_functor(arg);
3227}
3228
3229template <class FUNCTOR>
3230inline
3232{
3233 return d_functor;
3234}
3235
3236 // 'FUNCTOR &' partial specialization
3237
3238template <class FUNCTOR>
3239inline
3241: d_functor(fn)
3242{
3243}
3244
3245template <class FUNCTOR>
3246template <class ARG_TYPE>
3247inline
3248std::size_t
3250{
3251 return d_functor(arg);
3252}
3253
3254template <class FUNCTOR>
3255inline
3257{
3258 return d_functor;
3259}
3260
3261 // ---------------------------------
3262 // class HashTable_ComparatorWrapper
3263 // ---------------------------------
3264
3265template <class FUNCTOR>
3266inline
3271
3272template <class FUNCTOR>
3273inline
3275HashTable_ComparatorWrapper(const FUNCTOR& fn)
3276: d_functor(fn)
3277{
3278}
3279
3280template <class FUNCTOR>
3281template <class ARG1_TYPE, class ARG2_TYPE>
3282inline
3283bool
3285 ARG2_TYPE& arg2) const
3286{
3287 return d_functor(arg1, arg2);
3288}
3289
3290template <class FUNCTOR>
3292{
3293 return d_functor;
3294}
3295
3296template <class FUNCTOR>
3297inline
3298void
3300{
3301 using std::swap;
3302 swap(d_functor, other.d_functor);
3303}
3304
3305 // 'const FUNCTOR' partial specialization
3306
3307template <class FUNCTOR>
3308inline
3310: d_functor()
3311{
3312}
3313
3314template <class FUNCTOR>
3315inline
3317HashTable_ComparatorWrapper(const FUNCTOR& fn)
3318: d_functor(fn)
3319{
3320}
3321
3322template <class FUNCTOR>
3323template <class ARG1_TYPE, class ARG2_TYPE>
3324inline
3325bool
3327 ARG2_TYPE& arg2) const
3328{
3329 return d_functor(arg1, arg2);
3330}
3331
3332template <class FUNCTOR>
3334{
3335 return d_functor;
3336}
3337
3338 // 'FUNCTOR &' partial specialization
3339
3340template <class FUNCTOR>
3341inline
3343HashTable_ComparatorWrapper(FUNCTOR& fn)
3344: d_functor(fn)
3345{
3346}
3347
3348template <class FUNCTOR>
3349template <class ARG1_TYPE, class ARG2_TYPE>
3350inline
3351bool
3353 ARG2_TYPE& arg2) const
3354{
3355 return d_functor(arg1, arg2);
3356}
3357
3358template <class FUNCTOR>
3359inline
3361{
3362 return d_functor;
3363}
3364
3365 // ---------------------------
3366 // class HashTable_NodeProctor
3367 // ---------------------------
3368
3369// CREATORS
3370template <class FACTORY>
3371inline
3373 FACTORY *factory,
3375: d_factory_p(factory)
3376, d_node_p(node)
3377{
3378 BSLS_ASSERT_SAFE(factory);
3379}
3380
3381template <class FACTORY>
3382inline
3384{
3385 if (d_node_p) {
3386 d_factory_p->deleteNode(d_node_p);
3387 }
3388}
3389
3390// MANIPULATORS
3391template <class FACTORY>
3392inline
3394{
3395 d_node_p = 0;
3396}
3397
3398 // ----------------------------
3399 // class HashTable_ArrayProctor
3400 // ----------------------------
3401
3402// CREATORS
3403template <class FACTORY>
3404inline
3406 FACTORY *factory,
3408: d_factory_p(factory)
3409, d_anchor_p(anchor)
3410{
3411 BSLS_ASSERT_SAFE(factory);
3412 BSLS_ASSERT_SAFE(anchor);
3413}
3414
3415template <class FACTORY>
3416inline
3418{
3419 if (d_anchor_p) {
3420 HashTable_Util::destroyBucketArray(d_anchor_p->bucketArrayAddress(),
3421 d_anchor_p->bucketArraySize(),
3422 d_factory_p->allocator());
3423
3424 bslalg::BidirectionalLink *root = d_anchor_p->listRootAddress();
3425 while (root) {
3426 bslalg::BidirectionalLink *next = root->nextLink();
3427 d_factory_p->deleteNode(root);
3428 root = next;
3429 }
3430 }
3431}
3432
3433// MANIPULATORS
3434template <class FACTORY>
3435inline
3437{
3438 d_anchor_p = 0;
3439}
3440
3441 // --------------------
3442 // class HashTable_Util
3443 // --------------------
3444
3445template <class TYPE>
3446inline
3450
3451template <class TYPE>
3452inline
3454{
3455 // silence "unused parameter" warning in release builds:
3456 (void) ptr;
3457 BSLS_ASSERT(ptr);
3458}
3459
3460template <class TYPE>
3461inline
3463{
3464 // silence "unused parameter" warning in release builds:
3465 (void) ptr;
3466 BSLS_ASSERT(ptr);
3467}
3468
3469template <class ALLOCATOR>
3470inline
3473 std::size_t bucketArraySize,
3474 const ALLOCATOR& allocator)
3475{
3476 BSLS_ASSERT_SAFE(data);
3478 (1 < bucketArraySize
3480 || (1 == bucketArraySize
3482
3483#ifdef BSLS_ASSERT_SAFE_IS_ACTIVE
3484 typedef typename bsl::allocator_traits<ALLOCATOR>::size_type AllocSizeType;
3486 bucketArraySize <= std::numeric_limits<AllocSizeType>::max());
3487#endif
3488
3491 bucketArraySize);
3492 }
3493}
3494
3495template <class ALLOCATOR>
3496inline
3498 std::size_t bucketArraySize,
3499 const ALLOCATOR& allocator)
3500{
3501 BSLS_ASSERT_SAFE(anchor);
3502 BSLS_ASSERT_SAFE(0 != bucketArraySize);
3503
3504#ifdef BSLS_ASSERT_SAFE_IS_ACTIVE
3505 typedef typename bsl::allocator_traits<ALLOCATOR>::size_type AllocSizeType;
3507 bucketArraySize <= std::numeric_limits<AllocSizeType>::max());
3508#endif
3509
3510 typedef bslalg::HashTableBucket Bucket;
3511 Bucket *data = bslma::AllocatorUtil::allocateObject<Bucket>(allocator,
3512 bucketArraySize);
3513
3514 std::fill_n(data, bucketArraySize, Bucket());
3515
3516 anchor->setBucketArrayAddressAndSize(data, bucketArraySize);
3517}
3518
3519 //-------------------------------
3520 // class HashTable_ImplParameters
3521 //-------------------------------
3522
3523// CREATORS
3524template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3525inline
3527HashTable_ImplParameters(const ALLOCATOR& allocator)
3528: BaseHasher()
3529, BaseComparator()
3530, d_nodeFactory(allocator)
3531{
3532}
3533
3534template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3535inline
3537HashTable_ImplParameters(const HASHER& hash,
3538 const COMPARATOR& compare,
3539 const ALLOCATOR& allocator)
3540: BaseHasher(hash)
3541, BaseComparator(compare)
3542, d_nodeFactory(allocator)
3543{
3544}
3545
3546template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3547inline
3550 const ALLOCATOR& allocator)
3551: BaseHasher(static_cast<const BaseHasher&>(original))
3552, BaseComparator(static_cast<const BaseComparator&>(original))
3553, d_nodeFactory(allocator)
3554{
3555}
3556
3557template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3558inline
3561: BaseHasher(static_cast<const BaseHasher&>(original))
3562, BaseComparator(static_cast<const BaseComparator&>(original))
3563, d_nodeFactory(MoveUtil::move(MoveUtil::access(original).d_nodeFactory))
3564{
3565}
3566
3567// MANIPULATORS
3568template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3569inline
3570typename HashTable_ImplParameters<KEY_CONFIG,
3571 HASHER,
3572 COMPARATOR,
3573 ALLOCATOR>::NodeFactory &
3579
3580template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3581inline
3584{
3585 BSLS_ASSERT_SAFE(other);
3586
3587 using std::swap;
3588 swap(*static_cast<BaseHasher*>(this), *static_cast<BaseHasher*>(other));
3589
3590 swap(*static_cast<BaseComparator*>(this),
3591 *static_cast<BaseComparator*>(other));
3592
3593 nodeFactory().swapExchangeAllocators(other->nodeFactory());
3594}
3595
3596template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3597inline
3600{
3601 BSLS_ASSERT_SAFE(other);
3602
3603 using std::swap;
3604 swap(*static_cast<BaseHasher*>(this), *static_cast<BaseHasher*>(other));
3605
3606 swap(*static_cast<BaseComparator*>(this),
3607 *static_cast<BaseComparator*>(other));
3608
3609 nodeFactory().swapRetainAllocators(other->nodeFactory());
3610}
3611
3612// ACCESSORS
3613template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3614inline
3615const typename HashTable_ImplParameters<KEY_CONFIG,
3616 HASHER,
3617 COMPARATOR,
3618 ALLOCATOR>::BaseComparator &
3624
3625template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3626template <class DEDUCED_KEY>
3627inline
3628std::size_t HashTable_ImplParameters<KEY_CONFIG,
3629 HASHER,
3630 COMPARATOR,
3631 ALLOCATOR>::
3632hashCodeForKey(DEDUCED_KEY& key) const
3633{
3634 return static_cast<const BaseHasher &>(*this)(key);
3635}
3636
3637template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3638inline
3639const typename HashTable_ImplParameters<KEY_CONFIG,
3640 HASHER,
3641 COMPARATOR,
3642 ALLOCATOR>::BaseHasher &
3648
3649template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3650inline
3651const typename HashTable_ImplParameters<KEY_CONFIG,
3652 HASHER,
3653 COMPARATOR,
3654 ALLOCATOR>::NodeFactory &
3660
3661template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3662inline
3663const COMPARATOR&
3664HashTable_ImplParameters<KEY_CONFIG,
3665 HASHER,
3666 COMPARATOR,
3667 ALLOCATOR>::originalComparator() const
3668{
3669 return static_cast<const BaseComparator *>(this)->functor();
3670}
3671
3672template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3673inline
3674const HASHER& HashTable_ImplParameters<KEY_CONFIG,
3675 HASHER,
3676 COMPARATOR,
3677 ALLOCATOR>::originalHasher() const
3678{
3679 return static_cast<const BaseHasher *>(this)->functor();
3680}
3681
3682 //----------------
3683 // class HashTable
3684 //----------------
3685
3686// CREATORS
3687template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3688inline
3690HashTable(const ALLOCATOR& basicAllocator)
3691: d_parameters(basicAllocator)
3692, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3693, d_size()
3694, d_capacity()
3695, d_maxLoadFactor(1.0)
3696{
3699}
3700
3701template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3702inline
3704HashTable(const HASHER& hash,
3705 const COMPARATOR& compare,
3706 SizeType initialNumBuckets,
3707 float initialMaxLoadFactor,
3708 const ALLOCATOR& basicAllocator)
3709: d_parameters(hash, compare, basicAllocator)
3710, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3711, d_size()
3712, d_capacity(0)
3713, d_maxLoadFactor(initialMaxLoadFactor)
3714{
3715 BSLS_ASSERT_SAFE(0.0f < initialMaxLoadFactor);
3716
3719 }
3722 }
3723
3724 if (0 != initialNumBuckets) {
3725 size_t capacity; // This may be a different type than SizeType.
3727 &capacity,
3728 1,
3729 static_cast<size_t>(initialNumBuckets),
3730 d_maxLoadFactor);
3731 HashTable_Util::initAnchor(&d_anchor, numBuckets, basicAllocator);
3732 d_capacity = static_cast<SizeType>(capacity);
3733 }
3734}
3735
3736template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3737inline
3739HashTable(const HashTable& original)
3740: d_parameters(
3741 original.d_parameters,
3742 AllocatorTraits::select_on_container_copy_construction(original.allocator()))
3743, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3744, d_size(original.d_size)
3745, d_capacity(0)
3746, d_maxLoadFactor(original.d_maxLoadFactor)
3747{
3748 if (0 < d_size) {
3749 d_parameters.nodeFactory().reserveNodes(original.d_size);
3750 this->copyDataStructure(original.d_anchor.listRootAddress());
3751 }
3752}
3753
3754template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3755inline
3757 BloombergLP::bslmf::MovableRef<HashTable> original)
3758: d_parameters(MoveUtil::move(MoveUtil::access(original).d_parameters))
3759, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3760, d_size()
3761, d_capacity()
3762, d_maxLoadFactor(1.0)
3763{
3764 HashTable& lvalue = original;
3765 using std::swap;
3766 swap(d_anchor, lvalue.d_anchor);
3767 swap(d_size, lvalue.d_size);
3768 swap(d_capacity, lvalue.d_capacity);
3769 swap(d_maxLoadFactor, lvalue.d_maxLoadFactor);
3770}
3771
3772template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3773inline
3775HashTable(const HashTable& original, const ALLOCATOR& basicAllocator)
3776: d_parameters(original.d_parameters, basicAllocator)
3777, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3778, d_size(original.d_size)
3779, d_capacity(0)
3780, d_maxLoadFactor(original.d_maxLoadFactor)
3781{
3782 if (0 < d_size) {
3783 d_parameters.nodeFactory().reserveNodes(original.d_size);
3784 this->copyDataStructure(original.d_anchor.listRootAddress());
3785 }
3786}
3787
3788template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3791 const ALLOCATOR& basicAllocator)
3792: d_parameters(MoveUtil::access(original).d_parameters.originalHasher(),
3793 MoveUtil::access(original).d_parameters.originalComparator(),
3794 basicAllocator)
3795, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3796, d_size()
3797, d_capacity()
3798, d_maxLoadFactor(1.0)
3799{
3800 HashTable& lvalue = original;
3802 basicAllocator == lvalue.allocator())) {
3803 d_parameters.nodeFactory().adopt(
3804 MoveUtil::move(lvalue.d_parameters.nodeFactory()));
3805 using std::swap;
3806 swap(d_anchor, lvalue.d_anchor);
3807 swap(d_size, lvalue.d_size);
3808 swap(d_capacity, lvalue.d_capacity);
3809 swap(d_maxLoadFactor, lvalue.d_maxLoadFactor);
3810 }
3811 else {
3812 d_size = lvalue.d_size;
3813 d_maxLoadFactor = lvalue.d_maxLoadFactor;
3814 if (0 < d_size) {
3815 // 'original' left in the default state
3818 using std::swap;
3819 swap(anchor, lvalue.d_anchor);
3820
3821 lvalue.d_size = 0;
3822 lvalue.d_capacity = 0;
3823 lvalue.d_maxLoadFactor = 1.0f;
3824
3825 HashTable_ArrayProctor<typename ImplParameters::NodeFactory>
3826 arrayProctor(&lvalue.d_parameters.nodeFactory(),
3827 &anchor);
3828
3829 d_parameters.nodeFactory().reserveNodes(d_size);
3830 this->moveDataStructure(anchor.listRootAddress());
3831
3832 // 'arrayProctor' will care of deleting the nodes
3833 }
3834 }
3835}
3836
3837template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3838inline
3840{
3841#if defined(BDE_BUILD_TARGET_SAFE_2)
3842 // ASSERT class invariant only in SAFE_2 builds. Note that we specifically
3843 // use the MallocFree allocator, rather than allowing the default allocator
3844 // to supply memory to this state-checking function, in case the object
3845 // allocator *is* the default allocator, and so may be restricted during
3846 // testing. This would cause the test below to fail by throwing a bad
3847 // allocation exception, and so result in a throwing destructor. While the
3848 // MallocFree allocator might also run out of resources, that is not the
3849 // kind of catastrophic failure we are concerned with handling in an
3850 // invariant check that runs only in SAFE_2 builds from a destructor.
3851
3852 BSLS_ASSERT_SAFE(bslalg::HashTableImpUtil::isWellFormed<KEY_CONFIG>(
3853 this->d_anchor,
3854 this->d_parameters.hasher(),
3856#endif
3857
3858 this->removeAllAndDeallocate();
3859}
3860
3861// PRIVATE MANIPULATORS
3862template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3863void
3866{
3867 BSLS_ASSERT(0 != cursor);
3868 BSLS_ASSERT(0 < d_size);
3869
3870 // This function will completely replace 'this->d_anchor's state. It is
3871 // the caller's responsibility to ensure this will not leak resources owned
3872 // only by the previous state, such as the linked list.
3873
3874 // Allocate an appropriate number of buckets
3875
3876 size_t capacity;
3878 &capacity,
3879 static_cast<size_t>(d_size),
3880 2,
3881 d_maxLoadFactor);
3882
3883 d_anchor.setListRootAddress(0);
3884 HashTable_Util::initAnchor(&d_anchor, numBuckets, this->allocator());
3885
3886 // create a proctor for d_anchor's allocated array, and the list to follow.
3887
3889 arrayProctor(&d_parameters.nodeFactory(), &d_anchor);
3890
3891 d_capacity = static_cast<SizeType>(capacity);
3892
3893 do {
3894 // Computing hash code depends on user-supplied code, and may throw.
3895 // Therefore, obtain the hash code from the node we are about to copy,
3896 // before any memory is allocated, so there is no risk of leaking an
3897 // object. The hash code must be the same for both elements.
3898
3899 size_t hashCode = this->hashCodeForNode(cursor);
3900 bslalg::BidirectionalLink *newNode =
3901 d_parameters.nodeFactory().cloneNode(*cursor);
3902
3904 newNode,
3905 hashCode);
3906 }
3907 while (0 != (cursor = cursor->nextLink()));
3908
3909 // release the proctor
3910
3911 arrayProctor.release();
3912}
3913
3914template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3915void
3916HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::moveDataStructure(
3918{
3919 BSLS_ASSERT(0 != cursor);
3920 BSLS_ASSERT(0 < d_size);
3921
3922 // This function will completely replace 'this->d_anchor's state. It is
3923 // the caller's responsibility to ensure this will not leak resources owned
3924 // only by the previous state, such as the linked list.
3925
3926 // Allocate an appropriate number of buckets
3927
3928 size_t capacity;
3930 &capacity,
3931 static_cast<size_t>(d_size),
3932 2,
3933 d_maxLoadFactor);
3934
3935 d_anchor.setListRootAddress(0);
3936 HashTable_Util::initAnchor(&d_anchor, numBuckets, this->allocator());
3937
3938 d_capacity = static_cast<SizeType>(capacity);
3939
3940 // create a proctor for d_anchor's allocated array, and the list to follow.
3941
3942 HashTable_ArrayProctor<typename ImplParameters::NodeFactory>
3943 arrayProctor(&d_parameters.nodeFactory(), &d_anchor);
3944
3945 do {
3946 // Computing hash code depends on user-supplied code, and may throw.
3947 // Therefore, obtain the hash code from the node we are about to copy,
3948 // before any memory is allocated, so there is no risk of leaking an
3949 // object. The hash code must be the same for both elements.
3950
3951 size_t hashCode = this->hashCodeForNode(cursor);
3952 bslalg::BidirectionalLink *newNode =
3953 d_parameters.nodeFactory().moveIntoNewNode(cursor);
3954
3956 newNode,
3957 hashCode);
3958 }
3959 while (0 != (cursor = cursor->nextLink()));
3960
3961 // release the proctor
3962
3963 arrayProctor.release();
3964}
3965
3966template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3967void
3968HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::
3969quickSwapExchangeAllocators(HashTable *other)
3970{
3971 BSLS_ASSERT_SAFE(other);
3972
3973 d_parameters.quickSwapExchangeAllocators(&other->d_parameters);
3974
3975 using std::swap;
3976 swap(d_anchor, other->d_anchor);
3977 swap(d_size, other->d_size);
3978 swap(d_capacity, other->d_capacity);
3979 swap(d_maxLoadFactor, other->d_maxLoadFactor);
3980}
3981
3982template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3983void
3984HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::
3985quickSwapRetainAllocators(HashTable *other)
3986{
3987 BSLS_ASSERT_SAFE(other);
3988 BSLS_ASSERT_SAFE(this->allocator() == other->allocator());
3989
3990 d_parameters.quickSwapRetainAllocators(&other->d_parameters);
3991
3992 using std::swap;
3993 swap(d_anchor, other->d_anchor);
3994 swap(d_size, other->d_size);
3995 swap(d_capacity, other->d_capacity);
3996 swap(d_maxLoadFactor, other->d_maxLoadFactor);
3997}
3998
3999template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4000void
4001HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::
4002rehashIntoExactlyNumBuckets(SizeType newNumBuckets, SizeType capacity)
4003{
4004 /// An object of this proctor class guarantees that, if an exception is
4005 /// thrown by a user-supplied hash functor, the container remains in a
4006 /// valid, usable (but unspecified) state. In fact, that state will be
4007 /// empty, as there is no reliable way to re-index a bucket array if the
4008 /// hash functor is throwing, and the array is potentially corrupted
4009 /// following a failed ImpUtil::rehash call.
4010 ///
4011 /// See @ref bslstl_hashtable
4012 class Proctor {
4013
4014 private:
4015 HashTable *d_table_p;
4016 bslalg::HashTableAnchor *d_originalAnchor_p;
4017 bslalg::HashTableAnchor *d_newAnchor_p;
4018
4019#if !defined(BSLS_PLATFORM_CMP_MSVC)
4020 // Microsoft warns if these methods are declared private.
4021
4022 private:
4023 // NOT IMPLEMENTED
4024 Proctor(const Proctor&); // = delete;
4025 Proctor& operator=(const Proctor&); // = delete;
4026#endif
4027
4028 public:
4029 // CREATORS
4030 Proctor(HashTable *table,
4031 bslalg::HashTableAnchor *originalAnchor,
4032 bslalg::HashTableAnchor *newAnchor)
4033 : d_table_p(table)
4034 , d_originalAnchor_p(originalAnchor)
4035 , d_newAnchor_p(newAnchor)
4036 {
4037 BSLS_ASSERT_SAFE(table);
4038 BSLS_ASSERT_SAFE(originalAnchor);
4039 BSLS_ASSERT_SAFE(newAnchor);
4040 }
4041
4042 ~Proctor()
4043 {
4044 if (d_originalAnchor_p) {
4045 // Not dismissed, and the newAnchor now holds the correct
4046 // list-root.
4047
4048 d_originalAnchor_p->setListRootAddress(
4049 d_newAnchor_p->listRootAddress());
4050 d_table_p->removeAll();
4051 }
4052
4053 // Always destroy the spare anchor's bucket array at the end of
4054 // scope. On a non-exceptional run, this will effectively be the
4055 // original bucket-array, as the anchors are swapped.
4056
4057 HashTable_Util::destroyBucketArray(
4058 d_newAnchor_p->bucketArrayAddress(),
4059 d_newAnchor_p->bucketArraySize(),
4060 d_table_p->allocator());
4061 }
4062
4063 // MANIPULATORS
4064 void dismiss()
4065 {
4066 d_originalAnchor_p = 0;
4067 }
4068 };
4069
4070 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4071
4072 // Now that 'anchor' is not default constructible, we take a copy of the
4073 // anchor in the table. Would it be better for 'initAnchor' to be replaced
4074 // with a 'createArrayOfEmptyBuckets' function, and we use the result to
4075 // construct the 'newAnchor'?
4076
4077 bslalg::HashTableAnchor newAnchor(0, 0, 0);
4078 HashTable_Util::initAnchor(&newAnchor,
4079 static_cast<size_t>(newNumBuckets),
4080 this->allocator());
4081
4082 Proctor cleanUpIfUserHashThrows(this, &d_anchor, &newAnchor);
4083
4084 if (d_anchor.listRootAddress()) {
4085 bslalg::HashTableImpUtil::rehash<KEY_CONFIG>(
4086 &newAnchor,
4087 this->d_anchor.listRootAddress(),
4088 this->d_parameters.hasher());
4089 }
4090
4091 cleanUpIfUserHashThrows.dismiss();
4092
4093 d_anchor.swap(newAnchor);
4094 d_capacity = capacity;
4095}
4096
4097template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4098inline
4099void
4100HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::removeAllAndDeallocate()
4101{
4102 this->removeAllImp();
4104 d_anchor.bucketArraySize(),
4105 this->allocator());
4106}
4107
4108template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4109void
4110HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::removeAllImp()
4111{
4112 typedef bslalg::BidirectionalLink BidirectionalLink;
4113
4114 // Doing too much book-keeping of hash table - look for a more efficient
4115 // dispose-as-we-walk, that simply resets table.Anchor.next = 0, and
4116 // assigns the buckets index all null pointers
4117
4118 if (BidirectionalLink *root = d_anchor.listRootAddress()) {
4119 BidirectionalLink *next;
4120 do {
4121 next = root->nextLink();
4122 d_parameters.nodeFactory().deleteNode(
4123 static_cast<NodeType *>(root));
4124 }
4125 while(0 != (root = next));
4126 }
4127}
4128
4129// PRIVATE ACCESSORS
4130template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4131template <class DEDUCED_KEY>
4132inline
4134HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::find(
4135 DEDUCED_KEY& key,
4136 std::size_t hashValue) const
4137{
4138 return bslalg::HashTableImpUtil::find<KEY_CONFIG>(
4139 d_anchor,
4140 key,
4141 d_parameters.comparator(),
4142 hashValue);
4143}
4144
4145template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4146inline
4148HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::getBucketAddress(
4149 SizeType bucketIndex) const
4150{
4151 BSLS_ASSERT_SAFE(bucketIndex < this->numBuckets());
4152
4153 return d_anchor.bucketArrayAddress() + bucketIndex;
4154}
4155
4156template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4157inline
4158std::size_t
4159HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::hashCodeForNode(
4160 bslalg::BidirectionalLink *node) const
4161{
4162 BSLS_ASSERT_SAFE(node);
4163
4164 return d_parameters.hashCodeForKey(
4165 bslalg::HashTableImpUtil::extractKey<KEY_CONFIG>(node));
4166}
4167
4168// MANIPULATORS
4169template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4170inline
4171HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>&
4173 const HashTable& rhs)
4174{
4175 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(this != &rhs)) {
4176
4177 if (AllocatorTraits::propagate_on_container_copy_assignment::value) {
4178 HashTable other(rhs, rhs.allocator());
4179 quickSwapExchangeAllocators(&other);
4180 }
4181 else {
4182 HashTable other(rhs, this->allocator());
4183 quickSwapRetainAllocators(&other);
4184 }
4185 }
4186 return *this;
4187}
4188
4189template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4190inline
4194{
4195 HashTable& lvalue = rhs;
4196 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(this != &lvalue)) {
4197 if (allocator() == lvalue.allocator()) {
4198 HashTable other(MoveUtil::move(lvalue));
4199 quickSwapRetainAllocators(&other);
4200 }
4201 else if (
4202 AllocatorTraits::propagate_on_container_move_assignment::value) {
4203 HashTable other(MoveUtil::move(lvalue));
4204 quickSwapExchangeAllocators(&other);
4205 }
4206 else {
4207 HashTable other(MoveUtil::move(lvalue), allocator());
4208 quickSwapRetainAllocators(&other);
4209 }
4210 }
4211 return *this;
4212}
4213
4214#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
4215template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4216template <class... ARGS>
4219 ARGS&&... arguments)
4220{
4221 typedef bslalg::HashTableImpUtil ImpUtil;
4222
4223 // Rehash (if appropriate) first as it will reduce load factor and so
4224 // potentially improve the 'find' time.
4225
4226 if (d_size >= d_capacity) {
4227 this->rehashForNumBuckets(numBuckets() * 2);
4228 }
4229
4230 // Next we must create the node from the constructor arguments provided.
4231
4232 bslalg::BidirectionalLink *newNode =
4233 d_parameters.nodeFactory().emplaceIntoNewNode(
4234 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
4235
4236 // This node needs wrapping in a proctor, in case either of the user-
4237 // supplied functors throws an exception.
4238
4240 nodeProctor(&d_parameters.nodeFactory(), newNode);
4241
4242 // Now we can search for the node in the table, being careful to compute
4243 // the hash value only once.
4244
4245 size_t hashCode = this->d_parameters.hashCodeForKey(
4246 ImpUtil::extractKey<KEY_CONFIG>(newNode));
4247 bslalg::BidirectionalLink *position = this->find(
4248 ImpUtil::extractKey<KEY_CONFIG>(newNode),
4249 hashCode);
4250
4251 if (!position) {
4252 ImpUtil::insertAtFrontOfBucket(&d_anchor, newNode, hashCode);
4253 }
4254 else {
4255 ImpUtil::insertAtPosition(&d_anchor, newNode, hashCode, position);
4256 }
4257 nodeProctor.release();
4258
4259 ++d_size;
4260
4261 return newNode;
4262}
4263
4264template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4265template <class... ARGS>
4269 ARGS&&... arguments)
4270{
4271 typedef bslalg::HashTableImpUtil ImpUtil;
4272
4273 // Rehash (if appropriate) first as it will reduce load factor and so
4274 // potentially improve the potential 'find' time later.
4275
4276 if (d_size >= d_capacity) {
4277 this->rehashForNumBuckets(numBuckets() * 2);
4278 }
4279
4280 // Next we must create the node from the constructor arguments provided.
4281
4282 bslalg::BidirectionalLink *newNode =
4283 d_parameters.nodeFactory().emplaceIntoNewNode(
4284 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
4285
4286 // There is potential for the user-supplied hasher and comparator to throw,
4287 // so now we need to manage our 'newNode' with a proctor.
4288
4290 nodeProctor(&d_parameters.nodeFactory(), newNode);
4291
4292 // Insert logic, first test the hint
4293
4294 size_t hashCode = this->d_parameters.hashCodeForKey(
4295 ImpUtil::extractKey<KEY_CONFIG>(newNode));
4296 if (!hint
4297 || !d_parameters.comparator()(ImpUtil::extractKey<KEY_CONFIG>(newNode),
4298 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
4299 hint = this->find(ImpUtil::extractKey<KEY_CONFIG>(newNode), hashCode);
4300 }
4301
4302 if (!hint) {
4303 ImpUtil::insertAtFrontOfBucket(&d_anchor, newNode, hashCode);
4304 }
4305 else {
4306 ImpUtil::insertAtPosition(&d_anchor, newNode, hashCode, hint);
4307 }
4308 nodeProctor.release();
4309
4310 ++d_size;
4311
4312 return newNode;
4313}
4314
4315template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4316template <class... ARGS>
4319 bool *isInsertedFlag,
4320 ARGS&&... arguments)
4321{
4322 BSLS_ASSERT(isInsertedFlag);
4323
4324 typedef bslalg::HashTableImpUtil ImpUtil;
4325
4326 // Rehash (if appropriate) first as it will reduce load factor and so
4327 // potentially improve the potential 'find' time later.
4328
4329 if (d_size >= d_capacity) {
4330 this->rehashForNumBuckets(numBuckets() * 2);
4331 }
4332
4333 // Next we must create the node from the constructor arguments provided.
4334
4335 bslalg::BidirectionalLink *newNode =
4336 d_parameters.nodeFactory().emplaceIntoNewNode(
4337 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
4338
4339 // There is potential for the user-supplied hasher and comparator to throw,
4340 // so now we need to manage our 'newNode' with a proctor.
4341
4343 nodeProctor(&d_parameters.nodeFactory(), newNode);
4344
4345 // Insert logic, first test the hint
4346
4347 size_t hashCode = this->d_parameters.hashCodeForKey(
4348 ImpUtil::extractKey<KEY_CONFIG>(newNode));
4349 bslalg::BidirectionalLink *position = this->find(
4350 ImpUtil::extractKey<KEY_CONFIG>(newNode),
4351 hashCode);
4352
4353 *isInsertedFlag = (!position);
4354
4355 if(!position) {
4356 if (d_size >= d_capacity) {
4357 this->rehashForNumBuckets(numBuckets() * 2);
4358 }
4359
4360 ImpUtil::insertAtFrontOfBucket(&d_anchor, newNode, hashCode);
4361 nodeProctor.release();
4362
4363 ++d_size;
4364 position = newNode;
4365 }
4366
4367 return position;
4368}
4369#endif
4370
4371template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4374 const KeyType& key)
4375{
4376 bool dummy = false;
4377 return tryEmplace(&dummy, (bslalg::BidirectionalLink*)0, key);
4378}
4379
4380template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4384{
4385 bool dummy = false;
4386 return tryEmplace(&dummy,
4388 MoveUtil::move(key));
4389}
4390
4391template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4394 bool *isInsertedFlag,
4395 const ValueType& value)
4396{
4397 BSLS_ASSERT(isInsertedFlag);
4398
4399 size_t hashCode = this->d_parameters.hashCodeForKey(
4400 KEY_CONFIG::extractKey(value));
4401 bslalg::BidirectionalLink *position = this->find(
4402 KEY_CONFIG::extractKey(value),
4403 hashCode);
4404
4405 *isInsertedFlag = (!position);
4406
4407 if(!position) {
4408 if (d_size >= d_capacity) {
4409 this->rehashForNumBuckets(numBuckets() * 2);
4410 }
4411
4412 position = d_parameters.nodeFactory().emplaceIntoNewNode(value);
4414 position,
4415 hashCode);
4416 ++d_size;
4417 }
4418
4419 return position;
4420}
4421
4422template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4425 bool *isInsertedFlag,
4427{
4428 ValueType& lvalue = value;
4429
4430 BSLS_ASSERT(isInsertedFlag);
4431
4432 size_t hashCode = this->d_parameters.hashCodeForKey(
4433 KEY_CONFIG::extractKey(lvalue));
4434 bslalg::BidirectionalLink *position = this->find(
4435 KEY_CONFIG::extractKey(lvalue),
4436 hashCode);
4437
4438 *isInsertedFlag = (!position);
4439
4440 if(!position) {
4441 if (d_size >= d_capacity) {
4442 this->rehashForNumBuckets(numBuckets() * 2);
4443 }
4444
4445 position = d_parameters.nodeFactory().emplaceIntoNewNode(
4446 MoveUtil::move(lvalue));
4448 position,
4449 hashCode);
4450 ++d_size;
4451 }
4452
4453 return position;
4454}
4455
4456template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4457template <class SOURCE_TYPE>
4458inline
4461 bool *isInsertedFlag,
4462 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value)
4463{
4464 BSLS_ASSERT(isInsertedFlag);
4465
4466 return emplaceIfMissing(isInsertedFlag,
4467 BSLS_COMPILERFEATURES_FORWARD(SOURCE_TYPE, value));
4468
4469}
4470
4471template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4472template <class SOURCE_TYPE>
4473inline
4480
4481template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4482template <class SOURCE_TYPE>
4483inline
4486 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value,
4488{
4489 return emplaceWithHint(hint,
4490 BSLS_COMPILERFEATURES_FORWARD(SOURCE_TYPE, value));
4491}
4492
4493#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
4494template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4495template <class KEY_ARG, class BDE_OTHER_TYPE>
4498 bool *isInsertedFlag,
4501 BDE_OTHER_TYPE&& obj)
4502{
4503 typedef bslalg::HashTableImpUtil ImpUtil;
4504
4505 const KEY_ARG& lvalue = key;
4506 size_t hashCode = this->d_parameters.hashCodeForKey(lvalue);
4507 // Use the hint, if we can
4508 if (!hint
4509 || !d_parameters.comparator()(lvalue,
4510 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
4511 hint = this->find(lvalue, hashCode);
4512 }
4513
4514 if (hint) { // assign
4515 static_cast<NodeType *>(hint)->value().second =
4516 BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, obj);
4517 *isInsertedFlag = false;
4518 return hint; // RETURN
4519 }
4520
4521 // insert
4522 if (d_size >= d_capacity) {
4523 this->rehashForNumBuckets(numBuckets() * 2);
4524 }
4525
4526 // Make a new node
4527 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
4528 BSLS_COMPILERFEATURES_FORWARD(KEY_ARG, key),
4529 BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, obj));
4530
4531 // Add it to the hash table
4533 nodeProctor(&d_parameters.nodeFactory(), hint);
4534 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
4535 nodeProctor.release();
4536 ++d_size;
4537
4538 *isInsertedFlag = true;
4539 return hint;
4540}
4541#endif
4542
4543template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4544void
4546 SizeType newNumBuckets)
4547{
4548 if (newNumBuckets > this->numBuckets()) {
4549 // Compute a "good" number of buckets, e.g., pick a prime number from a
4550 // sorted array of exponentially increasing primes.
4551
4552 size_t capacity;
4553 SizeType numBuckets = static_cast<SizeType>(
4555 &capacity,
4556 d_size + 1u,
4557 static_cast<size_t>(newNumBuckets),
4558 d_maxLoadFactor));
4559
4560 this->rehashIntoExactlyNumBuckets(numBuckets,
4561 static_cast<SizeType>(capacity));
4562 }
4563}
4564
4565template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4569{
4570 BSLS_ASSERT_SAFE(node);
4572 || d_anchor.listRootAddress() == node);
4573
4574 bslalg::BidirectionalLink *result = node->nextLink();
4575
4577 node,
4578 hashCodeForNode(node));
4579 --d_size;
4580
4581 d_parameters.nodeFactory().deleteNode(static_cast<NodeType *>(node));
4582
4583 return result;
4584}
4585
4586template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4587void
4589{
4590 this->removeAllImp();
4592 d_anchor.bucketArrayAddress()) {
4593 std::memset(d_anchor.bucketArrayAddress(),
4594 0,
4595 sizeof(bslalg::HashTableBucket) *
4596 d_anchor.bucketArraySize());
4597 }
4598
4599 d_anchor.setListRootAddress(0);
4600 d_size = 0;
4601}
4602
4603template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4604inline
4605void
4607 SizeType numElements)
4608{
4609 if (numElements < 1) { // Return avoids undefined behavior in node factory.
4610 return; // RETURN
4611 }
4612
4613 if (numElements > d_capacity) {
4614 // Compute a "good" number of buckets, e.g., pick a prime number from a
4615 // sorted array of exponentially increasing primes.
4616
4617 size_t capacity;
4618 SizeType numBuckets = static_cast<SizeType>(
4620 &capacity,
4621 numElements,
4622 static_cast<size_t>(this->numBuckets()),
4623 d_maxLoadFactor));
4624
4625 this->rehashIntoExactlyNumBuckets(numBuckets,
4626 static_cast<SizeType>(capacity));
4627 }
4628}
4629
4630template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4631inline
4633 float newMaxLoadFactor)
4634{
4635 BSLS_ASSERT_SAFE(0.0f < newMaxLoadFactor);
4636
4637 size_t capacity;
4638 SizeType numBuckets = static_cast<SizeType>(
4640 &capacity,
4641 std::max<SizeType>(d_size, 1u),
4642 static_cast<size_t>(this->numBuckets()),
4643 newMaxLoadFactor));
4644
4645 this->rehashIntoExactlyNumBuckets(numBuckets,
4646 static_cast<SizeType>(capacity));
4647
4648 // Always set this last, as there is potential to throw exceptions above.
4649
4650 d_maxLoadFactor = newMaxLoadFactor;
4651}
4652
4653template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4654void
4656{
4657 // This trait should perform 'if' at compile-time.
4658
4659 if (AllocatorTraits::propagate_on_container_swap::value) {
4660 quickSwapExchangeAllocators(&other);
4661 }
4662 else {
4663 // C++11 behavior: undefined for unequal allocators
4664 // BSLS_ASSERT(allocator() == other.allocator());
4665
4666 BSLS_ASSERT(d_parameters.nodeFactory().allocator() ==
4667 other.d_parameters.nodeFactory().allocator());
4668 quickSwapRetainAllocators(&other);
4669 }
4670}
4671
4672#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
4673template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4674template <class... ARGS>
4675inline
4678 bool *isInsertedFlag,
4680 const KeyType& key,
4681 ARGS&&... args)
4682{
4683 typedef bslalg::HashTableImpUtil ImpUtil;
4684
4685 const size_t hashCode = this->d_parameters.hashCodeForKey(key);
4686
4687 // Use the hint, if we can
4688 if (!hint
4689 || !d_parameters.comparator()(key,
4690 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
4691 hint = this->find(key, hashCode);
4692 }
4693
4694 // If the key exists, we're done
4695 if (hint) {
4696 *isInsertedFlag = false;
4697 return hint; // RETURN
4698 }
4699
4700 if (d_size >= d_capacity) {
4701 this->rehashForNumBuckets(numBuckets() * 2);
4702 }
4703
4704 // Make a new node
4705#if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR)
4706 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
4707 std::piecewise_construct,
4708 std::forward_as_tuple(key),
4709 std::forward_as_tuple(std::forward<ARGS>(args)...));
4710#else
4711 typedef typename ValueType::second_type MappedType;
4712
4713 // TBD: make 'this->allocator()' return the allocator by reference with
4714 // modifiable access rather than by value.
4715
4716 AllocatorType alloc = this->allocator();
4717
4718 bsls::ObjectBuffer<MappedType> defaultMapped;
4719 AllocatorTraits::construct(alloc, defaultMapped.address(),
4720 std::forward<ARGS>(args)...);
4721 bslma::DestructorGuard<MappedType> mappedGuard(defaultMapped.address());
4722
4723 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
4724 key,
4725 defaultMapped.object());
4726#endif
4727
4728 // Add it to the hash table
4730 nodeProctor(&d_parameters.nodeFactory(), hint);
4731 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
4732 nodeProctor.release();
4733 ++d_size;
4734
4735 *isInsertedFlag = true;
4736 return hint;
4737}
4738
4739
4740template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4741template <class... ARGS>
4742inline
4745 bool *isInsertedFlag,
4748 ARGS&&... args)
4749{
4750 typedef bslalg::HashTableImpUtil ImpUtil;
4751
4752 const KeyType& lvalue = key;
4753 const size_t hashCode = this->d_parameters.hashCodeForKey(key);
4754
4755 // Use the hint, if we can
4756 if (!hint
4757 || !d_parameters.comparator()(lvalue,
4758 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
4759 hint = this->find(lvalue, hashCode);
4760 }
4761
4762 // If the key exists, we're done
4763 if (hint) {
4764 *isInsertedFlag = false;
4765 return hint; // RETURN
4766 }
4767
4768 if (d_size >= d_capacity) {
4769 this->rehashForNumBuckets(numBuckets() * 2);
4770 }
4771
4772 // Make a new node
4773#if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR)
4774 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
4775 std::piecewise_construct,
4776 std::forward_as_tuple(MoveUtil::move(key)),
4777 std::forward_as_tuple(std::forward<ARGS>(args)...));
4778#else
4779 typedef typename ValueType::second_type MappedType;
4780
4781 // TBD: make 'this->allocator()' return the allocator by reference with
4782 // modifiable access rather than by value.
4783
4784 AllocatorType alloc = this->allocator();
4785
4786 bsls::ObjectBuffer<MappedType> defaultMapped;
4787 AllocatorTraits::construct(alloc, defaultMapped.address(),
4788 std::forward<ARGS>(args)...);
4789 bslma::DestructorGuard<MappedType> mappedGuard(defaultMapped.address());
4790
4791 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
4792 MoveUtil::move(key),
4793 defaultMapped.object());
4794#endif
4795
4796 // Add it to the hash table
4798 nodeProctor(&d_parameters.nodeFactory(), hint);
4799 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
4800 nodeProctor.release();
4801 ++d_size;
4802
4803 *isInsertedFlag = true;
4804 return hint;
4805}
4806#endif
4807
4808// ACCESSORS
4809template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4810inline
4812 allocator() const
4813{
4814 return d_parameters.nodeFactory().allocator();
4815}
4816
4817template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4818inline
4821 SizeType index) const
4822{
4823 BSLS_ASSERT_SAFE(index < this->numBuckets());
4824
4825 return d_anchor.bucketArrayAddress()[index];
4826}
4827
4828template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4829inline
4832 const KeyType& key) const
4833{
4834 typedef typename
4836
4837 // The following cast will not discard any useful bits, unless 'SizeType'
4838 // is larger than 'size_t', as the bucket computation takes a mod on the
4839 // supplied number of buckets. We use the following 'BSLMF_ASSERT' to
4840 // assert that assumption at compile time.
4841
4842 BSLMF_ASSERT(sizeof(SizeType) <= sizeof(size_t));
4843
4844 size_t hashCode = this->d_parameters.hashCodeForKey(key);
4846 hashCode,
4847 d_anchor.bucketArraySize()));
4848}
4849
4850template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4851inline
4852const COMPARATOR&
4857
4858template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4859inline
4862 SizeType index) const
4863{
4864 BSLS_ASSERT_SAFE(index < this->numBuckets());
4865
4866 return static_cast<SizeType>(bucketAtIndex(index).countElements());
4867}
4868
4869template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4870inline
4876
4877template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4878inline
4881 const KeyType& key) const
4882{
4883 return bslalg::HashTableImpUtil::find<KEY_CONFIG>(
4884 d_anchor,
4885 key,
4886 d_parameters.comparator(),
4887 d_parameters.hashCodeForKey(key));
4888}
4889
4890template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4893 bslalg::BidirectionalLink *first) const
4894{
4895 BSLS_ASSERT_SAFE(first);
4896
4897 typedef bslalg::HashTableImpUtil ImpUtil;
4898
4899 // The reference to the Key passed to the functor is only optionally
4900 // const-qualified. We must be sure to hold a reference with the correct
4901 // qualification.
4902
4903 typedef
4905 KeyRef;
4906 KeyRef k = ImpUtil::extractKey<KEY_CONFIG>(first);
4907
4908 while (0 != (first = first->nextLink()) &&
4909 d_parameters.comparator()(k,ImpUtil::extractKey<KEY_CONFIG>(first)))
4910 {
4911 // This loop body is intentionally left blank.
4912 }
4913 return first;
4914}
4915
4916template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4917inline
4918void
4922 const KeyType& key) const
4923{
4924 BSLS_ASSERT_SAFE(first);
4925 BSLS_ASSERT_SAFE(last);
4926
4927 *first = this->find(key);
4928 *last = *first ? this->findEndOfRange(*first) : 0;
4929}
4930
4931template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4932bool
4934 const HashTable& other) const
4935{
4936 // TBD: The template bloat of this function can be significantly reduced.
4937 //..
4938 // What matters is that the two hash tables:
4939 // i/ are the same size
4940 // ii/ have lists that are permutations of each other according to the
4941 // element's 'operator=='
4942 // This means that the implementation should be independent of all four
4943 // template parameters, but will depend on VALUE_TYPE deduced from the
4944 // KEY_CONFIG. Otherwise, after the initial size comparison, the rest
4945 // depends only on the anchors.
4946 //..
4947
4948 typedef typename KEY_CONFIG::ValueType ValueType;
4949 typedef typename ::bsl::allocator_traits<ALLOCATOR>::size_type SizeType;
4950 typedef bslalg::HashTableImpUtil ImpUtil;
4951
4952 // First test - are the containers the same size?
4953
4954 if (this->size() != other.size()) {
4955 return false; // RETURN
4956 }
4957 bslalg::BidirectionalLink *cursor = this->elementListRoot();
4958 if (!cursor) { // containers are the same size, and empty.
4959 return true; // RETURN
4960 }
4961
4962 while (cursor) {
4963 bslalg::BidirectionalLink *rhsFirst =
4964 ImpUtil::find<KEY_CONFIG>(other.d_anchor,
4965 ImpUtil::extractKey<KEY_CONFIG>(cursor),
4966 other.d_parameters.comparator(),
4967 other.d_parameters.hashCodeForKey(
4968 ImpUtil::extractKey<KEY_CONFIG>(cursor)));
4969 if (!rhsFirst) {
4970 return false; // no matching key // RETURN
4971 }
4972
4973 bslalg::BidirectionalLink *endRange = this->findEndOfRange(cursor);
4974 bslalg::BidirectionalLink *rhsLast = other.findEndOfRange(rhsFirst);
4975
4976 // Check the key-groups have the same length - a quick-fail test.
4977
4978 bslalg::BidirectionalLink *endWalker = cursor->nextLink();
4979 bslalg::BidirectionalLink *rhsWalker = rhsFirst->nextLink();
4980
4981 while (endWalker != endRange) {
4982
4983 if (rhsWalker == rhsLast) {
4984 return false; // different length subsequences // RETURN
4985 }
4986 endWalker = endWalker->nextLink();
4987 rhsWalker = rhsWalker->nextLink();
4988 }
4989
4990 if (rhsWalker != rhsLast) {
4991 return false; // different length subsequences // RETURN
4992 }
4993
4994 // Efficiently compare identical prefixes: O[N] if sequences have the
4995 // same elements in the same order. Note that comparison of values in
4996 // nodes is tested using 'operator==' and not the key-equality
4997 // comparator stored in the hash table.
4998
4999 while (cursor != endRange &&
5000 (ImpUtil::extractValue<KEY_CONFIG>(cursor) ==
5001 ImpUtil::extractValue<KEY_CONFIG>(rhsFirst)))
5002 {
5003 cursor = cursor->nextLink();
5004 rhsFirst = rhsFirst->nextLink();
5005 }
5006
5007 if (cursor == endRange) {
5008 continue; // CONTINUE
5009 }
5010
5011 // Now comes the harder part of validating that one subsequence is a
5012 // permutation of another, by counting elements that compare equal
5013 // using the equality operator, 'operator=='. Note that this code
5014 // could be simplified for hash-tables with unique keys, as we can omit
5015 // the counting-scan, and merely test for any match within the 'other'
5016 // range. Trade off the ease of a single well-tested code path, vs.
5017 // the importance of an efficient 'operator==' for hash containers.
5018 // This is currently the only place the hash-table would care about
5019 // uniqueness, and risk different hash-table types for unique- vs.
5020 // multi-containers. Note again that comparison of values in nodes is
5021 // tested using 'operator==' and not the key-equality comparator stored
5022 // in the hash tables.
5023
5024 for (bslalg::BidirectionalLink *marker = cursor;
5025 marker != endRange;
5026 marker = marker->nextLink())
5027 {
5028 const ValueType& valueAtMarker =
5029 ImpUtil::extractValue<KEY_CONFIG>(marker);
5030
5031 if (cursor != marker) { // skip on first pass only
5032 // Check if the value at 'marker' has already be seen.
5033
5034 bslalg::BidirectionalLink *scanner = cursor;
5035 while (scanner != marker &&
5036 ImpUtil::extractValue<KEY_CONFIG>(scanner) != valueAtMarker) {
5037 scanner = scanner->nextLink();
5038 }
5039 if (scanner != marker) { // We have seen 'lhs' one before.
5040 continue; // CONTINUE
5041 }
5042 }
5043
5044 SizeType matches = 0;
5045 for (bslalg::BidirectionalLink *scanner = rhsFirst;
5046 scanner != rhsLast;
5047 scanner = scanner->nextLink()) {
5048 if (ImpUtil::extractValue<KEY_CONFIG>(scanner) ==
5049 valueAtMarker) {
5050 ++matches;
5051 }
5052 }
5053 if (!matches) {
5054 return false; // RETURN
5055 }
5056
5057 // Remember, *scanner is by definition a good match
5058
5059 for (bslalg::BidirectionalLink *scanner = marker->nextLink();
5060 scanner != endRange;
5061 scanner = scanner->nextLink()) {
5062
5063 if (ImpUtil::extractValue<KEY_CONFIG>(scanner) ==
5064 valueAtMarker) {
5065 if (!--matches) { // equal matches, but excluding initial
5066 return false; // RETURN
5067 }
5068 }
5069 }
5070 if (1 != matches) {
5071 return false; // RETURN
5072 }
5073 }
5074 cursor = endRange;
5075 }
5076 return true;
5077}
5078
5079template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5080inline
5081const HASHER&
5086
5087template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5088inline
5090{
5091 return static_cast<float>(static_cast<double>(this->size())
5092 / static_cast<double>(this->numBuckets()));
5093}
5094
5095template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5096inline
5097float
5099{
5100 return d_maxLoadFactor;
5101}
5102
5103template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5104inline
5107{
5108 // This estimate is still on the high side, we should actually pick the
5109 // preceding entry from our table of prime numbers used for valid bucket
5110 // array sizes. There is no easy way to find that value at the moment
5111 // though.
5112
5113 typedef typename AllocatorTraits::
5114 template rebind_traits<bslalg::HashTableBucket>
5115 BucketAllocatorTraits;
5116 typedef typename BucketAllocatorTraits::allocator_type BucketAllocator;
5117
5118 return BucketAllocatorTraits::max_size(BucketAllocator(this->allocator()));
5119}
5120
5121template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5122inline
5125{
5126 return AllocatorTraits::max_size(this->allocator()) / sizeof(NodeType);
5127}
5128
5129template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5130inline
5136
5137template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5138inline
5144
5145template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5146inline
5152
5153} // close package namespace
5154
5155//-----------------------------------------------------------------------------
5156// free functions and operators
5157//-----------------------------------------------------------------------------
5158
5159template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5160inline
5161void
5164{
5166 TableType;
5167
5169 || a.allocator() == b.allocator()) {
5170 a.swap(b);
5171 }
5172 else {
5173 // C++11 behavior: undefined for unequal allocators
5174 // BSLS_ASSERT(allocator() == other.allocator());
5175
5176 TableType aCopy(a, b.allocator());
5177 TableType bCopy(b, a.allocator());
5178
5179 b.swap(aCopy);
5180 a.swap(bCopy);
5181 }
5182}
5183
5184template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5185inline
5189{
5190 return lhs.hasSameValue(rhs);
5191}
5192
5193template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5194inline
5198{
5199 return !(a == b);
5200}
5201
5202template <class FUNCTOR>
5203inline
5206{
5207 a.swap(b);
5208}
5209
5210template <class FUNCTOR>
5211inline
5214{
5215 a.swap(b);
5216}
5217
5218// ============================================================================
5219// TYPE TRAITS
5220// ============================================================================
5221
5222// Type traits for HashTable:
5223//: o A HashTable is bitwise movable if the both functors and the allocator are
5224//: bitwise movable.
5225//: o A HashTable uses 'bslma' allocators if the parameterized 'ALLOCATOR' is
5226//: convertible from 'bslma::Allocator*'.
5227
5228namespace bslma {
5229
5230template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5231struct UsesBslmaAllocator<bslstl::HashTable<KEY_CONFIG,
5232 HASHER,
5233 COMPARATOR,
5234 ALLOCATOR> >
5235 : bsl::is_convertible<Allocator*, ALLOCATOR>::type {
5236};
5237
5238template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5239struct UsesBslmaAllocator<bslstl::HashTable_ImplParameters<KEY_CONFIG,
5240 HASHER,
5241 COMPARATOR,
5242 ALLOCATOR> >
5243 : bsl::is_convertible<Allocator*, ALLOCATOR>::type {
5244};
5245
5246} // close namespace bslma
5247
5248namespace bslmf {
5249
5250template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5251struct IsBitwiseMoveable<bslstl::HashTable<KEY_CONFIG,
5252 HASHER,
5253 COMPARATOR,
5254 ALLOCATOR> >
5255: bsl::integral_constant< bool, bslmf::IsBitwiseMoveable<HASHER>::value
5256 && bslmf::IsBitwiseMoveable<COMPARATOR>::value
5257 && bslmf::IsBitwiseMoveable<ALLOCATOR>::value>
5258{};
5259
5260} // close namespace bslmf
5261
5262
5263#endif // End C++11 code
5264
5265#endif
5266
5267// ----------------------------------------------------------------------------
5268// Copyright 2013 Bloomberg Finance L.P.
5269//
5270// Licensed under the Apache License, Version 2.0 (the "License");
5271// you may not use this file except in compliance with the License.
5272// You may obtain a copy of the License at
5273//
5274// http://www.apache.org/licenses/LICENSE-2.0
5275//
5276// Unless required by applicable law or agreed to in writing, software
5277// distributed under the License is distributed on an "AS IS" BASIS,
5278// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5279// See the License for the specific language governing permissions and
5280// limitations under the License.
5281// ----------------------------- END-OF-FILE ----------------------------------
5282
5283/** @} */
5284/** @} */
5285/** @} */
Definition bslma_bslallocator.h:580
Definition bslalg_bidirectionalnode.h:357
Definition bslalg_functoradapter.h:228
HashTable_HashWrapper< CallableVariable< HASHER >::type > Type
This typedef is an alias for the functor.
Definition bslalg_functoradapter.h:234
Definition bslalg_hashtableanchor.h:541
BidirectionalLink * listRootAddress() const
Return the value listRootAddress attribute of this object.
Definition bslalg_hashtableanchor.h:708
void setBucketArrayAddressAndSize(HashTableBucket *bucketArrayAddress, std::size_t bucketArraySize)
Definition bslalg_hashtableanchor.h:679
std::size_t bucketArraySize() const
Return the value of the bucketArraySize attribute of this object.
Definition bslalg_hashtableanchor.h:714
void swap(HashTableAnchor &other)
Definition bslalg_hashtableanchor.h:701
void setListRootAddress(BidirectionalLink *value)
Definition bslalg_hashtableanchor.h:691
HashTableBucket * bucketArrayAddress() const
Definition bslalg_hashtableanchor.h:720
Definition bslma_allocator.h:457
Definition bslma_destructorguard.h:132
Definition bslmf_movableref.h:751
Definition bslstl_bidirectionalnodepool.h:270
bslalg::BidirectionalLink * cloneNode(const bslalg::BidirectionalLink &original)
Definition bslstl_bidirectionalnodepool.h:479
AllocatorType & allocator()
Definition bslstl_bidirectionalnodepool.h:471
void adopt(bslmf::MovableRef< BidirectionalNodePool > pool)
Definition bslstl_bidirectionalnodepool.h:460
bslalg::BidirectionalLink * emplaceIntoNewNode(Args &&... arguments)
Definition bslstl_bidirectionalnodepool.h:491
void deleteNode(bslalg::BidirectionalLink *linkNode)
Definition bslstl_bidirectionalnodepool.h:517
bslalg::BidirectionalLink * moveIntoNewNode(bslalg::BidirectionalLink *original)
Definition bslstl_bidirectionalnodepool.h:509
void reserveNodes(size_type numNodes)
Definition bslstl_bidirectionalnodepool.h:538
Definition bslstl_hashtable.h:2832
~HashTable_ArrayProctor()
Definition bslstl_hashtable.h:3417
void release()
Definition bslstl_hashtable.h:3436
bool operator()(ARG1_TYPE &arg1, ARG2_TYPE &arg2) const
Definition bslstl_hashtable.h:1749
void swap(HashTable_ComparatorWrapper &other)
Exchange the value of this object with the specified other object.
Definition bslstl_hashtable.h:3299
const FUNCTOR & functor() const
Definition bslstl_hashtable.h:3291
HashTable_ComparatorWrapper()
Definition bslstl_hashtable.h:3267
bool operator()(ARG1_TYPE &arg1, ARG2_TYPE &arg2) const
Definition bslstl_hashtable.h:3284
std::size_t operator()(ARG_TYPE &arg) const
Definition bslstl_hashtable.h:1624
const FUNCTOR & functor() const
Definition bslstl_hashtable.h:3191
HashTable_HashWrapper()
Definition bslstl_hashtable.h:3168
std::size_t operator()(ARG_TYPE &arg) const
Definition bslstl_hashtable.h:3184
void swap(HashTable_HashWrapper &other)
Exchange the value of this object with the specified other object.
Definition bslstl_hashtable.h:3198
Definition bslstl_hashtable.h:3041
std::size_t hashCodeForKey(DEDUCED_KEY &key) const
Definition bslstl_hashtable.h:3632
HashTable< KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR > HashTableType
Definition bslstl_hashtable.h:3059
NodeFactory & nodeFactory()
Definition bslstl_hashtable.h:3575
void quickSwapRetainAllocators(HashTable_ImplParameters *other)
Definition bslstl_hashtable.h:3599
const BaseComparator & comparator() const
Definition bslstl_hashtable.h:3620
BidirectionalNodePool< typename HashTableType::ValueType, NodeAllocator > NodeFactory
Definition bslstl_hashtable.h:3066
const BaseHasher & hasher() const
Definition bslstl_hashtable.h:3643
void quickSwapExchangeAllocators(HashTable_ImplParameters *other)
Definition bslstl_hashtable.h:3583
ReboundTraits::allocator_type NodeAllocator
Definition bslstl_hashtable.h:3062
HashTableType::AllocatorTraits::template rebind_traits< NodeType > ReboundTraits
Definition bslstl_hashtable.h:3061
const HASHER & originalHasher() const
Definition bslstl_hashtable.h:3677
const COMPARATOR & originalComparator() const
Definition bslstl_hashtable.h:3667
Definition bslstl_hashtable.h:2882
~HashTable_NodeProctor()
Definition bslstl_hashtable.h:3383
void release()
Definition bslstl_hashtable.h:3393
Definition bslstl_hashtable.h:1914
bslalg::BidirectionalLink * insertOrAssign(bool *isInsertedFlag, bslalg::BidirectionalLink *hint, BSLS_COMPILERFEATURES_FORWARD_REF(KEY_ARG) key, BDE_OTHER_TYPE &&obj)
Definition bslstl_hashtable.h:4497
bslalg::BidirectionalNode< ValueType > NodeType
Definition bslstl_hashtable.h:1922
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASHER, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< COMPARATOR, LOOKUP_KEY >::value, bslalg::BidirectionalLink * >::type tryEmplace(bool *isInsertedFlag, bslalg::BidirectionalLink *hint, LOOKUP_KEY &&key, ARGS &&... args)
Definition bslstl_hashtable.h:2528
HashTable & operator=(const HashTable &rhs)
Definition bslstl_hashtable.h:4172
KEY_CONFIG::KeyType KeyType
Definition bslstl_hashtable.h:1920
void rehashForNumBuckets(SizeType newNumBuckets)
Definition bslstl_hashtable.h:4545
ALLOCATOR AllocatorType
Definition bslstl_hashtable.h:1918
void setMaxLoadFactor(float newMaxLoadFactor)
Definition bslstl_hashtable.h:4632
void swap(HashTable &other)
Definition bslstl_hashtable.h:4655
ALLOCATOR allocator() const
Definition bslstl_hashtable.h:4812
SizeType countElementsInBucket(SizeType index) const
Definition bslstl_hashtable.h:4861
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASHER, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< COMPARATOR, LOOKUP_KEY >::value, bslalg::BidirectionalLink * >::type find(const LOOKUP_KEY &key) const
Definition bslstl_hashtable.h:2642
bslalg::BidirectionalLink * tryEmplace(bool *isInsertedFlag, bslalg::BidirectionalLink *hint, const KeyType &key, ARGS &&... args)
Definition bslstl_hashtable.h:4677
SizeType rehashThreshold() const
Definition bslstl_hashtable.h:5140
bslalg::BidirectionalLink * emplaceIfMissing(bool *isInsertedFlag, Args &&... arguments)
::bsl::allocator_traits< AllocatorType > AllocatorTraits
Definition bslstl_hashtable.h:1919
bool hasSameValue(const HashTable &other) const
Definition bslstl_hashtable.h:4933
const COMPARATOR & comparator() const
Definition bslstl_hashtable.h:4853
float maxLoadFactor() const
Definition bslstl_hashtable.h:5098
bslalg::BidirectionalLink * emplace(Args &&... arguments)
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASHER, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< COMPARATOR, LOOKUP_KEY >::value, void >::type findRange(bslalg::BidirectionalLink **first, bslalg::BidirectionalLink **last, const LOOKUP_KEY &key) const
Definition bslstl_hashtable.h:2688
bslalg::BidirectionalLink * insert(BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value)
Definition bslstl_hashtable.h:4475
const HASHER & hasher() const
Definition bslstl_hashtable.h:5082
bslalg::BidirectionalLink * findEndOfRange(bslalg::BidirectionalLink *first) const
Definition bslstl_hashtable.h:4892
bslalg::BidirectionalLink * emplaceWithHint(bslalg::BidirectionalLink *hint, Args &&... arguments)
HashTable & operator=(BloombergLP::bslmf::MovableRef< HashTable > rhs)
AllocatorTraits::size_type SizeType
Definition bslstl_hashtable.h:1923
void reserveForNumElements(SizeType numElements)
Definition bslstl_hashtable.h:4606
SizeType maxSize() const
Definition bslstl_hashtable.h:5124
bslalg::BidirectionalLink * remove(bslalg::BidirectionalLink *node)
Definition bslstl_hashtable.h:4567
SizeType numBuckets() const
Return the number of buckets contained in this hash table.
Definition bslstl_hashtable.h:5132
SizeType maxNumBuckets() const
Definition bslstl_hashtable.h:5106
bsl::remove_const< KeyType >::type NonConstKeyType
Definition bslstl_hashtable.h:1924
HashTable(const ALLOCATOR &basicAllocator=ALLOCATOR())
Definition bslstl_hashtable.h:3690
bslalg::BidirectionalLink * insertIfMissing(const KeyType &key)
Definition bslstl_hashtable.h:4373
~HashTable()
Destroy this object.
Definition bslstl_hashtable.h:3839
SizeType bucketIndexForKey(const KeyType &key) const
Definition bslstl_hashtable.h:4831
bslalg::BidirectionalLink * elementListRoot() const
Definition bslstl_hashtable.h:4872
SizeType size() const
Return the number of elements in this hash table.
Definition bslstl_hashtable.h:5148
KEY_CONFIG::ValueType ValueType
Definition bslstl_hashtable.h:1921
HashTable(BloombergLP::bslmf::MovableRef< HashTable > original, const ALLOCATOR &basicAllocator)
float loadFactor() const
Definition bslstl_hashtable.h:5089
const bslalg::HashTableBucket & bucketAtIndex(SizeType index) const
Definition bslstl_hashtable.h:4820
void removeAll()
Definition bslstl_hashtable.h:4588
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2012
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2018
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
void swap(OptionValue &a, OptionValue &b)
Definition balxml_encoderoptions.h:68
Definition bdlbb_blob.h:576
Definition bslstl_algorithm.h:82
void swap(BidirectionalNodePool< VALUE, ALLOCATOR > &a, BidirectionalNodePool< VALUE, ALLOCATOR > &b)
bool operator==(const BidirectionalIterator< T1, ITER_IMP, TAG_TYPE > &lhs, const BidirectionalIterator< T2, ITER_IMP, TAG_TYPE > &rhs)
bool operator!=(const BidirectionalIterator< T1, ITER_IMP, TAG_TYPE > &lhs, const BidirectionalIterator< T2, ITER_IMP, TAG_TYPE > &rhs)
void swap(TYPE &a, TYPE &b)
t_TYPE & type
This typedef defines the return type of this meta function.
Definition bslmf_addlvaluereference.h:129
Definition bslma_allocatortraits.h:1061
BloombergLP::bslma::AllocatorTraits_SizeType< ALLOCATOR_TYPE >::type size_type
Definition bslma_allocatortraits.h:1165
static void construct(ALLOCATOR_TYPE &basicAllocator, ELEMENT_TYPE *elementAddr, Args &&... arguments)
Definition bslma_allocatortraits.h:1472
Definition bslmf_conditional.h:120
Definition bslmf_enableif.h:525
Definition bslmf_integralconstant.h:244
Definition bslmf_isconvertible.h:867
Definition bslmf_isfunction.h:232
Definition bslmf_ispointer.h:138
t_TYPE type
This typedef is an alias to the (template parameter) t_TYPE.
Definition bslmf_removeconst.h:161
Definition bslalg_hashtablebucket.h:297
Definition bslalg_hashtableimputil.h:613
static void insertAtFrontOfBucket(HashTableAnchor *anchor, BidirectionalLink *link, std::size_t hashCode)
static void remove(HashTableAnchor *anchor, BidirectionalLink *link, std::size_t hashCode)
static void insertAtBackOfBucket(HashTableAnchor *anchor, BidirectionalLink *link, std::size_t hashCode)
static std::size_t computeBucketIndex(std::size_t hashCode, std::size_t numBuckets)
Definition bslalg_hashtableimputil.h:845
static void deallocateObject(const t_ALLOCATOR &allocator, t_POINTER p, std::size_t n=1)
Definition bslma_allocatorutil.h:926
Definition bslma_usesbslmaallocator.h:343
Definition bslmf_isbitwisemoveable.h:718
Definition bslmf_movableref.h:791
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
Definition bslstl_hashtable.h:1598
bsl::conditional< bsl::is_function< CALLABLE >::value, typenamebsl::add_lvalue_reference< CALLABLE >::type, CALLABLE >::type type
Definition bslstl_hashtable.h:1604
Definition bslstl_hashtable.h:3023
Definition bslstl_hashtable.h:3030
Definition bslstl_hashtable.h:2923
static bslma::Allocator * incidentalAllocator()
static bslalg::HashTableBucket * defaultBucketAddress()
static size_t nextPrime(size_t n)
static size_t growBucketsForLoadFactor(size_t *capacity, size_t minElements, size_t requestedBuckets, double maxLoadFactor)
Definition bslstl_hashtable.h:2972
static void destroyBucketArray(bslalg::HashTableBucket *data, std::size_t bucketArraySize, const ALLOCATOR &allocator)
Definition bslstl_hashtable.h:3471
static void initAnchor(bslalg::HashTableAnchor *anchor, std::size_t bucketArraySize, const ALLOCATOR &allocator)
Definition bslstl_hashtable.h:3497
static void assertNotNullPointer(TYPE &)
Definition bslstl_hashtable.h:3447
Definition bsls_objectbuffer.h:276
TYPE * address()
Definition bsls_objectbuffer.h:334
TYPE & object()
Definition bsls_objectbuffer.h:351