BDE 4.39.x 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// clang-format off
1542// Include version that can be compiled with C++03
1543// Generated on Mon Jan 13 08:31:39 2025
1544// Command line: sim_cpp11_features.pl bslstl_hashtable.h
1545
1546# define COMPILING_BSLSTL_HASHTABLE_H
1547# include <bslstl_hashtable_cpp03.h>
1548# undef COMPILING_BSLSTL_HASHTABLE_H
1549
1550// clang-format on
1551#else
1552
1553
1554
1555namespace bslstl {
1556
1557template <class KEY_CONFIG,
1558 class HASHER,
1559 class COMPARATOR,
1561class HashTable;
1562
1563template <class FACTORY>
1564class HashTable_ArrayProctor;
1565
1566template <class FACTORY>
1567class HashTable_NodeProctor;
1568
1569template <class FUNCTOR>
1570class HashTable_ComparatorWrapper;
1571
1572template <class FUNCTOR>
1573class HashTable_ComparatorWrapper<const FUNCTOR>;
1574
1575template <class FUNCTOR>
1576class HashTable_ComparatorWrapper<FUNCTOR &>;
1577
1578template <class FUNCTOR>
1579class HashTable_HashWrapper;
1580
1581template <class FUNCTOR>
1582class HashTable_HashWrapper<const FUNCTOR>;
1583
1584template <class FUNCTOR>
1585class HashTable_HashWrapper<FUNCTOR &>;
1586
1587struct HashTable_ImpDetails;
1588struct HashTable_Util;
1589
1590 // ======================
1591 // class CallableVariable
1592 // ======================
1593
1594/// This metafunction returns a `type` that is an alias for `CALLABLE`
1595/// unless that is a function type, in which case it is an alias for
1596/// `CALLABLE &`. This should be used to declare variables of an arbitrary
1597/// callable type, typically a template type parameter, that may turn out to be a function type.
1598///
1599/// \note Note that this metafunction is necessary as the C++
1600/// language does not allow variables of function type, nor may functions
1601/// return a function type.
1602///
1603/// See @ref bslstl_hashtable
1604template <class CALLABLE>
1606
1607 // TYPES
1608 typedef typename bsl::conditional<
1611 CALLABLE>::type type;
1612};
1613
1614 // ===========================
1615 // class HashTable_HashWrapper
1616 // ===========================
1617
1618/// This class provides a wrapper around a functor satisfying the `Hash`
1619/// requirements (@ref bslstl_hash ) such that the function call operator is
1620/// always declared as `const` qualified.
1621///
1622/// TBD Provide an optimization for the case of an empty base functor, where
1623/// we can safely const_cast want calling the base class operator.
1624///
1625///
1626/// \note Note that we would only one class, not two, with C++11 variadic
1627/// templates and perfect forwarding, and we could also easily detect
1628/// whether or not `FUNCTOR` provided a const-qualified `operator()`.
1629///
1630/// See @ref bslstl_hashtable
1631template <class FUNCTOR>
1633
1634 private:
1635 mutable FUNCTOR d_functor;
1636
1637 public:
1638 // CREATORS
1639
1640 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that
1641 /// has its default value.
1643
1644 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that is
1645 /// a copy of the specified `fn`.
1646 explicit HashTable_HashWrapper(const FUNCTOR& fn);
1647
1648 // MANIPULATORS
1649
1650 /// Exchange the value of this object with the specified `other` object.
1651 void swap(HashTable_HashWrapper &other);
1652
1653 // ACCESSORS
1654
1655 /// Call the wrapped `functor` with the specified `arg` and return the result.
1656 ///
1657 /// \note Note that `ARG_TYPE` will typically be deduced as a `const`
1658 /// type.
1659 template <class ARG_TYPE>
1660 std::size_t operator()(ARG_TYPE& arg) const;
1661
1662 /// Return a reference providing non-modifiable access to the hash
1663 /// functor wrapped by this object.
1664 const FUNCTOR& functor() const;
1665};
1666
1667/// This partial specialization handles `const` qualified functors, that may
1668/// not be stored as a `mutable` member in the primary template. The need
1669/// to wrap such functors diminishes greatly, as there is no need to play
1670/// mutable tricks to invoke the function call operator. An alternative to
1671/// providing this specialization would be to skip the wrapper entirely if using a `const` qualified functor in a `HashTable`.
1672///
1673/// \note Note that this type
1674/// has a `const` qualified data member, so is neither assignable nor
1675/// swappable.
1676template <class FUNCTOR>
1677class HashTable_HashWrapper<const FUNCTOR> {
1678
1679 private:
1680 const FUNCTOR d_functor;
1681
1682 public:
1683 // CREATORS
1684
1685 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that
1686 /// has its default value.
1688
1689 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that is
1690 /// a copy of the specified `fn`.
1691 explicit HashTable_HashWrapper(const FUNCTOR& fn);
1692
1693 // ACCESSORS
1694
1695 /// Call the wrapped `functor` with the specified `arg` and return the result.
1696 ///
1697 /// \note Note that `ARG_TYPE` will typically be deduced as a `const`
1698 /// type.
1699 template <class ARG_TYPE>
1700 std::size_t operator()(ARG_TYPE& arg) const;
1701
1702 /// Return a reference providing non-modifiable access to the hash
1703 /// functor wrapped by this object.
1704 const FUNCTOR& functor() const;
1705};
1706
1707/// This partial specialization handles `const` qualified functors, that may
1708/// not be stored as a `mutable` member in the primary template.
1709///
1710/// \note Note that the `FUNCTOR` type itself may be `const`-qualified, so this one partial
1711/// template specialization also handles `const FUNCTOR&` references. In
1712/// order to correctly parse with the reference-binding rules, we drop the
1713/// `const` in front of many of the references to `FUNCTOR` seen in the primary template definition.
1714///
1715/// \note Note that this type has a reference data
1716/// member, so is not default constructible, assignable or swappable.
1717template <class FUNCTOR>
1718class HashTable_HashWrapper<FUNCTOR &> {
1719
1720 private:
1721 FUNCTOR& d_functor;
1722
1723 public:
1724 // CREATORS
1725
1726 /// Create a `HashTable_HashWrapper` object wrapping a `FUNCTOR` that is
1727 /// a copy of the specified `fn`.
1728 explicit HashTable_HashWrapper(FUNCTOR& fn);
1729
1730 // ACCESSORS
1731
1732 /// Call the wrapped `functor` with the specified `arg` and return the result.
1733 ///
1734 /// \note Note that `ARG_TYPE` will typically be deduced as a `const`
1735 /// type.
1736 template <class ARG_TYPE>
1737 std::size_t operator()(ARG_TYPE& arg) const;
1738
1739 /// Return a reference providing non-modifiable access to the hash
1740 /// functor wrapped by this object.
1741 FUNCTOR& functor() const;
1742};
1743
1744/// Swap the functor wrapped by the specified `a` object with the functor
1745/// wrapped by the specified `b` object.
1746template <class FUNCTOR>
1749
1750 // =================================
1751 // class HashTable_ComparatorWrapper
1752 // =================================
1753
1754/// This class provides a wrapper around a functor that can compare two
1755/// values and return a `bool`, so that the function call operator is always
1756/// declared as `const` qualified.
1757///
1758/// TBD Provide an optimization for the case of an empty base functor, where
1759/// we can safely const_cast want calling the base class operator.
1760///
1761/// See @ref bslstl_hashtable
1762template <class FUNCTOR>
1764
1765 private:
1766 mutable FUNCTOR d_functor;
1767
1768 public:
1769 // CREATORS
1770
1771 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1772 /// that has its default value.
1774
1775 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1776 /// that is a copy of the specified `fn`.
1777 explicit HashTable_ComparatorWrapper(const FUNCTOR& fn);
1778
1779 // MANIPULATORS
1780
1781 /// Exchange the value of this object with the specified `other` object.
1782 void swap(HashTable_ComparatorWrapper &other);
1783
1784 // ACCESSORS
1785
1786 /// Call the wrapped `functor` with the specified `arg1` and `arg2` (in that order) and return the result.
1787 ///
1788 /// \note Note that `ARGn_TYPE` will
1789 /// typically be deduced as a `const` type.
1790 template <class ARG1_TYPE, class ARG2_TYPE>
1791 bool operator()(ARG1_TYPE& arg1, ARG2_TYPE& arg2) const;
1792
1793 /// Return a reference providing non-modifiable access to the hash
1794 /// functor wrapped by this object.
1795 const FUNCTOR& functor() const;
1796};
1797
1798/// This partial specialization handles `const` qualified functors, that may
1799/// not be stored as a `mutable` member in the primary template. The need
1800/// to wrap such functors diminishes greatly, as there is no need to play
1801/// mutable tricks to invoke the function call operator. An alternative to
1802/// providing this specialization would be to skip the wrapper entirely if using a `const` qualified functor in a `HashTable`.
1803///
1804/// \note Note that this type
1805/// has a `const` qualified data member, so is neither assignable nor
1806/// swappable.
1807template <class FUNCTOR>
1808class HashTable_ComparatorWrapper<const FUNCTOR> {
1809
1810 private:
1811 const FUNCTOR d_functor;
1812
1813 public:
1814 // CREATORS
1815
1816 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1817 /// that has its default value.
1819
1820 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1821 /// that is a copy of the specified `fn`.
1822 explicit HashTable_ComparatorWrapper(const FUNCTOR& fn);
1823
1824 // ACCESSORS
1825
1826 /// Call the wrapped `functor` with the specified `arg1` and `arg2` (in that order) and return the result.
1827 ///
1828 /// \note Note that `ARGn_TYPE` will
1829 /// typically be deduced as a `const` type.
1830 template <class ARG1_TYPE, class ARG2_TYPE>
1831 bool operator()(ARG1_TYPE& arg1, ARG2_TYPE& arg2) const;
1832
1833 /// Return a reference providing non-modifiable access to the hash
1834 /// functor wrapped by this object.
1835 const FUNCTOR& functor() const;
1836};
1837
1838/// This partial specialization handles `const` qualified functors, that may
1839/// not be stored as a `mutable` member in the primary template.
1840///
1841/// \note Note that the `FUNCTOR` type itself may be `const`-qualified, so this one partial
1842/// template specialization also handles `const FUNCTOR&` references. In
1843/// order to correctly parse with the reference-binding rules, we drop the
1844/// `const` in front of many of the references to `FUNCTOR` seen in the primary template definition.
1845///
1846/// \note Note that this type has a reference data
1847/// member, so is not default constructible, assignable or swappable.
1848template <class FUNCTOR>
1850
1851 private:
1852 FUNCTOR& d_functor;
1853
1854 public:
1855 // CREATORS
1856
1857 /// Create a `HashTable_ComparatorWrapper` object wrapping a `FUNCTOR`
1858 /// that is a copy of the specified `fn`.
1859 explicit HashTable_ComparatorWrapper(FUNCTOR& fn);
1860
1861 // ACCESSORS
1862
1863 /// Call the wrapped `functor` with the specified `arg1` and `arg2` (in that order) and return the result.
1864 ///
1865 /// \note Note that `ARGn_TYPE` will
1866 /// typically be deduced as a `const` type.
1867 template <class ARG1_TYPE, class ARG2_TYPE>
1868 bool operator()(ARG1_TYPE& arg1, ARG2_TYPE& arg2) const;
1869
1870 /// Return a reference providing non-modifiable access to the hash
1871 /// functor wrapped by this object.
1872 FUNCTOR& functor() const;
1873};
1874
1875/// Swap the functor wrapped by the specified `lhs` object with the functor
1876/// wrapped by the specified `rhs` object.
1877template <class FUNCTOR>
1880
1881 // ===============
1882 // class HashTable
1883 // ===============
1884
1885template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
1887
1888/// This class template implements a value-semantic container type holding
1889/// an unordered sequence of (possibly duplicate) elements, that can be
1890/// rapidly accessed using their key, with the constraint on the container
1891/// that elements whose keys compare equal according to the specified
1892/// `COMPARATOR` will be stored in a stable, contiguous sequence within the
1893/// container. The value type and key type of the elements maintained by a
1894/// `HashTable` are determined by aliases provided through the (template
1895/// parameter) type `KEY_CONFIG`. Elements in a `HashTable` are stored in
1896/// "nodes" that are allocated using an allocator of the specified
1897/// `ALLOCATOR` type (rebound to the node type), and elements are
1898/// constructed directly in the node using the allocator as described in the
1899/// C++11 standard under the allocator-aware container requirements in
1900/// ([container.requirements.general], C++11 23.2.1). The (template
1901/// parameter) types `HASHER` and `COMPARATOR` shall be `copy-constructible`
1902/// function-objects. `HASHER` shall support a function call operator
1903/// compatible with the following statements:
1904/// @code
1905/// HASHER hash;
1906/// KEY_CONFIG::KeyType key;
1907/// std::size_t result = hash(key);
1908/// @endcode
1909/// where the definition of the called function meets the requirements of a
1910/// hash function, as specified in @ref bslstl_hash . `COMPARATOR` shall
1911/// support the a function call operator compatible with the following
1912/// statements:
1913/// @code
1914/// COMPARATOR compare;
1915/// KEY_CONFIG::KeyType key1, key2;
1916/// bool result = compare(key1, key2);
1917/// @endcode
1918/// where the definition of the called function defines an equivalence
1919/// relationship on keys that is both reflexive and transitive. The
1920/// `HASHER` and `COMPARATOR` attributes of this class are further
1921/// constrained, such for any two objects whose keys compare equal by the
1922/// comparator, shall produce the same value from the hasher.
1923///
1924/// This class:
1925/// * supports a complete set of *value-semantic* operations
1926/// - except for `bdex` serialization
1927/// * is *exception-neutral* (agnostic except for the `at` method)
1928/// * is *alias-safe*
1929/// * is `const` *thread-safe*
1930/// For terminology see @ref bsldoc_glossary .
1931///
1932/// See @ref bslstl_hashtable
1933template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
1935
1936 public:
1937 // TYPES
1938 typedef ALLOCATOR AllocatorType;
1939 typedef ::bsl::allocator_traits<AllocatorType> AllocatorTraits;
1940 typedef typename KEY_CONFIG::KeyType KeyType;
1941 typedef typename KEY_CONFIG::ValueType ValueType;
1945
1946 private:
1947 // PRIVATE TYPES
1948 typedef
1950 ImplParameters;
1951
1952 /// This typedef is a convenient alias for the utility associated with
1953 /// movable references.
1955
1956 // CONSISTENCY CHECKS
1957
1958 // Assert consistency checks against Machiavellian users, specializing an
1959 // allocator for a specific type to have different propagation traits to
1960 // the primary template.
1961
1962 typedef typename AllocatorTraits::template rebind_traits<NodeType>
1963 ReboundTraits;
1964
1966 ReboundTraits::propagate_on_container_copy_assignment::value ==
1967 AllocatorTraits::propagate_on_container_copy_assignment::value);
1968
1970 ReboundTraits::propagate_on_container_move_assignment::value ==
1971 AllocatorTraits::propagate_on_container_move_assignment::value);
1972
1973 BSLMF_ASSERT(ReboundTraits::propagate_on_container_swap::value ==
1974 AllocatorTraits::propagate_on_container_swap::value);
1975
1976 private:
1977 // DATA
1978 ImplParameters d_parameters; // policies governing table behavior
1980 d_anchor; // list root and bucket array
1981 SizeType d_size; // number of elements in this table
1982 SizeType d_capacity; // max number of elements before a
1983 // rehash is required (computed from
1984 // 'd_maxLoadFactor')
1985 float d_maxLoadFactor; // maximum permitted load factor
1986
1987 private:
1988 // PRIVATE MANIPULATORS
1989
1990 /// Copy the sequence of elements from the list starting at the
1991 /// specified `cursor` and having `size` elements. Allocate a bucket
1992 /// array sufficiently large to store `size` elements while respecting
1993 /// the `maxLoadFactor`, and index the copied list into that new array
1994 /// of hash buckets. This hash table then takes ownership of the list and bucket array.
1995 ///
1996 /// \note Note that this method is intended to be called
1997 /// from copy constructors, which will have assigned some initial values
1998 /// for the `size` and other attributes that may not be consistent with
1999 /// the class invariants until after this method is called.
2000 void copyDataStructure(bslalg::BidirectionalLink *cursor);
2001
2002 /// Recreate the sequence of elements from the list starting at the
2003 /// specified `cursor` and having (member) `d_size` elements, ensuring
2004 /// that each `ValueType` object in the source list is move-inserted
2005 /// into the new sequence. Allocate a bucket array sufficiently large
2006 /// to store `d_size` elements, while respecting the `maxLoadFactor`,
2007 /// and index the new list into that new array of hash buckets. This
2008 /// hash table then takes ownership of the list and bucket array.
2009 ///
2010 /// \note Note that this method is intended to be called from move constructors
2011 /// (where the source and target allocators do not match), which will
2012 /// have assigned some initial values for the `size` and other
2013 /// attributes that may not be consistent with the class invariants
2014 /// until after this method completes. If an exception is thrown during
2015 /// this operation, this object is left in a valid but unspecified
2016 /// state; it is the caller's responsibility, however, to ensure the
2017 /// source hash-table is in a valid state if an exception is thrown
2018 void moveDataStructure(bslalg::BidirectionalLink *cursor);
2019
2020 /// Efficiently exchange the value, functors, and allocator of this
2021 /// object with those of the specified `other` object. This method
2022 /// provides the no-throw exception-safety guarantee.
2023 void quickSwapExchangeAllocators(HashTable *other);
2024
2025 /// Efficiently exchange the value and functors this object with those
2026 /// of the specified `other` object. This method provides the no-throw exception-safety guarantee.
2027 ///
2028 /// \pre The behavior is undefined unless this
2029 /// object was created with the same allocator as `other`.
2030 void quickSwapRetainAllocators(HashTable *other);
2031
2032 /// Re-organize this hash-table to have exactly the specified
2033 /// `newNumBuckets`, which will then be able to store the specified
2034 /// `capacity` number of elements without exceeding the `maxLoadFactor`.
2035 /// This operation provides the strong exception guarantee (see
2036 /// @ref bsldoc_glossary ) unless the `hasher` throws, in which case this
2037 /// operation provides the basic exception guarantee, leaving the
2038 /// hash-table in a valid, but otherwise unspecified (and potentially empty), state.
2039 ///
2040 /// \pre The behavior is undefined unless `size / newNumBuckets <= maxLoadFactor`.
2041 ///
2042 /// \note Note that the caller is
2043 /// responsible for correctly computing the `capacity` supported by the
2044 /// new number of buckets. This allows for a minor optimization where
2045 /// the value is computed only once per rehash.
2046 void rehashIntoExactlyNumBuckets(SizeType newNumBuckets,
2047 SizeType capacity);
2048
2049 /// Erase all the nodes in this hash-table, and deallocate their memory
2050 /// via the supplied node-factory. Destroy the array of buckets owned
2051 /// by this hash-table. If `d_anchor.bucketAddress()` is the default
2052 /// bucket address (`HashTable_ImpDetails::defaultBucketAddress`), then
2053 /// this hash-table does not own its array of buckets, and it will not
2054 /// be destroyed.
2055 void removeAllAndDeallocate();
2056
2057 /// Erase all the nodes in this table and deallocate their memory via
2058 /// the node factory, without performing the necessary bookkeeping to reflect such change.
2059 ///
2060 /// \note Note that this (private) method explicitly
2061 /// leaves the HashTable in an inconsistent state, and is expected to be
2062 /// useful when the anchor of this hash table is about to be overwritten
2063 /// with a new value, or when the hash table is going out of scope and
2064 /// the extra bookkeeping is not necessary.
2065 void removeAllImp();
2066
2067 // PRIVATE ACCESSORS
2068
2069 /// Return the address of the first node in this hash table having a key
2070 /// that compares equal (according to this hash-table's `comparator`) to the specified `key`.
2071 ///
2072 /// \pre The behavior is undefined unless the specified
2073 /// `hashValue` is the hash code for the `key` according to the `hasher` functor of this hash table.
2074 ///
2075 /// \note Note that this function's
2076 /// implementation relies on the supplied `hashValue` rather than
2077 /// recomputing it, eliminating some redundant computation for the
2078 /// public methods.
2079 template <class DEDUCED_KEY>
2080 bslalg::BidirectionalLink *find(DEDUCED_KEY& key,
2081 std::size_t hashValue) const;
2082
2083 /// Return the address of the bucket at the specified `bucketIndex` in bucket array of this hash table.
2084 ///
2085 /// \pre The behavior is undefined unless
2086 /// `bucketIndex < this->numBuckets()`.
2087 bslalg::HashTableBucket *getBucketAddress(SizeType bucketIndex) const;
2088
2089 /// Return the hash code for the element stored in the specified `node`
2090 /// using a copy of the hash functor supplied at construction.
2091 ///
2092 /// \pre The behavior is undefined unless `node` points to a list-node of type
2093 /// `bslalg::BidirectionalNode<KEY_CONFIG::ValueType>`.
2094 std::size_t hashCodeForNode(bslalg::BidirectionalLink *node) const;
2095
2096 public:
2097 // CREATORS
2098
2099 /// Create an empty hash-table. Optionally specify a `basicAllocator`
2100 /// used to supply memory. If `basicAllocator` is not supplied, a
2101 /// default-constructed object of the (template parameter) type
2102 /// `ALLOCATOR` is used. If the type `ALLOCATOR` is `bsl::allocator`
2103 /// and `basicAllocator` is not supplied, the currently installed
2104 /// default allocator is used to supply memory. Use 1.0 for the
2105 /// `maxLoadFactor`. Use a default constructed object of the (template
2106 /// parameter) type `HASHER` and a default constructed object of the
2107 /// (template parameter) type `COMPARATOR` to organize elements in the
2108 /// table. No memory is allocated unless the `HASHER` or `COMPARATOR` types allocate memory in their default constructor.
2109 ///
2110 /// \note Note that a
2111 /// `bslma::Allocator *` can be supplied for `basicAllocator` if the
2112 /// type `ALLOCATOR` is `bsl::allocator` (the default).
2113 explicit HashTable(const ALLOCATOR& basicAllocator = ALLOCATOR());
2114
2115 /// Create an empty hash-table using the specified `hash` and `compare`
2116 /// functors to organize elements in the table, which will initially
2117 /// have at least the specified `initialNumBuckets` and a
2118 /// `maxLoadFactor` of the specified `initialMaxLoadFactor`. Optionally
2119 /// specify a `basicAllocator` used to supply memory. If
2120 /// `basicAllocator` is not supplied, a default-constructed object of
2121 /// the (template parameter) type `ALLOCATOR` is used. If the type
2122 /// `ALLOCATOR` is `bsl::allocator` and `basicAllocator` is not
2123 /// supplied, the currently installed default allocator is used to
2124 /// supply memory. If this constructor tries to allocate a number of
2125 /// buckets larger than can be represented by this hash-table's
2126 /// `SizeType`, a `std::length_error` exception is thrown.
2127 ///
2128 /// \pre The behavior is undefined unless `0 < initialMaxLoadFactor`.
2129 /// \note Note that more than
2130 /// `initialNumBuckets` buckets may be created in order to preserve the
2131 /// bucket allocation strategy of the hash-table (but never fewer).
2132 /// Also note that a `bslma::Allocator *` can be supplied for
2133 /// `basicAllocator` if the type `ALLOCATOR` is `bsl::allocator` (the
2134 /// default).
2135 HashTable(const HASHER& hash,
2136 const COMPARATOR& compare,
2137 SizeType initialNumBuckets,
2138 float initialMaxLoadFactor,
2139 const ALLOCATOR& basicAllocator = ALLOCATOR());
2140
2141 /// Create a hash-table having the same value (and `maxLoadFactor`) as
2142 /// the specified `original` object. Use a copy of `original.hasher()`
2143 /// and a copy of `original.comparator()` to organize elements in this
2144 /// hash-table. Use the allocator returned by
2145 /// 'bsl::allocator_traits<ALLOCATOR>::
2146 /// select_on_container_copy_construction(original.allocator())'
2147 /// to allocate memory. This method requires that the `ValueType`
2148 /// defined by the (template parameter) type `KEY_CONFIG` be
2149 /// `copy-insertable` into this hash-table (see '{Requirements on `KEY_CONFIG`}).
2150 ///
2151 /// \note Note that this hash-table may have fewer buckets
2152 /// than `original`, and a correspondingly higher `loadFactor`, so long
2153 /// as `maxLoadFactor` is not exceeded. Also note that the created hash
2154 /// table may have a different `numBuckets` than `original`, and a
2155 /// correspondingly different `loadFactor`, as long as `maxLoadFactor`
2156 /// is not exceeded.
2157 HashTable(const HashTable& original);
2158
2159 /// Create a hash-table having the same value (and `maxLoadFactor`) as
2160 /// the specified `original` object by moving (in constant time) the
2161 /// contents of `original` to the new hash-table. Use a copy of
2162 /// `original.hasher()` and a copy of `original.comparator()` to
2163 /// organize elements in this hash-table. The allocator associated with
2164 /// `original` is propagated for use in the newly created hash-table.
2165 /// `original` is left in a valid but unspecified state.
2166 HashTable(BloombergLP::bslmf::MovableRef<HashTable> original);
2167
2168 /// Create a hash-table having the same value (and `maxLoadFactor`) as
2169 /// the specified `original` object that uses the specified
2170 /// `basicAllocator` to supply memory. Use a copy of
2171 /// `original.hasher()` and a copy of `original.comparator()` to
2172 /// organize elements in this hash-table. This method requires that the
2173 /// `ValueType` defined by the (template parameter) type `KEY_CONFIG` be `move-insertable` into this hash-table.
2174 ///
2175 /// \note Note that this hash-table
2176 /// may have a different `numBuckets` than `original`, and a
2177 /// correspondingly different `loadFactor`, as long as `maxLoadFactor`
2178 /// is not exceeded.
2179 HashTable(const HashTable& original, const ALLOCATOR& basicAllocator);
2180
2181 /// Create a hash table having the same value (and `maxLoadFactor`) as
2182 /// the specified `original` object that uses the specified
2183 /// `basicAllocator` to supply memory. The contents of `original` are
2184 /// moved (in constant time) to the new hash-table if
2185 /// `basicAllocator == original.get_allocator()`, and are move-inserted
2186 /// (in linear time) using `basicAllocator` otherwise. `original` is
2187 /// left in a valid but unspecified state. Use a copy of
2188 /// `original.hasher()` and a copy of `original.comparator()` to
2189 /// organize elements in this hash-table. This method requires that the
2190 /// `ValueType` defined by the (template parameter) type `KEY_CONFIG` be `move-insertable` into this hash-table.
2191 ///
2192 /// \note Note that this hash-table
2193 /// may have a different `numBuckets` than `original`, and a
2194 /// correspondingly different `loadFactor`, as long as `maxLoadFactor`
2195 /// is not exceeded. Also note that a `bslma::Allocator *` can be
2196 /// supplied for `basicAllocator` if the (template parameter)
2197 /// `ALLOCATOR` is `bsl::allocator` (the default).
2198 HashTable(BloombergLP::bslmf::MovableRef<HashTable> original,
2199 const ALLOCATOR& basicAllocator);
2200
2201 /// Destroy this object.
2202 ~HashTable();
2203
2204 // MANIPULATORS
2205
2206 /// Assign to this object the value, hasher, comparator and
2207 /// `maxLoadFactor` of the specified `rhs` object, propagate to this
2208 /// object the allocator of `rhs` if the `ALLOCATOR` type has trait
2209 /// @ref propagate_on_container_copy_assignment , and return a reference
2210 /// providing modifiable access to this object. This method requires
2211 /// that the `ValueType` defined by the (template parameter) type
2212 /// `KEY_CONFIG` be `copy-assignable` and `copy-insertable` into this
2213 /// hash-table (see {Requirements on `KEY_CONFIG`}). This method
2214 /// requires that the (template parameter) types `HASHER` and
2215 /// `COMPARATOR` be `copy-constructible` and `copy-assignable`.
2216 ///
2217 /// \note Note that these requirements are modeled after the unordered container
2218 /// requirements table in the C++11 standard, which is imprecise on this
2219 /// operation; these requirements might simplify in the future, if the
2220 /// standard is updated.
2221 HashTable& operator=(const HashTable& rhs);
2222
2223 /// Assign to this object the value, hasher, comparator, and
2224 /// `maxLoadFactor` of the specified `rhs` object, propagate to this
2225 /// object the allocator of `rhs` if the `ALLOCATOR` type has trait
2226 /// @ref propagate_on_container_move_assignment , and return a reference
2227 /// providing modifiable access to this object. If this hash-table and
2228 /// `rhs` use the same allocator (after considering the aforementioned
2229 /// trait), all of the contents of `rhs` are moved to this hash-table in
2230 /// constant time; otherwise, all elements in this hash table are either
2231 /// destroyed or move-assigned to and each additional element in `rhs`
2232 /// is move-inserted into this hash-table. `rhs` is left in a valid but
2233 /// unspecified state. This method requires that the `ValueType`
2234 /// defined by the (template parameter) type `KEY_CONFIG` be both
2235 /// `move-assignable` and `move-insertable` into this hash-table (see
2236 /// {Requirements on `KEY_CONFIG`}).
2237 HashTable& operator=(BloombergLP::bslmf::MovableRef<HashTable> rhs);
2238
2239#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
2240 /// Insert into this hash-table a newly-created `ValueType` object,
2241 /// constructed by forwarding the specified (variable number of)
2242 /// `arguments` to the corresponding constructor of `ValueType`, and
2243 /// return the address of the newly inserted node. If a key equivalent
2244 /// to that of the newly-created object already exists in this
2245 /// hash-table, then insert the newly-created object immediately before
2246 /// the first such element. Additional buckets are allocated, as
2247 /// needed, to preserve the invariant `loadFactor <= maxLoadFactor`. If
2248 /// this function tries to allocate a number of buckets larger than can
2249 /// be represented by this hash-table's `SizeType`, a
2250 /// `std::length_error` exception is thrown. This method requires that
2251 /// the `ValueType` defined in the (template parameter) type
2252 /// `KEY_CONFIG` be `emplace-constructible` into this hash-table from
2253 /// `arguments` (see {Requirements on `KEY_CONFIG`});
2254 template <class... Args>
2255 bslalg::BidirectionalLink *emplace(Args&&... arguments);
2256
2257 /// Insert into this hash-table a newly-created `ValueType` object,
2258 /// constructed by forwarding the specified (variable number of)
2259 /// `arguments` to the corresponding constructor of `ValueType`
2260 /// (immediately preceding the specified `hint` if `hint` is not null
2261 /// and the key of the node pointed to by `hint` is equivalent to that
2262 /// of the newly-created object), and return the address of the newly
2263 /// inserted node. If `hint` is null or the key of the node pointed to
2264 /// by `hint` is not equivalent to that of the newly created object, and
2265 /// a key equivalent to that of the newly-created object already exists
2266 /// in this hash-table, then insert the newly-created object immediately
2267 /// before the first such element. Additional buckets will be
2268 /// allocated, as needed, to preserve the invariant
2269 /// `loadFactor <= maxLoadFactor`. If this function tries to allocate a
2270 /// number of buckets larger than can be represented by this hash
2271 /// table's `SizeType`, a `std::length_error` exception is thrown. This
2272 /// method requires that `ValueType` defined in the (template parameter)
2273 /// type `KEY_CONFIG` be `emplace-constructible` into this hash-table
2274 /// from `arguments` (see {Requirements on `KEY_CONFIG`}).
2275 ///
2276 /// \pre The behavior is undefined unless `hint` is either null or points to a node in
2277 /// this hash table.
2278 template <class... Args>
2281 Args&&... arguments);
2282
2283 /// Insert into this hash-table a newly-created `ValueType` object,
2284 /// constructed by forwarding the specified (variable number of)
2285 /// `arguments` to the corresponding constructor of `ValueType`, if a
2286 /// key equivalent to that of the newly-created object does not already
2287 /// exist in this hash-table. Return the address of the (possibly newly
2288 /// created and inserted) element in this hash table whose key is
2289 /// equivalent to that of an object created from `arguments`. Load
2290 /// `true` into the specified `isInsertedFlag` if a new value was
2291 /// inserted, and `false` if an equivalent key was already present. If
2292 /// this hash-table contains more than one element with an equivalent
2293 /// key, return the first such element (from the contiguous sequence of
2294 /// elements having a matching key). Additional buckets are allocated,
2295 /// as needed, to preserve the invariant `loadFactor <= maxLoadFactor`.
2296 /// If this function tries to allocate a number of buckets larger than
2297 /// can be represented by this hash-table's `SizeType`, a
2298 /// `std::length_error` exception is thrown. This method requires that
2299 /// the `ValueType` defined in the (template parameter) type
2300 /// `KEY_CONFIG` be `emplace-constructible` into this hash-table from
2301 /// `arguments` (see {Requirements on `KEY_CONFIG`});
2302 template <class... Args>
2304 Args&&... arguments);
2305#endif
2306
2307 /// Insert into this hash-table a newly-created `ValueType` object,
2308 /// constructed by forwarding the specified `key` and a
2309 /// default-constructed object of the type `ValueType::second_type`, to
2310 /// the corresponding constructor of `ValueType`, if `key` does not
2311 /// already exist in this hash-table. Return the address of the
2312 /// (possibly newly created and inserted) element in this hash-table
2313 /// whose key is equivalent to `key`. If this hash-table contains more
2314 /// than one element with the supplied `key`, return the first such
2315 /// element (from the contiguous sequence of elements having a matching
2316 /// key). Additional buckets are allocated, as needed, to preserve the
2317 /// invariant `loadFactor <= maxLoadFactor`. If this function tries to
2318 /// allocate a number of buckets larger than can be represented by this
2319 /// hash table's `SizeType`, a `std::length_error` exception is thrown.
2320 /// This method requires that the `ValueType` defined in the (template
2321 /// parameter) type `KEY_CONFIG` be `emplace-constructible` into this
2322 /// hash-table from a `pair` of arguments representing the key and
2323 /// value, respectively (see {Requirements on `KEY_CONFIG`});
2327
2328 /// Insert the specified `value` into this hash-table if a key
2329 /// equivalent to that of `value` does not already exist in this
2330 /// hash-table. Return the address of the (possibly newly inserted)
2331 /// element in this hash-table whose key is equivalent to that of
2332 /// `value`. If this hash-table contains more than one element with a
2333 /// matching key, return the first such element (from the contiguous
2334 /// sequence of elements having a matching key). Additional buckets are
2335 /// allocated, as needed, to preserve the invariant
2336 /// `loadFactor <= maxLoadFactor`. If this function tries to allocate a
2337 /// number of buckets larger than can be represented by this
2338 /// hash-table's `SizeType`, a `std::length_error` exception is thrown.
2339 /// This method requires that the `ValueType` defined in the (template
2340 /// parameter) type `KEY_CONFIG` be `copy-insertable` into this
2341 /// hash-table (see {Requirements on `KEY_CONFIG`});
2343 bool *isInsertedFlag,
2344 const ValueType& value);
2345
2346 /// Insert the specified `value` into this hash-table if a key
2347 /// equivalent to that of `value` does not already exist in this
2348 /// hash-table. Return the address of the (possibly newly inserted)
2349 /// element in this hash-table whose key is equivalent to that of
2350 /// `value`. `value` is left in a valid but unspecified state. If this
2351 /// hash-table contains more than one element with a matching key,
2352 /// return the first such element (from the contiguous sequence of
2353 /// elements having a matching key). Additional buckets are allocated,
2354 /// as needed, to preserve the invariant `loadFactor <= maxLoadFactor`.
2355 /// If this function tries to allocate a number of buckets larger than
2356 /// can be represented by this hash-table's `SizeType`, a
2357 /// `std::length_error` exception is thrown. This method requires that
2358 /// the `ValueType` defined in the (template parameter) type
2359 /// `KEY_CONFIG` be `move-insertable` into this hash-table (see
2360 /// {Requirements on `KEY_CONFIG`});
2362 bool *isInsertedFlag,
2364
2365 /// Insert into this hash-table a `ValueType` object created from the
2366 /// specified `value` if a key equivalent to that of such an object does
2367 /// not already exist in this hash-table. Return the address of the
2368 /// (possibly newly inserted) element in this hash-table whose key is
2369 /// equivalent to that of the object created from `value`. Load `true`
2370 /// into the specified `isInsertedFlag` if a new value was inserted, and
2371 /// `false` if an equivalent key was already present. If this
2372 /// hash-table contains more than one element with an equivalent key,
2373 /// return the first such element (from the contiguous sequence of
2374 /// elements having a matching key). Additional buckets are allocated,
2375 /// as needed, to preserve the invariant `loadFactor <= maxLoadFactor`.
2376 /// If this function tries to allocate a number of buckets larger than
2377 /// can be represented by this hash-table's `SizeType`, a
2378 /// `std::length_error` exception is thrown. This method requires that
2379 /// the `ValueType` defined in the (template parameter) type
2380 /// `KEY_CONFIG` be `move-insertable` into this hash-table (see
2381 /// {Requirements on `KEY_CONFIG`}) and the (template parameter) type
2382 /// `SOURCE_TYPE` be implicitly convertible to `ValueType`.
2383 template <class SOURCE_TYPE>
2386 bool *isInsertedFlag,
2387 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value);
2388
2389#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
2390 /// Insert into this hash-table a `ValueType` object created from the
2391 /// specified `value` if a key equivalent to that of such an object does
2392 /// not already exist in this hash-table. Return the address of the
2393 /// (possibly newly inserted) element in this hash-table whose key is
2394 /// equivalent to that of the object created from `value`. Load `true`
2395 /// into the specified `isInsertedFlag` if a new value was inserted, and
2396 /// `false` if an equivalent key was already present. If this
2397 /// hash-table contains more than one element with an equivalent key,
2398 /// return the first such element (from the contiguous sequence of
2399 /// elements having a matching key). Additional buckets are allocated,
2400 /// as needed, to preserve the invariant `loadFactor <= maxLoadFactor`.
2401 /// If this function tries to allocate a number of buckets larger than
2402 /// can be represented by this hash-table's `SizeType`, a
2403 /// `std::length_error` exception is thrown. This method requires that
2404 /// the `ValueType` defined in the (template parameter) type
2405 /// `KEY_CONFIG` be `move-insertable` into this hash-table (see
2406 /// {Requirements on `KEY_CONFIG`}) and the (template parameter) type
2407 /// `SOURCE_TYPE` be implicitly convertible to `ValueType`.
2408 template <class LOOKUP_KEY>
2409 typename bsl::enable_if<
2410 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2411 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value
2412 , bslalg::BidirectionalLink *>::type
2414 bool *isInsertedFlag,
2415 BSLS_COMPILERFEATURES_FORWARD_REF(LOOKUP_KEY) value)
2416 {
2417 // Note: implemented inline due to Sun CC compilation error.
2418
2419 BSLS_ASSERT(isInsertedFlag);
2420
2421 const LOOKUP_KEY& lvalue = value;
2422
2423 size_t hashCode = this->d_parameters.hashCodeForTransparentKey(lvalue);
2424
2425 bslalg::BidirectionalLink *position =
2426 bslalg::HashTableImpUtil::findTransparent<KEY_CONFIG>(
2427 d_anchor,
2428 lvalue,
2429 d_parameters.comparator(),
2430 hashCode);
2431
2432 *isInsertedFlag = (!position);
2433
2434 if(!position) {
2435 if (d_size >= d_capacity) {
2436 this->rehashForNumBuckets(numBuckets() * 2);
2437 }
2438
2439 position = d_parameters.nodeFactory().emplaceIntoNewNode(
2440 BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, value));
2442 position,
2443 hashCode);
2444 ++d_size;
2445 }
2446
2447 return position;
2448 }
2449#endif
2450
2451 /// Insert into this hash-table a `ValueType` object created from the
2452 /// specified `value` and return the address of the newly inserted node.
2453 /// If a key equivalent to that of the newly-created object already
2454 /// exists in this hash-table, then insert the new object immediately
2455 /// before the first such element. Additional buckets are allocated, as
2456 /// needed, to preserve the invariant `loadFactor <= maxLoadFactor`. If
2457 /// this function tries to allocate a number of buckets larger than can
2458 /// be represented by this hash-table's `SizeType`, a
2459 /// `std::length_error` exception is thrown. This method requires that
2460 /// the `ValueType` defined in the (template parameter) type
2461 /// `KEY_CONFIG` be `move-insertable` into this hash-table (see
2462 /// {Requirements on `KEY_CONFIG`}) and the (template parameter) type
2463 /// `SOURCE_TYPE` be implicitly convertible to `ValueType`.
2464 ///
2465 /// \note Note that this method is deprecated is provided only to ensure backward
2466 /// compatibility with existing clients; use the `emplace` method
2467 /// instead.
2468 template <class SOURCE_TYPE>
2470 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value);
2471
2472 /// Insert into this hash-table a `ValueType` object created from the
2473 /// specified `value` (immediately preceding the specified `hint` if
2474 /// `hint` is not null and the key of the node pointed to by `hint` is
2475 /// equivalent to that of the newly-created object), and return the
2476 /// address of the newly inserted node. If `hint` is null or the key of
2477 /// the node pointed to by `hint` is not equivalent to that of the newly
2478 /// created object, and a key equivalent to that of the newly-created
2479 /// object already exists in this hash-table, then insert the
2480 /// newly-created object immediately before the first such element.
2481 /// Additional buckets will be allocated, as needed, to preserve the
2482 /// invariant `loadFactor <= maxLoadFactor`. If this function tries to
2483 /// allocate a number of buckets larger than can be represented by this
2484 /// hash-table's `SizeType`, a `std::length_error` exception is thrown.
2485 /// This method requires that `ValueType` defined in the (template
2486 /// parameter) type `KEY_CONFIG` be `move-insertable` into this
2487 /// hash-table (see {Requirements on `KEY_CONFIG`}) and the (template
2488 /// parameter) type `SOURCE_TYPE` be implicitly convertible to `ValueType`.
2489 ///
2490 /// \note Note that this method is deprecated and is provided
2491 /// only to ensure backward compatibility with existing clients; use the
2492 /// `emplaceWithHint` method instead.
2493 template <class SOURCE_TYPE>
2495 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value,
2497
2498#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
2499 /// If a key equivalent to the specified `key` already exists in this
2500 /// hash-table, assign the specified `obj` to the value associated with
2501 /// that key, load `false` into the specified `isInsertedFlag` and
2502 /// return a pointer to the existing entry. Otherwise, insert into this
2503 /// hash-table a newly-created `value_type` object, constructed from
2504 /// `key` and `obj`, load `true` into `isInsertedFlag`, and return a
2505 /// pointer to the newly-created entry. Use the optionally specified
2506 /// `hint` as a starting place for the search for the existing key.
2507 template <class KEY_ARG, class BDE_OTHER_TYPE>
2509 bool *isInsertedFlag,
2512 BDE_OTHER_TYPE&& obj);
2513
2514 /// If a key equivalent to the specified `key` already exists in this
2515 /// hash-table, assign the specified `obj` to the value associated with
2516 /// that key, load `false` into the specified `isInsertedFlag` and
2517 /// return a pointer to the existing entry. Otherwise, insert into this
2518 /// hash-table a newly-created `value_type` object, constructed from
2519 /// `key` and `obj`, load `true` into `isInsertedFlag`, and return a
2520 /// pointer to the newly-created entry. Use the optionally specified
2521 /// `hint` as a starting place for the search for the existing key.
2522 template <class LOOKUP_KEY, class BDE_OTHER_TYPE>
2523 typename bsl::enable_if<
2524 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2525 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value
2526 , bslalg::BidirectionalLink *>::type
2527 insertOrAssignTransparent(bool *isInsertedFlag,
2529 LOOKUP_KEY&& key,
2530 BDE_OTHER_TYPE&& obj)
2531 {
2532 // Note: implemented inline due to Sun CC compilation error.
2533
2534 typedef bslalg::HashTableImpUtil ImpUtil;
2535
2536 size_t hashCode = this->d_parameters.hashCodeForTransparentKey(key);
2537 // Use the hint, if we can
2538 if (!hint
2539 || !d_parameters.comparator()(key,
2540 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
2541 hint = bslalg::HashTableImpUtil::findTransparent<KEY_CONFIG>(
2542 d_anchor,
2543 key,
2544 d_parameters.comparator(),
2545 hashCode);
2546 }
2547
2548 if (hint) { // assign
2549 static_cast<NodeType *>(hint)->value().second =
2550 BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, obj);
2551 *isInsertedFlag = false;
2552 return hint; // RETURN
2553 }
2554
2555 // insert
2556 if (d_size >= d_capacity) {
2557 this->rehashForNumBuckets(numBuckets() * 2);
2558 }
2559
2560 // Make a new node
2561 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
2562 BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key),
2563 BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, obj));
2564
2565 // Add it to the hash table
2567 nodeProctor(&d_parameters.nodeFactory(), hint);
2568 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
2569 nodeProctor.release();
2570 ++d_size;
2571
2572 *isInsertedFlag = true;
2573 return hint;
2574 }
2575#endif
2576
2577 /// Re-organize this hash-table to have at least the specified
2578 /// `newNumBuckets`, preserving the invariant
2579 /// `loadFactor <= maxLoadFactor`. If this function tries to allocate a
2580 /// number of buckets larger than can be represented by this hash
2581 /// table's `SizeType`, a `std::length_error` exception is thrown. This
2582 /// operation provides the strong exception guarantee (see
2583 /// @ref bsldoc_glossary ) unless the `hasher` throws, in which case this
2584 /// operation provides the basic exception guarantee, leaving the
2585 /// hash-table in a valid, but otherwise unspecified (and potentially empty), state.
2586 ///
2587 /// \note Note that more buckets than requested may be
2588 /// allocated in order to preserve the bucket allocation strategy of the
2589 /// hash table (but never fewer).
2590 void rehashForNumBuckets(SizeType newNumBuckets);
2591
2592 /// Remove the specified `node` from this hash-table, and return the
2593 /// address of the node immediately after `node` in this hash-table
2594 /// (prior to its removal), or a null pointer value if `node` is the
2595 /// last node in the table. This method invalidates only iterators and
2596 /// references to the removed node and previously saved values of the
2597 /// `end()` iterator, and preserves the relative order of the nodes not removed.
2598 ///
2599 /// \pre The behavior is undefined unless `node` refers to a node
2600 /// in this hash-table.
2602
2603 /// Remove all the elements from this hash-table.
2604 /// \note Note that this
2605 /// hash-table is empty after this call, but allocated memory may be
2606 /// retained for future use. The destructor of each (non-trivial)
2607 /// element that is remove shall be run.
2608 void removeAll();
2609
2610 /// Re-organize this hash-table to have a sufficient number of buckets
2611 /// to accommodate at least the specified `numElements` without
2612 /// exceeding the `maxLoadFactor`, and ensure that there are sufficient
2613 /// nodes pre-allocated in this object's node pool. If this function
2614 /// tries to allocate a number of buckets larger than can be represented
2615 /// by this hash table's `SizeType`, a `std::length_error` exception is
2616 /// thrown. This operation provides the strong exception guarantee (see
2617 /// @ref bsldoc_glossary ) unless the `hasher` throws, in which case this
2618 /// operation provides the basic exception guarantee, leaving the
2619 /// hash-table in a valid, but otherwise unspecified (and potentially
2620 /// empty), state.
2621 void reserveForNumElements(SizeType numElements);
2622
2623 /// Set the maximum load factor permitted by this hash table to the
2624 /// specified `newMaxLoadFactor`, where load factor is the statistical
2625 /// mean number of elements per bucket. If 'newMaxLoadFactor <
2626 /// loadFactor', allocate at least enough buckets to re-establish the
2627 /// invariant `loadFactor <= maxLoadFactor`. If this function tries to
2628 /// allocate a number of buckets larger than can be represented by this
2629 /// hash table's `SizeType`, a `std::length_error` exception is thrown.
2630 ///
2631 /// \pre The behavior is undefined unless `0 < maxLoadFactor`.
2632 void setMaxLoadFactor(float newMaxLoadFactor);
2633
2634 /// Exchange the value of this object, its `comparator` functor, its
2635 /// `hasher` functor, and its `maxLoadFactor` with those of the
2636 /// specified `other` object. Additionally, if
2637 /// `bslstl::AllocatorTraits<ALLOCATOR>::propagate_on_container_swap` is
2638 /// `true`, then exchange the allocator of this object with that of the
2639 /// `other` object, and do not modify either allocator otherwise. This
2640 /// method provides the no-throw exception-safety guarantee unless any
2641 /// of the `comparator` or `hasher` functors throw when swapped, leaving
2642 /// both objects in a safely destructible, but otherwise unusable,
2643 /// state. The operation guarantees `O[1]` complexity.
2644 ///
2645 /// \pre The behavior is undefined unless either this object has an allocator that compares
2646 /// equal to the allocator of `other`, or the trait
2647 /// `bslstl::AllocatorTraits<ALLOCATOR>::propagate_on_container_swap` is
2648 /// `true`.
2649 void swap(HashTable& other);
2650
2651#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
2652 /// If a key equivalent to the specified `key` already exists in this
2653 /// hash-table, load `false` into the specified `isInsertedFlag` and
2654 /// return a pointer to the existing entry. Otherwise, insert into this
2655 /// hash-table a newly-created `value_type` object, constructed from
2656 /// `key` and the specified `args`, load `true` into `isInsertedFlag`
2657 /// and return a pointer to the newly created entry. Use the optionally
2658 /// specified `hint` as a starting place for the search for the existing
2659 /// key.
2660 template <class... ARGS>
2662 bool *isInsertedFlag,
2664 const KeyType& key,
2665 ARGS&&... args);
2666
2667 /// If a key equivalent to the specified `key` already exists in this
2668 /// hash-table, load `false` into the specified `isInsertedFlag` and
2669 /// return a pointer to the existing entry. Otherwise, insert into this
2670 /// hash-table a newly-created `value_type` object, constructed from
2671 /// `std::forward<KEY>(key)` and the specified `args`, load `true` into
2672 /// `isInsertedFlag` and return a pointer to the newly created entry.
2673 /// Use the optionally specified `hint` as a starting place for the
2674 /// search for the existing key.
2675 template <class... ARGS>
2677 bool *isInsertedFlag,
2680 ARGS&&... args);
2681
2682
2683 /// If a key equivalent to the specified `key` already exists in this
2684 /// hash-table, load `false` into the specified `isInsertedFlag` and
2685 /// return a pointer to the existing entry. Otherwise, insert into this
2686 /// hash-table a newly-created `value_type` object, constructed from
2687 /// `key` and the specified `args`, load `true` into `isInsertedFlag`
2688 /// and return a pointer to the newly created entry. Use the optionally
2689 /// specified `hint` as a starting place for the search for the existing
2690 /// key.
2691 template <class LOOKUP_KEY, class... ARGS>
2692 typename bsl::enable_if<
2693 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2694 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value,
2696 bool *isInsertedFlag,
2698 LOOKUP_KEY&& key,
2699 ARGS&&... args)
2700 {
2701 // Note: implemented inline due to Sun CC compilation error.
2702
2703 typedef bslalg::HashTableImpUtil ImpUtil;
2704
2705 const std::size_t hashCode =
2706 this->d_parameters.hashCodeForTransparentKey(key);
2707
2708 // Use the hint, if we can
2709 if (!hint
2710 || !d_parameters.comparator()(
2711 key,
2712 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
2713
2714 hint = bslalg::HashTableImpUtil::findTransparent<KEY_CONFIG>(
2715 d_anchor,
2716 key,
2717 d_parameters.comparator(),
2718 hashCode);
2719 }
2720
2721 // If the key exists, we're done
2722 if (hint) {
2723 *isInsertedFlag = false;
2724 return hint; // RETURN
2725 }
2726
2727 if (d_size >= d_capacity) {
2728 this->rehashForNumBuckets(numBuckets() * 2);
2729 }
2730
2731 // Make a new node
2732 #if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR)
2733 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
2734 std::piecewise_construct,
2735 std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key)),
2736 std::forward_as_tuple(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...));
2737 #else
2738 typedef typename ValueType::second_type MappedType;
2739
2740 // TBD: make 'this->allocator()' return the allocator by reference with
2741 // modifiable access rather than by value.
2742
2743 AllocatorType alloc = this->allocator();
2744
2745 bsls::ObjectBuffer<MappedType> defaultMapped;
2746 AllocatorTraits::construct(alloc, defaultMapped.address(),
2747 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
2748 bslma::DestructorGuard<MappedType> mGuard(defaultMapped.address());
2749
2750 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
2751 BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key),
2752 defaultMapped.object());
2753 #endif
2754
2755 // Add it to the hash table
2757 nodeProctor(&d_parameters.nodeFactory(), hint);
2758 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
2759 nodeProctor.release();
2760 ++d_size;
2761
2762 *isInsertedFlag = true;
2763 return hint;
2764 }
2765#endif
2766
2767 // ACCESSORS
2768
2769 /// Return a copy of the allocator used to construct this hash table.
2770 ///
2771 /// \note Note that this is not the allocator used to allocate elements for
2772 /// this hash table, which is instead a copy of that allocator rebound
2773 /// to allocate the nodes used by the internal data structure of this
2774 /// hash table.
2775 ALLOCATOR allocator() const;
2776
2777 /// Return a reference offering non-modifiable access to the
2778 /// `HashTableBucket` at the specified `index` position in the array of buckets of this table.
2779 ///
2780 /// \pre The behavior is undefined unless 'index <
2781 /// numBuckets()'.
2783
2784 /// Return the index of the bucket that would contain all the elements
2785 /// having the specified `key`.
2786 SizeType bucketIndexForKey(const KeyType& key) const;
2787
2788 /// Return the index of the bucket that would contain all the elements
2789 /// equivalent to the specified `key`.
2790 template <class LOOKUP_KEY>
2791 typename bsl::enable_if<
2792 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2793 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value,
2794 SizeType>::type
2795 bucketIndexForKey(const LOOKUP_KEY& key) const
2796 {
2797 // Note: implemented inline due to Sun CC compilation error.
2798
2799 typedef typename
2801 SizeType;
2802
2803 // The following cast will not discard any useful bits, unless
2804 // 'SizeType' is larger than 'size_t', as the bucket computation takes
2805 // a mod on the supplied number of buckets. We use the following
2806 // 'BSLMF_ASSERT' to assert that assumption at compile time.
2807
2808 BSLMF_ASSERT(sizeof(SizeType) <= sizeof(size_t));
2809
2810 size_t hashCode = this->d_parameters.hashCodeForKey(key);
2811 return static_cast<SizeType>(
2813 hashCode,
2814 d_anchor.bucketArraySize()));
2815 }
2816
2817 /// Return a reference providing non-modifiable access to the
2818 /// key-equality comparison functor used by this hash table.
2819 const COMPARATOR& comparator() const;
2820
2821 /// Return the number elements contained in the bucket at the specified `index`.
2822 ///
2823 /// \note Note that this operation has linear run-time complexity
2824 /// with respect to the number of elements in the indexed bucket.
2826
2827 /// Return the address of the first element in this hash table, or a
2828 /// null pointer value if this hash table is empty.
2830
2831 /// Return the address of a link whose key is equivalent to the
2832 /// specified `key` (according to this hash-table's `comparator`), and a
2833 /// null pointer value if no such link exists. If this hash-table
2834 /// contains more than one element having the supplied `key`, return the
2835 /// first such element (from the contiguous sequence of elements having the same key).
2836 ///
2837 /// \pre The behavior is undefined unless `key` is equivalent
2838 /// to the elements of at most one equivalent-key group.
2839 template <class LOOKUP_KEY>
2840 typename bsl::enable_if<
2841 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2842 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value,
2844 find(const LOOKUP_KEY& key) const
2845 {
2846 // Note: implemented inline due to Sun CC compilation error.
2847
2848 return bslalg::HashTableImpUtil::findTransparent<KEY_CONFIG>(
2849 d_anchor,
2850 key,
2851 d_parameters.comparator(),
2852 d_parameters.hashCodeForKey(key));
2853 }
2854
2855 /// Return the address of a link whose key has the same value as the
2856 /// specified `key` (according to this hash-table's `comparator`), and a
2857 /// null pointer value if no such link exists. If this hash-table
2858 /// contains more than one element having the supplied `key`, return the
2859 /// first such element (from the contiguous sequence of elements having
2860 /// the same key).
2861 bslalg::BidirectionalLink *find(const KeyType& key) const;
2862
2863 /// Return the address of the first node after any nodes holding a value
2864 /// having the same key as the specified `first` node (according to this
2865 /// hash-table's `comparator`), and a null pointer value if all nodes
2866 /// following `first` hold values with the same key as `first`.
2867 ///
2868 /// \pre The behavior is undefined unless `first` is a link in this hash-table.
2869 ///
2870 /// \note Note that this hash-table ensures all elements having the same key
2871 /// form a contiguous sequence.
2873 bslalg::BidirectionalLink *first) const;
2874
2875 /// Load into the specified `first` and `last` pointers the respective
2876 /// addresses of the first and last link (in the list of elements owned
2877 /// by this hash table) where the contained elements have a key that is
2878 /// equivalent to the specified `key` using the `comparator` of this
2879 /// hash-table, and null pointer values if there are no elements matching `key`.
2880 ///
2881 /// \pre The behavior is undefined unless `key` is
2882 /// equivalent to the elements of at most one equivalent-key group.
2883 ///
2884 /// \note Note that the output values will form a closed range, where both
2885 /// `first` and `last` point to links satisfying the predicate (rather
2886 /// than a semi-open range where `last` would point to the element
2887 /// following the range). Also note that this hash-table ensures all
2888 /// elements having the same key form a contiguous sequence.
2889 template <class LOOKUP_KEY>
2890 typename bsl::enable_if<
2891 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value
2892 && BloombergLP::bslmf::IsTransparentPredicate<COMPARATOR,LOOKUP_KEY>::value,
2893 void>::type
2896 const LOOKUP_KEY& key) const
2897 {
2898 // Note: implemented inline due to Sun CC compilation error.
2899
2900 BSLS_ASSERT_SAFE(first);
2901 BSLS_ASSERT_SAFE(last);
2902
2903 *first = this->find(key);
2904 *last = *first ? this->findEndOfRange(*first) : 0;
2905 }
2906
2907 /// Load into the specified `first` and `last` pointers the respective
2908 /// addresses of the first and last link (in the list of elements owned
2909 /// by this hash table) where the contained elements have a key that
2910 /// compares equal to the specified `key` using the `comparator` of this
2911 /// hash-table, and null pointer values if there are no elements matching `key`.
2912 ///
2913 /// \note Note that the output values will form a closed
2914 /// range, where both `first` and `last` point to links satisfying the
2915 /// predicate (rather than a semi-open range where `last` would point to
2916 /// the element following the range). Also note that this hash-table
2917 /// ensures all elements having the same key form a contiguous sequence.
2920 const KeyType& key) const;
2921
2922 /// Return `true` if the specified `other` has the same value as this
2923 /// object, and `false` otherwise. Two `HashTable` objects have the
2924 /// same value if they have the same number of elements, and for every
2925 /// subset of elements in this object having keys that compare equal
2926 /// (according to that hash table's `comparator`), a corresponding
2927 /// subset of elements exists in the `other` object, having the same
2928 /// number of elements, where, for some permutation of the subset in
2929 /// this object, every element in that subset compares equal (using
2930 /// `operator==`) to the corresponding element in the `other` subset.
2931 ///
2932 /// \pre The behavior is undefined unless both the `hasher` and `comparator`
2933 /// of this object and the `other` return the same value for every valid input.
2934 ///
2935 /// \note Note that this method requires that the `ValueType` of the
2936 /// parameterized `KEY_CONFIG` be "equality-comparable" (see
2937 /// {Requirements on `KEY_CONFIG`}).
2938 bool hasSameValue(const HashTable& other) const;
2939
2940 /// Return a reference providing non-modifiable access to the hash
2941 /// functor used by this hash-table.
2942 const HASHER& hasher() const;
2943
2944 /// Return the current load factor for this table. The load factor is
2945 /// the statistical mean number of elements per bucket.
2946 float loadFactor() const;
2947
2948 /// Return the maximum load factor permitted by this hash table object,
2949 /// where the load factor is the statistical mean number of elements per bucket.
2950 ///
2951 /// \note Note that this hash table will enforce the maximum load
2952 /// factor by rehashing into a larger array of buckets on any any
2953 /// insertion operation where a successful insertion would exceed the
2954 /// maximum load factor. The maximum load factor may actually be less
2955 /// than the current load factor if the maximum load factor has been
2956 /// reset, but no insert operations have yet occurred.
2957 float maxLoadFactor() const;
2958
2959 /// Return a theoretical upper bound on the largest number of buckets that this hash-table could possibly have.
2960 ///
2961 /// \note Note that there is no
2962 /// guarantee that the hash-table can successfully maintain that number
2963 /// of buckets, or even close to that number of buckets without running
2964 /// out of resources.
2965 SizeType maxNumBuckets() const;
2966
2967 /// Return a theoretical upper bound on the largest number of elements that this hash-table could possibly hold.
2968 ///
2969 /// \note Note that there is no
2970 /// guarantee that the hash-table can successfully grow to the returned
2971 /// size, or even close to that size without running out of resources.
2972 SizeType maxSize() const;
2973
2974 /// Return the number of buckets contained in this hash table.
2975 SizeType numBuckets() const;
2976
2977 /// Return the number of elements this hash table can hold without
2978 /// requiring a rehash operation in order to respect the
2979 /// `maxLoadFactor`.
2980 SizeType rehashThreshold() const;
2981
2982 /// Return the number of elements in this hash table.
2983 SizeType size() const;
2984};
2985
2986/// Swap both the value, the hasher, the comparator, and the `maxLoadFactor`
2987/// of the specified `x` object with the value, the hasher, the comparator,
2988/// and the `maxLoadFactor` of the specified `y` object. Additionally, if
2989/// `bslstl::AllocatorTraits<ALLOCATOR>::propagate_on_container_swap` is
2990/// `true`, then exchange the allocator of `x` with that of `y`, and do not
2991/// modify either allocator otherwise. This method guarantees `O[1]`
2992/// complexity if `x` and `y` have the same allocator or if the allocators
2993/// propagate on swap, otherwise this operation will typically pay the cost
2994/// of two copy constructors, which may in turn throw. If the allocators
2995/// are the same or propagate, then this method provides the no-throw
2996/// exception-safety guarantee unless the `swap` function of the hasher or
2997/// comparator throw. Otherwise this method offers only the basic exception
2998/// safety guarantee.
2999template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3002
3003/// Return `true` if the specified `lhs` and `rhs` objects have the same
3004/// value, and `false` otherwise. Two `HashTable` objects have the same
3005/// value if they have the same number of elements, and for every subset of
3006/// elements in `lhs` having keys that compare equal (according to that hash
3007/// table's `comparator`), a corresponding subset of elements exists in
3008/// `rhs`, having the same number of elements, where, for some permutation
3009/// of the `lhs` subset, every element in that subset compares equal (using
3010/// `operator==`) to the corresponding element in the `rhs` subset.
3011///
3012/// \pre The behavior is undefined unless both the `hasher` and `comparator` of `lhs` and `rhs` return the same value for every valid input.
3013///
3014/// \note Note that this
3015/// method requires that the `ValueType` of the parameterized `KEY_CONFIG`
3016/// be "equality-comparable" (see {Requirements on `KEY_CONFIG`}).
3017template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3018bool operator==(
3021
3022/// Return `true` if the specified `lhs` and `rhs` objects do not have the
3023/// same value, and `false` otherwise. Two `HashTable` objects do not have
3024/// the same value if they do not have the same number of elements, or if,
3025/// for any key found in `lhs`, the subset of elements having that key
3026/// (according to the hash-table's `comparator`) in `lhs` either (1) does
3027/// not have the same number of elements as the subset of elements having
3028/// that key in `rhs`, or (2) there exists no permutation of the `lhs`
3029/// subset where each element compares equal (using `operator==`) to the
3030/// corresponding element in the `rhs` subset.
3031///
3032/// \pre The behavior is undefined unless both the `hasher` and `comparator` of `lhs` and `rhs` return the same value for every valid input.
3033///
3034/// \note Note that this method requires that
3035/// the `ValueType` of the parameterized `KEY_CONFIG` be
3036/// "equality-comparable" (see {Requirements on `KEY_CONFIG`}).
3037template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3038bool operator!=(
3041
3042 // ============================
3043 // class HashTable_ArrayProctor
3044 // ============================
3045
3046/// This class probably already exists in `bslalg`
3047///
3048/// See @ref bslstl_hashtable
3049template <class FACTORY>
3051
3052 private:
3053 // DATA
3054 FACTORY *d_factory_p;
3055 bslalg::HashTableAnchor *d_anchor_p;
3056
3057 private:
3058 // NOT IMPLEMENTED
3061
3062 public:
3063 // CREATORS
3064
3065 /// Create a `HashTable_ArrayProctor` managing the hash-table data
3066 /// structure owned by the specified `anchor` that was created using the
3067 /// specified `factory`.
3068 HashTable_ArrayProctor(FACTORY *factory,
3069 bslalg::HashTableAnchor *anchor);
3070
3071 /// Destroy the hash-table data structure managed by this proctor and
3072 /// reclaim all of its resources, unless there was a call to `release`
3073 /// this proctor.
3075
3076 // MANIPULATORS
3077
3078 /// Release from management the object currently managed by this
3079 /// proctor. If no object is currently being managed, this method has
3080 /// no effect.
3081 void release();
3082};
3083
3084 // ===========================
3085 // class HashTable_NodeProctor
3086 // ===========================
3087
3088/// This class implements a proctor that, unless its `release` method has
3089/// previously been invoked, automatically deallocates a managed list of
3090/// nodes upon destruction by recursively invoking the `deleteNode` method
3091/// of a supplied factory on each node. The (template parameter) type
3092/// `FACTORY` shall be provide a member function that can be called as if it
3093/// had the following signature:
3094/// @code
3095/// void deleteNode(bslalg::BidirectionalLink *node);
3096/// @endcode
3097///
3098/// See @ref bslstl_hashtable
3099template <class FACTORY>
3101
3102 private:
3103 // DATA
3104 FACTORY *d_factory_p;
3105 bslalg::BidirectionalLink *d_node_p;
3106
3107 private:
3108 // NOT IMPLEMENTED
3111
3112 public:
3113 // CREATORS
3114
3115 /// Create a new node-proctor that conditionally manages the specified
3116 /// `node` (if non-zero), and that uses the specified `factory` to
3117 /// destroy the node (unless released) upon its destruction.
3118 ///
3119 /// \pre The behavior is undefined unless `node` was created by the `factory`.
3120 HashTable_NodeProctor(FACTORY *factory,
3122
3123 /// Destroy this node proctor, and delete the node that it manages (if
3124 /// any) by invoking the `deleteNode` method of the factory supplied at
3125 /// construction. If no node is currently being managed, this method
3126 /// has no effect.
3128
3129 // MANIPULATORS
3130
3131 /// Release from management the node currently managed by this proctor.
3132 /// If no object is currently being managed, this method has no effect.
3133 void release();
3134};
3135
3136 // ==========================
3137 // class HashTable_ImpDetails
3138 // ==========================
3139
3140/// This utility `struct` provides a namespace for functions that are useful
3141/// when implementing a hash table.
3142///
3143/// See @ref bslstl_hashtable
3145
3146 // CLASS METHODS
3147
3148 /// Return the address of a statically initialized empty bucket that can
3149 /// be shared as the (un-owned) bucket array by all empty hash tables.
3151
3152 /// Return the suggested number of buckets to index a linked list that
3153 /// can hold as many as the specified `minElements` without exceeding
3154 /// the specified `maxLoadFactor`, and supporting at least the specified
3155 /// number of `requestedBuckets`. Set the specified `*capacity` to the
3156 /// maximum length of linked list that the returned number of buckets
3157 /// could index without exceeding the `maxLoadFactor`.
3158 ///
3159 /// \pre The behavior is undefined unless `0 < maxLoadFactor`, `0 < minElements` and
3160 /// `0 < requestedBuckets`.
3161 static size_t growBucketsForLoadFactor(size_t *capacity,
3162 size_t minElements,
3163 size_t requestedBuckets,
3164 double maxLoadFactor);
3165
3166 /// Return that address of an allocator that can be used to allocate
3167 /// temporary storage, but that is neither the default nor global allocator.
3168 ///
3169 /// \note Note that this function is intended to support detailed
3170 /// checks in `SAFE_2` builds, that may need additional storage for the
3171 /// evaluation of a validity check on a large data structure, but that
3172 /// should not change the expected values computed for regular allocator
3173 /// usage of the component as validated by the test driver.
3175
3176 /// Return the next prime number greater-than or equal to the specified
3177 /// `n` in the increasing sequence of primes chosen to disperse hash
3178 /// codes across buckets as uniformly as possible. Throw a
3179 /// `std::length_error` exception if `n` is greater than the last prime number in the sequence.
3180 ///
3181 /// \note Note that, typically, prime numbers in the
3182 /// sequence have increasing values that reflect a growth factor (e.g.,
3183 /// each value in the sequence may be, approximately, two times the
3184 /// preceding value).
3185 static size_t nextPrime(size_t n);
3186};
3187
3188 // ====================
3189 // class HashTable_Util
3190 // ====================
3191
3192/// This utility `struct` provide utilities for initializing and destroying
3193/// bucket lists in anchors that are managed by a `HashTable`. They cannot
3194/// migrate down to `bslalg::HashTableImpUtil` as they rely on the standard
3195/// library @ref bslma_allocatortraits for their implementation.
3196///
3197/// See @ref bslstl_hashtable
3199
3200 // CLASS METHODS
3201
3202 /// Assert that the passed argument (the specified `ptr`) is not a null pointer value.
3203 ///
3204 /// \note Note that this utility is necessary as the
3205 /// `HashTable` class template may be instantiated with function
3206 /// pointers for the hasher or comparator policies, but there is no easy
3207 /// way to assert in general that the value of a generic type passed to
3208 /// a function is not a null pointer value.
3209 template <class TYPE>
3210 static void assertNotNullPointer(TYPE&);
3211 template <class TYPE>
3212 static void assertNotNullPointer(TYPE * const& ptr);
3213 template <class TYPE>
3214 static void assertNotNullPointer(TYPE * & ptr);
3215
3216 /// Destroy the specified `data` array of the specified length
3217 /// `bucketArraySize`, that was allocated by the specified `allocator`.
3218 template<class ALLOCATOR>
3220 std::size_t bucketArraySize,
3221 const ALLOCATOR& allocator);
3222
3223 /// Load into the specified `anchor` a (contiguous) array of buckets of
3224 /// the specified `bucketArraySize` using memory supplied by the specified `allocator`.
3225 ///
3226 /// \pre The behavior is undefined unless
3227 /// `0 < bucketArraySize` and `0 == anchor->bucketArraySize()`.
3228 ///
3229 /// \note Note that this operation has no effect on `anchor->listRootAddress()`.
3230 template<class ALLOCATOR>
3231 static void initAnchor(bslalg::HashTableAnchor *anchor,
3232 std::size_t bucketArraySize,
3233 const ALLOCATOR& allocator);
3234};
3235
3236 // ==============================
3237 // class HashTable_ImplParameters
3238 // ==============================
3239
3240 // It looks like the 'CallableVariable' adaptation would be more
3241 // appropriately addressed as part of the 'bslalg::FunctorAdapter' wrapper
3242 // than intrusively in this component, and in similar ways by any other
3243 // container trying to support the full range of standard conforming
3244 // functors. Given that our intent is to support standard predicates, it
3245 // may be appropriate to handle calling non-'const' 'operator()' overloads
3246 // (via a 'mutable' member) too.
3247
3248template <class HASHER>
3250 : bslalg::FunctorAdapter<HashTable_HashWrapper<
3251 typename CallableVariable<HASHER>::type> >
3252{
3253};
3254
3255template <class COMPARATOR>
3257 : bslalg::FunctorAdapter<HashTable_ComparatorWrapper<
3258 typename CallableVariable<COMPARATOR>::type> >
3259{
3260};
3261
3262/// This class holds all the parameterized parts of a `HashTable` class,
3263/// efficiently exploiting the empty base optimization without adding
3264/// unforeseen namespace associations to the `HashTable` class itself due to
3265/// the structural inheritance.
3266template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3268 : private HashTable_BaseHasher<HASHER>::Type
3269 , private HashTable_Comparator<COMPARATOR>::Type
3270{
3271
3272 // PRIVATE TYPES
3273 typedef typename HashTable_BaseHasher<HASHER>::Type BaseHasher;
3274 typedef typename HashTable_Comparator<COMPARATOR>::Type BaseComparator;
3275
3276 /// This typedef is a convenient alias for the utility associated with
3277 /// movable references.
3279
3280 // typedefs stolen from HashTable
3281 typedef ALLOCATOR AllocatorType;
3282 typedef ::bsl::allocator_traits<AllocatorType> AllocatorTraits;
3283 typedef typename KEY_CONFIG::ValueType ValueType;
3285
3286 public:
3287 // PUBLIC TYPES
3289 typedef typename HashTableType::AllocatorTraits::
3290 template rebind_traits<NodeType> ReboundTraits;
3291 typedef typename ReboundTraits::allocator_type NodeAllocator;
3292
3293 typedef
3296
3297 private:
3298 // DATA
3299 NodeFactory d_nodeFactory; // nested 'struct's have public data by
3300 // convention, but should always be
3301 // accessed through the public methods.
3302
3303 private:
3304 // NOT IMPLEMENTED
3305
3306 /// = delete;
3309
3310 public:
3311 // CREATORS
3312
3313 /// Create a `HashTable_ImplParameters` object having default
3314 /// constructed `HASHER` and `COMPARATOR` functors, and using the
3315 /// specified `allocator` to provide a `BidirectionalNodePool`.
3316 explicit HashTable_ImplParameters(const ALLOCATOR& allocator);
3317
3318 /// Create a `HashTable_ImplParameters` object having the specified
3319 /// `hash` and `compare` functors, and using the specified `allocator`
3320 /// to provide a `BidirectionalNodePool`.
3321 HashTable_ImplParameters(const HASHER& hash,
3322 const COMPARATOR& compare,
3323 const ALLOCATOR& allocator);
3324
3325 /// Create a `HashTable_ImplParameters` object having the same `hasher`
3326 /// and `comparator` attributes as the specified `original`, and
3327 /// providing a `BidirectionalNodePool` using the specified `allocator`.
3329 const ALLOCATOR& allocator);
3330
3331 /// Create a `HashTable_ImplParameters` object with a copy of the
3332 /// `hasher` and `comparator` attributes associated with the specified
3333 /// `original` parameters object, and adopting all outstanding memory
3334 /// allocations and the allocator associated with `original`.
3335 ///
3336 /// \note Note that `original` is left in a valid but unspecified state.
3339
3340 // MANIPULATORS
3341
3342 /// Return a reference offering modifiable access to the `nodeFactory`
3343 /// owned by this object.
3345
3346 /// Efficiently exchange the value, functor, and allocator of this
3347 /// object with those of the specified `other` object. This method
3348 /// provides the no-throw exception-safety guarantee.
3350
3351 /// Efficiently exchange the value and functors this object with those
3352 /// of the specified `other` object. This method provides the no-throw exception-safety guarantee.
3353 ///
3354 /// \pre The behavior is undefined unless this
3355 /// object was created with the same allocator as `other`.
3357
3358 // ACCESSORS
3359
3360 /// Return a reference offering non-modifiable access to the
3361 /// `comparator` functor owned by this object.
3362 const BaseComparator& comparator() const;
3363
3364 /// Return the hash code for the specified `key` using a copy of the hash functor supplied at construction.
3365 ///
3366 /// \note Note that this function is
3367 /// provided as a common way to resolve `const_cast` issues in the case
3368 /// that the stored hash functor has a function call operator that is
3369 /// not declared as `const`.
3370 template <class DEDUCED_KEY>
3371 std::size_t hashCodeForKey(DEDUCED_KEY& key) const;
3372
3373 /// Return the hash code for the specified `key` using a copy of the hash functor supplied at construction.
3374 ///
3375 /// \note Note that this function is
3376 /// provided as a common way to resolve `const_cast` issues in the case
3377 /// that the stored hash functor has a function call operator that is
3378 /// not declared as `const`.
3379 template <class LOOKUP_KEY>
3380 typename bsl::enable_if<
3381 BloombergLP::bslmf::IsTransparentPredicate<HASHER, LOOKUP_KEY>::value,
3382 std::size_t>::type
3383 hashCodeForTransparentKey(const LOOKUP_KEY &key) const {
3384 return originalHasher()(key);
3385 }
3386
3387 /// Return a reference offering non-modifiable access to the `hasher`
3388 /// functor owned by this object.
3389 const BaseHasher& hasher() const;
3390
3391 /// Return a reference offering non-modifiable access to the
3392 /// `nodeFactory` owned by this object.
3393 const NodeFactory& nodeFactory() const;
3394
3395 /// Return a reference offering non-modifiable access to the
3396 /// `comparator` functor owned by this object.
3397 const COMPARATOR& originalComparator() const;
3398
3399 /// Return a reference offering non-modifiable access to the `hasher`
3400 /// functor owned by this object.
3401 const HASHER& originalHasher() const;
3402};
3403
3404// ============================================================================
3405// TEMPLATE AND INLINE FUNCTION DEFINITIONS
3406// ============================================================================
3407
3408 // ---------------------------
3409 // class HashTable_HashWrapper
3410 // ---------------------------
3411
3412template <class FUNCTOR>
3413inline
3418
3419template <class FUNCTOR>
3420inline
3422: d_functor(fn)
3423{
3424}
3425
3426template <class FUNCTOR>
3427template <class ARG_TYPE>
3428inline
3429std::size_t
3431{
3432 return d_functor(arg);
3433}
3434
3435template <class FUNCTOR>
3436inline
3438{
3439 return d_functor;
3440}
3441
3442template <class FUNCTOR>
3443inline
3445{
3446 using std::swap;
3447 swap(d_functor, other.d_functor);
3448}
3449
3450 // 'const FUNCTOR' partial specialization
3451
3452template <class FUNCTOR>
3453inline
3455: d_functor()
3456{
3457}
3458
3459template <class FUNCTOR>
3460inline
3462: d_functor(fn)
3463{
3464}
3465
3466template <class FUNCTOR>
3467template <class ARG_TYPE>
3468inline
3469std::size_t
3471{
3472 return d_functor(arg);
3473}
3474
3475template <class FUNCTOR>
3476inline
3478{
3479 return d_functor;
3480}
3481
3482 // 'FUNCTOR &' partial specialization
3483
3484template <class FUNCTOR>
3485inline
3487: d_functor(fn)
3488{
3489}
3490
3491template <class FUNCTOR>
3492template <class ARG_TYPE>
3493inline
3494std::size_t
3496{
3497 return d_functor(arg);
3498}
3499
3500template <class FUNCTOR>
3501inline
3503{
3504 return d_functor;
3505}
3506
3507 // ---------------------------------
3508 // class HashTable_ComparatorWrapper
3509 // ---------------------------------
3510
3511template <class FUNCTOR>
3512inline
3517
3518template <class FUNCTOR>
3519inline
3521HashTable_ComparatorWrapper(const FUNCTOR& fn)
3522: d_functor(fn)
3523{
3524}
3525
3526template <class FUNCTOR>
3527template <class ARG1_TYPE, class ARG2_TYPE>
3528inline
3529bool
3531 ARG2_TYPE& arg2) const
3532{
3533 return d_functor(arg1, arg2);
3534}
3535
3536template <class FUNCTOR>
3538{
3539 return d_functor;
3540}
3541
3542template <class FUNCTOR>
3543inline
3544void
3546{
3547 using std::swap;
3548 swap(d_functor, other.d_functor);
3549}
3550
3551 // 'const FUNCTOR' partial specialization
3552
3553template <class FUNCTOR>
3554inline
3556: d_functor()
3557{
3558}
3559
3560template <class FUNCTOR>
3561inline
3563HashTable_ComparatorWrapper(const FUNCTOR& fn)
3564: d_functor(fn)
3565{
3566}
3567
3568template <class FUNCTOR>
3569template <class ARG1_TYPE, class ARG2_TYPE>
3570inline
3571bool
3573 ARG2_TYPE& arg2) const
3574{
3575 return d_functor(arg1, arg2);
3576}
3577
3578template <class FUNCTOR>
3580{
3581 return d_functor;
3582}
3583
3584 // 'FUNCTOR &' partial specialization
3585
3586template <class FUNCTOR>
3587inline
3589HashTable_ComparatorWrapper(FUNCTOR& fn)
3590: d_functor(fn)
3591{
3592}
3593
3594template <class FUNCTOR>
3595template <class ARG1_TYPE, class ARG2_TYPE>
3596inline
3597bool
3599 ARG2_TYPE& arg2) const
3600{
3601 return d_functor(arg1, arg2);
3602}
3603
3604template <class FUNCTOR>
3605inline
3607{
3608 return d_functor;
3609}
3610
3611 // ---------------------------
3612 // class HashTable_NodeProctor
3613 // ---------------------------
3614
3615// CREATORS
3616template <class FACTORY>
3617inline
3619 FACTORY *factory,
3621: d_factory_p(factory)
3622, d_node_p(node)
3623{
3624 BSLS_ASSERT_SAFE(factory);
3625}
3626
3627template <class FACTORY>
3628inline
3630{
3631 if (d_node_p) {
3632 d_factory_p->deleteNode(d_node_p);
3633 }
3634}
3635
3636// MANIPULATORS
3637template <class FACTORY>
3638inline
3640{
3641 d_node_p = 0;
3642}
3643
3644 // ----------------------------
3645 // class HashTable_ArrayProctor
3646 // ----------------------------
3647
3648// CREATORS
3649template <class FACTORY>
3650inline
3652 FACTORY *factory,
3654: d_factory_p(factory)
3655, d_anchor_p(anchor)
3656{
3657 BSLS_ASSERT_SAFE(factory);
3658 BSLS_ASSERT_SAFE(anchor);
3659}
3660
3661template <class FACTORY>
3662inline
3664{
3665 if (d_anchor_p) {
3666 HashTable_Util::destroyBucketArray(d_anchor_p->bucketArrayAddress(),
3667 d_anchor_p->bucketArraySize(),
3668 d_factory_p->allocator());
3669
3670 bslalg::BidirectionalLink *root = d_anchor_p->listRootAddress();
3671 while (root) {
3672 bslalg::BidirectionalLink *next = root->nextLink();
3673 d_factory_p->deleteNode(root);
3674 root = next;
3675 }
3676 }
3677}
3678
3679// MANIPULATORS
3680template <class FACTORY>
3681inline
3683{
3684 d_anchor_p = 0;
3685}
3686
3687 // --------------------
3688 // class HashTable_Util
3689 // --------------------
3690
3691template <class TYPE>
3692inline
3696
3697template <class TYPE>
3698inline
3700{
3701 // silence "unused parameter" warning in release builds:
3702 (void) ptr;
3703 BSLS_ASSERT(ptr);
3704}
3705
3706template <class TYPE>
3707inline
3709{
3710 // silence "unused parameter" warning in release builds:
3711 (void) ptr;
3712 BSLS_ASSERT(ptr);
3713}
3714
3715template <class ALLOCATOR>
3716inline
3719 std::size_t bucketArraySize,
3720 const ALLOCATOR& allocator)
3721{
3722 BSLS_ASSERT_SAFE(data);
3724 (1 < bucketArraySize
3726 || (1 == bucketArraySize
3728
3729#ifdef BSLS_ASSERT_SAFE_IS_ACTIVE
3730 typedef typename bsl::allocator_traits<ALLOCATOR>::size_type AllocSizeType;
3732 bucketArraySize <= std::numeric_limits<AllocSizeType>::max());
3733#endif
3734
3737 bucketArraySize);
3738 }
3739}
3740
3741template <class ALLOCATOR>
3742inline
3744 std::size_t bucketArraySize,
3745 const ALLOCATOR& allocator)
3746{
3747 BSLS_ASSERT_SAFE(anchor);
3748 BSLS_ASSERT_SAFE(0 != bucketArraySize);
3749
3750#ifdef BSLS_ASSERT_SAFE_IS_ACTIVE
3751 typedef typename bsl::allocator_traits<ALLOCATOR>::size_type AllocSizeType;
3753 bucketArraySize <= std::numeric_limits<AllocSizeType>::max());
3754#endif
3755
3756 typedef bslalg::HashTableBucket Bucket;
3757 Bucket *data = bslma::AllocatorUtil::allocateObject<Bucket>(allocator,
3758 bucketArraySize);
3759
3760 std::fill_n(data, bucketArraySize, Bucket());
3761
3762 anchor->setBucketArrayAddressAndSize(data, bucketArraySize);
3763}
3764
3765 //-------------------------------
3766 // class HashTable_ImplParameters
3767 //-------------------------------
3768
3769// CREATORS
3770template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3771inline
3773HashTable_ImplParameters(const ALLOCATOR& allocator)
3774: BaseHasher()
3775, BaseComparator()
3776, d_nodeFactory(allocator)
3777{
3778}
3779
3780template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3781inline
3783HashTable_ImplParameters(const HASHER& hash,
3784 const COMPARATOR& compare,
3785 const ALLOCATOR& allocator)
3786: BaseHasher(hash)
3787, BaseComparator(compare)
3788, d_nodeFactory(allocator)
3789{
3790}
3791
3792template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3793inline
3796 const ALLOCATOR& allocator)
3797: BaseHasher(static_cast<const BaseHasher&>(original))
3798, BaseComparator(static_cast<const BaseComparator&>(original))
3799, d_nodeFactory(allocator)
3800{
3801}
3802
3803template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3804inline
3807: BaseHasher(static_cast<const BaseHasher&>(original))
3808, BaseComparator(static_cast<const BaseComparator&>(original))
3809, d_nodeFactory(MoveUtil::move(MoveUtil::access(original).d_nodeFactory))
3810{
3811}
3812
3813// MANIPULATORS
3814template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3815inline
3816typename HashTable_ImplParameters<KEY_CONFIG,
3817 HASHER,
3818 COMPARATOR,
3819 ALLOCATOR>::NodeFactory &
3825
3826template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3827inline
3830{
3831 BSLS_ASSERT_SAFE(other);
3832
3833 using std::swap;
3834 swap(*static_cast<BaseHasher*>(this), *static_cast<BaseHasher*>(other));
3835
3836 swap(*static_cast<BaseComparator*>(this),
3837 *static_cast<BaseComparator*>(other));
3838
3839 nodeFactory().swapExchangeAllocators(other->nodeFactory());
3840}
3841
3842template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3843inline
3846{
3847 BSLS_ASSERT_SAFE(other);
3848
3849 using std::swap;
3850 swap(*static_cast<BaseHasher*>(this), *static_cast<BaseHasher*>(other));
3851
3852 swap(*static_cast<BaseComparator*>(this),
3853 *static_cast<BaseComparator*>(other));
3854
3855 nodeFactory().swapRetainAllocators(other->nodeFactory());
3856}
3857
3858// ACCESSORS
3859template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3860inline
3861const typename HashTable_ImplParameters<KEY_CONFIG,
3862 HASHER,
3863 COMPARATOR,
3864 ALLOCATOR>::BaseComparator &
3870
3871template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3872template <class DEDUCED_KEY>
3873inline
3874std::size_t HashTable_ImplParameters<KEY_CONFIG,
3875 HASHER,
3876 COMPARATOR,
3877 ALLOCATOR>::
3878hashCodeForKey(DEDUCED_KEY& key) const
3879{
3880 return static_cast<const BaseHasher &>(*this)(key);
3881}
3882
3883template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3884inline
3885const typename HashTable_ImplParameters<KEY_CONFIG,
3886 HASHER,
3887 COMPARATOR,
3888 ALLOCATOR>::BaseHasher &
3894
3895template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3896inline
3897const typename HashTable_ImplParameters<KEY_CONFIG,
3898 HASHER,
3899 COMPARATOR,
3900 ALLOCATOR>::NodeFactory &
3906
3907template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3908inline
3909const COMPARATOR&
3910HashTable_ImplParameters<KEY_CONFIG,
3911 HASHER,
3912 COMPARATOR,
3913 ALLOCATOR>::originalComparator() const
3914{
3915 return static_cast<const BaseComparator *>(this)->functor();
3916}
3917
3918template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3919inline
3920const HASHER& HashTable_ImplParameters<KEY_CONFIG,
3921 HASHER,
3922 COMPARATOR,
3923 ALLOCATOR>::originalHasher() const
3924{
3925 return static_cast<const BaseHasher *>(this)->functor();
3926}
3927
3928 //----------------
3929 // class HashTable
3930 //----------------
3931
3932// CREATORS
3933template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3934inline
3936HashTable(const ALLOCATOR& basicAllocator)
3937: d_parameters(basicAllocator)
3938, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3939, d_size()
3940, d_capacity()
3941, d_maxLoadFactor(1.0)
3942{
3945}
3946
3947template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3948inline
3950HashTable(const HASHER& hash,
3951 const COMPARATOR& compare,
3952 SizeType initialNumBuckets,
3953 float initialMaxLoadFactor,
3954 const ALLOCATOR& basicAllocator)
3955: d_parameters(hash, compare, basicAllocator)
3956, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3957, d_size()
3958, d_capacity(0)
3959, d_maxLoadFactor(initialMaxLoadFactor)
3960{
3961 BSLS_ASSERT_SAFE(0.0f < initialMaxLoadFactor);
3962
3965 }
3968 }
3969
3970 if (0 != initialNumBuckets) {
3971 size_t capacity; // This may be a different type than SizeType.
3973 &capacity,
3974 1,
3975 static_cast<size_t>(initialNumBuckets),
3976 d_maxLoadFactor);
3977 HashTable_Util::initAnchor(&d_anchor, numBuckets, basicAllocator);
3978 d_capacity = static_cast<SizeType>(capacity);
3979 }
3980}
3981
3982template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
3983inline
3985HashTable(const HashTable& original)
3986: d_parameters(
3987 original.d_parameters,
3988 AllocatorTraits::select_on_container_copy_construction(original.allocator()))
3989, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
3990, d_size(original.d_size)
3991, d_capacity(0)
3992, d_maxLoadFactor(original.d_maxLoadFactor)
3993{
3994 if (0 < d_size) {
3995 d_parameters.nodeFactory().reserveNodes(original.d_size);
3996 this->copyDataStructure(original.d_anchor.listRootAddress());
3997 }
3998}
3999
4000template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4001inline
4003 BloombergLP::bslmf::MovableRef<HashTable> original)
4004: d_parameters(MoveUtil::move(MoveUtil::access(original).d_parameters))
4005, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
4006, d_size()
4007, d_capacity()
4008, d_maxLoadFactor(1.0)
4009{
4010 HashTable& lvalue = original;
4011 using std::swap;
4012 swap(d_anchor, lvalue.d_anchor);
4013 swap(d_size, lvalue.d_size);
4014 swap(d_capacity, lvalue.d_capacity);
4015 swap(d_maxLoadFactor, lvalue.d_maxLoadFactor);
4016}
4017
4018template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4019inline
4021HashTable(const HashTable& original, const ALLOCATOR& basicAllocator)
4022: d_parameters(original.d_parameters, basicAllocator)
4023, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
4024, d_size(original.d_size)
4025, d_capacity(0)
4026, d_maxLoadFactor(original.d_maxLoadFactor)
4027{
4028 if (0 < d_size) {
4029 d_parameters.nodeFactory().reserveNodes(original.d_size);
4030 this->copyDataStructure(original.d_anchor.listRootAddress());
4031 }
4032}
4033
4034template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4037 const ALLOCATOR& basicAllocator)
4038: d_parameters(MoveUtil::access(original).d_parameters.originalHasher(),
4039 MoveUtil::access(original).d_parameters.originalComparator(),
4040 basicAllocator)
4041, d_anchor(HashTable_ImpDetails::defaultBucketAddress(), 1, 0)
4042, d_size()
4043, d_capacity()
4044, d_maxLoadFactor(1.0)
4045{
4046 HashTable& lvalue = original;
4048 basicAllocator == lvalue.allocator())) {
4049 d_parameters.nodeFactory().adopt(
4050 MoveUtil::move(lvalue.d_parameters.nodeFactory()));
4051 using std::swap;
4052 swap(d_anchor, lvalue.d_anchor);
4053 swap(d_size, lvalue.d_size);
4054 swap(d_capacity, lvalue.d_capacity);
4055 swap(d_maxLoadFactor, lvalue.d_maxLoadFactor);
4056 }
4057 else {
4058 d_size = lvalue.d_size;
4059 d_maxLoadFactor = lvalue.d_maxLoadFactor;
4060 if (0 < d_size) {
4061 // 'original' left in the default state
4064 using std::swap;
4065 swap(anchor, lvalue.d_anchor);
4066
4067 lvalue.d_size = 0;
4068 lvalue.d_capacity = 0;
4069 lvalue.d_maxLoadFactor = 1.0f;
4070
4071 HashTable_ArrayProctor<typename ImplParameters::NodeFactory>
4072 arrayProctor(&lvalue.d_parameters.nodeFactory(),
4073 &anchor);
4074
4075 d_parameters.nodeFactory().reserveNodes(d_size);
4076 this->moveDataStructure(anchor.listRootAddress());
4077
4078 // 'arrayProctor' will care of deleting the nodes
4079 }
4080 }
4081}
4082
4083template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4084inline
4086{
4087#if defined(BDE_BUILD_TARGET_SAFE_2)
4088 // ASSERT class invariant only in SAFE_2 builds. Note that we specifically
4089 // use the MallocFree allocator, rather than allowing the default allocator
4090 // to supply memory to this state-checking function, in case the object
4091 // allocator *is* the default allocator, and so may be restricted during
4092 // testing. This would cause the test below to fail by throwing a bad
4093 // allocation exception, and so result in a throwing destructor. While the
4094 // MallocFree allocator might also run out of resources, that is not the
4095 // kind of catastrophic failure we are concerned with handling in an
4096 // invariant check that runs only in SAFE_2 builds from a destructor.
4097
4098 BSLS_ASSERT_SAFE(bslalg::HashTableImpUtil::isWellFormed<KEY_CONFIG>(
4099 this->d_anchor,
4100 this->d_parameters.hasher(),
4102#endif
4103
4104 this->removeAllAndDeallocate();
4105}
4106
4107// PRIVATE MANIPULATORS
4108template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4109void
4112{
4113 BSLS_ASSERT(0 != cursor);
4114 BSLS_ASSERT(0 < d_size);
4115
4116 // This function will completely replace 'this->d_anchor's state. It is
4117 // the caller's responsibility to ensure this will not leak resources owned
4118 // only by the previous state, such as the linked list.
4119
4120 // Allocate an appropriate number of buckets
4121
4122 size_t capacity;
4124 &capacity,
4125 static_cast<size_t>(d_size),
4126 2,
4127 d_maxLoadFactor);
4128
4129 d_anchor.setListRootAddress(0);
4130 HashTable_Util::initAnchor(&d_anchor, numBuckets, this->allocator());
4131
4132 // create a proctor for d_anchor's allocated array, and the list to follow.
4133
4135 arrayProctor(&d_parameters.nodeFactory(), &d_anchor);
4136
4137 d_capacity = static_cast<SizeType>(capacity);
4138
4139 do {
4140 // Computing hash code depends on user-supplied code, and may throw.
4141 // Therefore, obtain the hash code from the node we are about to copy,
4142 // before any memory is allocated, so there is no risk of leaking an
4143 // object. The hash code must be the same for both elements.
4144
4145 size_t hashCode = this->hashCodeForNode(cursor);
4146 bslalg::BidirectionalLink *newNode =
4147 d_parameters.nodeFactory().cloneNode(*cursor);
4148
4150 newNode,
4151 hashCode);
4152 }
4153 while (0 != (cursor = cursor->nextLink()));
4154
4155 // release the proctor
4156
4157 arrayProctor.release();
4158}
4159
4160template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4161void
4162HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::moveDataStructure(
4164{
4165 BSLS_ASSERT(0 != cursor);
4166 BSLS_ASSERT(0 < d_size);
4167
4168 // This function will completely replace 'this->d_anchor's state. It is
4169 // the caller's responsibility to ensure this will not leak resources owned
4170 // only by the previous state, such as the linked list.
4171
4172 // Allocate an appropriate number of buckets
4173
4174 size_t capacity;
4176 &capacity,
4177 static_cast<size_t>(d_size),
4178 2,
4179 d_maxLoadFactor);
4180
4181 d_anchor.setListRootAddress(0);
4182 HashTable_Util::initAnchor(&d_anchor, numBuckets, this->allocator());
4183
4184 d_capacity = static_cast<SizeType>(capacity);
4185
4186 // create a proctor for d_anchor's allocated array, and the list to follow.
4187
4188 HashTable_ArrayProctor<typename ImplParameters::NodeFactory>
4189 arrayProctor(&d_parameters.nodeFactory(), &d_anchor);
4190
4191 do {
4192 // Computing hash code depends on user-supplied code, and may throw.
4193 // Therefore, obtain the hash code from the node we are about to copy,
4194 // before any memory is allocated, so there is no risk of leaking an
4195 // object. The hash code must be the same for both elements.
4196
4197 size_t hashCode = this->hashCodeForNode(cursor);
4198 bslalg::BidirectionalLink *newNode =
4199 d_parameters.nodeFactory().moveIntoNewNode(cursor);
4200
4202 newNode,
4203 hashCode);
4204 }
4205 while (0 != (cursor = cursor->nextLink()));
4206
4207 // release the proctor
4208
4209 arrayProctor.release();
4210}
4211
4212template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4213void
4214HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::
4215quickSwapExchangeAllocators(HashTable *other)
4216{
4217 BSLS_ASSERT_SAFE(other);
4218
4219 d_parameters.quickSwapExchangeAllocators(&other->d_parameters);
4220
4221 using std::swap;
4222 swap(d_anchor, other->d_anchor);
4223 swap(d_size, other->d_size);
4224 swap(d_capacity, other->d_capacity);
4225 swap(d_maxLoadFactor, other->d_maxLoadFactor);
4226}
4227
4228template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4229void
4230HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::
4231quickSwapRetainAllocators(HashTable *other)
4232{
4233 BSLS_ASSERT_SAFE(other);
4234 BSLS_ASSERT_SAFE(this->allocator() == other->allocator());
4235
4236 d_parameters.quickSwapRetainAllocators(&other->d_parameters);
4237
4238 using std::swap;
4239 swap(d_anchor, other->d_anchor);
4240 swap(d_size, other->d_size);
4241 swap(d_capacity, other->d_capacity);
4242 swap(d_maxLoadFactor, other->d_maxLoadFactor);
4243}
4244
4245template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4246void
4247HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::
4248rehashIntoExactlyNumBuckets(SizeType newNumBuckets, SizeType capacity)
4249{
4250 /// An object of this proctor class guarantees that, if an exception is
4251 /// thrown by a user-supplied hash functor, the container remains in a
4252 /// valid, usable (but unspecified) state. In fact, that state will be
4253 /// empty, as there is no reliable way to re-index a bucket array if the
4254 /// hash functor is throwing, and the array is potentially corrupted
4255 /// following a failed ImpUtil::rehash call.
4256 ///
4257 /// See @ref bslstl_hashtable
4258 class Proctor {
4259
4260 private:
4261 HashTable *d_table_p;
4262 bslalg::HashTableAnchor *d_originalAnchor_p;
4263 bslalg::HashTableAnchor *d_newAnchor_p;
4264
4265#if !defined(BSLS_PLATFORM_CMP_MSVC)
4266 // Microsoft warns if these methods are declared private.
4267
4268 private:
4269 // NOT IMPLEMENTED
4270 Proctor(const Proctor&); // = delete;
4271 Proctor& operator=(const Proctor&); // = delete;
4272#endif
4273
4274 public:
4275 // CREATORS
4276 Proctor(HashTable *table,
4277 bslalg::HashTableAnchor *originalAnchor,
4278 bslalg::HashTableAnchor *newAnchor)
4279 : d_table_p(table)
4280 , d_originalAnchor_p(originalAnchor)
4281 , d_newAnchor_p(newAnchor)
4282 {
4283 BSLS_ASSERT_SAFE(table);
4284 BSLS_ASSERT_SAFE(originalAnchor);
4285 BSLS_ASSERT_SAFE(newAnchor);
4286 }
4287
4288 ~Proctor()
4289 {
4290 if (d_originalAnchor_p) {
4291 // Not dismissed, and the newAnchor now holds the correct
4292 // list-root.
4293
4294 d_originalAnchor_p->setListRootAddress(
4295 d_newAnchor_p->listRootAddress());
4296 d_table_p->removeAll();
4297 }
4298
4299 // Always destroy the spare anchor's bucket array at the end of
4300 // scope. On a non-exceptional run, this will effectively be the
4301 // original bucket-array, as the anchors are swapped.
4302
4303 HashTable_Util::destroyBucketArray(
4304 d_newAnchor_p->bucketArrayAddress(),
4305 d_newAnchor_p->bucketArraySize(),
4306 d_table_p->allocator());
4307 }
4308
4309 // MANIPULATORS
4310 void dismiss()
4311 {
4312 d_originalAnchor_p = 0;
4313 }
4314 };
4315
4316 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4317
4318 // Now that 'anchor' is not default constructible, we take a copy of the
4319 // anchor in the table. Would it be better for 'initAnchor' to be replaced
4320 // with a 'createArrayOfEmptyBuckets' function, and we use the result to
4321 // construct the 'newAnchor'?
4322
4323 bslalg::HashTableAnchor newAnchor(0, 0, 0);
4324 HashTable_Util::initAnchor(&newAnchor,
4325 static_cast<size_t>(newNumBuckets),
4326 this->allocator());
4327
4328 Proctor cleanUpIfUserHashThrows(this, &d_anchor, &newAnchor);
4329
4330 if (d_anchor.listRootAddress()) {
4331 bslalg::HashTableImpUtil::rehash<KEY_CONFIG>(
4332 &newAnchor,
4333 this->d_anchor.listRootAddress(),
4334 this->d_parameters.hasher());
4335 }
4336
4337 cleanUpIfUserHashThrows.dismiss();
4338
4339 d_anchor.swap(newAnchor);
4340 d_capacity = capacity;
4341}
4342
4343template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4344inline
4345void
4346HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::removeAllAndDeallocate()
4347{
4348 this->removeAllImp();
4350 d_anchor.bucketArraySize(),
4351 this->allocator());
4352}
4353
4354template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4355void
4356HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::removeAllImp()
4357{
4358 typedef bslalg::BidirectionalLink BidirectionalLink;
4359
4360 // Doing too much book-keeping of hash table - look for a more efficient
4361 // dispose-as-we-walk, that simply resets table.Anchor.next = 0, and
4362 // assigns the buckets index all null pointers
4363
4364 if (BidirectionalLink *root = d_anchor.listRootAddress()) {
4365 BidirectionalLink *next;
4366 do {
4367 next = root->nextLink();
4368 d_parameters.nodeFactory().deleteNode(
4369 static_cast<NodeType *>(root));
4370 }
4371 while(0 != (root = next));
4372 }
4373}
4374
4375// PRIVATE ACCESSORS
4376template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4377template <class DEDUCED_KEY>
4378inline
4380HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::find(
4381 DEDUCED_KEY& key,
4382 std::size_t hashValue) const
4383{
4384 return bslalg::HashTableImpUtil::find<KEY_CONFIG>(
4385 d_anchor,
4386 key,
4387 d_parameters.comparator(),
4388 hashValue);
4389}
4390
4391template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4392inline
4394HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::getBucketAddress(
4395 SizeType bucketIndex) const
4396{
4397 BSLS_ASSERT_SAFE(bucketIndex < this->numBuckets());
4398
4399 return d_anchor.bucketArrayAddress() + bucketIndex;
4400}
4401
4402template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4403inline
4404std::size_t
4405HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>::hashCodeForNode(
4406 bslalg::BidirectionalLink *node) const
4407{
4408 BSLS_ASSERT_SAFE(node);
4409
4410 return d_parameters.hashCodeForKey(
4411 bslalg::HashTableImpUtil::extractKey<KEY_CONFIG>(node));
4412}
4413
4414// MANIPULATORS
4415template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4416inline
4417HashTable<KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR>&
4419 const HashTable& rhs)
4420{
4421 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(this != &rhs)) {
4422
4423 if (AllocatorTraits::propagate_on_container_copy_assignment::value) {
4424 HashTable other(rhs, rhs.allocator());
4425 quickSwapExchangeAllocators(&other);
4426 }
4427 else {
4428 HashTable other(rhs, this->allocator());
4429 quickSwapRetainAllocators(&other);
4430 }
4431 }
4432 return *this;
4433}
4434
4435template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4436inline
4440{
4441 HashTable& lvalue = rhs;
4442 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(this != &lvalue)) {
4443 if (allocator() == lvalue.allocator()) {
4444 HashTable other(MoveUtil::move(lvalue));
4445 quickSwapRetainAllocators(&other);
4446 }
4447 else if (
4448 AllocatorTraits::propagate_on_container_move_assignment::value) {
4449 HashTable other(MoveUtil::move(lvalue));
4450 quickSwapExchangeAllocators(&other);
4451 }
4452 else {
4453 HashTable other(MoveUtil::move(lvalue), allocator());
4454 quickSwapRetainAllocators(&other);
4455 }
4456 }
4457 return *this;
4458}
4459
4460#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
4461template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4462template <class... ARGS>
4465 ARGS&&... arguments)
4466{
4467 typedef bslalg::HashTableImpUtil ImpUtil;
4468
4469 // Rehash (if appropriate) first as it will reduce load factor and so
4470 // potentially improve the 'find' time.
4471
4472 if (d_size >= d_capacity) {
4473 this->rehashForNumBuckets(numBuckets() * 2);
4474 }
4475
4476 // Next we must create the node from the constructor arguments provided.
4477
4478 bslalg::BidirectionalLink *newNode =
4479 d_parameters.nodeFactory().emplaceIntoNewNode(
4480 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
4481
4482 // This node needs wrapping in a proctor, in case either of the user-
4483 // supplied functors throws an exception.
4484
4486 nodeProctor(&d_parameters.nodeFactory(), newNode);
4487
4488 // Now we can search for the node in the table, being careful to compute
4489 // the hash value only once.
4490
4491 size_t hashCode = this->d_parameters.hashCodeForKey(
4492 ImpUtil::extractKey<KEY_CONFIG>(newNode));
4493 bslalg::BidirectionalLink *position = this->find(
4494 ImpUtil::extractKey<KEY_CONFIG>(newNode),
4495 hashCode);
4496
4497 if (!position) {
4498 ImpUtil::insertAtFrontOfBucket(&d_anchor, newNode, hashCode);
4499 }
4500 else {
4501 ImpUtil::insertAtPosition(&d_anchor, newNode, hashCode, position);
4502 }
4503 nodeProctor.release();
4504
4505 ++d_size;
4506
4507 return newNode;
4508}
4509
4510template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4511template <class... ARGS>
4515 ARGS&&... arguments)
4516{
4517 typedef bslalg::HashTableImpUtil ImpUtil;
4518
4519 // Rehash (if appropriate) first as it will reduce load factor and so
4520 // potentially improve the potential 'find' time later.
4521
4522 if (d_size >= d_capacity) {
4523 this->rehashForNumBuckets(numBuckets() * 2);
4524 }
4525
4526 // Next we must create the node from the constructor arguments provided.
4527
4528 bslalg::BidirectionalLink *newNode =
4529 d_parameters.nodeFactory().emplaceIntoNewNode(
4530 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
4531
4532 // There is potential for the user-supplied hasher and comparator to throw,
4533 // so now we need to manage our 'newNode' with a proctor.
4534
4536 nodeProctor(&d_parameters.nodeFactory(), newNode);
4537
4538 // Insert logic, first test the hint
4539
4540 size_t hashCode = this->d_parameters.hashCodeForKey(
4541 ImpUtil::extractKey<KEY_CONFIG>(newNode));
4542 if (!hint
4543 || !d_parameters.comparator()(ImpUtil::extractKey<KEY_CONFIG>(newNode),
4544 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
4545 hint = this->find(ImpUtil::extractKey<KEY_CONFIG>(newNode), hashCode);
4546 }
4547
4548 if (!hint) {
4549 ImpUtil::insertAtFrontOfBucket(&d_anchor, newNode, hashCode);
4550 }
4551 else {
4552 ImpUtil::insertAtPosition(&d_anchor, newNode, hashCode, hint);
4553 }
4554 nodeProctor.release();
4555
4556 ++d_size;
4557
4558 return newNode;
4559}
4560
4561template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4562template <class... ARGS>
4565 bool *isInsertedFlag,
4566 ARGS&&... arguments)
4567{
4568 BSLS_ASSERT(isInsertedFlag);
4569
4570 typedef bslalg::HashTableImpUtil ImpUtil;
4571
4572 // Rehash (if appropriate) first as it will reduce load factor and so
4573 // potentially improve the potential 'find' time later.
4574
4575 if (d_size >= d_capacity) {
4576 this->rehashForNumBuckets(numBuckets() * 2);
4577 }
4578
4579 // Next we must create the node from the constructor arguments provided.
4580
4581 bslalg::BidirectionalLink *newNode =
4582 d_parameters.nodeFactory().emplaceIntoNewNode(
4583 BSLS_COMPILERFEATURES_FORWARD(ARGS, arguments)...);
4584
4585 // There is potential for the user-supplied hasher and comparator to throw,
4586 // so now we need to manage our 'newNode' with a proctor.
4587
4589 nodeProctor(&d_parameters.nodeFactory(), newNode);
4590
4591 // Insert logic, first test the hint
4592
4593 size_t hashCode = this->d_parameters.hashCodeForKey(
4594 ImpUtil::extractKey<KEY_CONFIG>(newNode));
4595 bslalg::BidirectionalLink *position = this->find(
4596 ImpUtil::extractKey<KEY_CONFIG>(newNode),
4597 hashCode);
4598
4599 *isInsertedFlag = (!position);
4600
4601 if(!position) {
4602 if (d_size >= d_capacity) {
4603 this->rehashForNumBuckets(numBuckets() * 2);
4604 }
4605
4606 ImpUtil::insertAtFrontOfBucket(&d_anchor, newNode, hashCode);
4607 nodeProctor.release();
4608
4609 ++d_size;
4610 position = newNode;
4611 }
4612
4613 return position;
4614}
4615#endif
4616
4617template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4620 const KeyType& key)
4621{
4622 bool dummy = false;
4623 return tryEmplace(&dummy, (bslalg::BidirectionalLink*)0, key);
4624}
4625
4626template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4630{
4631 bool dummy = false;
4632 return tryEmplace(&dummy,
4634 MoveUtil::move(key));
4635}
4636
4637template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4640 bool *isInsertedFlag,
4641 const ValueType& value)
4642{
4643 BSLS_ASSERT(isInsertedFlag);
4644
4645 size_t hashCode = this->d_parameters.hashCodeForKey(
4646 KEY_CONFIG::extractKey(value));
4647 bslalg::BidirectionalLink *position = this->find(
4648 KEY_CONFIG::extractKey(value),
4649 hashCode);
4650
4651 *isInsertedFlag = (!position);
4652
4653 if(!position) {
4654 if (d_size >= d_capacity) {
4655 this->rehashForNumBuckets(numBuckets() * 2);
4656 }
4657
4658 position = d_parameters.nodeFactory().emplaceIntoNewNode(value);
4660 position,
4661 hashCode);
4662 ++d_size;
4663 }
4664
4665 return position;
4666}
4667
4668template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4671 bool *isInsertedFlag,
4673{
4674 ValueType& lvalue = value;
4675
4676 BSLS_ASSERT(isInsertedFlag);
4677
4678 size_t hashCode = this->d_parameters.hashCodeForKey(
4679 KEY_CONFIG::extractKey(lvalue));
4680 bslalg::BidirectionalLink *position = this->find(
4681 KEY_CONFIG::extractKey(lvalue),
4682 hashCode);
4683
4684 *isInsertedFlag = (!position);
4685
4686 if(!position) {
4687 if (d_size >= d_capacity) {
4688 this->rehashForNumBuckets(numBuckets() * 2);
4689 }
4690
4691 position = d_parameters.nodeFactory().emplaceIntoNewNode(
4692 MoveUtil::move(lvalue));
4694 position,
4695 hashCode);
4696 ++d_size;
4697 }
4698
4699 return position;
4700}
4701
4702template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4703template <class SOURCE_TYPE>
4704inline
4707 bool *isInsertedFlag,
4708 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value)
4709{
4710 BSLS_ASSERT(isInsertedFlag);
4711
4712 return emplaceIfMissing(isInsertedFlag,
4713 BSLS_COMPILERFEATURES_FORWARD(SOURCE_TYPE, value));
4714
4715}
4716
4717template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4718template <class SOURCE_TYPE>
4719inline
4726
4727template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4728template <class SOURCE_TYPE>
4729inline
4732 BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value,
4734{
4735 return emplaceWithHint(hint,
4736 BSLS_COMPILERFEATURES_FORWARD(SOURCE_TYPE, value));
4737}
4738
4739#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
4740template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4741template <class KEY_ARG, class BDE_OTHER_TYPE>
4744 bool *isInsertedFlag,
4747 BDE_OTHER_TYPE&& obj)
4748{
4749 typedef bslalg::HashTableImpUtil ImpUtil;
4750
4751 const KEY_ARG& lvalue = key;
4752 size_t hashCode = this->d_parameters.hashCodeForKey(lvalue);
4753 // Use the hint, if we can
4754 if (!hint
4755 || !d_parameters.comparator()(lvalue,
4756 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
4757 hint = this->find(lvalue, hashCode);
4758 }
4759
4760 if (hint) { // assign
4761 static_cast<NodeType *>(hint)->value().second =
4762 BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, obj);
4763 *isInsertedFlag = false;
4764 return hint; // RETURN
4765 }
4766
4767 // insert
4768 if (d_size >= d_capacity) {
4769 this->rehashForNumBuckets(numBuckets() * 2);
4770 }
4771
4772 // Make a new node
4773 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
4774 BSLS_COMPILERFEATURES_FORWARD(KEY_ARG, key),
4775 BSLS_COMPILERFEATURES_FORWARD(BDE_OTHER_TYPE, obj));
4776
4777 // Add it to the hash table
4779 nodeProctor(&d_parameters.nodeFactory(), hint);
4780 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
4781 nodeProctor.release();
4782 ++d_size;
4783
4784 *isInsertedFlag = true;
4785 return hint;
4786}
4787#endif
4788
4789template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4790void
4792 SizeType newNumBuckets)
4793{
4794 if (newNumBuckets > this->numBuckets()) {
4795 // Compute a "good" number of buckets, e.g., pick a prime number from a
4796 // sorted array of exponentially increasing primes.
4797
4798 size_t capacity;
4799 SizeType numBuckets = static_cast<SizeType>(
4801 &capacity,
4802 d_size + 1u,
4803 static_cast<size_t>(newNumBuckets),
4804 d_maxLoadFactor));
4805
4806 this->rehashIntoExactlyNumBuckets(numBuckets,
4807 static_cast<SizeType>(capacity));
4808 }
4809}
4810
4811template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4815{
4816 BSLS_ASSERT_SAFE(node);
4818 || d_anchor.listRootAddress() == node);
4819
4820 bslalg::BidirectionalLink *result = node->nextLink();
4821
4823 node,
4824 hashCodeForNode(node));
4825 --d_size;
4826
4827 d_parameters.nodeFactory().deleteNode(static_cast<NodeType *>(node));
4828
4829 return result;
4830}
4831
4832template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4833void
4835{
4836 this->removeAllImp();
4838 d_anchor.bucketArrayAddress()) {
4839 std::memset(d_anchor.bucketArrayAddress(),
4840 0,
4841 sizeof(bslalg::HashTableBucket) *
4842 d_anchor.bucketArraySize());
4843 }
4844
4845 d_anchor.setListRootAddress(0);
4846 d_size = 0;
4847}
4848
4849template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4850inline
4851void
4853 SizeType numElements)
4854{
4855 if (numElements < 1) { // Return avoids undefined behavior in node factory.
4856 return; // RETURN
4857 }
4858
4859 if (numElements > d_capacity) {
4860 // Compute a "good" number of buckets, e.g., pick a prime number from a
4861 // sorted array of exponentially increasing primes.
4862
4863 size_t capacity;
4864 SizeType numBuckets = static_cast<SizeType>(
4866 &capacity,
4867 numElements,
4868 static_cast<size_t>(this->numBuckets()),
4869 d_maxLoadFactor));
4870
4871 this->rehashIntoExactlyNumBuckets(numBuckets,
4872 static_cast<SizeType>(capacity));
4873 }
4874}
4875
4876template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4877inline
4879 float newMaxLoadFactor)
4880{
4881 BSLS_ASSERT_SAFE(0.0f < newMaxLoadFactor);
4882
4883 size_t capacity;
4884 SizeType numBuckets = static_cast<SizeType>(
4886 &capacity,
4887 std::max<SizeType>(d_size, 1u),
4888 static_cast<size_t>(this->numBuckets()),
4889 newMaxLoadFactor));
4890
4891 this->rehashIntoExactlyNumBuckets(numBuckets,
4892 static_cast<SizeType>(capacity));
4893
4894 // Always set this last, as there is potential to throw exceptions above.
4895
4896 d_maxLoadFactor = newMaxLoadFactor;
4897}
4898
4899template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4900void
4902{
4903 // This trait should perform 'if' at compile-time.
4904
4905 if (AllocatorTraits::propagate_on_container_swap::value) {
4906 quickSwapExchangeAllocators(&other);
4907 }
4908 else {
4909 // C++11 behavior: undefined for unequal allocators
4910 // BSLS_ASSERT(allocator() == other.allocator());
4911
4912 BSLS_ASSERT(d_parameters.nodeFactory().allocator() ==
4913 other.d_parameters.nodeFactory().allocator());
4914 quickSwapRetainAllocators(&other);
4915 }
4916}
4917
4918#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
4919template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4920template <class... ARGS>
4921inline
4924 bool *isInsertedFlag,
4926 const KeyType& key,
4927 ARGS&&... args)
4928{
4929 typedef bslalg::HashTableImpUtil ImpUtil;
4930
4931 const size_t hashCode = this->d_parameters.hashCodeForKey(key);
4932
4933 // Use the hint, if we can
4934 if (!hint
4935 || !d_parameters.comparator()(key,
4936 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
4937 hint = this->find(key, hashCode);
4938 }
4939
4940 // If the key exists, we're done
4941 if (hint) {
4942 *isInsertedFlag = false;
4943 return hint; // RETURN
4944 }
4945
4946 if (d_size >= d_capacity) {
4947 this->rehashForNumBuckets(numBuckets() * 2);
4948 }
4949
4950 // Make a new node
4951#if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR)
4952 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
4953 std::piecewise_construct,
4954 std::forward_as_tuple(key),
4955 std::forward_as_tuple(std::forward<ARGS>(args)...));
4956#else
4957 typedef typename ValueType::second_type MappedType;
4958
4959 // TBD: make 'this->allocator()' return the allocator by reference with
4960 // modifiable access rather than by value.
4961
4962 AllocatorType alloc = this->allocator();
4963
4964 bsls::ObjectBuffer<MappedType> defaultMapped;
4965 AllocatorTraits::construct(alloc, defaultMapped.address(),
4966 std::forward<ARGS>(args)...);
4967 bslma::DestructorGuard<MappedType> mappedGuard(defaultMapped.address());
4968
4969 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
4970 key,
4971 defaultMapped.object());
4972#endif
4973
4974 // Add it to the hash table
4976 nodeProctor(&d_parameters.nodeFactory(), hint);
4977 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
4978 nodeProctor.release();
4979 ++d_size;
4980
4981 *isInsertedFlag = true;
4982 return hint;
4983}
4984
4985
4986template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
4987template <class... ARGS>
4988inline
4991 bool *isInsertedFlag,
4994 ARGS&&... args)
4995{
4996 typedef bslalg::HashTableImpUtil ImpUtil;
4997
4998 const KeyType& lvalue = key;
4999 const size_t hashCode = this->d_parameters.hashCodeForKey(key);
5000
5001 // Use the hint, if we can
5002 if (!hint
5003 || !d_parameters.comparator()(lvalue,
5004 ImpUtil::extractKey<KEY_CONFIG>(hint))) {
5005 hint = this->find(lvalue, hashCode);
5006 }
5007
5008 // If the key exists, we're done
5009 if (hint) {
5010 *isInsertedFlag = false;
5011 return hint; // RETURN
5012 }
5013
5014 if (d_size >= d_capacity) {
5015 this->rehashForNumBuckets(numBuckets() * 2);
5016 }
5017
5018 // Make a new node
5019#if defined(BSLS_LIBRARYFEATURES_HAS_CPP11_PAIR_PIECEWISE_CONSTRUCTOR)
5020 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
5021 std::piecewise_construct,
5022 std::forward_as_tuple(MoveUtil::move(key)),
5023 std::forward_as_tuple(std::forward<ARGS>(args)...));
5024#else
5025 typedef typename ValueType::second_type MappedType;
5026
5027 // TBD: make 'this->allocator()' return the allocator by reference with
5028 // modifiable access rather than by value.
5029
5030 AllocatorType alloc = this->allocator();
5031
5032 bsls::ObjectBuffer<MappedType> defaultMapped;
5033 AllocatorTraits::construct(alloc, defaultMapped.address(),
5034 std::forward<ARGS>(args)...);
5035 bslma::DestructorGuard<MappedType> mappedGuard(defaultMapped.address());
5036
5037 hint = d_parameters.nodeFactory().emplaceIntoNewNode(
5038 MoveUtil::move(key),
5039 defaultMapped.object());
5040#endif
5041
5042 // Add it to the hash table
5044 nodeProctor(&d_parameters.nodeFactory(), hint);
5045 ImpUtil::insertAtFrontOfBucket(&d_anchor, hint, hashCode);
5046 nodeProctor.release();
5047 ++d_size;
5048
5049 *isInsertedFlag = true;
5050 return hint;
5051}
5052#endif
5053
5054// ACCESSORS
5055template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5056inline
5058 allocator() const
5059{
5060 return d_parameters.nodeFactory().allocator();
5061}
5062
5063template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5064inline
5067 SizeType index) const
5068{
5069 BSLS_ASSERT_SAFE(index < this->numBuckets());
5070
5071 return d_anchor.bucketArrayAddress()[index];
5072}
5073
5074template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5075inline
5078 const KeyType& key) const
5079{
5080 typedef typename
5082
5083 // The following cast will not discard any useful bits, unless 'SizeType'
5084 // is larger than 'size_t', as the bucket computation takes a mod on the
5085 // supplied number of buckets. We use the following 'BSLMF_ASSERT' to
5086 // assert that assumption at compile time.
5087
5088 BSLMF_ASSERT(sizeof(SizeType) <= sizeof(size_t));
5089
5090 size_t hashCode = this->d_parameters.hashCodeForKey(key);
5092 hashCode,
5093 d_anchor.bucketArraySize()));
5094}
5095
5096template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5097inline
5098const COMPARATOR&
5103
5104template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5105inline
5108 SizeType index) const
5109{
5110 BSLS_ASSERT_SAFE(index < this->numBuckets());
5111
5112 return static_cast<SizeType>(bucketAtIndex(index).countElements());
5113}
5114
5115template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5116inline
5122
5123template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5124inline
5127 const KeyType& key) const
5128{
5129 return bslalg::HashTableImpUtil::find<KEY_CONFIG>(
5130 d_anchor,
5131 key,
5132 d_parameters.comparator(),
5133 d_parameters.hashCodeForKey(key));
5134}
5135
5136template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5139 bslalg::BidirectionalLink *first) const
5140{
5141 BSLS_ASSERT_SAFE(first);
5142
5143 typedef bslalg::HashTableImpUtil ImpUtil;
5144
5145 // The reference to the Key passed to the functor is only optionally
5146 // const-qualified. We must be sure to hold a reference with the correct
5147 // qualification.
5148
5149 typedef
5151 KeyRef;
5152 KeyRef k = ImpUtil::extractKey<KEY_CONFIG>(first);
5153
5154 while (0 != (first = first->nextLink()) &&
5155 d_parameters.comparator()(k,ImpUtil::extractKey<KEY_CONFIG>(first)))
5156 {
5157 // This loop body is intentionally left blank.
5158 }
5159 return first;
5160}
5161
5162template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5163inline
5164void
5168 const KeyType& key) const
5169{
5170 BSLS_ASSERT_SAFE(first);
5171 BSLS_ASSERT_SAFE(last);
5172
5173 *first = this->find(key);
5174 *last = *first ? this->findEndOfRange(*first) : 0;
5175}
5176
5177template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5178bool
5180 const HashTable& other) const
5181{
5182 // TBD: The template bloat of this function can be significantly reduced.
5183 //..
5184 // What matters is that the two hash tables:
5185 // i/ are the same size
5186 // ii/ have lists that are permutations of each other according to the
5187 // element's 'operator=='
5188 // This means that the implementation should be independent of all four
5189 // template parameters, but will depend on VALUE_TYPE deduced from the
5190 // KEY_CONFIG. Otherwise, after the initial size comparison, the rest
5191 // depends only on the anchors.
5192 //..
5193
5194 typedef typename KEY_CONFIG::ValueType ValueType;
5195 typedef typename ::bsl::allocator_traits<ALLOCATOR>::size_type SizeType;
5196 typedef bslalg::HashTableImpUtil ImpUtil;
5197
5198 // First test - are the containers the same size?
5199
5200 if (this->size() != other.size()) {
5201 return false; // RETURN
5202 }
5203 bslalg::BidirectionalLink *cursor = this->elementListRoot();
5204 if (!cursor) { // containers are the same size, and empty.
5205 return true; // RETURN
5206 }
5207
5208 while (cursor) {
5209 bslalg::BidirectionalLink *rhsFirst =
5210 ImpUtil::find<KEY_CONFIG>(other.d_anchor,
5211 ImpUtil::extractKey<KEY_CONFIG>(cursor),
5212 other.d_parameters.comparator(),
5213 other.d_parameters.hashCodeForKey(
5214 ImpUtil::extractKey<KEY_CONFIG>(cursor)));
5215 if (!rhsFirst) {
5216 return false; // no matching key // RETURN
5217 }
5218
5219 bslalg::BidirectionalLink *endRange = this->findEndOfRange(cursor);
5220 bslalg::BidirectionalLink *rhsLast = other.findEndOfRange(rhsFirst);
5221
5222 // Check the key-groups have the same length - a quick-fail test.
5223
5224 bslalg::BidirectionalLink *endWalker = cursor->nextLink();
5225 bslalg::BidirectionalLink *rhsWalker = rhsFirst->nextLink();
5226
5227 while (endWalker != endRange) {
5228
5229 if (rhsWalker == rhsLast) {
5230 return false; // different length subsequences // RETURN
5231 }
5232 endWalker = endWalker->nextLink();
5233 rhsWalker = rhsWalker->nextLink();
5234 }
5235
5236 if (rhsWalker != rhsLast) {
5237 return false; // different length subsequences // RETURN
5238 }
5239
5240 // Efficiently compare identical prefixes: O[N] if sequences have the
5241 // same elements in the same order. Note that comparison of values in
5242 // nodes is tested using 'operator==' and not the key-equality
5243 // comparator stored in the hash table.
5244
5245 while (cursor != endRange &&
5246 (ImpUtil::extractValue<KEY_CONFIG>(cursor) ==
5247 ImpUtil::extractValue<KEY_CONFIG>(rhsFirst)))
5248 {
5249 cursor = cursor->nextLink();
5250 rhsFirst = rhsFirst->nextLink();
5251 }
5252
5253 if (cursor == endRange) {
5254 continue; // CONTINUE
5255 }
5256
5257 // Now comes the harder part of validating that one subsequence is a
5258 // permutation of another, by counting elements that compare equal
5259 // using the equality operator, 'operator=='. Note that this code
5260 // could be simplified for hash-tables with unique keys, as we can omit
5261 // the counting-scan, and merely test for any match within the 'other'
5262 // range. Trade off the ease of a single well-tested code path, vs.
5263 // the importance of an efficient 'operator==' for hash containers.
5264 // This is currently the only place the hash-table would care about
5265 // uniqueness, and risk different hash-table types for unique- vs.
5266 // multi-containers. Note again that comparison of values in nodes is
5267 // tested using 'operator==' and not the key-equality comparator stored
5268 // in the hash tables.
5269
5270 for (bslalg::BidirectionalLink *marker = cursor;
5271 marker != endRange;
5272 marker = marker->nextLink())
5273 {
5274 const ValueType& valueAtMarker =
5275 ImpUtil::extractValue<KEY_CONFIG>(marker);
5276
5277 if (cursor != marker) { // skip on first pass only
5278 // Check if the value at 'marker' has already be seen.
5279
5280 bslalg::BidirectionalLink *scanner = cursor;
5281 while (scanner != marker &&
5282 ImpUtil::extractValue<KEY_CONFIG>(scanner) != valueAtMarker) {
5283 scanner = scanner->nextLink();
5284 }
5285 if (scanner != marker) { // We have seen 'lhs' one before.
5286 continue; // CONTINUE
5287 }
5288 }
5289
5290 SizeType matches = 0;
5291 for (bslalg::BidirectionalLink *scanner = rhsFirst;
5292 scanner != rhsLast;
5293 scanner = scanner->nextLink()) {
5294 if (ImpUtil::extractValue<KEY_CONFIG>(scanner) ==
5295 valueAtMarker) {
5296 ++matches;
5297 }
5298 }
5299 if (!matches) {
5300 return false; // RETURN
5301 }
5302
5303 // Remember, *scanner is by definition a good match
5304
5305 for (bslalg::BidirectionalLink *scanner = marker->nextLink();
5306 scanner != endRange;
5307 scanner = scanner->nextLink()) {
5308
5309 if (ImpUtil::extractValue<KEY_CONFIG>(scanner) ==
5310 valueAtMarker) {
5311 if (!--matches) { // equal matches, but excluding initial
5312 return false; // RETURN
5313 }
5314 }
5315 }
5316 if (1 != matches) {
5317 return false; // RETURN
5318 }
5319 }
5320 cursor = endRange;
5321 }
5322 return true;
5323}
5324
5325template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5326inline
5327const HASHER&
5332
5333template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5334inline
5336{
5337 return static_cast<float>(static_cast<double>(this->size())
5338 / static_cast<double>(this->numBuckets()));
5339}
5340
5341template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5342inline
5343float
5345{
5346 return d_maxLoadFactor;
5347}
5348
5349template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5350inline
5353{
5354 // This estimate is still on the high side, we should actually pick the
5355 // preceding entry from our table of prime numbers used for valid bucket
5356 // array sizes. There is no easy way to find that value at the moment
5357 // though.
5358
5359 typedef typename AllocatorTraits::
5360 template rebind_traits<bslalg::HashTableBucket>
5361 BucketAllocatorTraits;
5362 typedef typename BucketAllocatorTraits::allocator_type BucketAllocator;
5363
5364 return BucketAllocatorTraits::max_size(BucketAllocator(this->allocator()));
5365}
5366
5367template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5368inline
5371{
5372 return AllocatorTraits::max_size(this->allocator()) / sizeof(NodeType);
5373}
5374
5375template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5376inline
5382
5383template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5384inline
5390
5391template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5392inline
5398
5399} // close package namespace
5400
5401//-----------------------------------------------------------------------------
5402// free functions and operators
5403//-----------------------------------------------------------------------------
5404
5405template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5406inline
5407void
5410{
5412 TableType;
5413
5415 || a.allocator() == b.allocator()) {
5416 a.swap(b);
5417 }
5418 else {
5419 // C++11 behavior: undefined for unequal allocators
5420 // BSLS_ASSERT(allocator() == other.allocator());
5421
5422 TableType aCopy(a, b.allocator());
5423 TableType bCopy(b, a.allocator());
5424
5425 b.swap(aCopy);
5426 a.swap(bCopy);
5427 }
5428}
5429
5430template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5431inline
5435{
5436 return lhs.hasSameValue(rhs);
5437}
5438
5439template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5440inline
5444{
5445 return !(a == b);
5446}
5447
5448template <class FUNCTOR>
5449inline
5452{
5453 a.swap(b);
5454}
5455
5456template <class FUNCTOR>
5457inline
5460{
5461 a.swap(b);
5462}
5463
5464// ============================================================================
5465// TYPE TRAITS
5466// ============================================================================
5467
5468// Type traits for HashTable:
5469//: o A HashTable is bitwise movable if the both functors and the allocator are
5470//: bitwise movable.
5471//: o A HashTable uses 'bslma' allocators if the parameterized 'ALLOCATOR' is
5472//: convertible from 'bslma::Allocator*'.
5473
5474namespace bslma {
5475
5476template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5477struct UsesBslmaAllocator<bslstl::HashTable<KEY_CONFIG,
5478 HASHER,
5479 COMPARATOR,
5480 ALLOCATOR> >
5481 : bsl::is_convertible<Allocator*, ALLOCATOR>::type {
5482};
5483
5484template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5485struct UsesBslmaAllocator<bslstl::HashTable_ImplParameters<KEY_CONFIG,
5486 HASHER,
5487 COMPARATOR,
5488 ALLOCATOR> >
5489 : bsl::is_convertible<Allocator*, ALLOCATOR>::type {
5490};
5491
5492} // close namespace bslma
5493
5494namespace bslmf {
5495
5496template <class KEY_CONFIG, class HASHER, class COMPARATOR, class ALLOCATOR>
5497struct IsBitwiseMoveable<bslstl::HashTable<KEY_CONFIG,
5498 HASHER,
5499 COMPARATOR,
5500 ALLOCATOR> >
5501: bsl::integral_constant< bool, bslmf::IsBitwiseMoveable<HASHER>::value
5502 && bslmf::IsBitwiseMoveable<COMPARATOR>::value
5503 && bslmf::IsBitwiseMoveable<ALLOCATOR>::value>
5504{};
5505
5506} // close namespace bslmf
5507
5508
5509#endif // End C++11 code
5510
5511#endif // End C++11 code
5512
5513// ----------------------------------------------------------------------------
5514// Copyright 2013 Bloomberg Finance L.P.
5515//
5516// Licensed under the Apache License, Version 2.0 (the "License");
5517// you may not use this file except in compliance with the License.
5518// You may obtain a copy of the License at
5519//
5520// http://www.apache.org/licenses/LICENSE-2.0
5521//
5522// Unless required by applicable law or agreed to in writing, software
5523// distributed under the License is distributed on an "AS IS" BASIS,
5524// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
5525// See the License for the specific language governing permissions and
5526// limitations under the License.
5527// ----------------------------- END-OF-FILE ----------------------------------
5528
5529/** @} */
5530/** @} */
5531/** @} */
Definition bslma_bslallocator.h:588
Definition bslalg_bidirectionalnode.h:357
Definition bslalg_functoradapter.h:230
Definition bslalg_hashtableanchor.h:542
BidirectionalLink * listRootAddress() const
Return the value listRootAddress attribute of this object.
Definition bslalg_hashtableanchor.h:695
void setBucketArrayAddressAndSize(HashTableBucket *bucketArrayAddress, std::size_t bucketArraySize)
Definition bslalg_hashtableanchor.h:666
std::size_t bucketArraySize() const
Return the value of the bucketArraySize attribute of this object.
Definition bslalg_hashtableanchor.h:701
void swap(HashTableAnchor &other)
Definition bslalg_hashtableanchor.h:688
void setListRootAddress(BidirectionalLink *value)
Definition bslalg_hashtableanchor.h:678
HashTableBucket * bucketArrayAddress() const
Definition bslalg_hashtableanchor.h:707
Definition bslma_allocator.h:545
Definition bslma_destructorguard.h:132
Definition bslmf_movableref.h:752
Definition bslstl_bidirectionalnodepool.h:274
Definition bslstl_hashtable.h:3050
~HashTable_ArrayProctor()
Definition bslstl_hashtable.h:3663
void release()
Definition bslstl_hashtable.h:3682
bool operator()(ARG1_TYPE &arg1, ARG2_TYPE &arg2) const
Definition bslstl_hashtable.h:1763
void swap(HashTable_ComparatorWrapper &other)
Exchange the value of this object with the specified other object.
Definition bslstl_hashtable.h:3545
const FUNCTOR & functor() const
Definition bslstl_hashtable.h:3537
HashTable_ComparatorWrapper()
Definition bslstl_hashtable.h:3513
bool operator()(ARG1_TYPE &arg1, ARG2_TYPE &arg2) const
Definition bslstl_hashtable.h:3530
std::size_t operator()(ARG_TYPE &arg) const
Definition bslstl_hashtable.h:1632
const FUNCTOR & functor() const
Definition bslstl_hashtable.h:3437
HashTable_HashWrapper()
Definition bslstl_hashtable.h:3414
std::size_t operator()(ARG_TYPE &arg) const
Definition bslstl_hashtable.h:3430
void swap(HashTable_HashWrapper &other)
Exchange the value of this object with the specified other object.
Definition bslstl_hashtable.h:3444
Definition bslstl_hashtable.h:3270
std::size_t hashCodeForKey(DEDUCED_KEY &key) const
Definition bslstl_hashtable.h:3878
HashTable< KEY_CONFIG, HASHER, COMPARATOR, ALLOCATOR > HashTableType
Definition bslstl_hashtable.h:3288
NodeFactory & nodeFactory()
Definition bslstl_hashtable.h:3821
void quickSwapRetainAllocators(HashTable_ImplParameters *other)
Definition bslstl_hashtable.h:3845
const BaseComparator & comparator() const
Definition bslstl_hashtable.h:3866
BidirectionalNodePool< typename HashTableType::ValueType, NodeAllocator > NodeFactory
Definition bslstl_hashtable.h:3295
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASHER, LOOKUP_KEY >::value, std::size_t >::type hashCodeForTransparentKey(const LOOKUP_KEY &key) const
Definition bslstl_hashtable.h:3383
const BaseHasher & hasher() const
Definition bslstl_hashtable.h:3889
void quickSwapExchangeAllocators(HashTable_ImplParameters *other)
Definition bslstl_hashtable.h:3829
ReboundTraits::allocator_type NodeAllocator
Definition bslstl_hashtable.h:3291
HashTableType::AllocatorTraits::template rebind_traits< NodeType > ReboundTraits
Definition bslstl_hashtable.h:3290
const HASHER & originalHasher() const
Definition bslstl_hashtable.h:3923
const COMPARATOR & originalComparator() const
Definition bslstl_hashtable.h:3913
Definition bslstl_hashtable.h:3100
~HashTable_NodeProctor()
Definition bslstl_hashtable.h:3629
void release()
Definition bslstl_hashtable.h:3639
Definition bslstl_hashtable.h:1934
bslalg::BidirectionalLink * insertOrAssign(bool *isInsertedFlag, bslalg::BidirectionalLink *hint, BSLS_COMPILERFEATURES_FORWARD_REF(KEY_ARG) key, BDE_OTHER_TYPE &&obj)
Definition bslstl_hashtable.h:4743
bslalg::BidirectionalNode< ValueType > NodeType
Definition bslstl_hashtable.h:1942
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:2695
HashTable & operator=(const HashTable &rhs)
Definition bslstl_hashtable.h:4418
KEY_CONFIG::KeyType KeyType
Definition bslstl_hashtable.h:1940
void rehashForNumBuckets(SizeType newNumBuckets)
Definition bslstl_hashtable.h:4791
ALLOCATOR AllocatorType
Definition bslstl_hashtable.h:1938
void setMaxLoadFactor(float newMaxLoadFactor)
Definition bslstl_hashtable.h:4878
void swap(HashTable &other)
Definition bslstl_hashtable.h:4901
ALLOCATOR allocator() const
Definition bslstl_hashtable.h:5058
SizeType countElementsInBucket(SizeType index) const
Definition bslstl_hashtable.h:5107
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:2844
bslalg::BidirectionalLink * tryEmplace(bool *isInsertedFlag, bslalg::BidirectionalLink *hint, const KeyType &key, ARGS &&... args)
Definition bslstl_hashtable.h:4923
SizeType rehashThreshold() const
Definition bslstl_hashtable.h:5386
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASHER, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< COMPARATOR, LOOKUP_KEY >::value, bslalg::BidirectionalLink * >::type insertIfMissingTransparent(bool *isInsertedFlag, BSLS_COMPILERFEATURES_FORWARD_REF(LOOKUP_KEY) value)
Definition bslstl_hashtable.h:2413
bslalg::BidirectionalLink * emplaceIfMissing(bool *isInsertedFlag, Args &&... arguments)
::bsl::allocator_traits< AllocatorType > AllocatorTraits
Definition bslstl_hashtable.h:1939
bool hasSameValue(const HashTable &other) const
Definition bslstl_hashtable.h:5179
const COMPARATOR & comparator() const
Definition bslstl_hashtable.h:5099
float maxLoadFactor() const
Definition bslstl_hashtable.h:5344
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:2894
bslalg::BidirectionalLink * insert(BSLS_COMPILERFEATURES_FORWARD_REF(SOURCE_TYPE) value)
Definition bslstl_hashtable.h:4721
const HASHER & hasher() const
Definition bslstl_hashtable.h:5328
bslalg::BidirectionalLink * findEndOfRange(bslalg::BidirectionalLink *first) const
Definition bslstl_hashtable.h:5138
bslalg::BidirectionalLink * emplaceWithHint(bslalg::BidirectionalLink *hint, Args &&... arguments)
HashTable & operator=(BloombergLP::bslmf::MovableRef< HashTable > rhs)
AllocatorTraits::size_type SizeType
Definition bslstl_hashtable.h:1943
void reserveForNumElements(SizeType numElements)
Definition bslstl_hashtable.h:4852
SizeType maxSize() const
Definition bslstl_hashtable.h:5370
bslalg::BidirectionalLink * remove(bslalg::BidirectionalLink *node)
Definition bslstl_hashtable.h:4813
SizeType numBuckets() const
Return the number of buckets contained in this hash table.
Definition bslstl_hashtable.h:5378
SizeType maxNumBuckets() const
Definition bslstl_hashtable.h:5352
bsl::remove_const< KeyType >::type NonConstKeyType
Definition bslstl_hashtable.h:1944
HashTable(const ALLOCATOR &basicAllocator=ALLOCATOR())
Definition bslstl_hashtable.h:3936
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASHER, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< COMPARATOR, LOOKUP_KEY >::value, SizeType >::type bucketIndexForKey(const LOOKUP_KEY &key) const
Definition bslstl_hashtable.h:2795
bslalg::BidirectionalLink * insertIfMissing(const KeyType &key)
Definition bslstl_hashtable.h:4619
~HashTable()
Destroy this object.
Definition bslstl_hashtable.h:4085
SizeType bucketIndexForKey(const KeyType &key) const
Definition bslstl_hashtable.h:5077
bslalg::BidirectionalLink * elementListRoot() const
Definition bslstl_hashtable.h:5118
SizeType size() const
Return the number of elements in this hash table.
Definition bslstl_hashtable.h:5394
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASHER, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< COMPARATOR, LOOKUP_KEY >::value, bslalg::BidirectionalLink * >::type insertOrAssignTransparent(bool *isInsertedFlag, bslalg::BidirectionalLink *hint, LOOKUP_KEY &&key, BDE_OTHER_TYPE &&obj)
Definition bslstl_hashtable.h:2527
KEY_CONFIG::ValueType ValueType
Definition bslstl_hashtable.h:1941
HashTable(BloombergLP::bslmf::MovableRef< HashTable > original, const ALLOCATOR &basicAllocator)
float loadFactor() const
Definition bslstl_hashtable.h:5335
const bslalg::HashTableBucket & bucketAtIndex(SizeType index) const
Definition bslstl_hashtable.h:5066
void removeAll()
Definition bslstl_hashtable.h:4834
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2343
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2349
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
void swap(OptionValue &a, OptionValue &b)
ALLOCATOR & lhs
Definition bslstl_string.h:3917
Definition baljsn_encoder_testtypes.h:76
Definition bdlbb_blob.h:579
Definition bslstl_algorithm.h:84
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)
t_TYPE & type
This typedef defines the return type of this meta function.
Definition bslmf_addlvaluereference.h:131
Definition bslma_allocatortraits.h:1089
BloombergLP::bslma::AllocatorTraits_SizeType< ALLOCATOR_TYPE >::type size_type
Definition bslma_allocatortraits.h:1196
Definition bslmf_conditional.h:123
Definition bslmf_enableif.h:530
Definition bslmf_integralconstant.h:261
Definition bslmf_isconvertible.h:875
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:164
Definition bslalg_hashtablebucket.h:297
Definition bslalg_hashtableimputil.h:615
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:858
static void deallocateObject(const t_ALLOCATOR &allocator, t_POINTER p, std::size_t n=1)
Definition bslma_allocatorutil.h:949
Definition bslma_usesbslmaallocator.h:344
Definition bslmf_isbitwisemoveable.h:718
Definition bslmf_movableref.h:795
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
Definition bslstl_hashtable.h:1605
bsl::conditional< bsl::is_function< CALLABLE >::value, typenamebsl::add_lvalue_reference< CALLABLE >::type, CALLABLE >::type type
Definition bslstl_hashtable.h:1611
Definition bslstl_hashtable.h:3252
Definition bslstl_hashtable.h:3259
Definition bslstl_hashtable.h:3144
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:3198
static void destroyBucketArray(bslalg::HashTableBucket *data, std::size_t bucketArraySize, const ALLOCATOR &allocator)
Definition bslstl_hashtable.h:3717
static void initAnchor(bslalg::HashTableAnchor *anchor, std::size_t bucketArraySize, const ALLOCATOR &allocator)
Definition bslstl_hashtable.h:3743
static void assertNotNullPointer(TYPE &)
Definition bslstl_hashtable.h:3693
Definition bsls_objectbuffer.h:277
TYPE * address()
Definition bsls_objectbuffer.h:335
TYPE & object()
Definition bsls_objectbuffer.h:352