BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlcc_stripedunorderedcontainerimpl.h
Go to the documentation of this file.
1/// @file bdlcc_stripedunorderedcontainerimpl.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_stripedunorderedcontainerimpl.h -*-C++-*-
8#ifndef INCLUDED_BDLCC_STRIPEDUNORDEREDCONTAINERIMPL
9#define INCLUDED_BDLCC_STRIPEDUNORDEREDCONTAINERIMPL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlcc_stripedunorderedcontainerimpl bdlcc_stripedunorderedcontainerimpl
15/// @brief Provide common implementation of *striped* un-ordered map/multimap.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlcc
19/// @{
20/// @addtogroup bdlcc_stripedunorderedcontainerimpl
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlcc_stripedunorderedcontainerimpl-purpose"> Purpose</a>
25/// * <a href="#bdlcc_stripedunorderedcontainerimpl-classes"> Classes </a>
26/// * <a href="#bdlcc_stripedunorderedcontainerimpl-description"> Description </a>
27/// * <a href="#bdlcc_stripedunorderedcontainerimpl-thread-safety"> Thread Safety </a>
28/// * <a href="#bdlcc_stripedunorderedcontainerimpl-runtime-complexity"> Runtime Complexity </a>
29/// * <a href="#bdlcc_stripedunorderedcontainerimpl-number-of-stripes"> Number of Stripes </a>
30/// * <a href="#bdlcc_stripedunorderedcontainerimpl-rehash"> Rehash </a>
31/// * <a href="#bdlcc_stripedunorderedcontainerimpl-concurrent-rehash"> Concurrent Rehash </a>
32/// * <a href="#bdlcc_stripedunorderedcontainerimpl-rehash-control"> Rehash Control </a>
33/// * <a href="#bdlcc_stripedunorderedcontainerimpl-usage"> Usage </a>
34///
35/// # Purpose {#bdlcc_stripedunorderedcontainerimpl-purpose}
36/// Provide common implementation of *striped* un-ordered map/multimap.
37///
38/// # Classes {#bdlcc_stripedunorderedcontainerimpl-classes}
39///
40/// - bdlcc::StripedUnorderedContainerImpl: striped container for key-value types
41///
42/// @see bdlcc_stripedunorderedmap, bdlcc_stripedunorderedmultimap
43///
44/// # Description {#bdlcc_stripedunorderedcontainerimpl-description}
45/// This component provides `bdlcc::StripedUnorderedContainerImpl`,
46/// a common implementation for `bdlcc::StripedUnorderedMap` and
47/// `bdlcc::StripedUnorderedMultiMap`, that are concurrent (fully thread-safe)
48/// associative containers that partition their underlying hash tables into a
49/// (user-defined) number of "bucket groups" and control access to each part of
50/// their hash tables by separate read-write locks. For most methods, the "map"
51/// and "multimap" classes forward to the analogous method in this "impl" class
52/// with an additional argument that specifies if the calling class has unique
53/// keys or not.
54///
55/// ## Thread Safety {#bdlcc_stripedunorderedcontainerimpl-thread-safety}
56///
57///
58/// The `bdlcc::StripedUnorderedContrainerImpl` class template is fully
59/// thread-safe (see {@ref bsldoc_glossary |Fully Thread-Safe}), assuming that the
60/// allocator is fully thread-safe. Each method is executed by the calling
61/// thread.
62///
63/// ## Runtime Complexity {#bdlcc_stripedunorderedcontainerimpl-runtime-complexity}
64///
65///
66/// @code
67/// +----------------------------------------------------+--------------------+
68/// | Operation | Complexity |
69/// +====================================================+====================+
70/// | insert, setValue, setComputedValue, update | Average: O[1] |
71/// | | Worst: O[n] |
72/// +----------------------------------------------------+--------------------+
73/// | erase, getValue | Average: O[1] |
74/// | | Worst: O[n] |
75/// +----------------------------------------------------+--------------------+
76/// | visit(key, visitor) | Average: O[1] |
77/// | visitReadOnly(key, visitor) | Worst: O[n] |
78/// +----------------------------------------------------+--------------------+
79/// | insertBulk, k elements | Average: O[k] |
80/// | | Worst: O[n*k] |
81/// +----------------------------------------------------+--------------------+
82/// | eraseBulk, k elements | Average: O[k] |
83/// | | Worst: O[n*k] |
84/// +----------------------------------------------------+--------------------+
85/// | rehash | O[n] |
86/// +----------------------------------------------------+--------------------+
87/// | visit(visitor), visitReadOnly(visitor) | O[n] |
88/// +----------------------------------------------------+--------------------+
89/// @endcode
90///
91/// ## Number of Stripes {#bdlcc_stripedunorderedcontainerimpl-number-of-stripes}
92///
93///
94/// Performance improves monotonically when the number of stripes increases.
95/// However, the rate of improvement decreases, and reaches a plateau. The
96/// plateau is reached roughly at four times the number of the threads
97/// *concurrently* using the hash map.
98///
99/// ## Rehash {#bdlcc_stripedunorderedcontainerimpl-rehash}
100///
101///
102///
103/// ### Concurrent Rehash {#bdlcc_stripedunorderedcontainerimpl-concurrent-rehash}
104///
105///
106/// A rehash operation is a re-organization of the hash map to a different
107/// number of buckets. This is a heavy operation that interferes with, but does
108/// *not* disallow, other operations on the container. Rehash is warranted when
109/// the current load factor exceeds the current maximum allowed load factor.
110/// Expressed explicitly:
111/// @code
112/// bucketCount() <= maxLoadFactor() * size();
113/// @endcode
114/// This above condition is tested implicitly by several methods and if found
115/// true (and if rehash is enabled and rehash is not underway), a rehash is
116/// started. The methods that check the load factor are:
117///
118/// * All methods that insert elements (i.e., increase `size()`).
119/// * The `maxLoadFactor(newMaxLoadFactor)` method.
120/// * The `rehash` method.
121///
122/// ### Rehash Control {#bdlcc_stripedunorderedcontainerimpl-rehash-control}
123///
124///
125/// `enableRehash` and `disableRehash` methods are provided to control the
126/// rehash enable flag. Note that disabling rehash does not impact a rehash in
127/// progress.
128///
129/// ## Usage {#bdlcc_stripedunorderedcontainerimpl-usage}
130///
131///
132/// There is no usage example for this component since it is not meant for
133/// direct client use.
134/// @}
135/** @} */
136/** @} */
137
138/** @addtogroup bdl
139 * @{
140 */
141/** @addtogroup bdlcc
142 * @{
143 */
144/** @addtogroup bdlcc_stripedunorderedcontainerimpl
145 * @{
146 */
147
148#include <bdlscm_version.h>
149
151
152#include <bslim_printer.h>
153
154#include <bslstl_hash.h>
155#include <bslstl_pair.h>
156
157#include <bslma_allocator.h>
159#include <bslma_default.h>
164
165#include <bslmf_assert.h>
166#include <bslmf_movableref.h>
168
170#include <bslmt_readlockguard.h>
171#include <bslmt_writelockguard.h>
172
173#include <bsls_assert.h>
174#include <bsls_atomic.h>
175#include <bsls_libraryfeatures.h>
176#include <bsls_objectbuffer.h>
177#include <bsls_platform.h> // BSLS_PLATFORM_CPU_X86_64
178
179#include <bsl_algorithm.h>
180#include <bsl_cstddef.h> // 'NULL'
181#include <bsl_functional.h>
182#include <bsl_iostream.h>
183#include <bsl_limits.h>
184#include <bsl_list.h>
185#include <bsl_optional.h>
186#include <bsl_sstream.h>
187#include <bsl_vector.h>
188
189#include <vector>
190
191
192namespace bdlcc {
193
194template <class KEY,
195 class VALUE,
196 class HASH = bsl::hash<KEY>,
197 class EQUAL = bsl::equal_to<KEY> >
198class StripedUnorderedContainerImpl;
199
200 // =============================================
201 // class StripedUnorderedContainerImpl_Constants
202 // =============================================
203
204/// This class defines constant values used to represent the state of a
205/// `StripedUnorderedContainerImpl` object.
206///
207/// See @ref bdlcc_stripedunorderedcontainerimpl
209 // PUBLIC CLASS DATA
210 static const int k_REHASH_IN_PROGRESS = 1; // state bit 0
211 static const int k_REHASH_ENABLED = 2; // state bit 1
212};
213
214 // =====================================================
215 // class StripedUnorderedContainerImpl_RehashBitSetGuard
216 // =====================================================
217
218/// This class defines a proctor type that attempts to set the rehash bit of a
219/// state object, and if successful, clears that bit upon destruction.
220///
221/// See @ref bdlcc_stripedunorderedcontainerimpl
223
224 private:
225 // DATA
226 bsls::AtomicInt *const d_state_p; // Points to bitfield to set
227 const bool d_lockSucceeded; // True if bit was set
228
229 // PRIVATE CLASS METHODS
230
231 /// Attempt to atomically set the value pointed to by the specified
232 /// 'state_p' from 'k_REHASH_ENABLED' to
233 /// 'k_REHASH_ENABLED | k_REHASH_IN_PROGRESS', returning true on success
234 /// and false on failure.
235 static bool trySetRehashBit(bsls::AtomicInt *state_p);
236
237 public:
238 // CREATORS
239
240 /// Create a `StripedUnorderedContainerImpl_RehashBitSetGuard` object that
241 /// attempts to set the rehash bit of the object pointed to by the
242 /// specified `state_p` argument. If successful, the rehash bit will be
243 /// cleared during destruction.
245 bsls::AtomicInt *state_p);
246
247 /// Unset the rehash bit previously set by this object and destroy this
248 /// `StripedUnorderedContainerImpl_RehashBitSetGuard` object.
250
251 // ACCESSORS
252
253 /// Returns true if the constructor successfully set the rehash bit.
254 bool holdsLock() const;
255};
256
257 // ========================================
258 // class StripedUnorderedContainerImpl_Node
259 // ========================================
260
261/// This class template represents a node in the singly-linked list of
262/// `(KEY, VALUE)` elements for each bucket of a hash map.
263///
264/// See @ref bdlcc_stripedunorderedcontainerimpl
265template <class KEY, class VALUE>
267
268 private:
269 // DATA
270
271 // Pointer to next element of the bucket
272 mutable StripedUnorderedContainerImpl_Node *d_next_p;
273
274 // footprint of key
276
277 // Footprint of value
279
280 // memory allocator (held, not owned).
281 bslma::Allocator *d_allocator_p;
282
283 private:
284 // NOT IMPLEMENTED
287 // = delete
290 // = delete
291
292 public:
293 // CREATORS
294
295 /// Create a `bdlcc::StripedUnorderedContainerImpl_Node` object having
296 /// the specified `key` and `value`, and with the specified `nextPtr`
297 /// pointer to the next node. Optionally specify a `basicAllocator`
298 /// used to supply memory. If `basicAllocator` is 0, the currently
299 /// installed default allocator is used.
301 const KEY& key,
302 const VALUE& value,
304 bslma::Allocator *basicAllocator = 0);
306 const KEY& key,
309 bslma::Allocator *basicAllocator = 0);
310
311 /// Create a `bdlcc::StripedUnorderedContainerImpl_Node` object having
312 /// the specified `key` and a value initialized to `VALUE()`, and with
313 /// the specified `nextPtr` pointer to the next node. Optionally
314 /// specify a `basicAllocator` used to supply memory. If
315 /// `basicAllocator` is 0, the currently installed default allocator is
316 /// used.
318 const KEY& key,
320 bslma::Allocator *basicAllocator = 0);
321
322 /// Destroy this object.
324
325 // MANIPULATORS
326
327 /// Return the address of the pointer to the next node.
329
330 /// Set this node's pointer-to-next-node to the specified `nextPtr`.
332
333 /// Return a reference providing modifiable access to the `value`
334 /// attribute of this object.
335 VALUE& value();
336
337 // ACCESSORS
338
339 /// Return a `const` reference to the `key` attribute of this object.
340 const KEY& key() const;
341
342 /// Return the pointer to the next node.
344
345 /// Return a `const` reference to the `value` attribute of this object.
346 const VALUE& value() const;
347
348 // Aspects
349
350 /// Return the allocator used by `StripedUnorderedContainerImpl_Node` to
351 /// allocate memory.
353};
354
355 // ==========================================
356 // class StripedUnorderedContainerImpl_Bucket
357 // ==========================================
358
359/// This class represents a bucket of the hash map. This class template
360/// represents the head of in the singly-linked list of `(KEY, VALUE)`
361/// elements in a hash map.
362///
363/// See @ref bdlcc_stripedunorderedcontainerimpl
364template <class KEY, class VALUE>
366
367 private:
368 // PRIVATE TYPES
369
370 /// This `typedef` is a convenient alias for the utility associated with
371 /// movable references.
372 typedef BloombergLP::bslmf::MovableRefUtil MoveUtil;
373
374 // DATA
375
376 // Pointer to the first element in the bucket
378
379 // Pointer to the last element in the bucket
381
382 // Number of nodes in this bucket
383 bsl::size_t d_size;
384
385 // memory allocator (held, not owned).
386 bslma::Allocator *d_allocator_p;
387
388 private:
389 // NOT IMPLEMENTED
394
395 public:
396 // TYPES
397
398 /// Enumeration to differentiate between processing all elements with
399 /// the same key, or just the first one (and typically the only one).
401
402 e_BUCKETSCOPE_FIRST = 0, // Act on first matching element found.
403 e_BUCKETSCOPE_ALL // Act on all matching elements.
404 };
405
406 // TRAITS
409
410 // CREATORS
411
412 /// Create an empty `bdlcc::StripedUnorderedContainerImpl_Bucket`
413 /// object. Optionally specify a `basicAllocator` used to supply
414 /// memory. If `basicAllocator` is 0, the currently installed default
415 /// allocator is used.
417 bslma::Allocator *basicAllocator = 0);
418
419 /// Create a `bdlcc::StripedUnorderedContainerImpl_Bucket` object having
420 /// the same value as the specified `original` object. The `original`
421 /// object is left in a valid but unspecified state.
424 original,
426
427 /// Destroy this object.
429
430 // MANIPULATORS
431
432 /// Add the specified `nodePtr` node at the end of this bucket.
434
435 /// Empty `StripedUnorderedContainerImpl_Bucket` and delete all nodes.
436 void clear();
437
438 /// Return the address of the head (node) of this bucket list.
440
441 /// Increment the `size` attribute of this bucket by the specified
442 /// `amount`.
443 void incrementSize(int amount);
444
445 /// Set the address of the head of this bucket list to the specified
446 /// `value`.
448
449 /// Set the `size` attribute of this bucket to the specified `value`.
450 void setSize(bsl::size_t value);
451
452 /// Set the pointer of the tail of this bucket list to the specified
453 /// `value`.
455
456 /// Set the value attribute of the element in this bucket having the
457 /// specified `key` to the specified `value`, using the specified
458 /// `equal` to compare keys. If no such element exists, insert
459 /// `(key, value)`. The behavior with respect to duplicate key values
460 /// in the bucket depends on the specified `scope`:
461 ///
462 ///: `e_BUCKETSCOPE_ALL`:
463 ///: Set `value` to every element in the bucket having `key`.
464 ///:
465 ///: `e_BUCKETSCOPE_FIRST`:
466 ///: Set `value` to the first element found having `key`.
467 ///
468 /// Return the number of elements found having `key` that had their value set.
469 ///
470 /// \note Note that, when there are multiple elements having
471 /// `key`, the selection of "first" is unspecified and subject to
472 /// change. Also note that specifying `e_BUCKETSCOPE_FIRST` is more
473 /// performant when there is a single element in the bucket having
474 /// `key`.
475 template <class EQUAL>
476 bsl::size_t setValue(const KEY& key,
477 const EQUAL& equal,
478 const VALUE& value,
479 BucketScope scope);
480
481 /// Set the value attribute of the element in this bucket having the
482 /// specified `key` to the specified `value`, using the specified
483 /// `equal` to compare keys. If no such element exists, insert
484 /// `(key, value)`. If there are multiple elements in this hash map
485 /// having `key` then set the value of the first such element found.
486 /// Return the number of elements found having `key` that had their value set.
487 ///
488 /// \note Note that, when there are multiple elements having
489 /// `key`, the selection of "first" is unspecified and subject to
490 /// change.
491 template <class EQUAL>
492 bsl::size_t setValue(const KEY& key,
493 const EQUAL& equal,
495
496 // ACCESSORS
497
498 /// Return `true` if this bucket contains no elements, and `false`
499 /// otherwise.
500 bool empty() const;
501
502 /// Return the head (node) of this bucket list.
504
505 /// Return the current number of elements in this bucket.
506 bsl::size_t size() const;
507
508 /// Return address of the tail (node) of this bucket list.
510
511 // Aspects
512
513 /// Return the allocator used by `StripedUnorderedContainerImpl_Bucket`
514 /// to allocate memory.
516};
517
518template <class KEY,
519 class VALUE,
520 class HASH = bsl::hash<KEY>,
521 class EQUAL = bsl::equal_to<KEY> >
523
527
528/// This struct is a constructor flag used to select the contructor that takes
529/// a `maxLoadFactor` value.
530///
531/// See @ref bdlcc_stripedunorderedcontainerimpl
534
535 // ===================================
536 // class StripedUnorderedContainerImpl
537 // ===================================
538
539/// This class implements the logic for a striped hash multimap with logic
540/// that supports a (unique) map as a special case.
541template <class KEY, class VALUE, class HASH, class EQUAL>
543
544 public:
545 // TYPES
546 enum {
547 k_DEFAULT_NUM_BUCKETS = 16, // Default # of buckets
548 k_DEFAULT_NUM_STRIPES = 4 // Default # of stripes
549 };
550
551 /// Node in a bucket.
553
554 /// Value type of a bulk insert entry.
556
557 /// An alias to a function meeting the following contract:
558 /// @code
559 /// bool visitorFunction(VALUE *value, const KEY& key);
560 /// // Visit the specified 'value' attribute associated with the
561 /// // specified 'key'. Return 'true' if this function may be
562 /// // called on additional elements, and 'false' otherwise (i.e., // if no other elements should be visited).
563 ///
564 /// \note Note that this
565 /// // functor can change the value associated with 'key'.
566 /// @endcode
567 typedef bsl::function<bool (VALUE *, const KEY&)> VisitorFunction;
568
569 /// An alias to a function meeting the following contract:
570 /// @code
571 /// bool visitorFunction(const VALUE& value, const KEY& key);
572 /// // Visit the specified 'value' attribute associated with the
573 /// // specified 'key'. Return 'true' if this function may be
574 /// // called on additional elements, and 'false' otherwise (i.e., // if no other elements should be visited).
575 ///
576 /// \note Note that this
577 /// // functor can *not* change the values associated with 'key'
578 /// // and 'value'.
579 /// @endcode
580 typedef bsl::function<bool (const VALUE&, const KEY&)>
582
583 /// An alias to a function meeting the following contract:
584 /// @code
585 /// bool eraseIfValuePredicate(const VALUE& value);
586 /// // Return 'true' if the specified 'value' is to be removed from // the container, and 'false' otherwise.
587 ///
588 /// \note Note that this
589 /// // functor can *not* change the values associated with 'value'.
590 /// @endcode
591 typedef bsl::function<bool(const VALUE&)> EraseIfValuePredicate;
592
593 private:
594 // PRIVATE TYPES
595 enum {
596 #if BSLS_PLATFORM_CPU_X86 || BSLS_PLATFORM_CPU_X86_64
597 k_PREFETCH_ENABLED = 1,
598 #else
599 k_PREFETCH_ENABLED = 0,
600 #endif
601 // Can be 0 or 1; if prefetch, we use 2 cachelines at a time
602 k_EFFECTIVE_CACHELINE_SIZE = (1 + k_PREFETCH_ENABLED) *
604 // Cacheline size to use; may be 1 or 2 cachelines
605 k_INT_PADDING = k_EFFECTIVE_CACHELINE_SIZE - sizeof(bsls::AtomicInt)
606 };
607
608 enum Multiplicity {
609 // Enumeration to differentiate between inserting only unique keys and
610 // inserting multiple values for the same key.
611
612 e_INSERT_UNIQUE = 0, // Insert a new element having 'key' if no element
613 // in hash map has 'key'; otherwise, update the
614 // value attribute of the existing element.
615
616 e_INSERT_ALWAYS // Insert a new element having 'key' even if the
617 // map already has an element(s) having the 'key'
618 // attribute.
619 };
620
621 enum Scope {
622 // Enumeration to differentiate between processing all elements with
623 // the same key, or just the first one (and typically the only one).
624
625 e_SCOPE_FIRST = 0, // Act on first matching element found.
626 e_SCOPE_ALL // Act on all matching elements.
627 };
628
630 typedef StripedUnorderedContainerImpl_LockElementReadGuard LERGuard;
631 typedef StripedUnorderedContainerImpl_LockElementWriteGuard LEWGuard;
632
633#ifdef BSLS_PLATFORM_CPU_32_BIT
634 typedef bsls::AtomicUint AtomicSizeT;
635#else
636 typedef bsls::AtomicUint64 AtomicSizeT;
637#endif
638 BSLMF_ASSERT(sizeof(AtomicSizeT) == sizeof(bsl::size_t));
639 BSLMF_ASSERT(!bsl::numeric_limits<bsl::size_t>::is_signed);
640
641 // DATA
642
643 // number of stripes
644 const bsl::size_t d_numStripes;
645
646 // number of buckets
647 AtomicSizeT d_numBuckets;
648
649 // d_numStripes - 1; this value is used to provide an efficient modulo
650 // (using bit-wise `&`) of d_numStripes (where d_numStripes must be a
651 // power of 2).
652 const bsl::size_t d_hashMask;
653
654 // maxLoadFactor (defaults to 1.0)
655 const float d_maxLoadFactor;
656
657 // hashing function for keys
658 HASH d_hasher;
659
660 // comparison function for keys
661 EQUAL d_comparator;
662
663 // * bit 0: 0-rehash not in progress; 1-rehash in progress.
664 // * bit 1: 0-rehash disabled; 1-rehash enabled.
665 mutable bsls::AtomicInt d_state;
666
667 // padding, so that `d_state` will have its own cache line
668 const char d_statePad[k_INT_PADDING];
669
670 // # of elements in the hash map
671 bsls::AtomicInt d_numElements;
672
673 // padding, so that `d_numElements` will have its own cache line
674 const char d_numElementsPad[k_INT_PADDING];
675
676 // hash table data, storing key-value pairs
678 d_buckets;
679
680 // Pointer to an array of locks for the stripes. Note that mutex can't
681 // be moved or copied, hence can't be in a vector.
682 LockElement *d_locks_p;
683
684 // memory allocator (held, not owned)
685 bslma::Allocator *d_allocator_p;
686
687 // FRIENDS
688 friend class
691
692 private:
693 // NOT IMPLEMENTED
696 // = delete
699 // = delete
700
701 // PRIVATE CLASS METHODS
702
703 /// Return the number of buckets needed by this implementation for the
704 /// specified `numBuckets` and `numStripes`. That value is the lowest
705 /// integer that is a power of 2 that is greater than or equal
706 /// `numBuckets`, `numStripes`, and 2.
707 static bsl::size_t adjustBuckets(bsl::size_t numBuckets,
708 bsl::size_t numStripes);
709
710 /// Return `true`
711 static bool alwaysTrue(const VALUE&);
712
713 /// Return the nearest higher power of 2 for the specified `num`.
714 static bsl::size_t powerCeil(bsl::size_t num);
715
716 // PRIVATE MANIPULATORS
717
718 /// Perform a rehash if the `loadFactor() > maxLoadFactor()`, and
719 /// `true == canRehash()`.
720 void checkRehash();
721
722 /// Remove from this hash map the element, if any, having the specified
723 /// `key`. If there a multiple elements having `key` and the specified
724 /// `scope` is `e_SCOPE_ALL`, erase them all; otherwise; erase just the
725 /// first element found. Return the number of elements erased.
726 ///
727 /// \note Note that, when there are multiple elements having `key`, the selection
728 /// of "first" is unspecified and subject to change.
729 bsl::size_t erase(const KEY& key, Scope scope);
730
731 /// Erase from this hash map elements in this hash map having any of the
732 /// values in the keys contained between the specified `first`
733 /// (inclusive) and `last` (exclusive) random-access iterators. The
734 /// iterators provide read access to a sequence of `KEY` objects. If
735 /// there are multiple elements for any key value and the specified
736 /// `scope` is `e_SCOPE_ALL` then erase them all; otherwise, erase just
737 /// the first such element found. Return the number of elements erased.
738 ///
739 /// \pre The behavior is undefined unless `first <= last`.
740 /// \note Note that, when
741 /// there are multiple elements having `key`, the selection of "first"
742 /// is unspecified and subject to change.
743 template <class RANDOM_ITER>
744 bsl::size_t eraseBulk(RANDOM_ITER first,
745 RANDOM_ITER last,
746 Scope scope);
747
748 /// Remove from this hash map the element, if any, having the specified
749 /// `key`, where specified `predicate` holds true. If there are
750 /// multiple elements having the `key` for which the `predicate` holds
751 /// true and the specified `scope` is `e_SCOPE_ALL`, erase them all;
752 /// otherwise, erase just the first element found. Return the number of elements erased.
753 ///
754 /// \note Note that, when there are multiple elements for
755 /// which `predicate` holds true, the selection of "first" is
756 /// unspecified and subject to change.
757 bsl::size_t eraseIf(const KEY& key,
758 Scope scope,
759 const EraseIfValuePredicate& predicate);
760
761 /// Insert into this hash map an element having the specified `key` and
762 /// `value`. The behavior with respect to duplicate key values in the
763 /// hash map depends on the specified `multiplicity`:
764 ///
765 ///: `e_INSERT_ALWAYS`:
766 ///: The insertion occurs irrespective of other elements in the hash
767 ///: map having the same `key` value.
768 ///:
769 ///: `e_INSERT_UNIQUE`:
770 ///: Insert a new element if no element in the hash map has the `key`
771 ///: value; otherwise, update the value attribute of the first element
772 ///: found having `key` to `value`.
773 ///
774 /// Return the number of elements inserted.
775 /// \note Note that, when there are
776 /// multiple elements having `key`, the selection of "first" is
777 /// unspecified and subject to change.
778 bsl::size_t insert(const KEY& key,
779 const VALUE& value,
780 Multiplicity multiplicity);
781 bsl::size_t insert(const KEY& key,
783 Multiplicity multiplicity);
784
785 /// Insert into this hash map elements having the key-value pairs
786 /// obtained between the specified `first` (inclusive) and `last`
787 /// (exclusive) random-access iterators. The iterators provide read
788 /// access to a sequence of `bsl::pair<KEY, VALUE>` objects. The
789 /// behavior with respect to duplicate key values in the hash map
790 /// depends on the specified `multiplicity`:
791 ///
792 ///: `e_INSERT_ALWAYS`:
793 ///: The insertion occurs irrespective of other elements in the hash
794 ///: map having the same `key` value. Note that this is the only
795 ///: way to adding elements with non-unique keys to the hash map.
796 ///:
797 ///: `e_INSERT_UNIQUE`:
798 ///: Insert a new element if no element in the hash map has the `key`
799 ///: value; otherwise, update the value attribute of the first element
800 ///: found having `key` to `value`.
801 ///
802 /// Return the number of elements inserted.
803 ///
804 /// \pre The behavior is undefined unless `first <= last`.
805 /// \note Note that, when there are multiple elements
806 /// having `key`, the selection of "first" is unspecified and subject to
807 /// change.
808 template <class RANDOM_ITER>
809 bsl::size_t insertBulk(RANDOM_ITER first,
810 RANDOM_ITER last,
811 Multiplicity multiplicity);
812
813 /// Invoke the specified `visitor` passing the specified `key`, and the
814 /// address of the attribute part of an element (of possibly many
815 /// elements) found in this hash map having `key`. That is, for
816 /// `(key, value)`, invoke:
817 /// @code
818 /// bool visitor(&value, key);
819 /// @endcode
820 /// If no element in the hash map has `key`, insert `(key, VALUE())` and
821 /// invoke to `visitor` with `value` pointing to the defsult constructed
822 /// value. If there are multiple elements having `key` and the
823 /// specified `scope` is `e_SCOPE_ALL` then apply `visitor` to each of
824 /// them; otherwise, `visitor` is applied to just the first such element
825 /// found. Return the number of elements visited or the negation of
826 /// that value if visitations stopped because `visitor` returned
827 /// `false`. `visitor` has exclusive access (i.e., write access) to the element.
828 ///
829 /// \pre The behavior is undefined if hash map manipulators and
830 /// `getValue*` methods are invoked from within `visitor`, as it may lead to a deadlock.
831 ///
832 /// \note Note that, when there are multiple elements
833 /// having `key`, the selection of "first" and the order applying
834 /// `visitor` are unspecified and subject to change. Also note that a
835 /// return value of `0` implies that an element was inserted.
836 int setComputedValue(const KEY& key,
837 const VisitorFunction& visitor,
838 Scope scope);
839
840 /// Set the value attribute of the element in this hash map having the
841 /// specified `key` to the specified `value`. If no such element
842 /// exists, insert `(key, value)`. The behavior with respect to
843 /// duplicate key values in the bucket depends on the specified
844 /// `scope`:
845 ///
846 ///: `e_SCOPE_ALL`:
847 ///: Set `value` to every element in the bucket having `key`.
848 ///:
849 ///: `e_SCOPE_FIRST`:
850 ///: Set `value` to the first element found having `key`.
851 ///
852 /// Return the number of elements found having `key`.
853 /// \note Note that if no
854 /// elements were found, and a new value was inserted, `0` is returned.
855 /// Also note that, when there are multiple elements having `key`, the
856 /// selection of "first" is unspecified and subject to change. Also
857 /// note that specifying `e_SCOPE_FIRST` is more performant when there
858 /// is a single element in the bucket having `key`.
859 bsl::size_t setValue(const KEY& key,
860 const VALUE& value,
861 Scope scope);
862
863 // PRIVATE ACCESSORS
864
865 /// Return the index of the bucket, in the array of buckets maintained
866 /// by this hash map, where values having a key equivalent to the
867 /// specified `key` would be inserted using the specified `numBuckets`.
868 /// This operation does not lock the related stripe or check the rehash state.
869 ///
870 /// \note Note that `numBuckets` does not have to be the current
871 /// number of buckets in this hash map.
872 bsl::size_t bucketIndex(const KEY& key, bsl::size_t numBuckets) const;
873
874 /// Return the stripe index associated with the specified `bucketIndex`.
875 bsl::size_t bucketToStripe(bsl::size_t bucketIndex) const;
876
877 /// Load, into the specified `*valuesPtr`, the value attributes of every
878 /// element in this hash map having the specified `key`. Return the number of elements found with `key`.
879 ///
880 /// \note Note that the order of the
881 /// values returned is not specified.
882 template <class VECTOR>
883 bsl::size_t getValueImpl(VECTOR *valuesPtr, const KEY& key) const;
884
885 /// Lock for read the stripe related to the specified `key`, setting the
886 /// specified `bucketIdx` to the bucket index associated with `key`.
887 /// Return the address to the lock-element associated with the returned
888 /// `bucketIdx`.
889 LockElement *lockRead(bsl::size_t *bucketIdx, const KEY& key) const;
890
891 /// Lock for write the stripe related to the specified `key`, setting
892 /// the specified `bucketIdx` to the bucket index associated with `key`.
893 /// Return the address to the lock-element associated with the returned
894 /// `bucketIdx`.
895 LockElement *lockWrite(bsl::size_t *bucketIdx, const KEY& key) const;
896
897 public:
898 // CREATORS
899
900 /// Create an empty `StripedUnorderedContainerImpl` object, a fully
901 /// thread-safe hash map where access is divided into "stripes" (a group
902 /// of buckets protected by a reader-write mutex). Optionally specify
903 /// `numInitialBuckets` and `numStripes` which define the minimum number
904 /// of buckets and the (fixed) number of stripes in this map.
905 /// Optionally specify a `basicAllocator` used to supply memory. If
906 /// `basicAllocator` is 0, the currently installed default allocator is
907 /// used. The hash map has rehash enabled.
909 bsl::size_t numInitialBuckets = k_DEFAULT_NUM_BUCKETS,
910 bsl::size_t numStripes = k_DEFAULT_NUM_STRIPES,
911 bslma::Allocator *basicAllocator = 0);
912
913 /// Create an empty `StripedUnorderedContainerImpl` object, a fully
914 /// thread-safe hash map where access is divided into "stripes" (a group of
915 /// buckets protected by a reader-write mutex). Specify `maxLoadFactor`
916 /// which defines the maximum ratio of elements to buckets.
917 ///
918 /// \pre The behavior is undefined unless `maxLoadFactor > 0`. Optionally specify
919 /// `numInitialBuckets` and `numStripes` which define the minimum number of
920 /// buckets and the (fixed) number of stripes in this map. Optionally
921 /// specify a `basicAllocator` used to supply memory. If `basicAllocator`
922 /// is 0, the currently installed default allocator is used. The hash map
923 /// has rehash enabled.
926 float maxLoadFactor = 1.0,
927 bsl::size_t numInitialBuckets = k_DEFAULT_NUM_BUCKETS,
928 bsl::size_t numStripes = k_DEFAULT_NUM_STRIPES,
929 bslma::Allocator *basicAllocator = 0);
930
931 /// Destroy this hash map. This method is *not* thread-safe.
933
934 // MANIPULATORS
935
936 /// Remove all elements from this striped hash map. If rehash is in
937 /// progress, block until it completes.
938 void clear();
939
940 /// Prevent rehash until the `enableRehash` method is called.
942
943 /// Allow rehash. If conditions warrant, rehash will be started by the
944 /// *next* method call that observes the load factor is exceeded (see {Concurrent Rehash}).
945 ///
946 /// \note Note that calling
947 /// `maxLoadFactor(maxLoadFactor())` (i.e., setting the maximum load
948 /// factor to its current value) will trigger a rehash if needed but
949 /// otherwise does not change the hash map.
951
952 /// Erase from this hash map the elements having the specified `key`.
953 /// Return the number of elements erased.
954 bsl::size_t eraseAll(const KEY& key);
955
956 /// Erase from this hash map the elements having the specified `key` for
957 /// which the specified `predicate` holds true. Return the number of
958 /// elements erased.
959 bsl::size_t eraseAllIf(const KEY& key,
960 const EraseIfValuePredicate& predicate);
961
962 /// Erase from this hash map elements in this hash map having any of the
963 /// values in the keys contained between the specified `first`
964 /// (inclusive) and `last` (exclusive) random-access iterators. The
965 /// iterators provide read access to a sequence of `KEY` objects. All
966 /// erasures are done by the calling thread and the order of erasure is
967 /// not specified. Return the number of elements removed.
968 ///
969 /// \pre The behavior is undefined unless `first <= last`.
970 /// \note Note that the map may not have
971 /// an element for every value in `keys`.
972 template <class RANDOM_ITER>
973 bsl::size_t eraseBulkAll(RANDOM_ITER first, RANDOM_ITER last);
974
975 /// Erase from this hash map elements in this hash map having any of the
976 /// values in the keys contained between the specified `first`
977 /// (inclusive) and `last` (exclusive) random-access iterators. The
978 /// iterators provide read access to a sequence of `KEY` objects. If
979 /// there are multiple elements for any key value, erase just the first
980 /// such element found. All erasures are done by the calling thread and
981 /// the order of erasure is not specified. Return the number of elements removed.
982 ///
983 /// \pre The behavior is undefined unless `first <= last`.
984 ///
985 /// \note Note that the map may not have an element for every value in `keys`.
986 template <class RANDOM_ITER>
987 bsl::size_t eraseBulkFirst(RANDOM_ITER first, RANDOM_ITER last);
988
989 /// Erase from this hash map the *first* element (of possibly many)
990 /// found to the specified `key`. Return the number of elements erased.
991 ///
992 /// \note Note that method is more performant than `eraseAll` when there is
993 /// one element having `key`.
994 bsl::size_t eraseFirst(const KEY& key);
995
996 /// Erase from this hash map the *first* element with specified `key`
997 /// (of possibly many) found, for which the specified `predicate` holds
998 /// true. Return the number of elements erased.
999 bsl::size_t eraseFirstIf(const KEY& key,
1000 const EraseIfValuePredicate& predicate);
1001
1002 /// Insert into this hash map an element having the specified `key` and `value`.
1003 ///
1004 /// \note Note that other elements having the same `key` may exist
1005 /// in this hash map.
1006 void insertAlways(const KEY& key, const VALUE& value);
1007
1008 /// Insert into this hash map an element having the specified `key` and
1009 /// the specified move-insertable `value`. The `value` object is left
1010 /// in a valid but unspecified state. If `value` is allocator-enabled
1011 /// and `allocator() != value.allocator()` this operation may cost as much as a copy.
1012 ///
1013 /// \note Note that other elements having the same `key` may
1014 /// exist in this hash map.
1015 void insertAlways(const KEY& key, bslmf::MovableRef<VALUE> value);
1016
1017 /// Insert into this hash map elements having the key-value pairs
1018 /// obtained between the specified `first` (inclusive) and `last`
1019 /// (exclusive) random-access iterators. The iterators provide read
1020 /// access to a sequence of `bsl::pair<KEY, VALUE>` objects. All
1021 /// insertions are done by the calling thread and the order of insertion is not specified.
1022 ///
1023 /// \pre The behavior is undefined unless `first <= last`.
1024 template <class RANDOM_ITER>
1025 void insertBulkAlways(RANDOM_ITER first, RANDOM_ITER last);
1026
1027 /// Insert into this hash map elements having the key-value pairs
1028 /// obtained between the specified `first` (inclusive) and `last`
1029 /// (exclusive) random-access iterators. The iterators provide read
1030 /// access to a sequence of `bsl::pair<KEY, VALUE>` objects. If an
1031 /// element having one of the keys already exists in this hash map, set
1032 /// the value attribute to the corresponding value from `data`. All
1033 /// insertions are done by the calling thread and the order of insertion
1034 /// is not specified. Return the number of elements inserted.
1035 ///
1036 /// \pre The behavior is undefined unless `first <= last`.
1037 template <class RANDOM_ITER>
1038 bsl::size_t insertBulkUnique(RANDOM_ITER first, RANDOM_ITER last);
1039
1040 /// Insert into this hash map an element having the specified `key` and
1041 /// `value`. If `key` already exists in this hash map, the value
1042 /// attribute of that element is set to `value`. Return 1 if an element is inserted, and 0 if an existing element is updated.
1043 ///
1044 /// \note Note that the
1045 /// return value equals the number of elements inserted.
1046 bsl::size_t insertUnique(const KEY& key, const VALUE& value);
1047
1048 /// Insert into this hash map an element having the specified `key` and
1049 /// the specified move-insertable `value`. If `key` already exists in
1050 /// this hash map, the value attribute of that element is set to
1051 /// `value`. Return 1 if an element is inserted, and 0 if an existing
1052 /// element is updated. The `value` object is left in a valid but
1053 /// unspecified state. If `value` is allocator-enabled and
1054 /// `allocator() != value.allocator()` this operation may cost as much as a copy.
1055 ///
1056 /// \note Note that the return value equals the number of elements
1057 /// inserted.
1058 bsl::size_t insertUnique(const KEY& key, bslmf::MovableRef<VALUE> value);
1059
1060 /// Recreate this hash map to one having at least the specified
1061 /// `numBuckets`. This operation is a no-op if *any* of the following
1062 /// are true: 1) rehash is disabled; 2) `numBuckets` less or equals the
1063 /// current number of buckets. See {Rehash}.
1064 void rehash(bsl::size_t numBuckets);
1065
1066 /// Serially invoke the specified `visitor` passing the specified `key`,
1067 /// and the address of the value of each element in this hash map having
1068 /// `key`. If `key` is not in the map, `value` will be default
1069 /// constructed. That is, for each `(key, value)` found, invoke:
1070 /// @code
1071 /// bool visitor(VALUE *value, const Key& key);
1072 /// @endcode
1073 /// If no element in the map has `key`, insert `(key, VALUE())` and
1074 /// invoke `visitor` with `value` pointing to the defsult constructed
1075 /// value. Return the number of elements visited or the negation of
1076 /// that value if visitations stopped because `visitor` returned
1077 /// `false`. `visitor`, when invoked, has exclusive access (i.e., write
1078 /// access) to each element during each invocation.
1079 ///
1080 /// \pre The behavior is undefined if hash map manipulators and `getValue*` methods are
1081 /// invoked from within `visitor`, as it may lead to a deadlock.
1082 ///
1083 /// \note Note that the `setComputedValueFirst` method is more performant than the
1084 /// when the hash map contains a single element for `key`. Also note
1085 /// that a return value of `0` implies that an element was inserted.
1086 int setComputedValueAll(const KEY& key,
1087 const VisitorFunction& visitor);
1088
1089 /// Invoke the specified `visitor` passing the specified `key`, and the
1090 /// address of the value attribute of the *first* element (of possibly
1091 /// many elements) found in this hash map having `key`. If `key` is not
1092 /// in the map, `value` will be default constructed. That is, for
1093 /// `(key, value)`, invoke:
1094 /// @code
1095 /// bool visitor(VALUE *value, const Key& key);
1096 /// @endcode
1097 /// If no element in the map has `key`, insert `(key, VALUE())` and
1098 /// invoke `visitor` with `value` pointing to the defsult constructed
1099 /// value. Return 1 if `key` was found and `visitor` returned `true`, 0
1100 /// if `key` was not found, and -1 if `key` was found and `visitor`
1101 /// returned `false`. `visitor`, when invoked, has exclusive access (i.e., write access) to the element.
1102 ///
1103 /// \pre The behavior is undefined if
1104 /// hash map manipulators and `getValue*` methods are invoked from within `visitor`, as it may lead to a deadlock.
1105 ///
1106 /// \note Note that the
1107 /// return value equals the number of elements inserted. Also note
1108 /// that, when there are multiple elements having `key`, the selection
1109 /// of "first" is implementation specific and subject to change. Also
1110 /// note that this method is more performant than the
1111 /// `setComputedValueAll` method when the hash map contains a single
1112 /// element for `key`. Also note that a return value of `0` implies
1113 /// that an element was inserted.
1114 int setComputedValueFirst(const KEY& key,
1115 const VisitorFunction& visitor);
1116
1117 /// Set the value attribute of every element in this hash map having the
1118 /// specified `key` to the specified `value`. If no such such element
1119 /// exists, insert `(key, value)`. Return the number of elements found with `key`.
1120 ///
1121 /// \note Note that if no elements were found, and a new value
1122 /// was inserted, `0` is returned.
1123 bsl::size_t setValueAll(const KEY& key, const VALUE& value);
1124
1125 /// Set the value attribute of the *first* element in this hash map (of
1126 /// possibly many) found to have the specified `key` to the specified
1127 /// `value`. If no such such element exists, insert `(key, value)`. Return the number of elements found with `key`.
1128 ///
1129 /// \note Note that if no
1130 /// elements were found, and a new value was inserted, `0` is returned.
1131 /// Also note that this method is more performant than `setValueAll`
1132 /// when there is one element having `key` in the hash map.
1133 bsl::size_t setValueFirst(const KEY& key, const VALUE& value);
1134
1135 /// Set the value attribute of the element in this hash map having the
1136 /// specified `key` to the specified `value`. If no such element
1137 /// exists, insert `(key, value)`. If there are multiple elements in
1138 /// this hash map having `key` then set the value of the first such
1139 /// element found. Return the number of elements found having `key`.
1140 ///
1141 /// \note Note that if no elements were found, and a new value was inserted,
1142 /// `0` is returned. Also note that, when there are multiple elements
1143 /// having `key`, the selection of "first" is unspecified and subject to
1144 /// change.
1145 bsl::size_t setValueFirst(const KEY& key, bslmf::MovableRef<VALUE> value);
1146
1147 /// Serially call the specified `visitor` on each element (if one
1148 /// exists) in this hash map having the specified `key` until every such
1149 /// element has been updated or `visitor` returns `false`. That is, for
1150 /// `(key, value)`, invoke:
1151 /// @code
1152 /// bool visitor(&value, key);
1153 /// @endcode
1154 /// Return the number of elements visited or the negation of that value
1155 /// if visitations stopped because `visitor` returned `false`.
1156 /// `visitor` has exclusive access (i.e., write access) to each element for duration of each invocation.
1157 ///
1158 /// \pre The behavior is undefined if hash
1159 /// map manipulators and `getValue*` methods are invoked from within
1160 /// `visitor`, as it may lead to a deadlock.
1161 ///
1162 /// @deprecated Use @ref visit(key, visitor) instead.
1163 int update(const KEY& key, const VisitorFunction& visitor);
1164
1165 /// Call the specified `visitor` (in an unspecified order) on the
1166 /// elements in this hash table until each element has been visited or
1167 /// `visitor` returns `false`. That is, for `(key, value)`, invoke:
1168 /// @code
1169 /// bool visitor(&value, key);
1170 /// @endcode
1171 /// Return the number of elements visited or the negation of that value
1172 /// if visitations stopped because `visitor` returned `false`.
1173 /// `visitor` has exclusive access (i.e., write access) to each element
1174 /// for duration of each invocation. Every element present in this hash
1175 /// map at the time `visit` is invoked will be visited unless it is
1176 /// removed before `visitor` is called for that element. Each
1177 /// visitation is done by the calling thread and the order of visitation
1178 /// is not specified. Elements inserted during the execution of `visit` may or may not be visited.
1179 ///
1180 /// \pre The behavior is undefined if hash map
1181 /// manipulators and `getValue*` methods are invoked from within `visitor`, as it may lead to a deadlock.
1182 ///
1183 /// \note Note that `visitor` can
1184 /// change the value of the visited elements.
1185 int visit(const VisitorFunction& visitor);
1186
1187 /// Serially call the specified `visitor` on each element (if one
1188 /// exists) in this hash map having the specified `key` until every such
1189 /// element has been updated or `visitor` returns `false`. That is, for
1190 /// `(key, value)`, invoke:
1191 /// @code
1192 /// bool visitor(&value, key);
1193 /// @endcode
1194 /// Return the number of elements visited or the negation of that value
1195 /// if visitations stopped because `visitor` returned `false`.
1196 /// `visitor` has exclusive access (i.e., write access) to each element for duration of each invocation.
1197 ///
1198 /// \pre The behavior is undefined if hash
1199 /// map manipulators and `getValue*` methods are invoked from within
1200 /// `visitor`, as it may lead to a deadlock.
1201 int visit(const KEY& key, const VisitorFunction& visitor);
1202
1203 // ACCESSORS
1204
1205 /// Return the index of the bucket, in the array of buckets maintained
1206 /// by this hash map, where elements having the specified `key` are inserted.
1207 ///
1208 /// \note Note that unless rehash is disabled, the value returned
1209 /// may be obsolete at the time it is returned.
1210 bsl::size_t bucketIndex(const KEY& key) const;
1211
1212 /// Return the number of buckets in the array of buckets maintained by this hash map.
1213 ///
1214 /// \note Note that unless rehash is disabled, the value
1215 /// returned may be obsolete by the time it is received.
1216 bsl::size_t bucketCount() const;
1217
1218 /// Return the number of elements contained in the bucket at the
1219 /// specified `index` in the array of buckets maintained by this hash map.
1220 ///
1221 /// \pre The behavior is undefined unless
1222 /// `0 <= index < bucketCount()`.
1223 bsl::size_t bucketSize(bsl::size_t index) const;
1224
1225 /// Return `true` if rehash is enabled and rehash is not in progress,
1226 /// and `false` otherwise.
1227 bool canRehash() const;
1228
1229 /// Return `true` if this hash map contains no elements, and `false`
1230 /// otherwise.
1231 bool empty() const;
1232
1233 /// Return (a copy of) the key-equality functor used by this hash map
1234 /// that returns `true` if two `KEY` objects have the same value, and
1235 /// `false` otherwise.
1236 EQUAL equalFunction() const;
1237
1238 /// Load, into the specified `*value`, the value attribute of the first
1239 /// element (of possibly many elements) found in this hash map having
1240 /// the specified `key`. Return 1 on success, and 0 if `key` does not exist in this hash.
1241 ///
1242 /// \note Note that the return value equals the number of
1243 /// values returned. Also note that, when there are multiple elements
1244 /// having `key`, the selection of "first" is implementation specific
1245 /// and subject to change.
1246 bsl::size_t getValue(VALUE *value, const KEY& key) const;
1247
1248 bsl::size_t getValue(bsl::vector<VALUE> *valuesPtr, const KEY& key) const;
1249 bsl::size_t getValue(std::vector<VALUE> *valuesPtr, const KEY& key) const;
1250#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1251 bsl::size_t getValue(std::pmr::vector<VALUE> *valuesPtr, const KEY& key)
1252 const;
1253#endif
1254 // Load, into the specified '*valuesPtr', the value attributes of every
1255 // element in this hash map having the specified 'key'. Return the
1256 // number of elements found with 'key'. Note that the order of the
1257 // values returned is not specified.
1258
1259 /// Return (a copy of) the unary hash functor used by this hash map to
1260 /// generate a hash value (of type `std::size_t`) for a `KEY` object.
1261 HASH hashFunction() const;
1262
1263 /// Return `true` if rehash is enabled, or `false` otherwise.
1264 bool isRehashEnabled() const;
1265
1266 /// Return the current quotient of the size of this hash map and the number of buckets.
1267 ///
1268 /// \note Note that the load factor is a measure of
1269 /// container "fullness"; that is, a high load factor typically implies
1270 /// many collisions (many elements landing in the same bucket) and that
1271 /// decreases performance.
1272 float loadFactor() const;
1273
1274 /// Return the maximum load factor allowed for this hash map. If an
1275 /// insert operation would cause the load factor to exceed the
1276 /// `maxLoadFactor()` and rehashing is enabled, then that insert
1277 /// increases the number of buckets and rehashes the elements of the
1278 /// container into that larger set of buckets.
1279 float maxLoadFactor() const;
1280
1281 /// Return the number of stripes in the hash.
1282 bsl::size_t numStripes() const;
1283
1284 /// Call the specified `visitor` (in an unspecified order) on the
1285 /// elements in this hash table until each element has been visited or
1286 /// `visitor` returns `false`. That is, for `(key, value)`, invoke:
1287 /// @code
1288 /// bool visitor(value, key);
1289 /// @endcode
1290 /// Return the number of elements visited or the negation of that value
1291 /// if visitations stopped because `visitor` returned `false`.
1292 /// `visitor` has read-only access to each element for duration of each
1293 /// invocation. Every element present in this hash map at the time
1294 /// `visit` is invoked will be visited unless it is removed before
1295 /// `visitor` is called for that element. Each visitation is done by
1296 /// the calling thread and the order of visitation is not specified.
1297 ///
1298 /// \pre The behavior is undefined if hash map manipulators are invoked from within `visitor`, as it may lead to a deadlock.
1299 ///
1300 /// \note Note that `visitor`
1301 /// can *not* change the value of the visited elements.
1302 int visitReadOnly(const ReadOnlyVisitorFunction& visitor) const;
1303
1304 /// Serially call the specified `visitor` on each element (if one
1305 /// exists) in this hash map having the specified `key` until every such
1306 /// element has been visited or `visitor` returns `false`. That is, for
1307 /// `(key, value)`, invoke:
1308 /// @code
1309 /// bool visitor(value, key);
1310 /// @endcode
1311 /// Return the number of elements visited or the negation of that value
1312 /// if visitations stopped because `visitor` returned `false`.
1313 /// `visitor` has read-only access to each element for duration of each invocation.
1314 ///
1315 /// \pre The behavior is undefined if hash map manipulators are
1316 /// invoked from within `visitor`, as it may lead to a deadlock.
1317 int visitReadOnly(const KEY& key,
1318 const ReadOnlyVisitorFunction& visitor) const;
1319
1320 /// Return the current number of elements in this hash.
1321 bsl::size_t size() const;
1322
1323 // Aspects
1324
1325 /// Return the allocator used by this hash map to supply memory.
1326 ///
1327 /// \note Note that if no allocator was supplied at construction the default
1328 /// allocator installed at that time is used.
1330};
1331
1332 // ============================================
1333 // class StripedUnorderedContainerImpl_TestUtil
1334 // ============================================
1335
1336/// This class implements a test utility that gives the test driver access
1337/// to the lock / unlock method of the Read/Write mutex. Its purpose is to
1338/// allow testing that the locking actually happens as planned.
1339///
1340/// See @ref bdlcc_stripedunorderedcontainerimpl
1341template <class KEY, class VALUE, class HASH, class EQUAL>
1343
1344 // PRIVATE TYPES
1346
1347 // DATA
1349
1350 public:
1351 // CREATORS
1352
1353 /// Create a `StripedUnorderedContainerImpl_TestUtil` object to test
1354 /// locking in the specified `hash`.
1357
1359 // Destroy this object.
1360
1361 // MANIPULATORS
1362
1363 /// Call the `lockRead` method of `bdlcc::StripedUnorderedContainerImpl`
1364 /// `d_locks_p` lock of the specified `key`.
1365 void lockRead(const KEY& key);
1366
1367 /// Call the `lockWrite` method of
1368 /// `bdlcc::StripedUnorderedContainerImpl` `d_locks_p` lock of the
1369 /// specified `key`.
1370 void lockWrite(const KEY& key);
1371
1372 /// Call the `unlockWrite` method of
1373 /// `bdlcc::StripedUnorderedContainerImpl` `d_locks_p` lock of the
1374 /// specified `key`.
1375 void unlockWrite(const KEY& key);
1376
1377 /// Call the `unlockRead` method of
1378 /// `bdlcc::StripedUnorderedContainerImpl` `d_locks_p` lock of the
1379 /// specified `key`.
1380 void unlockRead(const KEY& key);
1381};
1382
1383 // ===============================================
1384 // class StripedUnorderedContainerImpl_LockElement
1385 // ===============================================
1386
1387/// A mutex + support info; padded to cacheline size, one per stripe
1388///
1389/// See @ref bdlcc_stripedunorderedcontainerimpl
1391
1392 private:
1393 // PRIVATE TYPES
1395
1396 // PRIVATE CONSTANTS
1397 enum {
1398 #if BSLS_PLATFORM_CPU_X86 || BSLS_PLATFORM_CPU_X86_64
1399 k_PREFETCH_ENABLED = 1,
1400 #else
1401 k_PREFETCH_ENABLED = 0,
1402 #endif
1403 // Can be 0 or 1; if prefetch, we use 2 cachelines at a time
1404 k_EFFECTIVE_CACHELINE_SIZE = (1 + k_PREFETCH_ENABLED) *
1406 // Cacheline size to use; may be 1 or 2 cachelines
1407 k_LOCK_PADDING = k_EFFECTIVE_CACHELINE_SIZE >= sizeof(LockType) ?
1408 k_EFFECTIVE_CACHELINE_SIZE - sizeof(LockType) :
1409 2 * k_EFFECTIVE_CACHELINE_SIZE - sizeof(LockType)
1410 };
1411
1412 // DATA
1413 LockType d_lock;
1414 const char d_pad[k_LOCK_PADDING];
1415
1416 public:
1417 // CREATORS
1418
1419 /// Create an empty `StripedUnorderedContainerImpl_LockElement` object.
1421
1422 // MANIPULATORS
1423
1424 /// Read lock the lock element.
1425 void lockR();
1426
1427 /// Write lock the lock element.
1428 void lockW();
1429
1430 /// Read unlock the lock element.
1431 void unlockR();
1432
1433 /// Write unlock the lock element.
1434 void unlockW();
1435};
1436
1437
1438 // ========================================================
1439 // class StripedUnorderedContainerImpl_LockElementReadGuard
1440 // ========================================================
1441
1442/// A guard pattern on StripedUnorderedContainerImpl_LockElement, to release
1443/// on exception, for a lock element locked as read.
1444///
1445/// See @ref bdlcc_stripedunorderedcontainerimpl
1447
1448 private:
1449 // DATA
1450
1451 // Guarded LockElement pointer
1453
1454 public:
1455 // CREATORS
1456
1457 /// Create a guard object
1458 /// `StripedUnorderedContainerImpl_LockElementReadGuard` for the
1459 /// specified `lockElementPtr`
1460 /// `bdlcc::StripedUnorderedContainerImpl_LockElement` object.
1463
1464 /// Release the guarded object
1466
1467 // MANIPULATORS
1468
1469 /// Release the guarded object
1470 void release();
1471};
1472
1473 // =========================================================
1474 // class StripedUnorderedContainerImpl_LockElementWriteGuard
1475 // =========================================================
1476
1477/// A guard pattern on StripedUnorderedContainerImpl_LockElement, to release
1478/// on exception, for a lock element locked as write.
1479///
1480/// See @ref bdlcc_stripedunorderedcontainerimpl
1482
1483 private:
1484 // DATA
1485
1486 // Guarded LockElement pointer
1488
1489 public:
1490 // CREATORS
1491
1492 /// Create a guard object
1493 /// `StripedUnorderedContainerImpl_LockElementWriteGuard` for the
1494 /// specified `lockElementPtr`
1495 /// `bdlcc::StripedUnorderedContainerImpl_LockElement` object.
1498
1499 /// Release the guarded object
1501
1502 // MANIPULATORS
1503
1504 /// Release the guarded object
1505 void release();
1506};
1507
1508 // ==========================================================
1509 // class StripedUnorderedContainerImpl_ArrayOfLocksWriteGuard
1510 // ==========================================================
1511
1512/// This class holds locks on an array of locks, established in sequential
1513/// order, and unlocks them upon destruction in the RAII pattern.
1514///
1515/// See @ref bdlcc_stripedunorderedcontainerimpl
1517
1518 private:
1519 // DATA
1520
1521 // points to the first of a contiguous array of locks to be managed
1522 StripedUnorderedContainerImpl_LockElement * const d_firstLock_p; // held, not owned
1523
1524 // the number of locks currently owned, offset of next expected lock
1525 unsigned d_numLocked;
1526
1527 public:
1528 // CREATORS
1529
1530 /// Create a guard object
1531 /// 'StripedUnorderedContainerImpl_ArrayOfLocksWriteGuard' to lock and
1532 /// unlock elements in an array beginning with the lock pointed to by the specified 'firstLock'.
1533 ///
1534 /// \note Note that this lock is *not* locked on
1535 /// construction.
1538
1539 // Release all guarded locks.
1541
1542 // MANIPULATORS
1543
1544 /// Lock the specified `*lock_p` and add it to the collection of locks to
1545 /// be unlocked upon destruction of this object.
1546 ///
1547 /// \pre The behavior is undefined unless 'lock_p' is adjacent to the previously locked lock, or is the
1548 /// same lock provided to the constructor if this is the first call
1549 /// to `lock` on this object.
1551};
1552
1553/// A vector element needed for efficient sorting for the `insertBulk` and
1554/// `eraseBulk` methods.
1555///
1556/// See @ref bdlcc_stripedunorderedcontainerimpl
1558 public:
1559 // PUBLIC DATA
1562 bsl::size_t d_hashVal;
1563};
1564
1565// FREE OPERATOR
1566
1567/// Return `true` if the specified `lhs` is smaller than the specified `rhs`
1568/// in the order of stripe, and data.
1571
1572// ============================================================================
1573// INLINE DEFINITIONS
1574// ============================================================================
1575
1576 // =====================================================
1577 // class StripedUnorderedContainerImpl_RehashBitSetGuard
1578 // =====================================================
1579
1580// CREATORS
1581inline
1584: d_state_p(state_p)
1585, d_lockSucceeded(trySetRehashBit(d_state_p))
1586{
1587}
1588
1589inline
1592{
1593 const int k_REHASH_IN_PROGRESS =
1595 const int k_REHASH_ENABLED =
1597
1598 if (d_lockSucceeded) {
1599 int expected = k_REHASH_ENABLED | k_REHASH_IN_PROGRESS;
1600 for (;;) {
1601 int previous = d_state_p->testAndSwap(
1602 expected,
1603 expected & ~k_REHASH_IN_PROGRESS);
1604 if (previous == expected) {
1605 break;
1606 }
1607 expected = previous;
1608 }
1609 }
1610}
1611
1612inline
1614{
1615 return d_lockSucceeded;
1616}
1617
1618inline
1619bool StripedUnorderedContainerImpl_RehashBitSetGuard::trySetRehashBit(
1620 bsls::AtomicInt *state_p)
1621{
1622 const int k_REHASH_IN_PROGRESS =
1624 const int k_REHASH_ENABLED =
1626
1627 BSLS_ASSERT(state_p);
1628 return k_REHASH_ENABLED ==
1629 state_p->testAndSwap(k_REHASH_ENABLED,
1630 k_REHASH_ENABLED | k_REHASH_IN_PROGRESS);
1631}
1632
1633 // ----------------------------------------
1634 // class StripedUnorderedContainerImpl_Node
1635 // ----------------------------------------
1636
1637// CREATORS
1638template <class KEY, class VALUE>
1639inline
1642 const KEY& key,
1643 const VALUE& value,
1645 bslma::Allocator *basicAllocator)
1646: d_next_p(nextPtr)
1647, d_allocator_p(bslma::Default::allocator(basicAllocator))
1648{
1650 d_allocator_p,
1651 key);
1652 bslma::DestructorProctor<KEY> proctor(&d_key.object());
1653
1655 d_allocator_p,
1656 value);
1657 proctor.release();
1658}
1659
1660template <class KEY, class VALUE>
1661inline
1664 const KEY& key,
1667 bslma::Allocator *basicAllocator)
1668: d_next_p(nextPtr)
1669, d_allocator_p(bslma::Default::allocator(basicAllocator))
1670{
1672 d_allocator_p,
1673 key);
1674 bslma::DestructorProctor<KEY> proctor(&d_key.object());
1675
1676 VALUE& dummy = value;
1678 dummy,
1679 d_allocator_p);
1680 proctor.release();
1681}
1682
1683template <class KEY, class VALUE>
1686 const KEY& key,
1688 bslma::Allocator *basicAllocator)
1689: d_next_p(nextPtr)
1690, d_allocator_p(bslma::Default::allocator(basicAllocator))
1691{
1693 d_allocator_p,
1694 key);
1695 bslma::DestructorProctor<KEY> proctor(&d_key.object());
1696
1697 bslma::ConstructionUtil::construct(d_value.address(), d_allocator_p);
1698 proctor.release();
1699}
1700
1701
1702template <class KEY, class VALUE>
1703inline
1706{
1707 // Destroy the object buffers content
1708 bslma::DestructionUtil::destroy(d_key.address());
1709 bslma::DestructionUtil::destroy(d_value.address());
1710}
1711
1712
1713// MANIPULATORS
1714template <class KEY, class VALUE>
1715inline
1721
1722template <class KEY, class VALUE>
1723inline
1729
1730template <class KEY, class VALUE>
1731inline
1733{
1734 return d_value.object();
1735}
1736
1737// ACCESSORS
1738template <class KEY, class VALUE>
1739inline
1741{
1742 return d_key.object();
1743}
1744
1745template <class KEY, class VALUE>
1746inline
1749{
1750 return d_next_p;
1751}
1752
1753template <class KEY, class VALUE>
1754inline
1756{
1757 return d_value.object();
1758}
1759
1760 // Aspects
1761
1762template <class KEY, class VALUE>
1763inline
1766{
1767 return d_allocator_p;
1768}
1769
1770 // ------------------------------------------
1771 // class StripedUnorderedContainerImpl_Bucket
1772 // ------------------------------------------
1773
1774// CREATORS
1775template <class KEY, class VALUE>
1776inline
1779 bslma::Allocator *basicAllocator)
1780: d_head_p(NULL)
1781, d_tail_p(NULL)
1782, d_size(0)
1783, d_allocator_p(bslma::Default::allocator(basicAllocator))
1784{
1785}
1786
1787template <class KEY, class VALUE>
1788inline
1792 original,
1794: d_head_p(MoveUtil::move(MoveUtil::access(original).d_head_p))
1795, d_tail_p(MoveUtil::move(MoveUtil::access(original).d_tail_p))
1796, d_size( MoveUtil::access(original).d_size)
1797, d_allocator_p(MoveUtil::access(original).d_allocator_p)
1798{
1799 MoveUtil::access(original).d_head_p = NULL;
1800 MoveUtil::access(original).d_tail_p = NULL;
1801 MoveUtil::access(original).d_size = 0;
1802}
1803
1804template <class KEY, class VALUE>
1805inline
1811
1812// MANIPULATORS
1813template <class KEY, class VALUE>
1814inline
1817{
1818 BSLS_ASSERT(nodePtr->next() == NULL);
1819
1820 if (d_head_p == NULL) {
1821 d_head_p = nodePtr;
1822 }
1823 else {
1824 d_tail_p->setNext(nodePtr);
1825 }
1826 d_tail_p = nodePtr;
1827 ++d_size;
1828}
1829
1830template <class KEY, class VALUE>
1831inline
1833{
1834 // Delete all content in a loop
1835 for (StripedUnorderedContainerImpl_Node<KEY, VALUE> *curNode = d_head_p;
1836 curNode != NULL;) {
1838 curNode->next();
1839 d_allocator_p->deleteObject(curNode);
1840 curNode = nextPtr;
1841 }
1842 d_head_p = NULL;
1843 d_tail_p = NULL;
1844 d_size = 0;
1845}
1846
1847template <class KEY, class VALUE>
1848inline
1854
1855template <class KEY, class VALUE>
1856inline
1858 int amount)
1859{
1860 d_size += amount;
1861}
1862
1863template <class KEY, class VALUE>
1864inline
1870
1871template <class KEY, class VALUE>
1872inline
1874 bsl::size_t value)
1875{
1876 d_size = value;
1877}
1878
1879template <class KEY, class VALUE>
1880inline
1886
1887template <class KEY, class VALUE>
1888template <class EQUAL>
1890 const KEY& key,
1891 const EQUAL& equal,
1892 const VALUE& value,
1893 BucketScope scope)
1894{
1895 if (d_head_p == NULL) {
1896 d_head_p = new (*d_allocator_p)
1898 key,
1899 value,
1900 NULL,
1901 d_allocator_p);
1902 d_tail_p = d_head_p;
1903 d_size = 1;
1904 return 0; // RETURN
1905 }
1906
1908 int count = 0;
1909 for (; curNode != NULL; curNode = curNode->next()) {
1910 if (equal(curNode->key(), key)) {
1911 curNode->value() = value;
1912 if (e_BUCKETSCOPE_FIRST == scope) {
1913 return 1; // RETURN
1914 }
1915 ++count;
1916 }
1917 }
1918 if (count > 0) {
1919 return count; // RETURN
1920 }
1923 key,
1924 value,
1925 NULL,
1926 d_allocator_p);
1927 d_tail_p->setNext(newNode);
1928 d_tail_p = d_tail_p->next();
1929 ++d_size;
1930 return 0;
1931}
1932
1933template <class KEY, class VALUE>
1934template <class EQUAL>
1936 const KEY& key,
1937 const EQUAL& equal,
1939{
1940 if (d_head_p == NULL) {
1941 d_head_p = new (*d_allocator_p)
1943 key,
1945 NULL,
1946 d_allocator_p);
1947 d_tail_p = d_head_p;
1948 d_size = 1;
1949 return 0; // RETURN
1950 }
1952 for (; curNode != NULL; curNode = curNode->next()) {
1953 if (equal(curNode->key(), key)) {
1954#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
1955 curNode->value() = bslmf::MovableRefUtil::move(value);
1956#else
1957 curNode->value() = value;
1958#endif
1959 return 1; // RETURN
1960 }
1961 }
1964 key,
1966 NULL,
1967 d_allocator_p);
1968 d_tail_p->setNext(newNode);
1969 d_tail_p = d_tail_p->next();
1970 ++d_size;
1971 return 0;
1972}
1973
1974// ACCESSORS
1975template <class KEY, class VALUE>
1976inline
1978{
1979 return d_size == 0;
1980}
1981
1982template <class KEY, class VALUE>
1983inline
1986{
1987 return d_head_p;
1988}
1989
1990template <class KEY, class VALUE>
1991inline
1993{
1994 return d_size;
1995}
1996
1997template <class KEY, class VALUE>
1998inline
2001{
2002 return d_tail_p;
2003}
2004
2005 // Aspects
2006
2007template <class KEY, class VALUE>
2008inline
2010 const
2011{
2012 return d_allocator_p;
2013}
2014
2015 // -----------------------------------------------
2016 // class StripedUnorderedContainerImpl_LockElement
2017 // -----------------------------------------------
2018
2019// CREATORS
2020inline
2027
2028// MANIPULATORS
2029inline
2034
2035inline
2040
2041inline
2046
2047inline
2052
2053 // --------------------------------------------------------
2054 // class StripedUnorderedContainerImpl_LockElementReadGuard
2055 // --------------------------------------------------------
2056
2057// CREATORS
2058inline
2065
2066// MANIPULATORS
2067inline
2073
2074inline
2076{
2077 if (d_lockElement_p) {
2078 d_lockElement_p->unlockR();
2079 d_lockElement_p = NULL;
2080 }
2081}
2082
2083 // ---------------------------------------------------------
2084 // class StripedUnorderedContainerImpl_LockElementWriteGuard
2085 // ---------------------------------------------------------
2086
2087// CREATORS
2088inline
2095
2096// MANIPULATORS
2097inline
2103
2104inline
2106{
2107 if (d_lockElement_p) {
2108 d_lockElement_p->unlockW();
2109 d_lockElement_p = NULL;
2110 }
2111}
2112
2113 // ==========================================================
2114 // class StripedUnorderedContainerImpl_ArrayOfLocksWriteGuard
2115 // ==========================================================
2116
2117// CREATORS
2118inline
2122: d_firstLock_p(firstLock_p)
2123, d_numLocked(0)
2124{
2125 BSLS_ASSERT(firstLock_p);
2126}
2127
2128inline
2131{
2132 for (unsigned i = d_numLocked; i > 0; --i)
2133 {
2134 d_firstLock_p[i - 1].unlockW();
2135 }
2136}
2137
2138// MANIPULATORS
2139inline
2142{
2143 BSLS_ASSERT(lock_p == (d_firstLock_p + d_numLocked));
2144
2145 lock_p->lockW();
2146 ++d_numLocked;
2147}
2148
2149 // -----------------------------------
2150 // class StripedUnorderedContainerImpl
2151 // -----------------------------------
2152
2153// PRIVATE CLASS METHODS
2154template <class KEY, class VALUE, class HASH, class EQUAL>
2155inline
2156bsl::size_t
2158 bsl::size_t numBuckets,
2159 bsl::size_t numStripes)
2160{
2161 // 'numBuckets' must not less than 2, and must be a power of 2. To avoid
2162 // unused stripes, we also require numBuckets >= numStripes.
2163 if (numBuckets < 2) {
2164 numBuckets = 2;
2165 }
2166 if (numBuckets < numStripes) {
2167 numBuckets = numStripes;
2168 }
2169 numBuckets = powerCeil(numBuckets);
2170 return numBuckets;
2171}
2172
2173template <class KEY, class VALUE, class HASH, class EQUAL>
2174inline
2175bool StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::alwaysTrue(
2176 const VALUE&)
2177{
2178 return true;
2179}
2180
2181template <class KEY, class VALUE, class HASH, class EQUAL>
2182inline
2183bsl::size_t StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::powerCeil(
2184 bsl::size_t num)
2185{
2186 if (num <= 1) {
2187 return 1; // RETURN
2188 }
2189 int power = 2;
2190 --num;
2191 while (num >>= 1) {
2192 power <<= 1;
2193 }
2194 return power;
2195}
2196
2197// PRIVATE MANIPULATORS
2198template <class KEY, class VALUE, class HASH, class EQUAL>
2199inline
2200void StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::checkRehash()
2201{
2202 float loadF = loadFactor();
2203 if (d_maxLoadFactor < loadF && canRehash()) {
2204 int ratio = static_cast<int>(loadF / d_maxLoadFactor);
2205 int growthFactor = 2;
2206 while (growthFactor < ratio) {
2207 growthFactor <<= 1;
2208 }
2209 bsl::size_t newNumBuckets = d_numBuckets * growthFactor;
2210 rehash(newNumBuckets);
2211 }
2212}
2213
2214template <class KEY, class VALUE, class HASH, class EQUAL>
2215inline
2216bsl::size_t StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::erase(
2217 const KEY& key,
2218 Scope scope)
2219{
2220 return eraseIf(key, scope, alwaysTrue);
2221}
2222
2223template <class KEY, class VALUE, class HASH, class EQUAL>
2224template <class RANDOM_ITER>
2225bsl::size_t StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::eraseBulk(
2226 RANDOM_ITER first,
2227 RANDOM_ITER last,
2228 Scope scope)
2229{
2230 BSLS_ASSERT(first <= last);
2231
2232 bool eraseAll = scope == e_SCOPE_ALL;
2233 bsl::size_t count = 0;
2234 // For each key, store in a vector its stripe, location, and hash value.
2235 int dataSize = static_cast<int>(last - first);
2236
2238 sortIdxs(dataSize, bslma::Default::defaultAllocator());
2239 for (int i = 0; i < dataSize; ++i) {
2240 sortIdxs[i].d_hashVal = d_hasher(first[i]);
2241 bsl::size_t bucketIdx =
2243 d_numBuckets);
2244 sortIdxs[i].d_stripeIdx = static_cast<int>(bucketToStripe(bucketIdx));
2245 sortIdxs[i].d_dataIdx = i;
2246 }
2247 // Sort it by stripe, and location
2248 bsl::sort(sortIdxs.begin(), sortIdxs.end());
2249
2250 // Lock each stripe, and process all data points in it. Do not recalculate
2251 // hash code (hence keeping the hash value).
2252 int curStripeIdx;
2253 for (int j = 0; j < dataSize;) {
2254 curStripeIdx = sortIdxs[j].d_stripeIdx;
2255 LockElement& lockElement = d_locks_p[curStripeIdx];
2256 lockElement.lockW();
2257 LEWGuard guard(&lockElement);
2258 for (; j < dataSize && sortIdxs[j].d_stripeIdx == curStripeIdx; ++j) {
2259 int dataIdx = sortIdxs[j].d_dataIdx;
2260 bsl::size_t bucketIdx =
2262 sortIdxs[j].d_hashVal,
2263 d_numBuckets);
2264
2265 StripedUnorderedContainerImpl_Bucket<KEY, VALUE> &bucket =
2266 d_buckets[bucketIdx];
2267
2268 const KEY& key = first[dataIdx];
2269
2270 Node **prevNodeAddress = bucket.headAddress();
2271 Node *prevNode = NULL;
2272 while (*prevNodeAddress) {
2273 Node *node = *prevNodeAddress;
2274 if (d_comparator(node->key(), key)) {
2275 *prevNodeAddress = node->next();
2276 if (bucket.tail() == node) {
2277 bucket.setTail(prevNode);
2278 }
2279 d_allocator_p->deleteObject(node);
2280 bucket.incrementSize(-1);
2281 d_numElements.addRelaxed(-1);
2282 ++count;
2283 if (!eraseAll) {
2284 break;
2285 }
2286 }
2287 else {
2288 prevNode = node;
2289 prevNodeAddress = node->nextAddress();
2290 }
2291 }
2292 }
2293 }
2294
2295 return count;
2296}
2297
2298template <class KEY, class VALUE, class HASH, class EQUAL>
2299bsl::size_t StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::eraseIf(
2300 const KEY& key,
2301 Scope scope,
2302 const EraseIfValuePredicate& predicate)
2303{
2304 bool eraseAll = scope == e_SCOPE_ALL;
2305 bsl::size_t bucketIdx;
2306 LEWGuard guard(lockWrite(&bucketIdx, key));
2307
2308 StripedUnorderedContainerImpl_Bucket<KEY, VALUE> &bucket =
2309 d_buckets[bucketIdx];
2310
2311 typedef StripedUnorderedContainerImpl_Node<KEY, VALUE> Node;
2312
2313 bsl::size_t count = 0;
2314
2315 Node **prevNodeAddress = bucket.headAddress();
2316 Node *prevNode = NULL;
2317 while (*prevNodeAddress) {
2318 Node *node = *prevNodeAddress;
2319 if (d_comparator(node->key(), key) && predicate(node->value())) {
2320 *prevNodeAddress = node->next();
2321 if (bucket.tail() == node) {
2322 bucket.setTail(prevNode);
2323 }
2324 d_allocator_p->deleteObject(node);
2325 bucket.incrementSize(-1);
2326 d_numElements.addRelaxed(-1);
2327 ++count;
2328 if (!eraseAll) {
2329 return count; // RETURN
2330 }
2331 }
2332 else {
2333 prevNode = node;
2334 prevNodeAddress = node->nextAddress();
2335 }
2336 }
2337 return count;
2338}
2339
2340template <class KEY, class VALUE, class HASH, class EQUAL>
2341inline
2342bsl::size_t StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::insert(
2343 const KEY& key,
2344 const VALUE& value,
2345 Multiplicity multiplicity)
2346{
2347 bool insertAlways = multiplicity == e_INSERT_ALWAYS;
2348
2349 bsl::size_t bucketIdx;
2350 LEWGuard guard(lockWrite(&bucketIdx, key));
2351
2352 bsl::size_t ret = 0;
2353 if (insertAlways) {
2354 // Insert, ignoring an existing value if any. Use only in multimap.
2355 Node *node = new (*d_allocator_p)
2356 StripedUnorderedContainerImpl_Node<KEY, VALUE>(key,
2357 value,
2358 NULL,
2359 d_allocator_p);
2360 d_buckets[bucketIdx].addNode(node);
2361 }
2362 else {
2363 // Update only the first value if key exists. Use only in hash map.
2364 ret = d_buckets[bucketIdx].setValue(
2365 key,
2366 d_comparator,
2367 value,
2369 }
2370 if (ret == 1) {
2371 return 0; // RETURN
2372 }
2373 guard.release();
2374 d_numElements.addRelaxed(1);
2375 checkRehash();
2376 return 1;
2377}
2378
2379template <class KEY, class VALUE, class HASH, class EQUAL>
2380inline
2381bsl::size_t StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::insert(
2382 const KEY& key,
2384 Multiplicity multiplicity)
2385{
2386 bool insertAlways = multiplicity == e_INSERT_ALWAYS;
2387
2388 bsl::size_t bucketIdx;
2389 LEWGuard guard(lockWrite(&bucketIdx, key));
2390
2391 bsl::size_t ret = 0;
2392 if (insertAlways) {
2393 // Insert, ignoring an existing value if any. Use only in multimap.
2394 Node *node = new (*d_allocator_p)
2395 Node(key, bslmf::MovableRefUtil::move(value), NULL, d_allocator_p);
2396 d_buckets[bucketIdx].addNode(node);
2397 }
2398 else {
2399 // Update only the first value if key exists. Use only in hash map.
2400 ret = d_buckets[bucketIdx].setValue(
2401 key,
2402 d_comparator,
2404 }
2405 if (ret == 1) {
2406 return 0; // RETURN
2407 }
2408 guard.release();
2409 d_numElements.addRelaxed(1);
2410 checkRehash();
2411 return 1;
2412}
2413
2414template <class KEY, class VALUE, class HASH, class EQUAL>
2415template <class RANDOM_ITER>
2416bsl::size_t StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::insertBulk(
2417 RANDOM_ITER first,
2418 RANDOM_ITER last,
2419 Multiplicity multiplicity)
2420{
2421 BSLS_ASSERT(first <= last);
2422
2423 bool insertAlways = multiplicity == e_INSERT_ALWAYS;
2424 bsl::size_t count = 0;
2425 int dataSize = static_cast<int>(last - first);
2426
2428 sortIdxs(dataSize, bslma::Default::defaultAllocator());
2429
2430 // For each key, store in a vector its stripe, location, and hash value.
2431 for (int i = 0; i < dataSize; ++i) {
2432 sortIdxs[i].d_hashVal = d_hasher(first[i].first);
2433 bsl::size_t bucketIdx =
2435 d_numBuckets);
2436 sortIdxs[i].d_stripeIdx = static_cast<int>(bucketToStripe(bucketIdx));
2437 sortIdxs[i].d_dataIdx = i;
2438 }
2439 // Sort it by stripe, and location
2440 bsl::sort(sortIdxs.begin(), sortIdxs.end());
2441
2442 // Lock each stripe, and process all data points in it. Do not recalculate
2443 // hash code (hence keeping the hash value).
2444 int curStripeIdx;
2445 for (int j = 0; j < dataSize;) {
2446 curStripeIdx = sortIdxs[j].d_stripeIdx;
2447 LockElement& lockElement = d_locks_p[curStripeIdx];
2448 lockElement.lockW();
2449 LEWGuard guard(&lockElement);
2450 for (; j < dataSize && sortIdxs[j].d_stripeIdx == curStripeIdx; ++j) {
2451 int dataIdx = sortIdxs[j].d_dataIdx;
2452 bsl::size_t bucketIdx =
2454 sortIdxs[j].d_hashVal,
2455 d_numBuckets);
2456 const KEY& key = first[dataIdx].first;
2457 const VALUE& value = first[dataIdx].second;
2458
2459 if (insertAlways) {
2460 // Insert, ignoring an existing value if any. Use only in
2461 // multimap.
2462 StripedUnorderedContainerImpl_Node<KEY, VALUE> *node =
2463 new (*d_allocator_p)
2464 StripedUnorderedContainerImpl_Node<KEY, VALUE>(
2465 key,
2466 value,
2467 NULL,
2468 d_allocator_p);
2469 d_buckets[bucketIdx].addNode(node);
2470 ++count;
2471 d_numElements.addRelaxed(1);
2472 } else {
2473 bsl::size_t ret = d_buckets[bucketIdx].setValue(
2474 key,
2475 d_comparator,
2476 value,
2477 StripedUnorderedContainerImpl_Bucket<KEY, VALUE>::
2478 e_BUCKETSCOPE_FIRST);
2479 if (ret == 0) {
2480 ++count;
2481 d_numElements.addRelaxed(1);
2482 }
2483 }
2484 }
2485 }
2486 checkRehash();
2487 return count;
2488}
2489
2490template <class KEY, class VALUE, class HASH, class EQUAL>
2491int StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::setComputedValue(
2492 const KEY& key,
2493 const VisitorFunction& visitor,
2494 Scope scope)
2495{
2496 typedef StripedUnorderedContainerImpl_Bucket<KEY, VALUE> BucketClass;
2497 typename BucketClass::BucketScope setAll = scope == e_SCOPE_ALL
2498 ? BucketClass::e_BUCKETSCOPE_ALL
2499 : BucketClass::e_BUCKETSCOPE_FIRST;
2500
2501 bsl::size_t bucketIdx;
2502 LEWGuard guard(lockWrite(&bucketIdx, key));
2503
2504 StripedUnorderedContainerImpl_Bucket<KEY, VALUE>& bucket =
2505 d_buckets[bucketIdx];
2506 // Loop on the elements in the list
2507 int count = 0;
2508 StripedUnorderedContainerImpl_Node<KEY, VALUE> *curNode = bucket.head();
2509 for (; curNode != NULL; curNode = curNode->next()) {
2510 if (d_comparator(curNode->key(), key)) {
2511 bool ret = visitor(&curNode->value(), key);
2512 if (false == setAll) {
2513 return ret ? 1 : -1; // RETURN
2514 }
2515 ++count;
2516 if (false == ret) {
2517 return -count; // RETURN
2518 }
2519 }
2520 }
2521 if (count > 0) {
2522 return count; // RETURN
2523 }
2524
2525 // Not found - process as false, and return 0.
2526 StripedUnorderedContainerImpl_Node<KEY, VALUE> *addNode =
2527 new (*d_allocator_p)
2528 StripedUnorderedContainerImpl_Node<KEY, VALUE>(key,
2529 NULL,
2530 d_allocator_p);
2531 {
2533 StripedUnorderedContainerImpl_Node<KEY, VALUE>,
2535 proctor(addNode, d_allocator_p);
2536
2537 visitor(&addNode->value(), key);
2538 proctor.release();
2539 }
2540
2541 if (bucket.head() == NULL) {
2542 bucket.setHead(addNode);
2543 bucket.setTail(addNode);
2544 }
2545 else {
2546 bucket.tail()->setNext(addNode);
2547 bucket.setTail(addNode);
2548 }
2549 d_numElements.addRelaxed(1);
2550 bucket.incrementSize(1);
2551 guard.release();
2552 checkRehash();
2553 return 0;
2554}
2555
2556template <class KEY, class VALUE, class HASH, class EQUAL>
2557inline
2558bsl::size_t StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::setValue(
2559 const KEY& key,
2560 const VALUE& value,
2561 Scope scope)
2562{
2563 typedef StripedUnorderedContainerImpl_Bucket<KEY, VALUE> BucketClass;
2564 typename BucketClass::BucketScope setAll = scope == e_SCOPE_ALL
2565 ? BucketClass::e_BUCKETSCOPE_ALL
2566 : BucketClass::e_BUCKETSCOPE_FIRST;
2567
2568 bsl::size_t bucketIdx;
2569 LEWGuard guard(lockWrite(&bucketIdx, key));
2570
2571 StripedUnorderedContainerImpl_Bucket<KEY, VALUE>& bucket =
2572 d_buckets[bucketIdx];
2573
2574 bsl::size_t count = bucket.setValue(key, d_comparator, value, setAll);
2575 if (count == 0) {
2576 guard.release();
2577 d_numElements.addRelaxed(1);
2578 checkRehash();
2579 }
2580 return count;
2581}
2582
2583// PRIVATE ACCESSORS
2584template <class KEY, class VALUE, class HASH, class EQUAL>
2585inline
2586bsl::size_t
2587StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::bucketIndex(
2588 const KEY& key,
2589 bsl::size_t numBuckets) const
2590{
2591 bsl::size_t hashVal = d_hasher(key);
2592 bsl::size_t bucketIdx =
2594 return bucketIdx;
2595}
2596
2597template <class KEY, class VALUE, class HASH, class EQUAL>
2598inline
2599bsl::size_t
2600StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::bucketToStripe(
2601 bsl::size_t bucketIndex) const
2602{
2603 return bucketIndex & d_hashMask;
2604}
2605
2606template <class KEY, class VALUE, class HASH, class EQUAL>
2607template <class VECTOR>
2608inline
2609bsl::size_t
2610StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::getValueImpl(
2611 VECTOR *valuesPtr,
2612 const KEY& key) const
2613{
2614 static const bool isVector =
2615 bsl::is_same<bsl::vector<VALUE>, VECTOR>::value
2616#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
2617 || bsl::is_same<std::pmr::vector<VALUE>, VECTOR>::value
2618#endif
2619 || bsl::is_same<std::vector<VALUE>, VECTOR>::value;
2620 BSLMF_ASSERT(isVector);
2621
2622 BSLS_ASSERT(NULL != valuesPtr);
2623
2624 valuesPtr->clear();
2625
2626 bsl::size_t bucketIdx;
2627 LERGuard guard(lockRead(&bucketIdx, key));
2628
2629 bsl::size_t count = 0;
2630 const StripedUnorderedContainerImpl_Bucket<KEY, VALUE>& bucket = d_buckets[
2631 bucketIdx];
2632 // Loop on the elements in the list
2633 StripedUnorderedContainerImpl_Node<KEY, VALUE> *curNode = bucket.head();
2634 for (; curNode != NULL; curNode = curNode->next()) {
2635 if (d_comparator(curNode->key(), key)) {
2636 valuesPtr->push_back(curNode->value());
2637 ++count;
2638 }
2639 }
2640 return count;
2641}
2642
2643template <class KEY, class VALUE, class HASH, class EQUAL>
2644inline
2645StripedUnorderedContainerImpl_LockElement *
2646StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::lockRead(
2647 bsl::size_t *bucketIdx,
2648 const KEY& key) const
2649{
2650 // From key, get hash value, and current number of buckets.
2651 bsl::size_t hashVal = d_hasher(key);
2652 bsl::size_t numBuckets = d_numBuckets;
2653 bsl::size_t bucketIndex =
2654 bslalg::HashTableImpUtil::computeBucketIndex(hashVal, d_numBuckets);
2655 bsl::size_t stripeIdx = bucketToStripe(bucketIndex);
2656 LockElement& lockElement = d_locks_p[stripeIdx];
2657 lockElement.lockR();
2658 // When we get the lock, did the number of buckets change?
2659 if (numBuckets != d_numBuckets) {
2660 bucketIndex =
2661 bslalg::HashTableImpUtil::computeBucketIndex(hashVal, d_numBuckets);
2662 }
2663 *bucketIdx = bucketIndex;
2664 return &lockElement;
2665}
2666
2667template <class KEY, class VALUE, class HASH, class EQUAL>
2668inline
2669StripedUnorderedContainerImpl_LockElement *
2670StripedUnorderedContainerImpl<KEY, VALUE, HASH, EQUAL>::lockWrite(
2671 bsl::size_t *bucketIdx,
2672 const KEY& key) const
2673{
2674 // From key, get hash value, and current number of buckets.
2675 bsl::size_t hashVal = d_hasher(key);
2676 bsl::size_t numBuckets = d_numBuckets;
2677 bsl::size_t bucketIndex =
2678 bslalg::HashTableImpUtil::computeBucketIndex(hashVal, d_numBuckets);
2679 bsl::size_t stripeIdx = bucketToStripe(bucketIndex);
2680 LockElement& lockElement = d_locks_p[stripeIdx];
2681 lockElement.lockW();
2682
2683 // When we get the lock, did the number of buckets change?
2684 if (numBuckets != d_numBuckets) {
2685 bucketIndex =
2686 bslalg::HashTableImpUtil::computeBucketIndex(hashVal, d_numBuckets);
2687 }
2688 *bucketIdx = bucketIndex;
2689 return &lockElement;
2690}
2691
2692// CREATORS
2693template <class KEY, class VALUE, class HASH, class EQUAL>
2694inline
2698 float maxLoadFactor,
2699 bsl::size_t numInitialBuckets,
2700 bsl::size_t numStripes,
2701 bslma::Allocator *basicAllocator)
2702: d_numStripes(powerCeil(numStripes))
2703, d_numBuckets(adjustBuckets(numInitialBuckets, d_numStripes))
2704, d_hashMask(d_numStripes - 1)
2705, d_maxLoadFactor(maxLoadFactor)
2706, d_hasher()
2707, d_comparator()
2708, d_statePad()
2709, d_numElementsPad()
2710, d_buckets(d_numBuckets, basicAllocator)
2711, d_allocator_p(bslma::Default::allocator(basicAllocator))
2712{
2713 d_state = k_REHASH_ENABLED; // Rehash enabled, not in progress
2714 d_numElements = 0; // Hash empty
2715
2716 // Allocate array of 'LockElement' objects, and construct them.
2717 d_locks_p = reinterpret_cast<LockElement*>(
2718 d_allocator_p->allocate(d_numStripes * sizeof(LockElement)));
2719 for (bsl::size_t i = 0; i < d_numStripes; ++i) {
2720 bslma::ConstructionUtil::construct(&d_locks_p[i], d_allocator_p);
2721 }
2722}
2723
2724template <class KEY, class VALUE, class HASH, class EQUAL>
2725inline
2728 bsl::size_t numInitialBuckets,
2729 bsl::size_t numStripes,
2730 bslma::Allocator *basicAllocator)
2731: d_numStripes(powerCeil(numStripes))
2732, d_numBuckets(adjustBuckets(numInitialBuckets, d_numStripes))
2733, d_hashMask(d_numStripes - 1)
2734, d_maxLoadFactor(1.0)
2735, d_hasher()
2736, d_comparator()
2737, d_statePad()
2738, d_numElementsPad()
2739, d_buckets(d_numBuckets, basicAllocator)
2740, d_allocator_p(bslma::Default::allocator(basicAllocator))
2741{
2742 d_state = k_REHASH_ENABLED; // Rehash enabled, not in progress
2743 d_numElements = 0; // Hash empty
2744
2745 // Allocate array of 'LockElement' objects, and construct them.
2746 d_locks_p = reinterpret_cast<LockElement*>(
2747 d_allocator_p->allocate(d_numStripes * sizeof(LockElement)));
2748 for (bsl::size_t i = 0; i < d_numStripes; ++i) {
2749 bslma::ConstructionUtil::construct(&d_locks_p[i], d_allocator_p);
2750 }
2751}
2752
2753template <class KEY, class VALUE, class HASH, class EQUAL>
2754inline
2757{
2758 for (bsl::size_t i = 0; i < d_numStripes; ++i) {
2759 bslma::DestructionUtil::destroy(&d_locks_p[i]);
2760 }
2761 d_allocator_p->deallocate(d_locks_p);
2762}
2763
2764// MANIPULATORS
2765template <class KEY, class VALUE, class HASH, class EQUAL>
2766inline
2768{
2769 // Locking all stripes will inherently block until a rehash will complete
2770 for (bsl::size_t i = 0; i < d_numStripes; ++i) {
2771 d_locks_p[i].lockW();
2772 }
2773 for (bsl::size_t j = 0; j < d_numBuckets; ++j) {
2774 d_buckets[j].clear();
2775 }
2776 d_numElements = 0;
2777 for (bsl::size_t i = 0; i < d_numStripes; ++i) {
2778 d_locks_p[i].unlockW();
2779 }
2780}
2781
2782template <class KEY, class VALUE, class HASH, class EQUAL>
2783inline
2785{
2786 for (;;) {
2787 int oldState = d_state.load();
2788 int newState = oldState & ~k_REHASH_ENABLED;
2789 if (oldState == d_state.testAndSwap(oldState, newState)) {
2790 return; // RETURN
2791 }
2792 }
2793}
2794
2795template <class KEY, class VALUE, class HASH, class EQUAL>
2796inline
2798{
2799 for (;;) {
2800 int oldState = d_state.load();
2801 int newState = oldState | k_REHASH_ENABLED;
2802 if (oldState == d_state.testAndSwap(oldState, newState)) {
2803 break;
2804 }
2805 }
2806}
2807
2808template <class KEY, class VALUE, class HASH, class EQUAL>
2809inline
2811 const KEY& key)
2812{
2813 return erase(key, e_SCOPE_ALL);
2814}
2815
2816template <class KEY, class VALUE, class HASH, class EQUAL>
2817inline
2819 const KEY& key,
2820 const EraseIfValuePredicate& predicate)
2821{
2822 return eraseIf(key, e_SCOPE_ALL, predicate);
2823}
2824
2825template <class KEY, class VALUE, class HASH, class EQUAL>
2826template <class RANDOM_ITER>
2827inline
2828bsl::size_t
2830 RANDOM_ITER first,
2831 RANDOM_ITER last)
2832{
2833 BSLS_ASSERT(first <= last);
2834
2835 return eraseBulk(first, last, e_SCOPE_ALL);
2836}
2837
2838template <class KEY, class VALUE, class HASH, class EQUAL>
2839template <class RANDOM_ITER>
2840inline
2841bsl::size_t
2843 RANDOM_ITER first,
2844 RANDOM_ITER last)
2845{
2846 BSLS_ASSERT(first <= last);
2847
2848 return eraseBulk(first, last, e_SCOPE_FIRST);
2849}
2850
2851template <class KEY, class VALUE, class HASH, class EQUAL>
2852inline
2854 const KEY& key)
2855{
2856 return erase(key, e_SCOPE_FIRST);
2857}
2858
2859template <class KEY, class VALUE, class HASH, class EQUAL>
2860inline
2861bsl::size_t
2863 const KEY& key,
2864 const EraseIfValuePredicate& predicate)
2865{
2866 return eraseIf(key, e_SCOPE_FIRST, predicate);
2867}
2868
2869template <class KEY, class VALUE, class HASH, class EQUAL>
2870inline
2872 const KEY& key,
2873 const VALUE& value)
2874{
2875 insert(key, value, e_INSERT_ALWAYS);
2876}
2877
2878template <class KEY, class VALUE, class HASH, class EQUAL>
2879inline
2881 const KEY& key,
2883{
2884 insert(key, bslmf::MovableRefUtil::move(value), e_INSERT_ALWAYS);
2885}
2886
2887template <class KEY, class VALUE, class HASH, class EQUAL>
2888template <class RANDOM_ITER>
2889inline
2891 RANDOM_ITER first,
2892 RANDOM_ITER last)
2893{
2894 BSLS_ASSERT(first <= last);
2895
2896 insertBulk(first, last, e_INSERT_ALWAYS);
2897}
2898
2899template <class KEY, class VALUE, class HASH, class EQUAL>
2900template <class RANDOM_ITER>
2901inline
2902bsl::size_t
2904 RANDOM_ITER first,
2905 RANDOM_ITER last)
2906{
2907 BSLS_ASSERT(first <= last);
2908
2909 return insertBulk(first, last, e_INSERT_UNIQUE);
2910}
2911
2912template <class KEY, class VALUE, class HASH, class EQUAL>
2913inline
2914bsl::size_t
2916 const KEY& key,
2917 const VALUE& value)
2918{
2919 return insert(key, value, e_INSERT_UNIQUE);
2920}
2921
2922template <class KEY, class VALUE, class HASH, class EQUAL>
2923inline
2924bsl::size_t
2926 const KEY& key,
2928{
2929 return insert(key, bslmf::MovableRefUtil::move(value), e_INSERT_UNIQUE);
2930}
2931
2932template <class KEY, class VALUE, class HASH, class EQUAL>
2934 bsl::size_t numBuckets)
2935{
2936 // 'numBuckets' must not less than 2, and must be a power of 2. To avoid
2937 // unused stripes, we also require numBuckets >= numStripes.
2938 if (numBuckets < 2) {
2939 numBuckets = 2;
2940 }
2941 if (numBuckets < d_numStripes) {
2942 numBuckets = d_numStripes;
2943 }
2944 numBuckets = powerCeil(numBuckets);
2945
2946 if (numBuckets <= d_numBuckets) { // Skip if no change in # of buckets
2947 return; // RETURN
2948 }
2949 if (!canRehash()) { // Skip if can't rehash
2950 return; // RETURN
2951 }
2952
2953 // Set state to rehash
2955 if (!rehashGuard.holdsLock() || numBuckets <= d_numBuckets.loadRelaxed()) {
2956 return; // RETURN
2957 }
2958
2959 // Allocate a new data vector
2961 numBuckets,
2962 d_allocator_p);
2963
2965 // Main loop on stripes: lock a stripe and process all buckets in it
2966 for (bsl::size_t i = 0; i < d_numStripes; ++i) {
2967 locksGuard.lock(d_locks_p + i);
2968
2969 // Loop on the buckets of the current stripe. This is simple, as the
2970 // stripe is the last bits in a bucket index. We start with the
2971 // current stripe as the first bucket, and add 'd_numStripes' for the
2972 // next bucket, until 'd_numBuckets'.
2973 for (bsl::size_t j = i; j < d_numBuckets; j += d_numStripes) {
2975 d_buckets[j];
2976 // Process the nodes in the bucket. Note that we do not need to
2977 // delete the old node and allocate a new one, but can simply move
2978 // it.
2980 bucket.head(); curNode != NULL;) {
2982 curNode->next();
2983
2984 bsl::size_t newBucketIdx = bucketIndex(curNode->key(),
2985 numBuckets);
2986 curNode->setNext(NULL);
2987 newBuckets[newBucketIdx].addNode(curNode);
2988 curNode = nextPtr;
2989 }
2990 bucket.setHead(NULL);
2991 bucket.setTail(NULL);
2992 bucket.setSize(0);
2993 }
2994 }
2995 // Swap 'newBuckets' and 'd_buckets'. This requires the same allocator.
2996 d_buckets.swap(newBuckets);
2997
2998 // Update number of buckets.
2999 d_numBuckets = numBuckets;
3000}
3001
3002template <class KEY, class VALUE, class HASH, class EQUAL>
3003inline
3004int
3006 const KEY& key,
3007 const VisitorFunction& visitor)
3008{
3009 return setComputedValue(key, visitor, e_SCOPE_ALL);
3010}
3011
3012template <class KEY, class VALUE, class HASH, class EQUAL>
3013inline
3014int
3016 const KEY& key,
3017 const VisitorFunction& visitor)
3018{
3019 return setComputedValue(key, visitor, e_SCOPE_FIRST);
3020}
3021
3022template <class KEY, class VALUE, class HASH, class EQUAL>
3023inline
3024bsl::size_t
3026 const KEY& key,
3027 const VALUE& value)
3028{
3029 return setValue(key, value, e_SCOPE_ALL);
3030}
3031
3032template <class KEY, class VALUE, class HASH, class EQUAL>
3033inline
3034bsl::size_t
3036 const KEY& key,
3037 const VALUE& value)
3038{
3039 return setValue(key, value, e_SCOPE_FIRST);
3040}
3041
3042template <class KEY, class VALUE, class HASH, class EQUAL>
3043inline
3044bsl::size_t
3046 const KEY& key,
3048{
3049 bsl::size_t bucketIdx;
3050 LEWGuard guard(lockWrite(&bucketIdx, key));
3051
3053 d_buckets[bucketIdx];
3054
3055 bsl::size_t count = bucket.setValue(key,
3056 d_comparator,
3058 if (count == 0) {
3059 guard.release();
3060 d_numElements.addRelaxed(1);
3061 checkRehash();
3062 }
3063 return count;
3064}
3065
3066template <class KEY, class VALUE, class HASH, class EQUAL>
3067inline
3069 const KEY& key,
3070 const VisitorFunction& visitor)
3071{
3072 return visit(key, visitor);
3073}
3074
3075template <class KEY, class VALUE, class HASH, class EQUAL>
3077 const VisitorFunction& visitor)
3078{
3079 // Main loop on stripes: lock a stripe and process all buckets in it
3080 int count = 0;
3081 for (bsl::size_t i = 0; i < d_numStripes; ++i) {
3082 LockElement& lockElement = d_locks_p[i];
3083 lockElement.lockW();
3084 LEWGuard guard(&lockElement);
3085 // Loop on the buckets of the current stripe. This is simple, as the
3086 // stripe is the last bits in a bucket index. We start with the
3087 // current stripe as the first bucket, and add 'd_numStripes' for the
3088 // next bucket, until 'd_numBuckets'.
3089 for (bsl::size_t j = i; j < d_numBuckets; j += d_numStripes) {
3091 d_buckets[j];
3092 // Loop on the nodes in the bucket.
3094 bucket.head(); curNode != NULL;
3095 curNode = curNode->next()) {
3096 ++count;
3097 bool ret = visitor(&(curNode->value()), curNode->key());
3098 if (!ret) {
3099 return -count; // RETURN
3100 }
3101 }
3102 }
3103 }
3104 return count;
3105}
3106
3107template <class KEY, class VALUE, class HASH, class EQUAL>
3108inline
3110 const KEY& key,
3111 const VisitorFunction& visitor)
3112{
3113 bsl::size_t bucketIdx;
3114 LEWGuard guard(lockWrite(&bucketIdx, key));
3115
3117 d_buckets[bucketIdx];
3118
3119 // Loop on the elements in the list
3120 int count = 0;
3122 for (; curNode != NULL; curNode = curNode->next()) {
3123 if (d_comparator(curNode->key(), key)) {
3124 ++count;
3125 bool ret = visitor(&curNode->value(), key);
3126 if (ret == false) {
3127 return -count; // RETURN
3128 }
3129 }
3130 }
3131 return count;
3132}
3133
3134// ACCESSORS
3135template <class KEY, class VALUE, class HASH, class EQUAL>
3136inline
3137bsl::size_t
3142
3143template <class KEY, class VALUE, class HASH, class EQUAL>
3144inline
3145bsl::size_t
3147 const KEY& key) const
3148{
3149 return bucketIndex(key, d_numBuckets);
3150}
3151
3152template <class KEY, class VALUE, class HASH, class EQUAL>
3153inline
3155 bsl::size_t index) const
3156{
3157 BSLS_ASSERT(index < bucketCount());
3158
3159 return d_buckets[index].size();
3160}
3161
3162template <class KEY, class VALUE, class HASH, class EQUAL>
3163inline
3165{
3166 return d_state == k_REHASH_ENABLED;
3167}
3168
3169template <class KEY, class VALUE, class HASH, class EQUAL>
3170inline
3172{
3173 for (bsl::size_t i = 0; i < d_numBuckets; ++i) {
3174 if (!d_buckets[i].empty()) {
3175 return false; // RETURN
3176 }
3177 }
3178 return true;
3179}
3180
3181template <class KEY, class VALUE, class HASH, class EQUAL>
3182inline
3183EQUAL
3188
3189template <class KEY, class VALUE, class HASH, class EQUAL>
3190inline
3192 VALUE *value,
3193 const KEY& key) const
3194{
3195 BSLS_ASSERT(NULL != value);
3196
3197 bsl::size_t bucketIdx;
3198 LERGuard guard(lockRead(&bucketIdx, key));
3199
3200 const StripedUnorderedContainerImpl_Bucket<KEY, VALUE>& bucket = d_buckets[
3201 bucketIdx];
3202 // Loop on the elements in the list
3204 for (; curNode != NULL; curNode = curNode->next()) {
3205 if (d_comparator(curNode->key(), key)) {
3206 *value = curNode->value();
3207 return 1; // RETURN
3208 }
3209 }
3210 return 0;
3211}
3212
3213template <class KEY, class VALUE, class HASH, class EQUAL>
3214inline
3216 bsl::vector<VALUE> *valuesPtr,
3217 const KEY& key) const
3218{
3219 return getValueImpl(valuesPtr, key);
3220}
3221
3222template <class KEY, class VALUE, class HASH, class EQUAL>
3223inline
3225 std::vector<VALUE> *valuesPtr,
3226 const KEY& key) const
3227{
3228 return getValueImpl(valuesPtr, key);
3229}
3230
3231#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
3232template <class KEY, class VALUE, class HASH, class EQUAL>
3233inline
3235 std::pmr::vector<VALUE> *valuesPtr,
3236 const KEY& key) const
3237{
3238 return getValueImpl(valuesPtr, key);
3239}
3240#endif
3241
3242template <class KEY, class VALUE, class HASH, class EQUAL>
3243inline
3244HASH
3249
3250template <class KEY, class VALUE, class HASH, class EQUAL>
3251inline
3252bool
3254{
3255 return d_state & k_REHASH_ENABLED;
3256}
3257
3258template <class KEY, class VALUE, class HASH, class EQUAL>
3259inline
3260float
3262{
3263 return static_cast<float>(d_numElements.loadRelaxed()) /
3264 static_cast<float>(d_numBuckets);
3265}
3266
3267template <class KEY, class VALUE, class HASH, class EQUAL>
3268inline
3269float
3271{
3272 return d_maxLoadFactor;
3273}
3274
3275template <class KEY, class VALUE, class HASH, class EQUAL>
3276inline
3277bsl::size_t
3279{
3280 return static_cast<bsl::size_t>(d_numStripes);
3281}
3282
3283template <class KEY, class VALUE, class HASH, class EQUAL>
3285 const ReadOnlyVisitorFunction& visitor) const
3286{
3287 // Main loop on stripes: lock a stripe and process all buckets in it
3288 int count = 0;
3289 for (bsl::size_t i = 0; i < d_numStripes; ++i) {
3290 LockElement& lockElement = d_locks_p[i];
3291 lockElement.lockR();
3292 LERGuard guard(&lockElement);
3293 // Loop on the buckets of the current stripe. This is simple, as the
3294 // stripe is the last bits in a bucket index. We start with the
3295 // current stripe as the first bucket, and add 'd_numStripes' for the
3296 // next bucket, until 'd_numBuckets'.
3297 for (bsl::size_t j = i; j < d_numBuckets; j += d_numStripes) {
3299 d_buckets[j];
3300 // Loop on the nodes in the bucket.
3302 bucket.head(); curNode != NULL;
3303 curNode = curNode->next()) {
3304 ++count;
3305 bool ret = visitor(curNode->value(), curNode->key());
3306 if (!ret) {
3307 return -count; // RETURN
3308 }
3309 }
3310 }
3311 }
3312 return count;
3313}
3314
3315template <class KEY, class VALUE, class HASH, class EQUAL>
3316inline
3318 const KEY& key,
3319 const ReadOnlyVisitorFunction& visitor) const
3320{
3321 bsl::size_t bucketIdx;
3322 LERGuard guard(lockRead(&bucketIdx, key));
3323
3325 d_buckets[bucketIdx];
3326
3327 // Loop on the elements in the list
3328 int count = 0;
3330 for (; curNode != NULL; curNode = curNode->next()) {
3331 if (d_comparator(curNode->key(), key)) {
3332 ++count;
3333 bool ret = visitor(curNode->value(), key);
3334 if (ret == false) {
3335 return -count; // RETURN
3336 }
3337 }
3338 }
3339 return count;
3340}
3341
3342template <class KEY, class VALUE, class HASH, class EQUAL>
3343inline
3344bsl::size_t
3346{
3347 return d_numElements.loadRelaxed();
3348}
3349
3350 // Aspects
3351
3352template <class KEY, class VALUE, class HASH, class EQUAL>
3353inline
3356{
3357 return d_allocator_p;
3358}
3359
3360 // --------------------------------------------
3361 // class StripedUnorderedContainerImpl_TestUtil
3362 // --------------------------------------------
3363
3364// CREATORS
3365template <class KEY, class VALUE, class HASH, class EQUAL>
3366inline
3373
3374// MANIPULATORS
3375template <class KEY, class VALUE, class HASH, class EQUAL>
3376inline
3378 const KEY& key)
3379{
3380 bsl::size_t bucketIdx = d_hash.bucketIndex(key);
3381 bsl::size_t stripeIdx = d_hash.bucketToStripe(bucketIdx);
3382 LockElement& lockElement = d_hash.d_locks_p[stripeIdx];
3383 lockElement.lockR();
3384}
3385
3386template <class KEY, class VALUE, class HASH, class EQUAL>
3387inline
3389 lockWrite(const KEY& key)
3390{
3391 bsl::size_t bucketIdx = d_hash.bucketIndex(key);
3392 bsl::size_t stripeIdx = d_hash.bucketToStripe(bucketIdx);
3393 LockElement& lockElement = d_hash.d_locks_p[stripeIdx];
3394 lockElement.lockW();
3395}
3396
3397template <class KEY, class VALUE, class HASH, class EQUAL>
3398inline
3400 unlockRead(const KEY& key)
3401{
3402 bsl::size_t bucketIdx = d_hash.bucketIndex(key);
3403 bsl::size_t stripeIdx = d_hash.bucketToStripe(bucketIdx);
3404 LockElement& lockElement = d_hash.d_locks_p[stripeIdx];
3405 lockElement.unlockR();
3406}
3407
3408template <class KEY, class VALUE, class HASH, class EQUAL>
3409inline
3411 unlockWrite(const KEY& key)
3412{
3413 bsl::size_t bucketIdx = d_hash.bucketIndex(key);
3414 bsl::size_t stripeIdx = d_hash.bucketToStripe(bucketIdx);
3415 LockElement& lockElement = d_hash.d_locks_p[stripeIdx];
3416 lockElement.unlockW();
3417}
3418
3419} // close package namespace
3420
3421// FREE OPERATORS
3422inline
3423bool bdlcc::operator<(const StripedUnorderedContainerImpl_SortItem& lhs,
3424 const StripedUnorderedContainerImpl_SortItem& rhs)
3425{
3426 if (lhs.d_stripeIdx < rhs.d_stripeIdx) {
3427 return true; // RETURN
3428 }
3429 if (lhs.d_stripeIdx > rhs.d_stripeIdx) {
3430 return false; // RETURN
3431 }
3432 if (lhs.d_dataIdx < rhs.d_dataIdx) {
3433 return true; // RETURN
3434 }
3435 return false;
3436}
3437
3438namespace bslma {
3439
3440template <class KEY, class VALUE, class HASH, class EQUAL>
3441struct UsesBslmaAllocator<bdlcc::StripedUnorderedContainerImpl<KEY,
3442 VALUE,
3443 HASH,
3444 EQUAL> >
3445 : bsl::true_type {
3446};
3447
3448} // close namespace bslma
3449
3450
3451
3452#endif
3453
3454// ----------------------------------------------------------------------------
3455// Copyright 2020 Bloomberg Finance L.P.
3456//
3457// Licensed under the Apache License, Version 2.0 (the "License"); you may not
3458// use this file except in compliance with the License. You may obtain a copy
3459// of the License at
3460//
3461// http://www.apache.org/licenses/LICENSE-2.0
3462//
3463// Unless required by applicable law or agreed to in writing, software
3464// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
3465// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3466// License for the specific language governing permissions and limitations
3467// under the License.
3468// ----------------------------- END-OF-FILE ----------------------------------
3469
3470/** @} */
3471/** @} */
3472/** @} */
Definition bdlcc_stripedunorderedcontainerimpl.h:1516
~StripedUnorderedContainerImpl_ArrayOfLocksWriteGuard()
Definition bdlcc_stripedunorderedcontainerimpl.h:2130
StripedUnorderedContainerImpl_ArrayOfLocksWriteGuard(StripedUnorderedContainerImpl_LockElement *firstLock_p)
Definition bdlcc_stripedunorderedcontainerimpl.h:2120
void lock(StripedUnorderedContainerImpl_LockElement *lock_p)
Definition bdlcc_stripedunorderedcontainerimpl.h:2140
Definition bdlcc_stripedunorderedcontainerimpl.h:365
void addNode(StripedUnorderedContainerImpl_Node< KEY, VALUE > *nodePtr)
Add the specified nodePtr node at the end of this bucket.
Definition bdlcc_stripedunorderedcontainerimpl.h:1815
StripedUnorderedContainerImpl_Node< KEY, VALUE > * tail() const
Return address of the tail (node) of this bucket list.
Definition bdlcc_stripedunorderedcontainerimpl.h:2000
void setSize(bsl::size_t value)
Set the size attribute of this bucket to the specified value.
Definition bdlcc_stripedunorderedcontainerimpl.h:1873
void setHead(StripedUnorderedContainerImpl_Node< KEY, VALUE > *value)
Definition bdlcc_stripedunorderedcontainerimpl.h:1865
BucketScope
Definition bdlcc_stripedunorderedcontainerimpl.h:400
@ e_BUCKETSCOPE_FIRST
Definition bdlcc_stripedunorderedcontainerimpl.h:402
@ e_BUCKETSCOPE_ALL
Definition bdlcc_stripedunorderedcontainerimpl.h:403
~StripedUnorderedContainerImpl_Bucket()
Destroy this object.
Definition bdlcc_stripedunorderedcontainerimpl.h:1807
void setTail(StripedUnorderedContainerImpl_Node< KEY, VALUE > *value)
Definition bdlcc_stripedunorderedcontainerimpl.h:1881
BSLMF_NESTED_TRAIT_DECLARATION(StripedUnorderedContainerImpl_Bucket, bslma::UsesBslmaAllocator)
bsl::size_t size() const
Return the current number of elements in this bucket.
Definition bdlcc_stripedunorderedcontainerimpl.h:1992
StripedUnorderedContainerImpl_Node< KEY, VALUE > ** headAddress()
Return the address of the head (node) of this bucket list.
Definition bdlcc_stripedunorderedcontainerimpl.h:1850
void incrementSize(int amount)
Definition bdlcc_stripedunorderedcontainerimpl.h:1857
StripedUnorderedContainerImpl_Node< KEY, VALUE > * head() const
Return the head (node) of this bucket list.
Definition bdlcc_stripedunorderedcontainerimpl.h:1985
bslma::Allocator * allocator() const
Definition bdlcc_stripedunorderedcontainerimpl.h:2009
bsl::size_t setValue(const KEY &key, const EQUAL &equal, const VALUE &value, BucketScope scope)
Definition bdlcc_stripedunorderedcontainerimpl.h:1889
bool empty() const
Definition bdlcc_stripedunorderedcontainerimpl.h:1977
void clear()
Empty StripedUnorderedContainerImpl_Bucket and delete all nodes.
Definition bdlcc_stripedunorderedcontainerimpl.h:1832
Definition bdlcc_stripedunorderedcontainerimpl.h:1446
StripedUnorderedContainerImpl_LockElementReadGuard(StripedUnorderedContainerImpl_LockElement *lockElementPtr)
Definition bdlcc_stripedunorderedcontainerimpl.h:2060
~StripedUnorderedContainerImpl_LockElementReadGuard()
Release the guarded object.
Definition bdlcc_stripedunorderedcontainerimpl.h:2069
void release()
Release the guarded object.
Definition bdlcc_stripedunorderedcontainerimpl.h:2075
Definition bdlcc_stripedunorderedcontainerimpl.h:1481
~StripedUnorderedContainerImpl_LockElementWriteGuard()
Release the guarded object.
Definition bdlcc_stripedunorderedcontainerimpl.h:2099
StripedUnorderedContainerImpl_LockElementWriteGuard(StripedUnorderedContainerImpl_LockElement *lockElementPtr)
Definition bdlcc_stripedunorderedcontainerimpl.h:2090
void release()
Release the guarded object.
Definition bdlcc_stripedunorderedcontainerimpl.h:2105
Definition bdlcc_stripedunorderedcontainerimpl.h:1390
void lockR()
Read lock the lock element.
Definition bdlcc_stripedunorderedcontainerimpl.h:2030
void unlockW()
Write unlock the lock element.
Definition bdlcc_stripedunorderedcontainerimpl.h:2048
void unlockR()
Read unlock the lock element.
Definition bdlcc_stripedunorderedcontainerimpl.h:2042
StripedUnorderedContainerImpl_LockElement()
Create an empty StripedUnorderedContainerImpl_LockElement object.
Definition bdlcc_stripedunorderedcontainerimpl.h:2022
void lockW()
Write lock the lock element.
Definition bdlcc_stripedunorderedcontainerimpl.h:2036
Definition bdlcc_stripedunorderedcontainerimpl.h:266
~StripedUnorderedContainerImpl_Node()
Destroy this object.
Definition bdlcc_stripedunorderedcontainerimpl.h:1705
bslma::Allocator * allocator() const
Definition bdlcc_stripedunorderedcontainerimpl.h:1765
const KEY & key() const
Return a const reference to the key attribute of this object.
Definition bdlcc_stripedunorderedcontainerimpl.h:1740
void setNext(StripedUnorderedContainerImpl_Node *nextPtr)
Set this node's pointer-to-next-node to the specified nextPtr.
Definition bdlcc_stripedunorderedcontainerimpl.h:1724
StripedUnorderedContainerImpl_Node ** nextAddress()
Return the address of the pointer to the next node.
Definition bdlcc_stripedunorderedcontainerimpl.h:1717
StripedUnorderedContainerImpl_Node * next() const
Return the pointer to the next node.
Definition bdlcc_stripedunorderedcontainerimpl.h:1748
VALUE & value()
Definition bdlcc_stripedunorderedcontainerimpl.h:1732
Definition bdlcc_stripedunorderedcontainerimpl.h:222
bool holdsLock() const
Returns true if the constructor successfully set the rehash bit.
Definition bdlcc_stripedunorderedcontainerimpl.h:1613
~StripedUnorderedContainerImpl_RehashBitSetGuard()
Definition bdlcc_stripedunorderedcontainerimpl.h:1591
StripedUnorderedContainerImpl_RehashBitSetGuard(bsls::AtomicInt *state_p)
Definition bdlcc_stripedunorderedcontainerimpl.h:1583
Definition bdlcc_stripedunorderedcontainerimpl.h:1342
void unlockRead(const KEY &key)
Definition bdlcc_stripedunorderedcontainerimpl.h:3400
void lockWrite(const KEY &key)
Definition bdlcc_stripedunorderedcontainerimpl.h:3389
void lockRead(const KEY &key)
Definition bdlcc_stripedunorderedcontainerimpl.h:3377
void unlockWrite(const KEY &key)
Definition bdlcc_stripedunorderedcontainerimpl.h:3411
StripedUnorderedContainerImpl_TestUtil(StripedUnorderedContainerImpl< KEY, VALUE, HASH, EQUAL > &hash)
Definition bdlcc_stripedunorderedcontainerimpl.h:3368
Definition bdlcc_stripedunorderedcontainerimpl.h:542
bsl::size_t getValue(VALUE *value, const KEY &key) const
Definition bdlcc_stripedunorderedcontainerimpl.h:3191
bsl::size_t bucketSize(bsl::size_t index) const
Definition bdlcc_stripedunorderedcontainerimpl.h:3154
bool empty() const
Definition bdlcc_stripedunorderedcontainerimpl.h:3171
StripedUnorderedContainerImpl_Node< KEY, VALUE > Node
Node in a bucket.
Definition bdlcc_stripedunorderedcontainerimpl.h:552
float loadFactor() const
Definition bdlcc_stripedunorderedcontainerimpl.h:3261
bsl::size_t setValueFirst(const KEY &key, bslmf::MovableRef< VALUE > value)
Definition bdlcc_stripedunorderedcontainerimpl.h:3045
int update(const KEY &key, const VisitorFunction &visitor)
Definition bdlcc_stripedunorderedcontainerimpl.h:3068
int visitReadOnly(const KEY &key, const ReadOnlyVisitorFunction &visitor) const
Definition bdlcc_stripedunorderedcontainerimpl.h:3317
float maxLoadFactor() const
Definition bdlcc_stripedunorderedcontainerimpl.h:3270
bsl::size_t insertUnique(const KEY &key, bslmf::MovableRef< VALUE > value)
Definition bdlcc_stripedunorderedcontainerimpl.h:2925
bsl::size_t setValueFirst(const KEY &key, const VALUE &value)
Definition bdlcc_stripedunorderedcontainerimpl.h:3035
bsl::size_t numStripes() const
Return the number of stripes in the hash.
Definition bdlcc_stripedunorderedcontainerimpl.h:3278
HASH hashFunction() const
Definition bdlcc_stripedunorderedcontainerimpl.h:3245
bsl::function< bool(VALUE *, const KEY &)> VisitorFunction
Definition bdlcc_stripedunorderedcontainerimpl.h:567
bsl::size_t bucketIndex(const KEY &key) const
Definition bdlcc_stripedunorderedcontainerimpl.h:3146
bsl::size_t insertBulkUnique(RANDOM_ITER first, RANDOM_ITER last)
Definition bdlcc_stripedunorderedcontainerimpl.h:2903
void rehash(bsl::size_t numBuckets)
Definition bdlcc_stripedunorderedcontainerimpl.h:2933
bsl::size_t insertUnique(const KEY &key, const VALUE &value)
Definition bdlcc_stripedunorderedcontainerimpl.h:2915
bsl::pair< KEY, VALUE > KVType
Value type of a bulk insert entry.
Definition bdlcc_stripedunorderedcontainerimpl.h:555
int visit(const KEY &key, const VisitorFunction &visitor)
Definition bdlcc_stripedunorderedcontainerimpl.h:3109
StripedUnorderedContainerImpl(StripedUnorderedContainerImplMaxLoadFactorFlag, float maxLoadFactor=1.0, bsl::size_t numInitialBuckets=k_DEFAULT_NUM_BUCKETS, bsl::size_t numStripes=k_DEFAULT_NUM_STRIPES, bslma::Allocator *basicAllocator=0)
Definition bdlcc_stripedunorderedcontainerimpl.h:2696
void disableRehash()
Prevent rehash until the enableRehash method is called.
Definition bdlcc_stripedunorderedcontainerimpl.h:2784
bool isRehashEnabled() const
Return true if rehash is enabled, or false otherwise.
Definition bdlcc_stripedunorderedcontainerimpl.h:3253
bsl::size_t eraseFirstIf(const KEY &key, const EraseIfValuePredicate &predicate)
Definition bdlcc_stripedunorderedcontainerimpl.h:2862
StripedUnorderedContainerImpl(bsl::size_t numInitialBuckets=k_DEFAULT_NUM_BUCKETS, bsl::size_t numStripes=k_DEFAULT_NUM_STRIPES, bslma::Allocator *basicAllocator=0)
Definition bdlcc_stripedunorderedcontainerimpl.h:2727
void clear()
Definition bdlcc_stripedunorderedcontainerimpl.h:2767
void insertBulkAlways(RANDOM_ITER first, RANDOM_ITER last)
Definition bdlcc_stripedunorderedcontainerimpl.h:2890
bsl::size_t size() const
Return the current number of elements in this hash.
Definition bdlcc_stripedunorderedcontainerimpl.h:3345
bsl::size_t eraseFirst(const KEY &key)
Definition bdlcc_stripedunorderedcontainerimpl.h:2853
bsl::size_t eraseBulkFirst(RANDOM_ITER first, RANDOM_ITER last)
Definition bdlcc_stripedunorderedcontainerimpl.h:2842
void insertAlways(const KEY &key, bslmf::MovableRef< VALUE > value)
Definition bdlcc_stripedunorderedcontainerimpl.h:2880
~StripedUnorderedContainerImpl()
Destroy this hash map. This method is not thread-safe.
Definition bdlcc_stripedunorderedcontainerimpl.h:2756
bsl::size_t setValueAll(const KEY &key, const VALUE &value)
Definition bdlcc_stripedunorderedcontainerimpl.h:3025
void insertAlways(const KEY &key, const VALUE &value)
Definition bdlcc_stripedunorderedcontainerimpl.h:2871
bslma::Allocator * allocator() const
Definition bdlcc_stripedunorderedcontainerimpl.h:3355
int visitReadOnly(const ReadOnlyVisitorFunction &visitor) const
Definition bdlcc_stripedunorderedcontainerimpl.h:3284
int setComputedValueAll(const KEY &key, const VisitorFunction &visitor)
Definition bdlcc_stripedunorderedcontainerimpl.h:3005
bsl::function< bool(const VALUE &)> EraseIfValuePredicate
Definition bdlcc_stripedunorderedcontainerimpl.h:591
void enableRehash()
Definition bdlcc_stripedunorderedcontainerimpl.h:2797
bool canRehash() const
Definition bdlcc_stripedunorderedcontainerimpl.h:3164
bsl::size_t eraseAllIf(const KEY &key, const EraseIfValuePredicate &predicate)
Definition bdlcc_stripedunorderedcontainerimpl.h:2818
friend class StripedUnorderedContainerImpl_LockElement
Definition bdlcc_stripedunorderedcontainerimpl.h:690
bsl::size_t eraseBulkAll(RANDOM_ITER first, RANDOM_ITER last)
Definition bdlcc_stripedunorderedcontainerimpl.h:2829
int setComputedValueFirst(const KEY &key, const VisitorFunction &visitor)
Definition bdlcc_stripedunorderedcontainerimpl.h:3015
bsl::function< bool(const VALUE &, const KEY &)> ReadOnlyVisitorFunction
Definition bdlcc_stripedunorderedcontainerimpl.h:581
bsl::size_t bucketCount() const
Definition bdlcc_stripedunorderedcontainerimpl.h:3138
bsl::size_t getValue(std::vector< VALUE > *valuesPtr, const KEY &key) const
Definition bdlcc_stripedunorderedcontainerimpl.h:3224
@ k_DEFAULT_NUM_STRIPES
Definition bdlcc_stripedunorderedcontainerimpl.h:548
@ k_DEFAULT_NUM_BUCKETS
Definition bdlcc_stripedunorderedcontainerimpl.h:547
EQUAL equalFunction() const
Definition bdlcc_stripedunorderedcontainerimpl.h:3184
bsl::size_t getValue(bsl::vector< VALUE > *valuesPtr, const KEY &key) const
Definition bdlcc_stripedunorderedcontainerimpl.h:3215
int visit(const VisitorFunction &visitor)
Definition bdlcc_stripedunorderedcontainerimpl.h:3076
bsl::size_t eraseAll(const KEY &key)
Definition bdlcc_stripedunorderedcontainerimpl.h:2810
Forward declaration.
Definition bslstl_function.h:946
Definition bslstl_pair.h:1280
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
virtual void * allocate(size_type size)=0
Definition bslma_destructorproctor.h:259
void release()
Definition bslma_destructorproctor.h:328
Definition bslma_rawdeleterproctor.h:242
Definition bslmf_movableref.h:752
Definition bslmt_readerwritermutex.h:244
void unlockRead()
Definition bslmt_readerwritermutex.h:380
void unlockWrite()
Definition bslmt_readerwritermutex.h:386
void lockRead()
Definition bslmt_readerwritermutex.h:350
void lockWrite()
Definition bslmt_readerwritermutex.h:356
Definition bsls_atomic.h:744
int testAndSwap(int compareValue, int swapValue)
Definition bsls_atomic.h:1723
Definition bsls_atomic.h:1205
Definition bsls_atomic.h:1050
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlcc_boundedqueue.h:270
bool operator<(const StripedUnorderedContainerImpl_SortItem &lhs, const StripedUnorderedContainerImpl_SortItem &rhs)
ALLOCATOR const STRING_VIEW_LIKE_TYPE & rhs
Definition bslstl_string.h:3918
ALLOCATOR & lhs
Definition bslstl_string.h:3917
Definition baljsn_encoder_testtypes.h:76
Definition bdlcc_stripedunorderedcontainerimpl.h:532
Definition bdlcc_stripedunorderedcontainerimpl.h:208
static const int k_REHASH_IN_PROGRESS
Definition bdlcc_stripedunorderedcontainerimpl.h:210
static const int k_REHASH_ENABLED
Definition bdlcc_stripedunorderedcontainerimpl.h:211
Definition bdlcc_stripedunorderedcontainerimpl.h:1557
int d_stripeIdx
Definition bdlcc_stripedunorderedcontainerimpl.h:1560
int d_dataIdx
Definition bdlcc_stripedunorderedcontainerimpl.h:1561
bsl::size_t d_hashVal
Definition bdlcc_stripedunorderedcontainerimpl.h:1562
Definition bslstl_equalto.h:316
Definition bslstl_hash.h:495
Definition bslmf_issame.h:146
static std::size_t computeBucketIndex(std::size_t hashCode, std::size_t numBuckets)
Definition bslalg_hashtableimputil.h:858
static void moveConstruct(TARGET_TYPE *address, TARGET_TYPE &original, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1660
static void construct(TARGET_TYPE *address, const ALLOCATOR &allocator)
Definition bslma_constructionutil.h:1244
static Allocator * defaultAllocator()
Definition bslma_default.h:905
Definition bslma_usesbslmaallocator.h:344
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
@ e_CACHE_LINE_SIZE
Definition bslmt_platform.h:214
Definition bsls_objectbuffer.h:277
TYPE * address()
Definition bsls_objectbuffer.h:335
TYPE & object()
Definition bsls_objectbuffer.h:352