BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlcc_stripedunorderedmap.h
Go to the documentation of this file.
1/// @file bdlcc_stripedunorderedmap.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_stripedunorderedmap.h -*-C++-*-
8#ifndef INCLUDED_BDLCC_STRIPEDUNORDEREDMAP
9#define INCLUDED_BDLCC_STRIPEDUNORDEREDMAP
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlcc_stripedunorderedmap bdlcc_stripedunorderedmap
15/// @brief Provide a bucket-group locking (i.e., *striped*) unordered map.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlcc
19/// @{
20/// @addtogroup bdlcc_stripedunorderedmap
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlcc_stripedunorderedmap-purpose"> Purpose</a>
25/// * <a href="#bdlcc_stripedunorderedmap-classes"> Classes </a>
26/// * <a href="#bdlcc_stripedunorderedmap-description"> Description </a>
27/// * <a href="#bdlcc_stripedunorderedmap-thread-safety"> Thread Safety </a>
28/// * <a href="#bdlcc_stripedunorderedmap-runtime-complexity"> Runtime Complexity </a>
29/// * <a href="#bdlcc_stripedunorderedmap-number-of-stripes"> Number of Stripes </a>
30/// * <a href="#bdlcc_stripedunorderedmap-set-vs-insert-methods"> Set vs. Insert Methods </a>
31/// * <a href="#bdlcc_stripedunorderedmap-rehash"> Rehash </a>
32/// * <a href="#bdlcc_stripedunorderedmap-concurrent-rehash"> Concurrent Rehash </a>
33/// * <a href="#bdlcc_stripedunorderedmap-rehash-control"> Rehash Control </a>
34/// * <a href="#bdlcc_stripedunorderedmap-usage"> Usage </a>
35/// * <a href="#bdlcc_stripedunorderedmap-example-1-basic-usage"> Example 1: Basic Usage </a>
36/// * <a href="#bdlcc_stripedunorderedmap-example-2-track-stats"> Example 2: Track Stats </a>
37/// * <a href="#bdlcc_stripedunorderedmap-example-3-visiting-all-the-container-elements"> Example 3: Visiting all the Container Elements </a>
38///
39/// # Purpose {#bdlcc_stripedunorderedmap-purpose}
40/// Provide a bucket-group locking (i.e., *striped*) unordered map.
41///
42/// # Classes {#bdlcc_stripedunorderedmap-classes}
43///
44/// - bdlcc::StripedUnorderedMap: Striped hash map
45///
46/// @see bdlcc_stripedunorderedmultimap,
47/// bdlcc_stripedunorderedcontainerimpl
48///
49/// # Description {#bdlcc_stripedunorderedmap-description}
50/// This component provides a single concurrent (fully thread-safe)
51/// associative container, `bdlcc::StripedUnorderedMap`, that partitions the
52/// underlying hash table into a (user defined) number of "bucket groups" and
53/// controls access to each bucket group by a separate read-write lock. This
54/// design allows greater concurrency (and improved performance) than a
55/// `bsl::unordered_map` object protected by a single lock.
56///
57/// The terms "bucket", "load factor", and "rehash" have the same meaning as
58/// they do in the @ref bslstl_unorderedmap component (see
59/// {@ref bslstl_unorderedmap |Unordered Map Configuration}). A general
60/// introduction to these ideas can be found at:
61/// https://en.wikipedia.org/wiki/Hash_table
62///
63/// `bdlcc::StripedUnorderedMap` (and concurrent containers in general) does not
64/// provide iterators that allow users to manipulate or traverse the values of
65/// elements in a map. Alternatively, this container provides the
66/// `setComputedValue` method that allows users to change the value for a given
67/// key via a user provided functor and the `visit` method that will apply a
68/// user provided functor the value of every key in the map.
69///
70/// The `bdlcc::StripedUnorderedMap` class is an *irregular* value-semantic
71/// type, even if `KEY` and `VALUE` are VSTs. This class does not implement
72/// equality comparison, assignment operator, or copy constructor.
73///
74/// ## Thread Safety {#bdlcc_stripedunorderedmap-thread-safety}
75///
76///
77/// The `bdlcc::StripedUnorderedMap` class template is fully thread-safe (see
78/// {@ref bsldoc_glossary |Fully Thread-Safe}), assuming that the allocator is fully
79/// thread-safe. Each method is executed by the calling thread.
80///
81/// ## Runtime Complexity {#bdlcc_stripedunorderedmap-runtime-complexity}
82///
83///
84/// @code
85/// +----------------------------------------------------+--------------------+
86/// | Operation | Complexity |
87/// +====================================================+====================+
88/// | insert, setValue, setComputedValue, update | Average: O[1] |
89/// | | Worst: O[n] |
90/// +----------------------------------------------------+--------------------+
91/// | erase, getValue | Average: O[1] |
92/// | | Worst: O[n] |
93/// +----------------------------------------------------+--------------------+
94/// | visit(key, visitor) | Average: O[1] |
95/// | visitReadOnly(key, visitor) | Worst: O[n] |
96/// +----------------------------------------------------+--------------------+
97/// | insertBulk, k elements | Average: O[k] |
98/// | | Worst: O[n*k] |
99/// +----------------------------------------------------+--------------------+
100/// | eraseBulk, k elements | Average: O[k] |
101/// | | Worst: O[n*k] |
102/// +----------------------------------------------------+--------------------+
103/// | rehash | O[n] |
104/// +----------------------------------------------------+--------------------+
105/// | visit(visitor), visitReadOnly(visitor) | O[n] |
106/// +----------------------------------------------------+--------------------+
107/// @endcode
108///
109/// ## Number of Stripes {#bdlcc_stripedunorderedmap-number-of-stripes}
110///
111///
112/// Performance improves monotonically when the number of stripes increases.
113/// However, the rate of improvement decreases, and reaches a plateau. The
114/// plateau is reached roughly at four times the number of the threads
115/// *concurrently* using the hash map.
116///
117/// ## Set vs. Insert Methods {#bdlcc_stripedunorderedmap-set-vs-insert-methods}
118///
119///
120/// This container provides several `set*` methods and analogously named
121/// `insert*` methods having semantics that are identical except for the meaning
122/// of the return value. The rationale is best explained in the context of the
123/// `bdlcc::StripedUnorderedMultiMap` class. See
124/// {@ref bdlcc_stripedunorderedmultimap |Set vs. Insert methods}. The behavior as
125/// seen in *this* component is the degenerate case when the number of elements
126/// updated (or inserted) is limited to 0 or 1.
127///
128/// ## Rehash {#bdlcc_stripedunorderedmap-rehash}
129///
130///
131///
132/// ### Concurrent Rehash {#bdlcc_stripedunorderedmap-concurrent-rehash}
133///
134///
135/// A rehash operation is a re-organization of the hash map to a different
136/// number of buckets. This is a heavy operation that interferes with, but does
137/// *not* disallow, other operations on the container. Rehash is warranted when
138/// the current load factor exceeds the current maximum allowed load factor.
139/// Expressed explicitly:
140/// @code
141/// bucketCount() <= maxLoadFactor() * size();
142/// @endcode
143/// This above condition is tested implicitly by several methods and if found
144/// true (and if rehash is enabled and rehash is not underway), a rehash is
145/// started. The methods that check the load factor are:
146///
147/// * All methods that insert elements (i.e., increase `size()`).
148/// * The `maxLoadFactor(newMaxLoadFactor)` method.
149/// * The `rehash` method.
150///
151/// ### Rehash Control {#bdlcc_stripedunorderedmap-rehash-control}
152///
153///
154/// `enableRehash` and `disableRehash` methods are provided to control the
155/// rehash enable flag. Note that disabling rehash does not impact a rehash in
156/// progress.
157///
158/// ## Usage {#bdlcc_stripedunorderedmap-usage}
159///
160///
161/// In this section we show intended use of this component.
162///
163/// ### Example 1: Basic Usage {#bdlcc_stripedunorderedmap-example-1-basic-usage}
164///
165///
166/// This example shows some basic usage of `bdlcc::StripedUnorderedMap`.
167///
168/// First, we define a `bdlcc::StripedUnorderedMap` object, `myFriends`, that
169/// maps `int` to `bsl::string`:
170/// @code
171/// bdlcc::StripedUnorderedMap<int, bsl::string> myFriends;
172/// @endcode
173/// Notice that we are using the default value number of buckets, number of
174/// stripes, and allocator.
175///
176/// Then, we insert three elements into the map and verify that the size is the
177/// expected value:
178/// @code
179/// assert(0 == myFriends.size());
180/// myFriends.insert(0, "Alex");
181/// myFriends.insert(1, "John");
182/// myFriends.insert(2, "Rob");
183/// assert(3 == myFriends.size());
184/// @endcode
185/// Next, we demonstrate `insertBulk` by creating a vector of three key-value
186/// pairs and add them to the map using a single method call:
187/// @code
188/// typedef bsl::pair<int, bsl::string> PairType;
189/// bsl::vector<PairType> insertData;
190/// insertData.push_back(PairType(3, "Jim"));
191/// insertData.push_back(PairType(4, "Jeff"));
192/// insertData.push_back(PairType(5, "Ian" ));
193/// assert(3 == insertData.size())
194///
195/// assert(3 == myFriends.size());
196/// myFriends.insertBulk(insertData.begin(), insertData.end());
197/// assert(6 == myFriends.size());
198/// @endcode
199/// Then, we `getValue` method to retrieve the previously inserted string
200/// associated with the value 1:
201/// @code
202/// bsl::string value;
203/// bsl::size_t rc = myFriends.getValue(&value, 1);
204/// assert(1 == rc);
205/// assert("John" == value);
206/// @endcode
207/// Now, we change the value associated with 1 from "John" to "Jack" and confirm
208/// that the size of the map has not changed:
209/// @code
210/// rc = myFriends.setValue(1, "Jack");
211/// assert(1 == rc);
212/// assert(6 == myFriends.size());
213///
214/// rc = myFriends.getValue(&value, 1);
215/// assert(1 == rc);
216/// assert("Jack" == value);
217/// @endcode
218/// Finally, we erase the element `(3, "Jim")` from the map, confirm that the
219/// map size is decremented, and that element can no longer be found in the map:
220/// @code
221/// rc = myFriends.erase(3);
222/// assert(1 == rc);
223/// assert(5 == myFriends.size());
224///
225/// rc = myFriends.getValue(&value, 3);
226/// assert(0 == rc);
227/// @endcode
228///
229/// ### Example 2: Track Stats {#bdlcc_stripedunorderedmap-example-2-track-stats}
230///
231///
232/// This example uses the `setComputedValue` and `update` methods to keep track
233/// of user ID usage counts (stats). A striped unordered map has the user ID as
234/// the key, and the count as the value. There are 2 functors, one used to
235/// increase the count (and set it to `1` if the user ID has not been referenced
236/// yet), and the other is used to decrease the count.
237/// @code
238/// typedef bdlcc::StripedUnorderedMap<int, int> StatsMap;
239/// @endcode
240///
241/// First, define a functor, `IncFunctor`, that has parameters corresponding to
242/// the `KEY` and `VALUE` types of `StatsMap` and, when invoked, adds 1 to
243/// whatever existing value is associated with the given `KEY` value. As a new
244/// value is initialized with default (0), adding 1 to it works correctly:
245/// @code
246/// struct IncFunctor {
247/// bool operator()(int *value, // 'VALUE *'
248/// const int&) // 'const KEY&'
249/// {
250/// *value += 1;
251/// return true;
252/// }
253/// };
254/// @endcode
255///
256/// Next, define a functor, `DecFunctor`, that has parameters corresponding to
257/// the `KEY` and `VALUE` types of `StatsMap` and, when invoked, subtracts 1
258/// from whatever existing value is associated with the given `KEY` value:
259/// @code
260/// struct DecFunctor {
261/// bool operator()(int *value, // 'VALUE *'
262/// const int& ) // 'const KEY&'
263/// {
264/// *value -= 1;
265/// return true;
266/// }
267/// };
268/// @endcode
269///
270/// Then, create `myStats`, a `StatsMap` object with (as we did in {Example 1}
271/// default number of buckets, number of stripes, and allocator:
272/// @code
273/// StatsMap myStats;
274/// @endcode
275/// Next, instantiate `myIncFunctor` and `myDecFunctor` from `IncFunctor` and
276/// `DecFunctor`, respectively:
277/// @code
278/// IncFunctor myIncFunctor;
279/// DecFunctor myDecFunctor;
280/// @endcode
281/// Next, increase count for three user IDs:
282/// @code
283/// assert(0 == myStats.size());
284/// int rc = myStats.setComputedValue(1001, myIncFunctor);
285/// assert(0 == rc);
286/// rc = myStats.setComputedValue(1002, myIncFunctor);
287/// assert(0 == rc);
288/// rc = myStats.setComputedValue(1003, myIncFunctor);
289/// assert(0 == rc);
290/// assert(3 == myStats.size());
291/// int value = 0;
292/// rc = myStats.getValue(&value, 1001);
293/// assert(1 == rc);
294/// assert(1 == value);
295/// @endcode
296/// Now, increase count for existing user IDs. Confirm that the values have
297/// been updated as expected.
298/// @code
299/// rc = myStats.setComputedValue(1001, myIncFunctor);
300/// assert(1 == rc);
301/// rc = myStats.setComputedValue(1002, myIncFunctor);
302/// assert(1 == rc);
303/// rc = myStats.setComputedValue(1001, myIncFunctor);
304/// assert(1 == rc);
305/// assert(3 == myStats.size());
306/// rc = myStats.getValue(&value, 1001);
307/// assert(1 == rc);
308/// assert(3 == value);
309/// rc = myStats.getValue(&value, 1002);
310/// assert(1 == rc);
311/// assert(2 == value);
312/// @endcode
313/// Finally decrease count for existing user IDs. Confirm that the values have
314/// been updated as expected.
315/// @code
316/// int ret = myStats.update(1001, myDecFunctor);
317/// assert(1 == ret);
318/// ret = myStats.update(1003, myDecFunctor);
319/// assert(1 == ret);
320/// assert(3 == myStats.size());
321/// rc = myStats.getValue(&value, 1001);
322/// assert(1 == rc);
323/// assert(2 == value);
324/// rc = myStats.getValue(&value, 1003);
325/// assert(1 == rc);
326/// assert(0 == value);
327/// @endcode
328/// ### Example 3: Visiting all the Container Elements {#bdlcc_stripedunorderedmap-example-3-visiting-all-the-container-elements}
329///
330///
331/// This example uses the `visit` method to apply a transformation (as defined
332/// by a functor) to the value of every key-value pair in the map. This example
333/// will construct a map from names (type `bsl::string`) to some (arbitrary)
334/// measure of salary (type `int`):
335/// @code
336/// typedef bdlcc::StripedUnorderedMap<bsl::string, int> SalaryMap;
337/// @endcode
338/// First, define a functor, `mySalaryAdjustmentVisitor`, that increases values
339/// above 1000 by 3% and lower values by 5%. The fractional part of increases
340/// are truncated to `int` values:
341/// @code
342/// struct mySalaryAdjustmentVisitor {
343/// bool operator()(int *value, // 'VALUE *'
344/// const bsl::string&) // 'const KEY&'
345/// {
346/// if (*value <= 1000) {
347/// *value = static_cast<int>(*value * 1.05);
348/// } else {
349/// *value = static_cast<int>(*value * 1.03);
350/// }
351/// return true;
352/// }
353/// };
354/// @endcode
355/// Then, default create `mySalaries`, a `SalaryMap` object:
356/// @code
357/// SalaryMap mySalaries;
358/// @endcode
359/// Next, load `mySalaries` with some representative elements:
360/// @code
361/// mySalaries.insert("Alex", 1000);
362/// mySalaries.insert("John", 800);
363/// mySalaries.insert("Rob", 1100);
364/// assert(3 == mySalaries.size());
365/// @endcode
366/// Now, apply `mySalaryAdjustmentVisitor` to every element in the map:
367/// @code
368/// mySalaryAdjustmentVisitor func;
369/// mySalaries.visit(func);
370/// assert(3 == mySalaries.size());
371/// @endcode
372/// Finally, confirm that the values have been adjusted as expected:
373/// @code
374///
375/// int value;
376/// bsl::size_t rc;
377///
378/// rc = mySalaries.getValue(&value, "Alex");
379/// assert(1 == rc);
380/// assert(1050 == value);
381///
382/// rc = mySalaries.getValue(&value, "John");
383/// assert(1 == rc);
384/// assert( 840 == value);
385///
386/// rc = mySalaries.getValue(&value, "Rob");
387/// assert(1 == rc);
388/// assert(1133 == value);
389/// @endcode
390/// @}
391/** @} */
392/** @} */
393
394/** @addtogroup bdl
395 * @{
396 */
397/** @addtogroup bdlcc
398 * @{
399 */
400/** @addtogroup bdlcc_stripedunorderedmap
401 * @{
402 */
403
404#include <bdlscm_version.h>
405
407
408#include <bslmf_movableref.h>
409
410#include <bsls_assert.h>
411
412#include <bsl_functional.h>
413
414
415namespace bdlcc {
416
417 // =========================
418 // class StripedUnorderedMap
419 // =========================
420
421/// This class template defines a fully thread-safe container that provides a
422/// mapping from keys (of template parameter type `KEY`) to their associated
423/// mapped values (of template parameter type `VALUE`).
424///
425/// The buckets of this hash map are guarded by `numStripes` reader-writer
426/// locks, a value specified on construction. Partitioning the buckets among
427/// several locks allows greater overall concurrency than a
428/// `bsl::unordered_map` object guarded by a single lock.
429///
430/// The interface is inspired by, but not identical to that of
431/// `bsl::unordered_map`. Notably absent are iterators, which are of limited
432/// practicality in the typical use case because they are readily invalidated
433/// when the map population is open to modification by multiple threads.
434///
435/// See @ref bdlcc_stripedunorderedmap
436template <class KEY,
437 class VALUE,
438 class HASH = bsl::hash<KEY>,
439 class EQUAL = bsl::equal_to<KEY> >
441
442 private:
443 // PRIVATE TYPES
445
446 // DATA
447
448 // implementation of the striped hash map
449 Impl d_imp;
450
451 // NOT IMPLEMENTED
453 // = delete
456 // = delete
457
458 public:
459 // PUBLIC CONSTANTS
460 enum {
461 k_DEFAULT_NUM_BUCKETS = 16, // Default number of buckets
462 k_DEFAULT_NUM_STRIPES = 4 // Default number of stripes
463 };
464
465 // PUBLIC TYPES
466
467 /// Value type of a bulk insert entry.
469
470 /// An alias to a function meeting the following contract:
471 /// @code
472 /// /// Return `true` if the specified `value` is to be removed from
473 /// /// the container, and `false` otherwise. Note that this
474 /// /// functor can *not* change the values associated with `value`.
475 /// bool eraseIfValuePredicate(const VALUE& value);
476 /// @endcode
477 typedef bsl::function<bool(const VALUE&)> EraseIfValuePredicate;
478
479 /// An alias to a function meeting the following contract:
480 /// @code
481 /// /// Visit the specified `value` attribute associated with the
482 /// /// specified `key`. Return `true` if this function may be
483 /// /// called on additional elements, and `false` otherwise (i.e.,
484 /// /// if no other elements should be visited). Note that this
485 /// /// functor can change the value associated with `key`.
486 /// bool visitorFunction(VALUE *value, const KEY& key);
487 /// @endcode
488 typedef bsl::function<bool (VALUE *, const KEY&)> VisitorFunction;
489
490 /// An alias to a function meeting the following contract:
491 /// @code
492 /// /// Visit the specified `value` attribute associated with the
493 /// /// specified `key`. Return `true` if this function may be
494 /// /// called on additional elements, and `false` otherwise (i.e.,
495 /// /// if no other elements should be visited). Note that this
496 /// /// functor can *not* change the value associated with `key`
497 /// /// and `value`.
498 /// bool visitorFunction(const VALUE& value, const KEY& key);
499 /// @endcode
500 typedef bsl::function<bool (const VALUE&, const KEY&)>
502
503 // CREATORS
504
505 explicit StripedUnorderedMap(
506 bsl::size_t numInitialBuckets = k_DEFAULT_NUM_BUCKETS,
507 bsl::size_t numStripes = k_DEFAULT_NUM_STRIPES,
508 bslma::Allocator *basicAllocator = 0);
509 /// Create an empty `StripedUnorderedMap` object, a fully thread-safe
510 /// hash map where access is partitioned into "stripes" (a group of
511 /// buckets protected a reader-writer mutex). Optionally specify
512 /// `numInitialBuckets` and `numStripes` which define the minimum number
513 /// of buckets and the (fixed) number of stripes in this map.
514 /// Optionally specify a `basicAllocator` used to supply memory. If
515 /// `basicAllocator` is 0, the currently installed default allocator is
516 /// used. The hash map has rehash enabled. Note that the number of
517 /// stripes will not change after construction, but the number of
518 /// buckets may (unless rehashing is disabled via `disableRehash`).
519 explicit StripedUnorderedMap(
520 bslma::Allocator *basicAllocator);
521
522 /// Destroy this hash map.
524
525 // MANIPULATORS
526
527 /// Remove all elements from this hash map. If rehash is in progress,
528 /// block until it completes.
529 void clear();
530
531 /// Prevent future rehash until `enableRehash` is called.
532 void disableRehash();
533
534 /// Allow rehash. If conditions warrant, rehash will be started by the
535 /// *next* method call that observes the load factor is exceeded (see
536 /// {Concurrent Rehash}). Note that calling
537 /// `maxLoadFactor(maxLoadFactor())` (i.e., setting the maximum load
538 /// factor to its current value) will trigger a rehash if needed but
539 /// otherwise does not change the hash map.
540 void enableRehash();
541
542 /// Erase from this hash map the element having the specified `key`.
543 /// Return 1 on success and 0 if `key` does not exist. Note that the
544 /// returned value equals the number of elements removed.
545 bsl::size_t erase(const KEY& key);
546
547 /// Erase from this hash map elements in this hash map having any of the
548 /// values in the keys contained between the specified `first`
549 /// (inclusive) and `last` (exclusive) random-access iterators. The
550 /// iterators provide read access to a sequence of `KEY` objects. All
551 /// erasures are done by the calling thread and the order of erasure is
552 /// not specified. Return the number of elements removed. The behavior
553 /// is undefined unless `first <= last`. Note that the map may not have
554 /// an element for every value in `keys`.
555 template <class RANDOM_ITER>
556 bsl::size_t eraseBulk(RANDOM_ITER first, RANDOM_ITER last);
557
558 /// Remove from this hash map the element, if any, having the specified
559 /// `key`, where specified `predicate` holds true. Return the number of
560 /// elements erased.
561 bsl::size_t eraseIf(const KEY& key,
562 const EraseIfValuePredicate& predicate);
563
564 /// Insert into this hash map an element having the specified `key` and
565 /// `value`. If `key` already exists in this hash map, the value
566 /// attribute of that element is set to `value`. Return 1 if an element
567 /// is inserted, and 0 if an existing element is updated. Note that the
568 /// return value equals the number of elements inserted.
569 bsl::size_t insert(const KEY& key, const VALUE& value);
570
571 /// Insert into this hash map an element having the specified `key` and
572 /// the specified move-insertable `value`. If `key` already exists in
573 /// this hash map, the value attribute of that element is set to
574 /// `value`. Return 1 if an element is inserted, and 0 if an existing
575 /// element is updated. The `value` object is left in a valid but
576 /// unspecified state. If `value` is allocator-enabled and
577 /// `allocator() != value.allocator()` this operation may cost as much
578 /// as a copy. Note that the return value equals the number of elements
579 /// inserted.
580 bsl::size_t insert(const KEY& key, bslmf::MovableRef<VALUE> value);
581
582 /// Insert into this hash map elements having the key-value pairs
583 /// obtained between the specified `first` (inclusive) and `last`
584 /// (exclusive) random-access iterators. The iterators provide read
585 /// access to a sequence of `bsl::pair<KEY, VALUE>` objects. If an
586 /// element having one of the keys already exists in this hash map, set
587 /// the value attribute to the corresponding value from `data`. All
588 /// insertions are done by the calling thread and the order of insertion
589 /// is not specified. Return the number of elements inserted. The
590 /// behavior is undefined unless `first <= last`.
591 template <class RANDOM_ITER>
592 bsl::size_t insertBulk(RANDOM_ITER first, RANDOM_ITER last);
593
594 /// Set the maximum load factor of this unordered map to the specified
595 /// `newMaxLoadFactor`. If `newMaxLoadFactor < loadFactor()`, this
596 /// operation will cause an immediate rehash; otherwise, this operation
597 /// has a constant-time cost. The rehash will increase the number of
598 /// buckets by a power of 2. The behavior is undefined unless
599 /// `0 < newMaxLoadFactor`.
600 void maxLoadFactor(float newMaxLoadFactor);
601
602 /// Recreate this hash map to one having at least the specified
603 /// `numBuckets`. This operation is a no-op if *any* of the following
604 /// are true: 1) rehash is disabled; 2) `numBuckets` less or equals the
605 /// current number of buckets. See {Rehash}.
606 void rehash(bsl::size_t numBuckets);
607
608 /// Invoke the specified `visitor` on the value associated with the
609 /// specified `key`. The `visitor` will be passed the address of the
610 /// value, and `key`. If `key` is not in the map, `value` will be
611 /// default constructed. That is, `visitor` must be invocable with the
612 /// `VisitorFunction` signature:
613 /// @code
614 /// bool visitor(VALUE *value, const Key& key);
615 /// @endcode
616 /// If no element in the map has `key`, insert `(key, VALUE())` and
617 /// invoke `visitor` with `value` pointing to the default constructed
618 /// value. Return 1 if `key` was found and `visitor` returned `true`, 0
619 /// if `key` was not found, and -1 if `key` was found and `visitor`
620 /// returned `false`. `visitor`, when invoked, has exclusive access
621 /// (i.e., write access) to the element. The behavior is undefined if
622 /// hash map manipulators and `getValue*` methods are invoked from
623 /// within `visitor`, as it may lead to a deadlock. Note that the
624 /// return value equals the number of elements found having `key`. Also
625 /// note that a return value of `0` implies that an element was
626 /// inserted.
627 int setComputedValue(const KEY& key,
628 const VisitorFunction& visitor);
629
630 /// Set the value attribute of the element in this hash map having the
631 /// specified `key` to the specified `value`. If no such such element
632 /// exists, insert `(key, value)`. Return 1 if `key` was found, and 0
633 /// otherwise. Note that the return value equals the number of elements
634 /// found having `key`.
635 bsl::size_t setValue(const KEY& key, const VALUE& value);
636
637 /// Set the value attribute of the element in this hash map having the
638 /// specified `key` to the specified move-insertable `value`. If no
639 /// such such element exists, insert `(key, value)`. Return 1 if `key`
640 /// was found, and 0 otherwise. The `value` object is left in a valid
641 /// but unspecified state. If `value` is allocator-enabled and
642 /// `allocator() != value.allocator()` this operation may cost as much
643 /// as a copy. Note that the return value equals the number of elements
644 /// found having `key`.
645 bsl::size_t setValue(const KEY& key, bslmf::MovableRef<VALUE> value);
646
647 /// @deprecated Use @ref visit(key, visitor) instead.
648 ///
649 /// Call the specified `visitor` with the element (if one exists) in
650 /// this hash map having the specified `key`. That is:
651 /// @code
652 /// bool visitor(&value, key);
653 /// @endcode
654 /// Return the number of elements updated or -1 if `visitor` returned
655 /// `false`. `visitor` has exclusive access (i.e., write access) the
656 /// element for during its invocation. The behavior is undefined if
657 /// hash map manipulators and `getValue*` methods are invoked from
658 /// within `visitor`, as it may lead to a deadlock.
659 int update(const KEY& key, const VisitorFunction& visitor);
660
661 /// Call the specified `visitor` (in an unspecified order) on all
662 /// elements in this hash table until each such element has been visited
663 /// or `visitor` returns `false`. That is, for `(key, value)`, invoke:
664 /// @code
665 /// bool visitor(&value, key);
666 /// @endcode
667 /// Return the number of elements visited or the negation of that value
668 /// if visitations stopped because `visitor` returned `false`.
669 /// `visitor` has exclusive access (i.e., write access) to each element
670 /// for duration of each invocation. Every element present in this hash
671 /// map at the time `visit` is invoked will be visited unless it is
672 /// removed before `visitor` is called for that element. Each
673 /// visitation is done by the calling thread and the order of visitation
674 /// is not specified. Elements inserted during the execution of `visit`
675 /// may or may not be visited. The behavior is undefined if hash map
676 /// manipulators and `getValue*` methods are invoked from within
677 /// `visitor`, as it may lead to a deadlock. Note that `visitor` can
678 /// change the value of the visited elements.
679 int visit(const VisitorFunction& visitor);
680
681 /// Call the specified `visitor` with the element (if one exists) in
682 /// this hash map having the specified `key`. That is:
683 /// @code
684 /// bool visitor(&value, key);
685 /// @endcode
686 /// Return the number of elements updated or -1 if `visitor` returned
687 /// `false`. `visitor` has exclusive access (i.e., write access) the
688 /// element for during its invocation. The behavior is undefined if
689 /// hash map manipulators and `getValue*` methods are invoked from
690 /// within `visitor`, as it may lead to a deadlock.
691 int visit(const KEY& key, const VisitorFunction& visitor);
692
693 // ACCESSORS
694
695 /// Return the number of buckets in the array of buckets maintained by
696 /// this hash map. Note that unless rehash is disabled, the value
697 /// returned may be obsolete by the time it is received.
698 bsl::size_t bucketCount() const;
699
700 /// Return the index of the bucket, in the array of buckets maintained
701 /// by this hash map, where elements having the specified `key` are
702 /// inserted. Note that unless rehash is disabled, the value returned
703 /// may be obsolete at the time it is returned.
704 bsl::size_t bucketIndex(const KEY& key) const;
705
706 /// Return the number of elements contained in the bucket at the
707 /// specified `index` in the array of buckets maintained by this hash
708 /// map. The behavior is undefined unless
709 /// `0 <= index < bucketCount()`. Note that unless rehash is disabled
710 /// the value returned may be obsolete by the time it is returned.
711 bsl::size_t bucketSize(bsl::size_t index) const;
712
713 /// Return `true` if this hash map contains no elements, and `false`
714 /// otherwise.
715 bool empty() const;
716
717 /// Return (a copy of) the key-equality functor used by this hash map.
718 /// The returned function will return `true` if two `KEY` objects have
719 /// the same value, and `false` otherwise.
720 EQUAL equalFunction() const;
721
722 /// Load, into the specified `*value`, the value attribute of the
723 /// element in this hash map having the specified `key`. Return 1 on
724 /// success and 0 if `key` does not exist in this hash map. Note that
725 /// the return value equals the number of values returned.
726 bsl::size_t getValue(VALUE *value, const KEY& key) const;
727
728 /// Return (a copy of) the unary hash functor used by this hash map.
729 /// The return function will generate a hash value (of type
730 /// `std::size_t`) for a `KEY` object.
731 HASH hashFunction() const;
732
733 /// Return `true` if rehash is enabled, or `false` otherwise.
734 bool isRehashEnabled() const;
735
736 /// Return the current quotient of the size of this hash map and the
737 /// number of buckets. Note that the load factor is a measure of
738 /// container "fullness"; that is, a high load factor typically implies
739 /// many collisions (many elements landing in the same bucket) and that
740 /// decreases performance. See {Rehash Control}.
741 float loadFactor() const;
742
743 /// Return the maximum load factor allowed for this hash map. If an
744 /// insert operation would cause the load factor to exceed the
745 /// `maxLoadFactor()` and rehashing is enabled, then that insert
746 /// increases the number of buckets and rehashes the elements of the
747 /// container into that larger set of buckets. See {Rehash Control}.
748 float maxLoadFactor() const;
749
750 /// Return the number of stripes in the hash.
751 bsl::size_t numStripes() const;
752
753 /// Call the specified `visitor` (in an unspecified order) on all
754 /// elements in this hash table until each such element has been visited
755 /// or `visitor` returns `false`. That is, for `(key, value)`, invoke:
756 /// @code
757 /// bool visitor(value, key);
758 /// @endcode
759 /// Return the number of elements visited or the negation of that value
760 /// if visitations stopped because `visitor` returned `false`.
761 /// `visitor` has read-only access to each element for duration of each
762 /// invocation. Every element present in this hash map at the time
763 /// `visit` is invoked will be visited unless it is removed before
764 /// `visitor` is called for that element. Each visitation is done by
765 /// the calling thread and the order of visitation is not specified.
766 /// The behavior is undefined if hash map manipulators are invoked from
767 /// within `visitor`, as it may lead to a deadlock. Note that `visitor`
768 /// can *not* change the value of the visited elements.
769 int visitReadOnly(const ReadOnlyVisitorFunction& visitor) const;
770
771 /// Call the specified `visitor` on element (if one exists) in this hash
772 /// map having the specified `key`. That is, for `(key, value)`,
773 /// invoke:
774 /// @code
775 /// bool visitor(value, key);
776 /// @endcode
777 /// Return the number of elements visited or `-1` if `visitor` returned
778 /// `false`. `visitor` has read-only access to each element for
779 /// duration of each invocation. The behavior is undefined if hash map
780 /// manipulators are invoked from within `visitor`, as it may lead to a
781 /// deadlock.
782 int visitReadOnly(const KEY& key,
783 const ReadOnlyVisitorFunction& visitor) const;
784
785 /// Return the current number of elements in this hash map.
786 bsl::size_t size() const;
787
788 // Aspects
789
790 /// Return the allocator used by this hash map to supply memory. Note that
791 /// if no allocator was supplied at construction the default allocator
792 /// installed at that time is used.
794};
795
796// ============================================================================
797// INLINE DEFINITIONS
798// ============================================================================
799
800 // -------------------------
801 // class StripedUnorderedMap
802 // -------------------------
803
804// CREATORS
805template <class KEY, class VALUE, class HASH, class EQUAL>
806inline
808 bsl::size_t numInitialBuckets,
809 bsl::size_t numStripes,
810 bslma::Allocator *basicAllocator)
811: d_imp(numInitialBuckets, numStripes, basicAllocator)
812{
813}
814
815template <class KEY, class VALUE, class HASH, class EQUAL>
816inline
818 bslma::Allocator *basicAllocator)
819: d_imp(k_DEFAULT_NUM_BUCKETS, k_DEFAULT_NUM_STRIPES, basicAllocator)
820{
821}
822
823// MANIPULATORS
824template <class KEY, class VALUE, class HASH, class EQUAL>
825inline
827{
828 d_imp.clear();
829}
830
831template <class KEY, class VALUE, class HASH, class EQUAL>
832inline
834{
835 d_imp.disableRehash();
836}
837
838template <class KEY, class VALUE, class HASH, class EQUAL>
839inline
841{
842 d_imp.enableRehash();
843}
844
845template <class KEY, class VALUE, class HASH, class EQUAL>
846inline
848{
849 return d_imp.eraseFirst(key);
850}
851
852template <class KEY, class VALUE, class HASH, class EQUAL>
853template <class RANDOM_ITER>
854inline
856 RANDOM_ITER first,
857 RANDOM_ITER last)
858{
859 BSLS_ASSERT(first <= last);
860
861 return d_imp.eraseBulkFirst(first, last);
862}
863
864template <class KEY, class VALUE, class HASH, class EQUAL>
865inline
867 const KEY& key,
868 const EraseIfValuePredicate& predicate)
869{
870 return d_imp.eraseFirstIf(key, predicate);
871}
872
873template <class KEY, class VALUE, class HASH, class EQUAL>
874inline
876 const KEY& key,
877 const VALUE& value)
878{
879 return d_imp.insertUnique(key, value);
880}
881
882template <class KEY, class VALUE, class HASH, class EQUAL>
883inline
885 const KEY& key,
887{
888 return d_imp.insertUnique(key, bslmf::MovableRefUtil::move(value));
889}
890
891template <class KEY, class VALUE, class HASH, class EQUAL>
892template <class RANDOM_ITER>
893inline
895 RANDOM_ITER first,
896 RANDOM_ITER last)
897{
898 BSLS_ASSERT(first <= last);
899
900 return d_imp.insertBulkUnique(first, last);
901}
902
903template <class KEY, class VALUE, class HASH, class EQUAL>
904inline
906 float newMaxLoadFactor)
907{
908 BSLS_ASSERT(0 < newMaxLoadFactor);
909
910 d_imp.maxLoadFactor(newMaxLoadFactor);
911}
912
913template <class KEY, class VALUE, class HASH, class EQUAL>
914inline
915void
917{
918 d_imp.rehash(numBuckets);
919}
920
921template <class KEY, class VALUE, class HASH, class EQUAL>
922inline
924 const KEY& key,
925 const VisitorFunction& visitor)
926{
927 return d_imp.setComputedValueFirst(key, visitor);
928}
929
930template <class KEY, class VALUE, class HASH, class EQUAL>
931inline
933 const KEY& key,
934 const VALUE& value)
935{
936 return d_imp.setValueFirst(key, value);
937}
938
939template <class KEY, class VALUE, class HASH, class EQUAL>
940inline
942 const KEY& key,
944{
945 return d_imp.setValueFirst(key, bslmf::MovableRefUtil::move(value));
946}
947
948template <class KEY, class VALUE, class HASH, class EQUAL>
949inline
951 const KEY& key,
952 const VisitorFunction& visitor)
953{
954 return d_imp.update(key, visitor);
955}
956
957template <class KEY, class VALUE, class HASH, class EQUAL>
958inline
960 const VisitorFunction& visitor)
961{
962 return d_imp.visit(visitor);
963}
964
965template <class KEY, class VALUE, class HASH, class EQUAL>
966inline
968 const KEY& key,
969 const VisitorFunction& visitor)
970{
971 return d_imp.visit(key, visitor);
972}
973
974// ACCESSORS
975template <class KEY, class VALUE, class HASH, class EQUAL>
976inline
978{
979 return d_imp.bucketCount();
980}
981
982template <class KEY, class VALUE, class HASH, class EQUAL>
983inline
985 const KEY& key) const
986{
987 return d_imp.bucketIndex(key);
988}
989
990template <class KEY, class VALUE, class HASH, class EQUAL>
991inline
993 bsl::size_t index) const
994{
995 BSLS_ASSERT(bucketCount() > index);
996
997 return d_imp.bucketSize(index);
998}
999
1000template <class KEY, class VALUE, class HASH, class EQUAL>
1001inline
1003{
1004 return d_imp.empty();
1005}
1006
1007template <class KEY, class VALUE, class HASH, class EQUAL>
1008inline
1010{
1011 return d_imp.equalFunction();
1012}
1013
1014template <class KEY, class VALUE, class HASH, class EQUAL>
1015inline
1017 VALUE *value,
1018 const KEY& key) const
1019{
1020 return d_imp.getValue(value, key);
1021}
1022
1023template <class KEY, class VALUE, class HASH, class EQUAL>
1024inline
1026{
1027 return d_imp.hashFunction();
1028}
1029
1030template <class KEY, class VALUE, class HASH, class EQUAL>
1031inline
1033{
1034 return d_imp.isRehashEnabled();
1035}
1036
1037template <class KEY, class VALUE, class HASH, class EQUAL>
1038inline
1040{
1041 return d_imp.loadFactor();
1042}
1043
1044template <class KEY, class VALUE, class HASH, class EQUAL>
1045inline
1047{
1048 return d_imp.maxLoadFactor();
1049}
1050
1051template <class KEY, class VALUE, class HASH, class EQUAL>
1052inline
1054{
1055 return d_imp.numStripes();
1056}
1057
1058template <class KEY, class VALUE, class HASH, class EQUAL>
1059inline
1061 const ReadOnlyVisitorFunction& visitor) const
1062{
1063 return d_imp.visitReadOnly(visitor);
1064}
1065
1066template <class KEY, class VALUE, class HASH, class EQUAL>
1067inline
1069 const KEY& key,
1070 const ReadOnlyVisitorFunction& visitor) const
1071{
1072 return d_imp.visitReadOnly(key, visitor);
1073}
1074
1075template <class KEY, class VALUE, class HASH, class EQUAL>
1076inline
1078{
1079 return d_imp.size();
1080}
1081
1082 // Aspects
1083
1084template <class KEY, class VALUE, class HASH, class EQUAL>
1085inline
1087 const
1088{
1089 return d_imp.allocator();
1090}
1091
1092} // close package namespace
1093
1094namespace bslma {
1095
1096template <class KEY, class VALUE, class HASH, class EQUAL>
1097struct UsesBslmaAllocator<bdlcc::StripedUnorderedMap<KEY, VALUE, HASH, EQUAL> >
1098 : bsl::true_type {
1099};
1100
1101} // close namespace bslma
1102
1103
1104
1105#endif
1106
1107// ----------------------------------------------------------------------------
1108// Copyright 2018 Bloomberg Finance L.P.
1109//
1110// Licensed under the Apache License, Version 2.0 (the "License"); you may not
1111// use this file except in compliance with the License. You may obtain a copy
1112// of the License at
1113//
1114// http://www.apache.org/licenses/LICENSE-2.0
1115//
1116// Unless required by applicable law or agreed to in writing, software
1117// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1118// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1119// License for the specific language governing permissions and limitations
1120// under the License.
1121// ----------------------------- END-OF-FILE ----------------------------------
1122
1123/** @} */
1124/** @} */
1125/** @} */
Definition bdlcc_stripedunorderedcontainerimpl.h:473
Definition bdlcc_stripedunorderedmap.h:440
int update(const KEY &key, const VisitorFunction &visitor)
Definition bdlcc_stripedunorderedmap.h:950
bsl::function< bool(const VALUE &, const KEY &)> ReadOnlyVisitorFunction
Definition bdlcc_stripedunorderedmap.h:501
int visitReadOnly(const ReadOnlyVisitorFunction &visitor) const
Definition bdlcc_stripedunorderedmap.h:1060
bsl::function< bool(VALUE *, const KEY &)> VisitorFunction
Definition bdlcc_stripedunorderedmap.h:488
EQUAL equalFunction() const
Definition bdlcc_stripedunorderedmap.h:1009
bsl::size_t numStripes() const
Return the number of stripes in the hash.
Definition bdlcc_stripedunorderedmap.h:1053
void enableRehash()
Definition bdlcc_stripedunorderedmap.h:840
void rehash(bsl::size_t numBuckets)
Definition bdlcc_stripedunorderedmap.h:916
bsl::size_t bucketSize(bsl::size_t index) const
Definition bdlcc_stripedunorderedmap.h:992
~StripedUnorderedMap()=default
Destroy this hash map.
bsl::size_t setValue(const KEY &key, const VALUE &value)
Definition bdlcc_stripedunorderedmap.h:932
bsl::pair< KEY, VALUE > KVType
Value type of a bulk insert entry.
Definition bdlcc_stripedunorderedmap.h:468
bool empty() const
Definition bdlcc_stripedunorderedmap.h:1002
bslma::Allocator * allocator() const
Definition bdlcc_stripedunorderedmap.h:1086
float maxLoadFactor() const
Definition bdlcc_stripedunorderedmap.h:1046
bsl::size_t insertBulk(RANDOM_ITER first, RANDOM_ITER last)
Definition bdlcc_stripedunorderedmap.h:894
int visit(const VisitorFunction &visitor)
Definition bdlcc_stripedunorderedmap.h:959
void clear()
Definition bdlcc_stripedunorderedmap.h:826
bsl::function< bool(const VALUE &)> EraseIfValuePredicate
Definition bdlcc_stripedunorderedmap.h:477
@ k_DEFAULT_NUM_BUCKETS
Definition bdlcc_stripedunorderedmap.h:461
@ k_DEFAULT_NUM_STRIPES
Definition bdlcc_stripedunorderedmap.h:462
void disableRehash()
Prevent future rehash until enableRehash is called.
Definition bdlcc_stripedunorderedmap.h:833
bsl::size_t erase(const KEY &key)
Definition bdlcc_stripedunorderedmap.h:847
bsl::size_t bucketIndex(const KEY &key) const
Definition bdlcc_stripedunorderedmap.h:984
bsl::size_t eraseIf(const KEY &key, const EraseIfValuePredicate &predicate)
Definition bdlcc_stripedunorderedmap.h:866
bsl::size_t bucketCount() const
Definition bdlcc_stripedunorderedmap.h:977
bsl::size_t getValue(VALUE *value, const KEY &key) const
Definition bdlcc_stripedunorderedmap.h:1016
bsl::size_t size() const
Return the current number of elements in this hash map.
Definition bdlcc_stripedunorderedmap.h:1077
bsl::size_t eraseBulk(RANDOM_ITER first, RANDOM_ITER last)
Definition bdlcc_stripedunorderedmap.h:855
bsl::size_t insert(const KEY &key, const VALUE &value)
Definition bdlcc_stripedunorderedmap.h:875
HASH hashFunction() const
Definition bdlcc_stripedunorderedmap.h:1025
bool isRehashEnabled() const
Return true if rehash is enabled, or false otherwise.
Definition bdlcc_stripedunorderedmap.h:1032
float loadFactor() const
Definition bdlcc_stripedunorderedmap.h:1039
int setComputedValue(const KEY &key, const VisitorFunction &visitor)
Definition bdlcc_stripedunorderedmap.h:923
Forward declaration.
Definition bslstl_function.h:934
Definition bslstl_pair.h:1210
Definition bslma_allocator.h:457
Definition bslmf_movableref.h:751
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlcc_boundedqueue.h:270
Definition balxml_encoderoptions.h:68
Definition bslstl_equalto.h:311
Definition bslstl_hash.h:498
Definition bslma_usesbslmaallocator.h:343
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060