BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlc_flathashtable.h
Go to the documentation of this file.
1/// @file bdlc_flathashtable.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlc_flathashtable.h -*-C++-*-
8#ifndef INCLUDED_BDLC_FLATHASHTABLE
9#define INCLUDED_BDLC_FLATHASHTABLE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlc_flathashtable bdlc_flathashtable
15/// @brief Provide an open-addressed hash table like Abseil `flat_hash_map`.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlc
19/// @{
20/// @addtogroup bdlc_flathashtable
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlc_flathashtable-purpose"> Purpose</a>
25/// * <a href="#bdlc_flathashtable-classes"> Classes </a>
26/// * <a href="#bdlc_flathashtable-description"> Description </a>
27/// * <a href="#bdlc_flathashtable-load-factor-and-resizing"> Load Factor and Resizing </a>
28/// * <a href="#bdlc_flathashtable-requirements-on-key-entry-entry_util-hash-and-equal"> Requirements on KEY, ENTRY, ENTRY_UTIL, HASH, and EQUAL </a>
29/// * <a href="#bdlc_flathashtable-iterator-pointer-and-reference-invalidation"> Iterator, Pointer, and Reference Invalidation </a>
30/// * <a href="#bdlc_flathashtable-exception-safety"> Exception Safety </a>
31/// * <a href="#bdlc_flathashtable-move-semantics-in-c-03"> Move Semantics in C++03 </a>
32/// * <a href="#bdlc_flathashtable-usage"> Usage </a>
33///
34/// # Purpose {#bdlc_flathashtable-purpose}
35/// Provide an open-addressed hash table like Abseil @ref flat_hash_map .
36///
37/// # Classes {#bdlc_flathashtable-classes}
38///
39/// - bdlc::FlatHashTable: open-addressed hash table like Abseil @ref flat_hash_map
40///
41/// @see bdlc_flathashmap, bdlc_flathashset
42///
43/// # Description {#bdlc_flathashtable-description}
44/// This component provides the class template
45/// `bdlc::FlatHashTable`, which forms the underlying implementation of
46/// `bdlc::FlatHashMap` and `bdlc::FlatHashSet`. It is based on the Abseil
47/// implementation of @ref flat_hash_map . The data structure is an open-addressed
48/// hash table. (In "open addressing", entries are kept in an array, the hash
49/// value of an entry points to its possible initial location, and searches for
50/// an entry proceed by stepping to other positions in the table. This differs
51/// from "separate chaining", in which the hash value is used to locate a
52/// "bucket" of entries that all have the same hash value.)
53///
54/// This version differs from typical open-addressing schemes in that it uses an
55/// array of bytes parallel to the array of entries to hold hashlets (for this
56/// implementation, the seven lowest-order bits of the hash) of used entries or
57/// indicators of unused (empty or erased) entries. This hashlet array permits
58/// use of platform-specific instructions to optimize various methods (e.g.,
59/// through use of SSE instructions).
60///
61/// The implemented data structure is inspired by Google's @ref flat_hash_map
62/// CppCon presentations (available on YouTube). The implementation draws from
63/// Google's open source `raw_hash_set.h` file at:
64/// https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal.
65///
66/// ## Load Factor and Resizing {#bdlc_flathashtable-load-factor-and-resizing}
67///
68///
69/// An invariant of `bdlc::FlatHashTable` is that
70/// `0 <= load_factor() <= max_load_factor() <= 1.0`. Any operation that would
71/// result in `load_factor() > max_load_factor()` for a `bdlc::FlatHashTable`
72/// instance causes the capacity to increase. This resizing allocates new
73/// memory, copies or moves all elements to the new memory, and reclaims the
74/// original memory. The transfer of elements involves rehashing the element to
75/// determine its new location. As such, all iterators, pointers, and
76/// references to elements of the `bdlc::FlatHashTable` are invalidated.
77///
78/// Note that the value returned by @ref max_load_factor is implementation
79/// dependent and cannot be changed by the user.
80///
81/// ## Requirements on KEY, ENTRY, ENTRY_UTIL, HASH, and EQUAL {#bdlc_flathashtable-requirements-on-key-entry-entry_util-hash-and-equal}
82///
83///
84/// The template parameter type `ENTRY` must be copy or move constructible. The
85/// template parameter types `HASH` and `EQUAL` must be default and copy
86/// constructible function objects.
87///
88/// `ENTRY_UTIL` must support static methods `constructFromKey`, `construct`,
89/// and `key` compatible with the following statements for objects `entry` of
90/// type `ENTRY`, `key` of type `KEY`, and `allocator` of type
91/// `bslma::Allocator`:
92/// @code
93/// ENTRY_UTIL::constructFromKey(&entry, &allocator, key);
94/// ENTRY_UTIL::construct(&entry, &allocator, args...);
95/// const KEY& keyOfEntry = ENTRY_UTIL::key(entry);
96/// @endcode
97///
98/// `HASH` must support a function call operator compatible with the following
99/// statements for an object `key` of type `KEY`:
100/// @code
101/// HASH hash;
102/// bsl::size_t result = hash(key);
103/// @endcode
104///
105/// `EQUAL` must support a function call operator compatible with the
106/// following statements for objects `key1` and `key2` of type `KEY`:
107/// @code
108/// EQUAL equal;
109/// bool result = equal(key1, key2);
110/// @endcode
111/// where the definition of the called function defines an equivalence
112/// relationship on keys that is both reflexive and transitive.
113///
114/// `HASH` and `EQUAL` function-objects are further constrained; if the
115/// comparator claims that two values are equal, the hasher must produce the
116/// same hash value for each.
117///
118/// If support for `operator==` is required, the type `ENTRY` must be
119/// equality-comparable.
120///
121/// ## Iterator, Pointer, and Reference Invalidation {#bdlc_flathashtable-iterator-pointer-and-reference-invalidation}
122///
123///
124/// Any change in capacity of a `bdlc::FlatHashTable` invalidates all pointers,
125/// references, and iterators. A `bdlc::FlatHashTable` manipulator that erases
126/// an element invalidates all pointers, references, and iterators to the erased
127/// elements.
128///
129/// ## Exception Safety {#bdlc_flathashtable-exception-safety}
130///
131///
132/// A `bdlc::FlatHashTable` is exception neutral, and all of the methods of
133/// `bdlc::FlatHashTable` provide the basic exception safety guarantee (see
134/// {@ref bsldoc_glossary |Basic Guarantee}).
135///
136/// ## Move Semantics in C++03 {#bdlc_flathashtable-move-semantics-in-c-03}
137///
138///
139/// Move-only types are supported by `bdlc::FlatHashTable` on C++11, and later,
140/// platforms only (where `BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES` is defined),
141/// and are not supported on C++03 platforms. Unfortunately, in C++03, there
142/// are user types where a `bslmf::MovableRef` will not safely degrade to a
143/// lvalue reference when a move constructor is not available (types providing a
144/// constructor template taking any type), so `bslmf::MovableRefUtil::move`
145/// cannot be used directly on a user supplied template type. See internal bug
146/// report 99039150 for more information.
147///
148/// ## Usage {#bdlc_flathashtable-usage}
149///
150///
151/// There is no usage example for this component since it is not meant for
152/// direct client use.
153/// @}
154/** @} */
155/** @} */
156
157/** @addtogroup bdl
158 * @{
159 */
160/** @addtogroup bdlc
161 * @{
162 */
163/** @addtogroup bdlc_flathashtable
164 * @{
165 */
166
167#include <bdlscm_version.h>
168
170
171#include <bdlb_bitutil.h>
172
174#include <bslalg_swaputil.h>
175
176#include <bslma_allocator.h>
178#include <bslma_default.h>
182
183#include <bslmf_assert.h>
184#include <bslmf_enableif.h>
187#include <bslmf_isconvertible.h>
189#include <bslmf_movableref.h>
190#include <bslmf_util.h> // 'forward(V)'
191
192#include <bsls_assert.h>
194#include <bsls_keyword.h>
195#include <bsls_objectbuffer.h>
196#include <bsls_performancehint.h>
197#include <bsls_platform.h>
198#include <bsls_types.h>
199#include <bsls_util.h> // 'forward<T>(V)'
200
201#include <bsl_cstddef.h>
202#include <bsl_cstdint.h>
203#include <bsl_cstring.h>
204#include <bsl_iterator.h>
205#include <bsl_limits.h>
206#include <bsl_type_traits.h>
207#include <bsl_utility.h>
208
209#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
210// clang-format off
211// Include version that can be compiled with C++03
212// Generated on Mon Jan 13 08:32:17 2025
213// Command line: sim_cpp11_features.pl bdlc_flathashtable.h
214
215# define COMPILING_BDLC_FLATHASHTABLE_H
217# undef COMPILING_BDLC_FLATHASHTABLE_H
218
219// clang-format on
220#else
221
222
223namespace bdlc {
224
225// FORWARD DECLARATIONS
226struct FlatHashTable_ImplUtil;
227
228template <class ENTRY>
229class FlatHashTable_IteratorImp;
230
231template <class ENTRY>
232bool operator==(const class FlatHashTable_IteratorImp<ENTRY>&,
234
235 // ===============================
236 // class FlatHashTable_IteratorImp
237 // ===============================
238
239/// This class implements the methods required by `bsl::ForwardIterator` to
240/// provide forward iterators. As such, an instance of this class
241/// represents a position within a flat hash table. This class uses no
242/// features of the `ENTRY` type except for addresses of `ENTRY` objects.
243template <class ENTRY>
245{
246 // PRIVATE TYPES
248
249 // DATA
250 ENTRY *d_entries_p;
251 const bsl::uint8_t *d_controls_p;
252 bsl::size_t d_additionalLength;
253
254 // FRIENDS
255 friend bool operator==<>(const FlatHashTable_IteratorImp&,
257
258 public:
259 // CREATORS
260
261 /// Create a `FlatHashTable_IteratorImp` having the default,
262 /// non-dereferencable value.
264
265 /// Create a `FlatHashTable_IteratorImp` referencing the first element
266 /// of the specified `entries` and `controls`, which have the specified `additionalLength` values.
267 ///
268 /// \pre The behavior is undefined unless
269 /// `entries` points to at least `1 + additionalLength` entry values and
270 /// `controls` points to at least
271 /// `1 + additionalLength + ControlGroup::k_SIZE` control values.
272 FlatHashTable_IteratorImp(ENTRY *entries,
273 const bsl::uint8_t *controls,
274 bsl::size_t additionalLength);
275
276 /// Create a `FlatHashTable_IteratorImp` having the same value as the
277 /// specified `original`.
279
281 // Destroy this object.
282
283 // MANIPULATORS
284
285 /// Assign to this `FlatHashTable_IteratorImp` the value of the
286 /// specified `rhs`.
288
289 /// Advance the `FlatHashTable_IteratorImp` to the next present element
290 /// in the underlying flat hash table. If there is no such element,
291 /// assign this object to `FlatHashTable_InteratorImp()`.
292 ///
293 /// \pre The behavior is undefined unless this `FlatHashTable_IteratorImp` refers to a
294 /// valid element of the underlying sequence.
295 void operator++();
296
297 // ACCESSORS
298
299 /// Return a reference to the element referred to by this `FlatHashTable_IteratorImp`.
300 ///
301 /// \pre The behavior is undefined unless this
302 /// `FlatHashTable_IteratorImp() != *this`.
303 ENTRY& operator*() const;
304};
305
306// FREE OPERATORS
307
308/// Return true if the specified `a` and `b` are equal. Two
309/// `FlatHashTable_IteratorImp` objects are equal if they both refer to the
310/// same element of the underlying flat hash table, or are both not dereferenceable.
311///
312/// \pre The behavior is undefined unless `a` and `b` refer to
313/// the same `FlatHashTable`.
314template <class ENTRY>
315bool operator==(const FlatHashTable_IteratorImp<ENTRY>& a,
317
318 // ===================
319 // class FlatHashTable
320 // ===================
321
322/// This class template provides a flat hash table implementation useful for
323/// implementing a flat hash set and flat hash map.
324template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
326{
327 // PRIVATE TYPES
330 typedef FlatHashTable_IteratorImp<ENTRY> IteratorImp;
331
332 public:
333 // TYPES
334 typedef KEY key_type;
335 typedef ENTRY entry_type;
336 typedef ENTRY_UTIL entry_util_type;
337 typedef HASH hash_type;
338 typedef EQUAL key_equal_type;
339
340 typedef typename bslstl::ForwardIterator<ENTRY,
341 IteratorImp> iterator;
342 typedef typename bslstl::ForwardIterator<const ENTRY,
343 IteratorImp> const_iterator;
344
345 private:
346 // DATA
347 ENTRY *d_entries_p; // entries of this table
348 bsl::uint8_t *d_controls_p; // control values of this table
349 bsl::size_t d_size; // number of active values
350 bsl::size_t d_capacity; // size of values array
351 int d_groupControlShift; // number of bits to shift hash
352 HASH d_hasher; // hashing functor
353 EQUAL d_equal; // equality functor
354 bslma::Allocator *d_allocator_p; // allocator
355
356 // PRIVATE CLASS METHODS
357
358 /// Return the index of the first available entry indicated by the
359 /// specified `controls` at or after the specified `index`, assuming
360 /// `controls` has the specified `capacity`.
361 ///
362 /// \pre The behavior is undefined unless `index < capacity` and `controls` has at least `capacity`
363 /// entries.
364 static bsl::size_t findAvailable(bsl::uint8_t *controls,
365 bsl::size_t index,
366 bsl::size_t capacity);
367
368 // PRIVATE MANIPULATORS
369
370 /// Load `true` into the specified `notFound` if there is no entry in
371 /// this table having the specified `key` with the specified
372 /// `hashValue`, and `false` otherwise. Return the index of the entry
373 /// within `d_entries_p` which contains the `key` if such an entry
374 /// exists, otherwise insert an entry with value obtained from
375 /// `ENTRY_UTIL::construct` and return the index of this entry. This
376 /// method rehashes the table if the `key` was not present and the
377 /// addition of an entry would cause the load factor to exceed `max_load_factor()`.
378 ///
379 /// \pre The behavior is undefined unless
380 /// `hashValue == d_hasher(key)`.
381 bsl::size_t indexOfKey(bool *notFound,
382 const KEY& key,
383 bsl::size_t hashValue);
384
385 /// Load `true` into the specified `notFound` if there is no entry in
386 /// this table equvalent to the specified `key` with the specified
387 /// `hashValue`, and `false` otherwise. Return the index of the entry
388 /// within `d_entries_p` which contains the `key` if such an entry
389 /// exists, otherwise insert an entry with value obtained from
390 /// `ENTRY_UTIL::construct` and return the index of this entry. This
391 /// method rehashes the table if the `key` was not present and the
392 /// addition of an entry would cause the load factor to exceed `max_load_factor()`.
393 ///
394 /// \pre The behavior is undefined unless
395 /// `hashValue == d_hasher(key)`.
396 template <class LOOKUP_KEY>
397 typename bsl::enable_if<
398 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
399 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
400 , bsl::size_t>::type
401 indexOfKeyTransparent(bool *notFound,
402 const LOOKUP_KEY& key,
403 bsl::size_t hashValue)
404 {
405 BSLS_ASSERT_SAFE(hashValue == d_hasher(key));
406
407 bsl::size_t index = findTransparentKey(key, hashValue);
408
409 if (index == d_capacity) {
410 *notFound = true;
411
412 if (d_size >= k_MAX_LOAD_FACTOR_NUMERATOR
413 * (d_capacity / k_MAX_LOAD_FACTOR_DENOMINATOR)) {
414 rehashRaw(d_capacity > 0 ? 2 * d_capacity : k_MIN_CAPACITY);
415 }
416
417 index = (hashValue >> d_groupControlShift) * GroupControl::k_SIZE;
418 index = findAvailable(d_controls_p, index, d_capacity);
419 }
420 else {
421 *notFound = false;
422 }
423
424 return index;
425 }
426
427 /// Change the capacity of this table to the specified `newCapacity`,
428 /// and redistribute all the contained elements into the new sequence of
429 /// entries, according to their hash values.
430 ///
431 /// \pre The behavior is undefined unless `0 < newCapacity` and `newCapacity` satisfies all class
432 /// invariants.
433 void rehashRaw(bsl::size_t newCapacity);
434
435 // PRIVATE ACCESSORS
436
437 /// Return the index of the entry within `d_entries_p` containing the
438 /// specified `key`, which has the specified `hashValue`, or
439 /// `d_capacity` if the `key` is not present.
440 ///
441 /// \pre The behavior is undefined unless `hashValue == d_hasher(key)`.
442 bsl::size_t findKey(const KEY& key, bsl::size_t hashValue) const;
443
444 /// Return the index of the entry within `d_entries_p` containing a key
445 /// equivalent to the specified `key`, which has the specified `hashValue`,
446 /// or `d_capacity` if a key equivalent to `key` is not present.
447 ///
448 /// \pre The behavior is undefined unless `hashValue == d_hasher(key)`.
449 template <class LOOKUP_KEY>
450 typename bsl::enable_if<
451 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
452 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
453 , bsl::size_t>::type
454 findTransparentKey(const LOOKUP_KEY& key, bsl::size_t hashValue) const
455 {
456 // Note: implemented inline due to Sun CC compilation error.
457
458 BSLS_ASSERT_SAFE(hashValue == d_hasher(key));
459
460 bsl::size_t index = (hashValue >> d_groupControlShift)
462 bsl::uint8_t hashlet = static_cast<bsl::uint8_t>(
463 hashValue & k_HASHLET_MASK);
464
465 for (bsl::size_t i = 0; i < d_capacity; i += GroupControl::k_SIZE) {
466 bsl::uint8_t *controlStart = d_controls_p + index;
467 ENTRY *entryStart = d_entries_p + index;
468
469 GroupControl groupControl(controlStart);
470 bsl::uint32_t candidates = groupControl.match(hashlet);
471 while (candidates) {
472 int offset = bdlb::BitUtil::numTrailingUnsetBits(candidates);
473
474 ENTRY *entry = entryStart + offset;
475
477 d_equal(ENTRY_UTIL::key(*entry), key))) {
478 return index + offset; // RETURN
479 }
480 candidates = bdlb::BitUtil::withBitCleared(candidates, offset);
481 }
482 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(groupControl.neverFull()))
483 {
484 break;
485 }
486
487 index = (index + GroupControl::k_SIZE) & (d_capacity - 1);
488 }
489
490 return d_capacity;
491 }
492
493 /// Return the minimum capacity that satisfies all class invariants, and
494 /// is at least the specified `minimumCapacity`.
495 bsl::size_t minimumCompliantCapacity(bsl::size_t minimumCapacity) const;
496
497 private:
498 // NOT IMPLEMENTED
499 FlatHashTable();
500
501 public:
502 // PUBLIC CLASS DATA
503 static const bsl::size_t k_MIN_CAPACITY = 2 * GroupControl::k_SIZE;
504 // min. non-zero capacity
505
506 static const bsl::int8_t k_HASHLET_MASK = 0x7f; // hashlet = hash & MASK
507
508 static const bsl::size_t k_MAX_LOAD_FACTOR_NUMERATOR = 7;
509 // numerator of fraction
510 // that specifies the
511 // maximum load factor
512
513 static const bsl::size_t k_MAX_LOAD_FACTOR_DENOMINATOR = 8;
514 // denominator of
515 // fraction that
516 // specifies the maximum
517 // load factor
518
519 // CREATORS
520
521 /// Create an empty table having at least the specified `capacity`, that
522 /// will use the specified `hash` to generate hash values for the keys
523 /// of the entries contained in this table, and the specified `equal` to
524 /// verify that the keys of the two entries are the same. Optionally
525 /// specify a `basicAllocator` used to supply memory. If
526 /// `basicAllocator` is 0, the currently installed default allocator is
527 /// used. If `0 == capacity`, no memory is allocated and the object is
528 /// defined to be in the "zero-capacity" state.
530 const HASH& hash,
531 const EQUAL& equal,
532 bslma::Allocator *basicAllocator = 0);
533
534 /// Create a table having the same value, hasher, and key-equality
535 /// comparator as the specified `original`. Optionally specify a
536 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
537 /// the currently installed default allocator is used.
539 bslma::Allocator *basicAllocator = 0);
540
541 /// Create an table having the same value as the specified `original`
542 /// object by moving (in constant time) the contents of `original` to
543 /// the new table. Use a copy of `original.hash_function()` to generate
544 /// hash values for the keys of the entries contained in this table.
545 /// Use a copy of `original.key_eq()` to verify that two keys are equal.
546 /// The allocator associated with `original` is propagated for use in
547 /// the newly-created table. `original` is left in a (valid)
548 /// unspecified state.
550
551 /// Create a table having the same value, hasher, and key-equality
552 /// comparator as the specified `original` object by moving the contents
553 /// of `original` to the new table, and using the specified
554 /// `basicAllocator` to supply memory. Use a copy of
555 /// `original.hash_function()` to generate hash values for the entries
556 /// contained in this table. Use a copy of `original.key_eq()` to
557 /// verify that the keys of two entries are equal. This method requires
558 /// that the (template parameter) type `ENTRY` be `move-insertable` into
559 /// this `FlatHashTable`. If `basicAllocator` is 0, the currently
560 /// installed default allocator is used. If `original` and the newly
561 /// created object have the same allocator then the value of `original`
562 /// becomes unspecified but valid, and no exceptions will be thrown;
563 /// otherwise `original` is unchanged (and an exception may be thrown).
565 bslma::Allocator *basicAllocator);
566
567 /// Destroy this object and each of its entries.
569
570 // MANIPULATORS
571
572 /// Assign to this object the value, hasher, and key-equality functor of
573 /// the specified `rhs` object and return a reference offering
574 /// modifiable access to this object.
576
577 /// Assign to this object the value, hash function, and key-equality
578 /// comparator of the specified `rhs` object and return a reference
579 /// offering modifiable access to this object. The entries of `rhs` are
580 /// moved (in constant time) to this object if the two have the same
581 /// allocator, otherwise entries from `rhs` are moved into this table.
582 /// In either case, `rhs` is left in a valid but unspecified state. If
583 /// an exception is thrown, this object is left in a valid but
584 /// unspecified state.
586
587 /// If an entry with the specified `key` is not already present in this
588 /// table, insert an entry having the value defined by
589 /// `ENTRY_UTIL::construct`; otherwise, this method has no effect.
590 /// Return an iterator referring to the (possibly newly inserted) object
591 /// in this table with the `key`.
592 template <class KEY_TYPE>
594
595 /// Remove all entries from this table.
596 /// \note Note that this table will be
597 /// empty after calling this method, but allocated memory may be
598 /// retained for future use. See the `capacity` method.
599 void clear();
600
601 /// Return a pair of iterators providing modifiable access to the
602 /// sequence of objects in this flat hash table having the specified
603 /// `key`, where the first iterator is positioned at the start of the
604 /// sequence, and the second is positioned one past the end of the
605 /// sequence. If this table contains no object having `key`, then the
606 /// two returned iterators will have the same value, `end()`.
607 ///
608 /// \note Note that since each key in a flat hash table is unique, the returned range
609 /// contains at most one element.
611
612 /// Return a pair of iterators providing non-modifiable access to the
613 /// sequence of objects in this table having a key equivalent to the
614 /// specified `key`, where the first iterator is positioned at the start
615 /// of the sequence, and the second is positioned one past the end of the
616 /// sequence. If this table contains no objects having a key equivalent to
617 /// the specified `key`, then the two returned iterators will have the same value, `end()`.
618 ///
619 /// \note Note that since a table maintains unique keys, the
620 /// range will contain at most one entry.
621 template <class LOOKUP_KEY>
622 typename bsl::enable_if<
623 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
624 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
626 equal_range(const LOOKUP_KEY& key)
627 {
628 // Note: implemented inline due to Sun CC compilation error.
629
630 iterator it1 = find(key);
631 iterator it2 = it1;
632 if (it1 != end()) {
633 ++it2;
634 }
635 return bsl::make_pair(it1, it2);
636 }
637
638#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
639 /// Create an `ENTRY` object from the specified `args`, and attempt to
640 /// add it to this flat hash table. Return a `bsl::pair` containing an
641 /// iterator to the newly inserted object and `true` if the element was
642 /// added. If an entry with the same key already exists in this flat
643 /// hash table, return an iterator to that entry and `false`. This
644 /// method requires that the `ENTRY` be `copy-constructible`.
645 template< class... ARGS>
647#endif
648
649 /// Remove from this table the object having the specified `key`, if it
650 /// exists, and return 1; otherwise (there is no object with a key equal
651 /// to `key` in this table) return 0 with no other effect. This method
652 /// invalidates all iterators, and references to the removed element.
653 bsl::size_t erase(const KEY& key);
654
655#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
656 /// Remove from this table the object having the specified `key`, if it
657 /// exists, and return 1; otherwise (there is no object with a key equal
658 /// to `key` in this table) return 0 with no other effect. This method
659 /// invalidates all iterators, and references to the removed element.
660 template <class LOOKUP_KEY>
661 typename bsl::enable_if<
662 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
663 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
664 , bsl::size_t>::type
665 erase(LOOKUP_KEY&& key)
666 {
667 // Note: implemented inline due to Sun CC compilation error.
668
669 iterator it = find(key);
670 if (it == end()) {
671 return 0; // RETURN
672 }
673 erase(it);
674 return 1;
675 }
676#endif
677
678 /// Remove from this table the object at the specified `position`, and
679 /// return an iterator referring to the element immediately following
680 /// the removed element, or to the past-the-end position if the removed
681 /// element was the last element in the sequence of elements maintained
682 /// by this table. This method invalidates all iterators, and references to the removed element.
683 ///
684 /// \pre The behavior is undefined unless
685 /// `position` refers to an object in this table.
688
689 /// Remove from this table the objects starting at the specified `first`
690 /// position up to, but not including, the specified `last` position,
691 /// and return `last`. This method invalidates all iterators, and references to the removed element.
692 ///
693 /// \pre The behavior is undefined unless
694 /// `first` and `last` either refer to elements in this table or are the
695 /// `end` iterator, and the `first` position is at or before the `last`
696 /// position in the iteration sequence provided by this container.
698
699 /// Return an iterator providing modifiable access to the object in this
700 /// flat hash table with a key equal to the specified `key`, if such an
701 /// entry exists, and `end()` otherwise.
702 iterator find(const KEY& key);
703
704 /// Return an iterator providing modifiable access to the object in this
705 /// flat hash table with a key equivalent to the specified `key`, if such
706 /// an entry exists, and `end()` otherwise.
707 template <class LOOKUP_KEY>
708 typename bsl::enable_if<
709 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
710 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
711 , iterator>::type
712 find(const LOOKUP_KEY& key)
713 {
714 // Note: implemented inline due to Sun CC compilation error.
715
716 bsl::size_t index = findTransparentKey(key, d_hasher(key));
717 if (index < d_capacity) {
718 return iterator(IteratorImp(d_entries_p + index,
719 d_controls_p + index,
720 d_capacity - index - 1)); // RETURN
721 }
722 return end();
723 }
724
725 /// Insert the specified `entry` into this table if the key of the
726 /// `entry` does not already exist in this table; otherwise, this method
727 /// has no effect. Return a `pair` whose `first` member is an iterator
728 /// referring to the (possibly newly inserted) object in this table
729 /// whose key is the equal to that of the object to be inserted, and
730 /// whose `second` member is `true` if a new entry was inserted, and
731 /// `false` if a entry having an equal key was already present. Bitwise
732 /// movable types that are not bitwise copyable will be copied (to avoid
733 /// confusion with regard to calling the `entry` destructor after this
734 /// call).
737
738#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
739 /// Insert the specified `key` into this table if a key equivalent to `key`
740 /// does not already exist in this table; otherwise, this method has no
741 /// effect. Return a `pair` whose `first` member is an iterator
742 /// referring to the (possibly newly inserted) object in this table
743 /// whose key is the equal to that of the object to be inserted, and
744 /// whose `second` member is `true` if a new entry was inserted, and
745 /// `false` if a entry having an equal key was already present. Bitwise
746 /// movable types that are not bitwise copyable will be copied (to avoid
747 /// confusion with regard to calling the `entry` destructor after this
748 /// call).
749 template <class LOOKUP_KEY>
750 typename bsl::enable_if<
751 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
752 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
754 insertTransparent(LOOKUP_KEY&& key)
755 {
756 // Note that some compilers require functions declared with 'enable_if'
757 // to be defined inline.
758
759 bool notFound;
760 bsl::size_t hashValue = d_hasher(key);
761 bsl::size_t index = indexOfKeyTransparent(&notFound,
762 key,
763 hashValue);
764
765 if (notFound) {
766 ENTRY_UTIL::construct(
767 d_entries_p + index,
768 d_allocator_p,
769 BSLS_COMPILERFEATURES_FORWARD(LOOKUP_KEY, key));
770
771 d_controls_p[index] = static_cast<bsl::uint8_t>(
772 hashValue & k_HASHLET_MASK);
773
774 ++d_size;
775 }
776
777 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
778 d_controls_p + index,
779 d_capacity - index - 1),
780 notFound);
781 }
782#endif
783
784 /// Create an object for each iterator in the range starting at the
785 /// specified `first` iterator and ending immediately before the
786 /// specified `last` iterator, by converting from the object referred to
787 /// by each iterator. Insert into this table each such object whose key
788 /// is not already contained. The (template parameter) type
789 /// `INPUT_ITERATOR` shall meet the requirements of an input iterator
790 /// defined in the C++11 standard [24.2.3] providing access to values of a type convertible to `ENTRY`.
791 ///
792 /// \pre The behavior is undefined unless
793 /// `first` and `last` refer to a sequence of valid values where `first`
794 /// is at a position at or before `last`.
795 template <class INPUT_ITERATOR>
796 void insert(INPUT_ITERATOR first, INPUT_ITERATOR last);
797
798 /// Change the capacity of this table to at least the specified
799 /// `minimumCapacity`, and redistribute all the contained elements into
800 /// a new sequence of entries, according to their hash values. If
801 /// `0 == minimumCapacity` and `0 == size()`, the table is returned to
802 /// the zero-capacity state. On return, `load_factor()` is less than or
803 /// equal to `max_load_factor()` and all iterators, pointers, and
804 /// references to elements of this `FlatHashTable` are invalidated.
805 void rehash(bsl::size_t minimumCapacity);
806
807 /// Change the capacity of this table to at least a capacity that can
808 /// accommodate the specified `numEntries` (accounting for the load
809 /// factor invariant), and redistribute all the contained elements into
810 /// a new sequence of entries, according to their hash values. If
811 /// `0 == numEntries` and `0 == size()`, the table is returned to the
812 /// zero-capacity state. After this call, `load_factor()` will be less than or equal to `max_load_factor()`.
813 ///
814 /// \note Note that this method is
815 /// effectively equivalent to:
816 /// @code
817 /// rehash(bsl::ceil(numEntries / max_load_factor()))
818 /// @endcode
819 void reserve(bsl::size_t numEntries);
820
821 /// Remove all entries from this table and release all memory from this
822 /// table, returning the table to the zero-capacity state.
823 void reset();
824
825#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
826 /// If a key equivalent to the specified `key` already exists in this
827 /// map, return a pair containing an iterator referring to the existing
828 /// item, and `false`. Otherwise, insert into this map a newly-created
829 /// `ENTRY` object, constructed from `key` and the specified `args`, and
830 /// return a pair containing an iterator referring to the newly-created
831 /// entry and `true`. This method requires that the (template
832 /// parameter) types `KEY` and `VALUE` are `emplace-constructible` from
833 /// `key` and `args` respectively. For C++03, `VALUE` must also be
834 /// `copy-constructible`.
835 template< class... ARGS>
836 bsl::pair<iterator, bool> try_emplace(const KEY& key, ARGS&&... args);
837
838 /// If a key equivalent to the specified `key` already exists in this
839 /// map, return a pair containing an iterator referring to the existing
840 /// item, and `false`. Otherwise, insert into this map a newly-created
841 /// `ENTRY` object, constructed from `std::forward<KEY>(key)` and the
842 /// specified `args`, and return a pair containing an iterator referring
843 /// to the newly-created entry and `true`. This method requires that
844 /// the (template parameter) types `KEY` and `VALUE` are
845 /// `emplace-constructible` from `key` and `args` respectively. For
846 /// C++03, `VALUE` must also be `copy-constructible`.
847 template <class... ARGS>
849 BloombergLP::bslmf::MovableRef<KEY> key,
850 ARGS&&... args);
851
852 /// If a key equivalent to the specified `key` already exists in this map
853 /// return a pair containing an iterator referring to the existing
854 /// item, and `false`. Otherwise, insert into this map a newly-created
855 /// `ENTRY` object, constructed from `std::forward<LOOKUP_KEY>(k)` and the
856 /// specified `args`, and return a pair containing an iterator referring
857 /// to the newly-created entry and `true`. This method requires that
858 /// the (template parameter) types `KEY` and `VALUE` are
859 /// `emplace-constructible` from `key` and `args` respectively. For
860 /// C++03, `VALUE` must also be `copy-constructible`.
861 template <class LOOKUP_KEY, class... ARGS>
862 typename bsl::enable_if<
863 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
864 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
866 try_emplace(LOOKUP_KEY&& key, ARGS&&... args)
867 {
868 // Note: `args` contains @ref piecewise_construct and `key`
869 bool notFound;
870 bsl::size_t hashValue = d_hasher(key);
871 bsl::size_t index = indexOfKeyTransparent(&notFound, key, hashValue);
872
873 if (notFound) {
874 ENTRY_UTIL::construct(d_entries_p + index,
875 d_allocator_p,
876 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
877
878 d_controls_p[index] = static_cast<bsl::uint8_t>(
879 hashValue & k_HASHLET_MASK);
880 ++d_size;
881 }
882
883 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
884 d_controls_p + index,
885 d_capacity - index - 1),
886 notFound);
887 }
888#endif
889
890
891 // Iterators
892
893 /// Return an iterator representing the beginning of the sequence of
894 /// entries held by this container.
896
897 /// Return an iterator representing one past the end of the sequence of
898 /// entries held by this container.
900
901 // Aspects
902
903 /// Efficiently exchange the value of this table with the value of the
904 /// specified `other` table. This method provides the no-throw exception-safety guarantee.
905 ///
906 /// \pre The behavior is undefined unless this
907 /// array was created with the same allocator as `other`.
908 void swap(FlatHashTable& other);
909
910 // ACCESSORS
911
912 /// Return the number of elements this table could hold if the load
913 /// factor were 1.
914 bsl::size_t capacity() const;
915
916 /// Return `true` if this table contains an entry having the specified
917 /// `key`, and `false` otherwise.
918 bool contains(const KEY& key) const;
919
920 /// Return the address of the first element of the underlying array of
921 /// control values in this table, or 0 if this table is in the
922 /// zero-capacity state. An element of this array has the value
923 /// `FlatHashTable_GroupControl::k_EMPTY`,
924 /// `FlatHashTable_GroupControl::k_ERASED`, or a seven bit hashlet value
925 /// for the in-use position (the highest-order bit is unset).
926 const bsl::uint8_t *controls() const;
927
928 /// Return the number of objects contained within this table having the specified `key`.
929 ///
930 /// \note Note that since a table maintains unique keys, the
931 /// returned value will be either 0 or 1.
932 bsl::size_t count(const KEY& key) const;
933
934 /// Return `true` if this table contains no entries, and `false`
935 /// otherwise.
936 bool empty() const;
937
938 /// Return the address of the first element of the underlying array of
939 /// entries in this table, or 0 if this table is in the zero-capacity state.
940 ///
941 /// \pre The behavior is undefined unless the address is verified
942 /// in-use through use of the `controls` array before dereferencing an
943 /// entry in this array.
944 const ENTRY *entries() const;
945
946 /// Return a pair of iterators providing non-modifiable access to the
947 /// sequence of objects in this table having the specified `key`, where
948 /// the first iterator is positioned at the start of the sequence, and
949 /// the second is positioned one past the end of the sequence. If this
950 /// table contains no objects having `key`, then the two returned iterators will have the same value, `end()`.
951 ///
952 /// \note Note that since a
953 /// table maintains unique keys, the range will contain at most one
954 /// entry.
956 const KEY& key) const;
957
958 /// Return a pair of iterators providing non-modifiable access to the
959 /// sequence of objects in this table having a key equivalent to the
960 /// specified `key`, where the first iterator is positioned at the start
961 /// of the sequence, and the second is positioned one past the end of the
962 /// sequence. If this table contains no objects having a key equivalent to
963 /// the specified `key`, then the two returned iterators will have the same value, `end()`.
964 ///
965 /// \note Note that since a table maintains unique keys, the
966 /// range will contain at most one entry.
967 template <class LOOKUP_KEY>
968 typename bsl::enable_if<
969 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
970 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
972 equal_range(const LOOKUP_KEY& key) const
973 {
974 // Note: implemented inline due to Sun CC compilation error.
975
976 const_iterator cit1 = find(key);
977 const_iterator cit2 = cit1;
978 if (cit1 != end()) {
979 ++cit2;
980 }
981 return bsl::make_pair(cit1, cit2);
982 }
983
984 /// Return an iterator representing the position of the entry in this
985 /// flat hash table having the specified `key`, or `end()` if no such
986 /// entry exists in this table.
987 const_iterator find(const KEY& key) const;
988
989 /// Return an iterator representing the position of the entry in this
990 /// flat hash table that is equivalent to the specified `key`, or `end()`
991 // if no such entry exists in this table.
992 template <class LOOKUP_KEY>
993 typename bsl::enable_if<
994 BloombergLP::bslmf::IsTransparentPredicate<HASH, LOOKUP_KEY>::value
995 && BloombergLP::bslmf::IsTransparentPredicate<EQUAL,LOOKUP_KEY>::value
996 , const_iterator>::type
997 find(const LOOKUP_KEY& key) const
998 {
999 // Note: implemented inline due to Sun CC compilation error.
1000
1001 bsl::size_t index = findTransparentKey(key, d_hasher(key));
1002 if (index < d_capacity) {
1003 return const_iterator(IteratorImp(d_entries_p + index,
1004 d_controls_p + index,
1005 d_capacity - index - 1)); // RETURN
1006 }
1007 return end();
1008 }
1009
1010 /// Return (a copy of) the unary hash functor used by this flat hash
1011 /// table to generate a hash value (of type `bsl::size_t) for a `KEY'
1012 /// object.
1013 HASH hash_function() const;
1014
1015 /// Return (a copy of) the binary key-equality functor used by this flat
1016 /// hash table that returns `true` if two `KEY` objects are equal, and
1017 /// `false` otherwise.
1018 EQUAL key_eq() const;
1019
1020 /// Return the current ratio between the number of elements in this
1021 /// table and its capacity.
1022 float load_factor() const;
1023
1024 /// Return the maximum load factor allowed for this table.
1025 /// \note Note that if
1026 /// an insert operation would cause the load factor to exceed the
1027 /// @ref max_load_factor , that same insert operation will increase the
1028 /// capacity and rehash the entries of the container (see `insert` and `rehash`).
1029 ///
1030 /// \note Note that the value returned by @ref max_load_factor is
1031 /// implementation dependent and cannot be changed by the user.
1032 float max_load_factor() const;
1033
1034 /// Return the number of entries in this table.
1035 bsl::size_t size() const;
1036
1037 // Iterators
1038
1040
1041 /// Return an iterator representing the beginning of the sequence of
1042 /// entries held by this container.
1044
1046
1047 /// Return an iterator representing one past the end of the sequence of
1048 /// entries held by this container.
1050
1051 // Aspects
1052
1053 /// Return the allocator used by this hash table to supply memory.
1055};
1056
1057// FREE OPERATORS
1058
1059/// Return `true` if the specified `lhs` and `rhs` objects have the same
1060/// value, and `false` otherwise. Two `FlatHashTable` objects have the same
1061/// value if they have the same number of entries, and for each entry that
1062/// is contained in `lhs` there is a entry contained in `rhs` having the same value.
1063///
1064/// \note Note that this method requires the (template parameter)
1065/// type `ENTRY` to be equality-comparable.
1066template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1069
1070/// Return `true` if the specified `lhs` and `rhs` objects do not have the
1071/// same value, and `false` otherwise. Two `FlatHashTable` objects do not
1072/// have the same value if they do not have the same number of entries, or
1073/// that for some entry contained in `lhs` there is not a entry in `rhs` having the same value.
1074///
1075/// \note Note that this method requires the (template
1076/// parameter) type `ENTRY` to be equality-comparable.
1077template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1080
1081// FREE FUNCTIONS
1082
1083/// Exchange the values of the specified `a` and `b` objects. This function
1084/// provides the no-throw exception-safety guarantee if the two objects were
1085/// created with the same allocator and the basic guarantee otherwise.
1086template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1089
1090 // =============================
1091 // struct FlatHashTable_ImplUtil
1092 // =============================
1093
1094/// This component-private, utility `struct` provides a namespace for a
1095/// suite of operations used in the implementation of the `FlatHashTable`
1096/// class template.
1097///
1098/// See @ref bdlc_flathashtable
1100
1101 private:
1102 // PRIVATE TYPES
1104
1105 /// This component-private, mechanism class template provides a proctor
1106 /// that, unless its `release` method has been previously invoked, on
1107 /// destruction automatically destroys the populated `ENTRY_TYPE`
1108 /// elements of an `ENTRY_TYPE` array supplied on construction as
1109 /// indicated by a "control" byte array supplied on construction.
1110 template <class ENTRY_TYPE>
1111 class DestroyEntryArrayProctor;
1112
1113 // PRIVATE CLASS METHODS
1114
1115 /// Copy the specified range `[firstSourceControl, lastSourceControl)`
1116 /// to the array specified by `firstDestinationControl`, and copy each
1117 /// element in the specified range `[firstSourceEntry, lastSourceEntry)`
1118 /// at the same index as each byte in the range '[firstSourceControl,
1119 /// lastSourceControl)' that has its most-significant bit unset, to the
1120 /// corresponding location in the contiguous storage for `ENTRY_TYPE`
1121 /// objects specified by `firstDestinationEntry`. Use the specified
1122 /// `entryAllocator` as the object allocator for each newly-constructed
1123 /// `ENTRY_TYPE` object if `ENTRY_TYPE` is allocator-aware. If
1124 /// `entryAllocator` is 0, the currently-installed default allocator is
1125 /// used. No exception is thrown if the specified `ENTRY_TYPE` is
1126 /// nothrow-copyable, otherwise an exception may be thrown.
1127 ///
1128 /// \pre The behavior is undefined unless
1129 /// `bslmf::IsBitwiseCopyable<ENTRY_TYPE>::value` is equal to the
1130 /// `value` member of the type of the specified `tag`,
1131 /// `firstDestinationEntry` is a pointer to the first byte of
1132 /// uninitialized and correctly aligned storage for at least
1133 /// `bsl::distance(firstSourceEntry, lastSourceEntry)` `ENTRY_TYPE`
1134 /// objects, `firstDestinationControl` is a pointer to the first byte of
1135 /// `bsl::distance(firstSourceEntry, lastSourceEntry)` bytes of
1136 /// uninitialized storage, the range '[firstSourceEntry,
1137 /// lastSourceEntry)' denotes a contiguous array of storage for
1138 /// optionally-constructed `ENTRY_TYPE` objects, the range
1139 /// `[firstSourceControl, lastSourceControl)` denotes a contiguous array
1140 /// of `bsl::uint8_t` objects, an `ENTRY_TYPE` object exists at the same
1141 /// index in the `[firstSourceEntry, lastSourceEntry)` storage range as
1142 /// each byte in the range `[firstControlEntry, lastControlEntry)` that
1143 /// has its most significant bit unset, and
1144 /// `bsl::distance(firstSourceEntry, lastSourceEntry)` is equal to
1145 /// `bsl::distance(firstSourceControl, lastSourceControl)`.
1146 template <class ENTRY_TYPE>
1147 static void copyEntryAndControlArrays(
1148 ENTRY_TYPE *firstDestinationEntry,
1149 bsl::uint8_t *firstDestinationControl,
1150 const ENTRY_TYPE *firstSourceEntry,
1151 const ENTRY_TYPE *lastSourceEntry,
1152 const bsl::uint8_t *firstSourceControl,
1153 const bsl::uint8_t *lastSourceControl,
1154 bslma::Allocator *entryAllocator,
1155 bsl::false_type bitwiseCopyable);
1156 template <class ENTRY_TYPE>
1157 static void copyEntryAndControlArrays(
1158 ENTRY_TYPE *firstDestinationEntry,
1159 bsl::uint8_t *firstDestinationControl,
1160 const ENTRY_TYPE *firstSourceEntry,
1161 const ENTRY_TYPE *lastSourceEntry,
1162 const bsl::uint8_t *firstSourceControl,
1163 const bsl::uint8_t *lastSourceControl,
1164 bslma::Allocator *entryAllocator,
1165 bsl::true_type bitwiseCopyable);
1166
1167
1168 /// Destroy each entry object in the storage specified by the range
1169 /// `[firstEntry, lastEntry)` if the most-significant bit is unset in
1170 /// the corresponding element in the specified range
1171 /// `[firstControl, lastControl)` (i.e., the most-significant bit of the
1172 /// element in the "control" array that has the same index as the
1173 /// element in the "entry" array is unset). No exception is thrown.
1174 ///
1175 /// \pre The behavior is undefined unless
1176 /// `bslmf::IsTriviallyDestructible<ENTRY_TYPE>::value` is equal to the
1177 /// `value` member of the type of the specified `tag`, the range
1178 /// `[firstEntry, lastEntry)` denotes a contiguous array of storage for
1179 /// optionally-constructed `ENTRY_TYPE` objects, the range
1180 /// `[firstControl, lastControl)` denotes a contiguous array of
1181 /// `bsl::uint8_t` objects, the two arrays have the same number of
1182 /// elements, and an `ENTRY_TYPE` object exists at the same index in the
1183 /// `[firstEntry, lastEntry)` storage range for each element in the
1184 /// `[firstControl, lastControl)` range that has its first bit unset.
1185 template <class ENTRY_TYPE>
1186 static void destroyEntryArray(ENTRY_TYPE *firstEntry,
1187 ENTRY_TYPE *lastEntry,
1188 const bsl::uint8_t *firstControl,
1189 const bsl::uint8_t *lastControl,
1190 bsl::false_type triviallyDestructible);
1191 template <class ENTRY_TYPE>
1192 static void destroyEntryArray(ENTRY_TYPE *firstEntry,
1193 ENTRY_TYPE *lastEntry,
1194 const bsl::uint8_t *firstControl,
1195 const bsl::uint8_t *lastControl,
1196 bsl::true_type triviallyDestructible);
1197
1198 public:
1199 // CLASS METHODS
1200
1201 /// Copy the specified range `[firstSourceControl, lastSourceControl)`
1202 /// to the array specified by `firstDestinationControl`, and copy each
1203 /// element in the specified range `[firstSourceEntry, lastSourceEntry)`
1204 /// at the same index as each byte in the range '[firstSourceControl,
1205 /// lastSourceControl)' that has its most-significant bit unset, to the
1206 /// corresponding location in the contiguous storage for `ENTRY_TYPE`
1207 /// objects specified by `firstDestinationEntry`. Use the specified
1208 /// `entryAllocator` as the object allocator for each newly-constructed
1209 /// `ENTRY_TYPE` object if `ENTRY_TYPE` is allocator-aware. If
1210 /// `entryAllocator` is 0, the currently-installed default allocator is
1211 /// used. No exception is thrown if the specified `ENTRY_TYPE` is
1212 /// nothrow-copyable, otherwise an exception may be thrown.
1213 ///
1214 /// \pre The behavior is undefined unless `firstDestinationEntry` is a pointer to
1215 /// the first byte of uninitialized and correctly aligned storage for at
1216 /// least `bsl::distance(firstSourceEntry, lastSourceEntry)`
1217 /// `ENTRY_TYPE` objects, `firstDestinationControl` is a pointer to the
1218 /// first byte of `bsl::distance(firstSourceEntry, lastSourceEntry)`
1219 /// bytes of uninitialized storage, the range '[firstSourceEntry,
1220 /// lastSourceEntry)' denotes a contiguous array of storage for
1221 /// optionally-constructed `ENTRY_TYPE` objects, the range
1222 /// `[firstSourceControl, lastSourceControl)` denotes a contiguous array
1223 /// of `bsl::uint8_t` objects, an `ENTRY_TYPE` object exists at the same
1224 /// index in the `[firstSourceEntry, lastSourceEntry)` storage range as
1225 /// each byte in the range `[firstControlEntry, lastControlEntry)` that
1226 /// has its most significant bit unset, and
1227 /// `bsl::distance(firstSourceEntry, lastSourceEntry)` is equal to
1228 /// `bsl::distance(firstSourceControl, lastSourceControl)`.
1229 template <class ENTRY_TYPE>
1230 static void
1231 copyEntryAndControlArrays(ENTRY_TYPE *firstDestinationEntry,
1232 bsl::uint8_t *firstDestinationControl,
1233 const ENTRY_TYPE *firstSourceEntry,
1234 const ENTRY_TYPE *lastSourceEntry,
1235 const bsl::uint8_t *firstSourceControl,
1236 const bsl::uint8_t *lastSourceControl,
1237 bslma::Allocator *entryAllocator);
1238
1239 /// Destroy each entry object in the storage specified by the range
1240 /// `[firstEntry, lastEntry)` if the most-significant bit is unset in
1241 /// the corresponding element in the specified range '[firstControl,
1242 /// lastControl)' (i.e., the most-significant bit of the element in the
1243 /// "control" array that has the same index as the element in the
1244 /// "entry" array is unset). No exception is thrown.
1245 ///
1246 /// \pre The behavior is undefined unless the range `[firstEntry, lastEntry)` denotes a
1247 /// contiguous array of storage for optionally-constructed `ENTRY_TYPE`
1248 /// objects, the range `[firstControl, lastControl)` denotes a
1249 /// contiguous array of `bsl::uint8_t` objects, the two arrays have the
1250 /// same number of elements, and an `ENTRY_TYPE` object exists at the
1251 /// same index in the `[firstEntry, lastEntry)` storage range for each
1252 /// element in the `[firstControl, lastControl)` range that has its
1253 /// first bit unset.
1254 template <class ENTRY_TYPE>
1255 static void destroyEntryArray(ENTRY_TYPE *firstEntry,
1256 ENTRY_TYPE *lastEntry,
1257 const bsl::uint8_t *firstControl,
1258 const bsl::uint8_t *lastControl);
1259};
1260
1261 // ======================================================
1262 // class FlatHashTable_ImplUtil::DestroyEntryArrayProctor
1263 // ======================================================
1264
1265/// This component-private, mechanism class template provides a proctor
1266/// that, unless its `release` method has been previously invoked, on
1267/// destruction automatically destroys the populated `ENTRY_TYPE` elements
1268/// of an `ENTRY_TYPE` array supplied on construction as indicated by a
1269/// "control" byte array supplied on construction.
1270template <class ENTRY_TYPE>
1271class FlatHashTable_ImplUtil::DestroyEntryArrayProctor {
1272
1273 // PRIVATE TYPES
1274 typedef FlatHashTable_GroupControl GroupControl;
1275 typedef FlatHashTable_ImplUtil ImplUtil;
1276
1277 // DATA
1278
1279 // pointer to first element of entry array
1280 ENTRY_TYPE *d_firstEntry_p;
1281
1282 // pointer to one-past-the-end of entry array
1283 ENTRY_TYPE *d_lastEntry_p;
1284
1285 // pointer to first element of control array
1286 const bsl::uint8_t *d_firstControl_p;
1287
1288 // pointer to one-past-the-end of control array
1289 const bsl::uint8_t *d_lastControl_p;
1290
1291 private:
1292 // NOT IMPLEMENTED
1293 DestroyEntryArrayProctor(const DestroyEntryArrayProctor&);
1294 DestroyEntryArrayProctor& operator=(const DestroyEntryArrayProctor&);
1295
1296 public:
1297 // CREATORS
1298
1299 /// Create a new `DestroyEntryArrayProctor` object for the contiguous
1300 /// `ENTRY_TYPE` storage delimited by the range specified by
1301 /// `[firstEntry, lastEntry)` controlled by the bytes in the range
1302 /// specified by `[firstControl, lastControl)`.
1303 ///
1304 /// \pre The behavior is undefined unless 'bsl::distance(firstEntry, lastEntry) == bsl::distance(`firstControl, lastControl)`.
1305 ///
1306 /// \note Note that these ranges
1307 /// may be valid sub-ranges (or "views") of larger arrays, and these
1308 /// sub-ranges can be grown or shrunk by `moveEnd`.
1309 DestroyEntryArrayProctor(ENTRY_TYPE *firstEntry,
1310 ENTRY_TYPE *lastEntry,
1311 const bsl::uint8_t *firstControl,
1312 const bsl::uint8_t *lastControl);
1313
1314 /// Destroy this object and each object in the entry storage array held
1315 /// by this object where the most-significant bit of the corresponding
1316 /// element in the control array held by this object is unset.
1317 ~DestroyEntryArrayProctor();
1318
1319 // MANIPULATORS
1320
1321 /// Move the end of the entry and control ranges held by this object by
1322 /// the specified `offset`.
1323 void moveEnd(bsl::ptrdiff_t offset);
1324
1325 /// Release the entry and control ranges held by this object from
1326 /// management by this object, and set this object's held entry and
1327 /// control arrays to the corresponding empty arrays. If the entry and
1328 /// control arrays held by this object are empty, this method has no
1329 /// effect.
1330 void release();
1331};
1332
1333// ============================================================================
1334// INLINE DEFINITIONS
1335// ============================================================================
1336
1337 // -------------------------------
1338 // class FlatHashTable_IteratorImp
1339 // -------------------------------
1340
1341// CREATORS
1342template <class ENTRY>
1343inline
1345: d_entries_p(0)
1346, d_controls_p(0)
1347, d_additionalLength(0)
1348{
1349}
1350
1351template <class ENTRY>
1352inline
1354 ENTRY *entries,
1355 const bsl::uint8_t *controls,
1356 bsl::size_t additionalLength)
1357: d_entries_p(entries)
1358, d_controls_p(controls)
1359, d_additionalLength(additionalLength)
1360{
1361}
1362
1363template <class ENTRY>
1364inline
1366 const FlatHashTable_IteratorImp& original)
1367: d_entries_p(original.d_entries_p)
1368, d_controls_p(original.d_controls_p)
1369, d_additionalLength(original.d_additionalLength)
1370{
1371}
1372
1373// MANIPULATORS
1374template <class ENTRY>
1375inline
1377 const FlatHashTable_IteratorImp& rhs)
1378{
1379 d_entries_p = rhs.d_entries_p;
1380 d_controls_p = rhs.d_controls_p;
1381 d_additionalLength = rhs.d_additionalLength;
1382
1383 return *this;
1384}
1385
1386template <class ENTRY>
1387inline
1389{
1390 BSLS_ASSERT_SAFE(d_entries_p);
1391 BSLS_ASSERT_SAFE(d_controls_p);
1392
1393 while (d_additionalLength) {
1394 ++d_entries_p;
1395 ++d_controls_p;
1396 --d_additionalLength;
1397 if (0 == (*d_controls_p & 0x80)) {
1398 return; // RETURN
1399 }
1400 }
1401
1402 d_entries_p = 0;
1403 d_controls_p = 0;
1404}
1405
1406// ACCESSORS
1407template <class ENTRY>
1408inline
1410{
1411 BSLS_ASSERT_SAFE(d_entries_p);
1412 BSLS_ASSERT_SAFE(d_controls_p);
1413
1414 return *d_entries_p;
1415}
1416
1417} // close package namespace
1418
1419// FREE OPERATORS
1420template <class ENTRY>
1421inline
1422bool bdlc::operator==(const FlatHashTable_IteratorImp<ENTRY>& a,
1423 const FlatHashTable_IteratorImp<ENTRY>& b)
1424{
1425 return a.d_entries_p == b.d_entries_p
1426 && a.d_controls_p == b.d_controls_p
1427 && a.d_additionalLength == b.d_additionalLength;
1428}
1429
1430namespace bdlc {
1431
1432 // -------------------
1433 // class FlatHashTable
1434 // -------------------
1435
1436// PRIVATE CLASS METHODS
1437template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1438bsl::size_t FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>::findAvailable(
1439 bsl::uint8_t *controls,
1440 bsl::size_t index,
1441 bsl::size_t capacity)
1442{
1443 BSLS_ASSERT_SAFE(index < capacity);
1444
1445 for (bsl::size_t i = 0; i < capacity; i += GroupControl::k_SIZE) {
1446 bsl::uint8_t *controlStart = controls + index;
1447
1448 GroupControl groupControl(controlStart);
1449 bsl::uint32_t candidates = groupControl.available();
1450
1451 if (candidates) {
1452 return index
1453 + bdlb::BitUtil::numTrailingUnsetBits(candidates); // RETURN
1454 }
1455
1456 index = (index + GroupControl::k_SIZE) & (capacity - 1);
1457 }
1458
1459 BSLS_ASSERT_OPT_UNREACHABLE("FlatHash ran out of available slots,"
1460 " even though it should have found one");
1461 return capacity;
1462}
1463
1464// PRIVATE MANIPULATORS
1465template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1466bsl::size_t FlatHashTable<KEY,
1467 ENTRY,
1468 ENTRY_UTIL,
1469 HASH,
1470 EQUAL>::indexOfKey(bool *notFound,
1471 const KEY& key,
1472 bsl::size_t hashValue)
1473{
1474 BSLS_ASSERT_SAFE(hashValue == d_hasher(key));
1475
1476 bsl::size_t index = findKey(key, hashValue);
1477
1478 if (index == d_capacity) {
1479 *notFound = true;
1480
1481 if (d_size >= k_MAX_LOAD_FACTOR_NUMERATOR
1482 * (d_capacity / k_MAX_LOAD_FACTOR_DENOMINATOR)) {
1483 rehashRaw(d_capacity > 0 ? 2 * d_capacity : k_MIN_CAPACITY);
1484 }
1485
1486 index = (hashValue >> d_groupControlShift) * GroupControl::k_SIZE;
1487 index = findAvailable(d_controls_p, index, d_capacity);
1488 }
1489 else {
1490 *notFound = false;
1491 }
1492
1493 return index;
1494}
1495
1496template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1497void FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>::rehashRaw(
1498 bsl::size_t newCapacity)
1499{
1500 BSLS_ASSERT_SAFE( 0 < newCapacity);
1501 BSLS_ASSERT_SAFE(newCapacity == minimumCompliantCapacity(newCapacity));
1502
1503 FlatHashTable tmp(newCapacity,
1504 d_hasher,
1505 d_equal,
1506 d_allocator_p);
1507
1508 for (bsl::size_t i = 0; i < d_capacity; i += GroupControl::k_SIZE) {
1509 bsl::uint8_t *controlStart = d_controls_p + i;
1510 ENTRY *entryStart = d_entries_p + i;
1511
1512 GroupControl groupControl(controlStart);
1513 bsl::uint32_t candidates = groupControl.inUse();
1514 while (candidates) {
1515 int offset = bdlb::BitUtil::numTrailingUnsetBits(candidates);
1516 ENTRY *entry = entryStart + offset;
1517
1518 // create a destructor proctor for the element to be moved
1519 bslma::DestructorProctor<ENTRY> proctor(entry);
1520
1521 // perform book-keeping for the destruction
1522 *(controlStart + offset) = GroupControl::k_ERASED;
1523 --d_size;
1524
1525 // place the element in the new container
1526 bsl::size_t hashValue = tmp.d_hasher(ENTRY_UTIL::key(*entry));
1527 bsl::size_t index = (hashValue >> tmp.d_groupControlShift)
1528 * GroupControl::k_SIZE;
1529
1530 index = findAvailable(tmp.d_controls_p, index, tmp.d_capacity);
1531
1532 bslma::ConstructionUtil::destructiveMove(tmp.d_entries_p + index,
1533 tmp.d_allocator_p,
1534 entry);
1535
1536 // release destructor proctor
1537 proctor.release();
1538
1539 tmp.d_controls_p[index] = static_cast<bsl::uint8_t>(
1540 hashValue & k_HASHLET_MASK);
1541
1542 ++tmp.d_size;
1543
1544 candidates = bdlb::BitUtil::withBitCleared(candidates, offset);
1545 }
1546 }
1547
1548 d_allocator_p->deallocate(d_entries_p);
1549 d_allocator_p->deallocate(d_controls_p);
1550
1551 d_entries_p = 0;
1552 d_controls_p = 0;
1553 d_capacity = 0;
1554 d_groupControlShift = 0;
1555
1556 bslalg::SwapUtil::swap(&d_entries_p, &tmp.d_entries_p);
1557 bslalg::SwapUtil::swap(&d_controls_p, &tmp.d_controls_p);
1558 bslalg::SwapUtil::swap(&d_size, &tmp.d_size);
1559 bslalg::SwapUtil::swap(&d_capacity, &tmp.d_capacity);
1560 bslalg::SwapUtil::swap(&d_groupControlShift, &tmp.d_groupControlShift);
1561}
1562
1563// PRIVATE ACCESSORS
1564template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1565bsl::size_t FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>::findKey(
1566 const KEY& key,
1567 bsl::size_t hashValue) const
1568{
1569 BSLS_ASSERT_SAFE(hashValue == d_hasher(key));
1570
1571 bsl::size_t index = (hashValue >> d_groupControlShift)
1572 * GroupControl::k_SIZE;
1573 bsl::uint8_t hashlet = static_cast<bsl::uint8_t>(
1574 hashValue & k_HASHLET_MASK);
1575
1576 for (bsl::size_t i = 0; i < d_capacity; i += GroupControl::k_SIZE) {
1577 bsl::uint8_t *controlStart = d_controls_p + index;
1578 ENTRY *entryStart = d_entries_p + index;
1579
1580 GroupControl groupControl(controlStart);
1581 bsl::uint32_t candidates = groupControl.match(hashlet);
1582 while (candidates) {
1583 int offset = bdlb::BitUtil::numTrailingUnsetBits(candidates);
1584
1585 ENTRY *entry = entryStart + offset;
1586
1588 d_equal(ENTRY_UTIL::key(*entry), key))) {
1589 return index + offset; // RETURN
1590 }
1591 candidates = bdlb::BitUtil::withBitCleared(candidates, offset);
1592 }
1593 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(groupControl.neverFull())) {
1594 break;
1595 }
1596
1597 index = (index + GroupControl::k_SIZE) & (d_capacity - 1);
1598 }
1599
1600 return d_capacity;
1601}
1602
1603template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1604bsl::size_t FlatHashTable<KEY,
1605 ENTRY,
1606 ENTRY_UTIL,
1607 HASH,
1608 EQUAL>::minimumCompliantCapacity(
1609 bsl::size_t minimumCapacity) const
1610{
1611 bsl::size_t minForEntries = ((d_size + k_MAX_LOAD_FACTOR_NUMERATOR - 1)
1612 / k_MAX_LOAD_FACTOR_NUMERATOR)
1613 * k_MAX_LOAD_FACTOR_DENOMINATOR;
1614
1615 bsl::size_t capacity = minimumCapacity >= minForEntries
1616 ? minimumCapacity
1617 : minForEntries;
1618
1619 if (0 < capacity) {
1620 capacity = capacity > k_MIN_CAPACITY
1621 ? static_cast<bsl::size_t>(bdlb::BitUtil::roundUpToBinaryPower(
1622 static_cast<bsl::uint64_t>(capacity)))
1623 : k_MIN_CAPACITY;
1624 }
1625
1626 return capacity;
1627}
1628
1629// CREATORS
1630template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1631inline
1633 bsl::size_t capacity,
1634 const HASH& hash,
1635 const EQUAL& equal,
1636 bslma::Allocator *basicAllocator)
1637: d_entries_p(0)
1638, d_controls_p(0)
1639, d_size(0)
1640, d_capacity(0)
1641, d_groupControlShift(0)
1642, d_hasher(hash)
1643, d_equal(equal)
1644, d_allocator_p(bslma::Default::allocator(basicAllocator))
1645{
1646 if (0 < capacity) {
1647 d_capacity = capacity > k_MIN_CAPACITY
1648 ? static_cast<bsl::size_t>(bdlb::BitUtil::roundUpToBinaryPower(
1649 static_cast<bsl::uint64_t>(capacity)))
1651
1652 d_groupControlShift = static_cast<int>(
1653 sizeof(bsl::size_t) * 8
1654 - bdlb::BitUtil::log2(static_cast<bsl::uint64_t>(
1655 d_capacity
1657
1658 ENTRY *entries = static_cast<ENTRY *>(
1659 d_allocator_p->allocate(d_capacity * sizeof(ENTRY)));
1660
1662 d_allocator_p);
1663
1664 d_controls_p = static_cast<bsl::uint8_t *>(
1665 d_allocator_p->allocate(d_capacity));
1666 bsl::memset(d_controls_p, GroupControl::k_EMPTY, d_capacity);
1667
1668 proctor.release();
1669 d_entries_p = entries;
1670 }
1671}
1672
1673template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1674inline
1676 const FlatHashTable& original,
1677 bslma::Allocator *basicAllocator)
1678: d_entries_p(0)
1679, d_controls_p(0)
1680, d_size(0)
1681, d_capacity(0)
1682, d_groupControlShift(0)
1683, d_hasher(original.hash_function())
1684, d_equal(original.key_eq())
1685, d_allocator_p(bslma::Default::allocator(basicAllocator))
1686{
1687 if (0 != original.d_capacity) {
1688 bsl::uint8_t *const controls = static_cast<bsl::uint8_t *>(
1689 d_allocator_p->allocate(original.d_capacity));
1691 controls,
1692 d_allocator_p);
1693
1694 ENTRY *const entries = static_cast<ENTRY *>(
1695 d_allocator_p->allocate(original.d_capacity * sizeof(ENTRY)));
1697 entries,
1698 d_allocator_p);
1699
1700 ImplUtil::copyEntryAndControlArrays(
1701 entries,
1702 controls,
1703 original.d_entries_p,
1704 original.d_entries_p + original.d_capacity,
1705 original.d_controls_p,
1706 original.d_controls_p + original.d_capacity,
1707 d_allocator_p);
1708
1709 entriesProctor.release();
1710 controlsProctor.release();
1711
1712 d_entries_p = entries;
1713 d_controls_p = controls;
1714 d_size = original.d_size;
1715 d_capacity = original.d_capacity;
1716 d_groupControlShift = original.d_groupControlShift;
1717 }
1718}
1719
1720template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1721inline
1724: d_entries_p(bslmf::MovableRefUtil::access(original).d_entries_p)
1725, d_controls_p(bslmf::MovableRefUtil::access(original).d_controls_p)
1726, d_size(bslmf::MovableRefUtil::access(original).d_size)
1727, d_capacity(bslmf::MovableRefUtil::access(original).d_capacity)
1728, d_groupControlShift(
1729 bslmf::MovableRefUtil::access(original).d_groupControlShift)
1730, d_hasher(bslmf::MovableRefUtil::access(original).d_hasher)
1731, d_equal(bslmf::MovableRefUtil::access(original).d_equal)
1732, d_allocator_p(bslmf::MovableRefUtil::access(original).d_allocator_p)
1733{
1734 FlatHashTable& reference = original;
1735
1736 reference.d_entries_p = 0;
1737 reference.d_controls_p = 0;
1738 reference.d_size = 0;
1739 reference.d_capacity = 0;
1740 reference.d_groupControlShift = 0;
1741}
1742
1743template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1746 bslma::Allocator *basicAllocator)
1747: d_entries_p(0)
1748, d_controls_p(0)
1749, d_size(0)
1750, d_capacity(0)
1751, d_groupControlShift(0)
1752, d_hasher(bslmf::MovableRefUtil::access(original).d_hasher)
1753, d_equal(bslmf::MovableRefUtil::access(original).d_equal)
1754, d_allocator_p(bslma::Default::allocator(basicAllocator))
1755{
1756 FlatHashTable& reference = original;
1757 if (d_allocator_p == reference.d_allocator_p) {
1758 bslalg::SwapUtil::swap(&d_entries_p, &reference.d_entries_p);
1759 bslalg::SwapUtil::swap(&d_controls_p, &reference.d_controls_p);
1760 bslalg::SwapUtil::swap(&d_size, &reference.d_size);
1761 bslalg::SwapUtil::swap(&d_capacity, &reference.d_capacity);
1762 bslalg::SwapUtil::swap(&d_groupControlShift,
1763 &reference.d_groupControlShift);
1764 }
1765 else if (reference.d_capacity) {
1766 bsl::uint8_t *const controls = static_cast<bsl::uint8_t *>(
1767 d_allocator_p->allocate(reference.d_capacity));
1769 controls,
1770 d_allocator_p);
1771
1772 ENTRY *const entries = static_cast<ENTRY *>(
1773 d_allocator_p->allocate(reference.d_capacity * sizeof(ENTRY)));
1775 entries,
1776 d_allocator_p);
1777
1778 ImplUtil::copyEntryAndControlArrays(
1779 entries,
1780 controls,
1781 reference.d_entries_p,
1782 reference.d_entries_p + reference.d_capacity,
1783 reference.d_controls_p,
1784 reference.d_controls_p + reference.d_capacity,
1785 d_allocator_p);
1786
1787 entriesProctor.release();
1788 controlsProctor.release();
1789
1790 d_entries_p = entries;
1791 d_controls_p = controls;
1792 d_size = reference.d_size;
1793 d_capacity = reference.d_capacity;
1794 d_groupControlShift = reference.d_groupControlShift;
1795 }
1796}
1797
1798template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1799inline
1801{
1803 (d_capacity == 0 && d_groupControlShift == 0) ||
1804 (d_groupControlShift ==
1805 static_cast<int>(sizeof(bsl::size_t) * 8 -
1806 bdlb::BitUtil::log2(static_cast<bsl::uint64_t>(
1807 d_capacity / GroupControl::k_SIZE)))));
1808
1809 if (0 != d_entries_p) {
1810 ImplUtil::destroyEntryArray(d_entries_p,
1811 d_entries_p + d_capacity,
1812 d_controls_p,
1813 d_controls_p + d_capacity);
1814
1815 d_allocator_p->deallocate(d_entries_p);
1816 d_allocator_p->deallocate(d_controls_p);
1817 }
1818}
1819
1820// MANIPULATORS
1821template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1822inline
1825 const FlatHashTable& rhs)
1826{
1827 if (this != &rhs) {
1828 FlatHashTable tmp(rhs, d_allocator_p);
1829 swap(tmp);
1830 }
1831 return *this;
1832}
1833
1834template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1835inline
1839{
1840 FlatHashTable& reference = rhs;
1841 if (this != &reference) {
1843 d_allocator_p);
1844 swap(table);
1845 }
1846 return *this;
1847}
1848
1849template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1850template <class KEY_TYPE>
1851inline
1854{
1855 bool notFound;
1856 bsl::size_t hashValue = d_hasher(key);
1857 bsl::size_t index = indexOfKey(&notFound, key, hashValue);
1858
1859 if (notFound) {
1860 ENTRY_UTIL::constructFromKey(d_entries_p + index,
1861 d_allocator_p,
1862 BSLS_COMPILERFEATURES_FORWARD(KEY_TYPE, key));
1863
1864 d_controls_p[index] = static_cast<bsl::uint8_t>(
1865 hashValue & k_HASHLET_MASK);
1866
1867 ++d_size;
1868 }
1869
1870 return d_entries_p[index];
1871}
1872
1873template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1874inline
1876{
1877 ImplUtil::destroyEntryArray(d_entries_p,
1878 d_entries_p + d_capacity,
1879 d_controls_p,
1880 d_controls_p + d_capacity);
1881
1882 if (d_controls_p) {
1883 bsl::memset(d_controls_p, GroupControl::k_EMPTY, d_capacity);
1884 }
1885
1886 d_size = 0;
1887}
1888
1889template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1890inline
1891bsl::pair<
1895{
1896 iterator it1 = find(key);
1897 if (it1 == end()) {
1898 return bsl::make_pair(it1, it1); // RETURN
1899 }
1900 iterator it2 = it1;
1901 ++it2;
1902 return bsl::make_pair(it1, it2);
1903}
1904
1905#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1906template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1907template< class... ARGS>
1908inline
1909bsl::pair<typename
1911 bool>
1913{
1915 ENTRY_UTIL::construct(value.address(),
1916 d_allocator_p,
1917 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
1918
1920 return this->insert(bslmf::MovableRefUtil::move(value.object()));
1921}
1922#endif
1923
1924
1925template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1926inline
1928 const KEY& key)
1929{
1930 iterator it = find(key);
1931 if (it == end()) {
1932 return 0; // RETURN
1933 }
1934 erase(it);
1935 return 1;
1936}
1937
1938template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1939inline
1942 typename FlatHashTable<KEY,
1943 ENTRY,
1944 ENTRY_UTIL,
1945 HASH,
1946 EQUAL>::const_iterator position)
1947{
1948 BSLS_ASSERT_SAFE(position != end());
1949
1950 bsl::size_t index = &*position - d_entries_p;
1951 bslma::DestructionUtil::destroy(d_entries_p + index);
1952 d_controls_p[index] = GroupControl::k_ERASED;
1953 --d_size;
1954
1955 if (d_size) {
1956 for (bsl::size_t i = index + 1; i < d_capacity; ++i) {
1957 if (0 == (d_controls_p[i] & GroupControl::k_EMPTY)) {
1958 return iterator(IteratorImp(d_entries_p + i,
1959 d_controls_p + i,
1960 d_capacity - i - 1)); // RETURN
1961 }
1962 }
1963 }
1964 return iterator();
1965}
1966
1967template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1968inline
1971 typename FlatHashTable<KEY,
1972 ENTRY,
1973 ENTRY_UTIL,
1974 HASH,
1975 EQUAL>::iterator position)
1976{
1977 // Note that this overload is necessary to avoid ambiguity when the key is
1978 // a table iterator.
1979
1980 BSLS_ASSERT_SAFE(position != end());
1981
1982 bsl::size_t index = &*position - d_entries_p;
1983 bslma::DestructionUtil::destroy(d_entries_p + index);
1984 d_controls_p[index] = GroupControl::k_ERASED;
1985 --d_size;
1986
1987 if (d_size) {
1988 for (bsl::size_t i = index + 1; i < d_capacity; ++i) {
1989 if (0 == (d_controls_p[i] & GroupControl::k_EMPTY)) {
1990 return iterator(IteratorImp(d_entries_p + i,
1991 d_controls_p + i,
1992 d_capacity - i - 1)); // RETURN
1993 }
1994 }
1995 }
1996 return iterator();
1997}
1998
1999template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2002 typename FlatHashTable<KEY,
2003 ENTRY,
2004 ENTRY_UTIL,
2005 HASH,
2006 EQUAL>::const_iterator first,
2007 typename FlatHashTable<KEY,
2008 ENTRY,
2009 ENTRY_UTIL,
2010 HASH,
2011 EQUAL>::const_iterator last)
2012{
2013 iterator rv;
2014 {
2015 if (last != end()) {
2016 bsl::size_t index = &*last - d_entries_p;
2017 rv = iterator(IteratorImp(d_entries_p + index,
2018 d_controls_p + index,
2019 d_capacity - index - 1));
2020 }
2021 else {
2022 rv = end();
2023 }
2024 }
2025
2026 for (; first != last; ++first) {
2027 erase(first);
2028 }
2029
2030 return rv;
2031}
2032
2033template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2034inline
2037{
2038 bsl::size_t index = findKey(key, d_hasher(key));
2039 if (index < d_capacity) {
2040 return iterator(IteratorImp(d_entries_p + index,
2041 d_controls_p + index,
2042 d_capacity - index - 1)); // RETURN
2043 }
2044 return end();
2045}
2046
2047template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2048inline
2051{
2052 bool notFound;
2053 bsl::size_t hashValue = d_hasher(ENTRY_UTIL::key(entry));
2054 bsl::size_t index = indexOfKey(&notFound,
2055 ENTRY_UTIL::key(entry),
2056 hashValue);
2057
2058 if (notFound) {
2059 ENTRY_UTIL::construct(d_entries_p + index, d_allocator_p, entry);
2060 d_controls_p[index] = static_cast<bsl::uint8_t>(
2061 hashValue & k_HASHLET_MASK);
2062 ++d_size;
2063 }
2064
2065 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
2066 d_controls_p + index,
2067 d_capacity - index - 1),
2068 notFound);
2069}
2070
2071template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2072inline
2076{
2077 bool notFound;
2078 bsl::size_t hashValue = d_hasher(ENTRY_UTIL::key(entry));
2079 bsl::size_t index = indexOfKey(&notFound,
2080 ENTRY_UTIL::key(entry),
2081 hashValue);
2082
2083 if (notFound) {
2084 ENTRY_UTIL::construct(d_entries_p + index,
2085 d_allocator_p,
2086 BSLS_COMPILERFEATURES_FORWARD(ENTRY, entry));
2087
2088 d_controls_p[index] = static_cast<bsl::uint8_t>(
2089 hashValue & k_HASHLET_MASK);
2090
2091 ++d_size;
2092 }
2093
2094 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
2095 d_controls_p + index,
2096 d_capacity - index - 1),
2097 notFound);
2098}
2099
2100template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2101template <class INPUT_ITERATOR>
2102inline
2104 INPUT_ITERATOR first,
2105 INPUT_ITERATOR last)
2106{
2107 for (; first != last; ++first) {
2108 insert(*first);
2109 }
2110}
2111
2112template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2113inline
2115 bsl::size_t minimumCapacity)
2116{
2117 minimumCapacity = minimumCompliantCapacity(minimumCapacity);
2118
2119 if (0 < minimumCapacity) {
2120 rehashRaw(minimumCapacity);
2121 }
2122 else {
2123 d_allocator_p->deallocate(d_entries_p);
2124 d_allocator_p->deallocate(d_controls_p);
2125
2126 d_entries_p = 0;
2127 d_controls_p = 0;
2128 d_capacity = 0;
2129 d_groupControlShift = 0;
2130 }
2131}
2132
2133template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2134inline
2136 bsl::size_t numEntries)
2137{
2138 if (0 == d_capacity && 0 == numEntries) {
2139 // From DRQS 167247593, 'reserve(0)' on an empty container is a
2140 // performance concern.
2141
2142 return; // RETURN
2143 }
2144
2145 bsl::size_t minForEntries = ((numEntries + k_MAX_LOAD_FACTOR_NUMERATOR - 1)
2146 / k_MAX_LOAD_FACTOR_NUMERATOR)
2147 * k_MAX_LOAD_FACTOR_DENOMINATOR;
2148
2149 rehash(minForEntries);
2150}
2151
2152template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2153inline
2155{
2156 if (0 != d_entries_p) {
2157 ImplUtil::destroyEntryArray(d_entries_p,
2158 d_entries_p + d_capacity,
2159 d_controls_p,
2160 d_controls_p + d_capacity);
2161
2162 d_allocator_p->deallocate(d_entries_p);
2163 d_allocator_p->deallocate(d_controls_p);
2164
2165 d_entries_p = 0;
2166 d_controls_p = 0;
2167 d_capacity = 0;
2168 d_size = 0;
2169 d_groupControlShift = 0;
2170 }
2171}
2172
2173#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
2174/// Note: `args` contains @ref piecewise_construct and `key`
2175template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2176template< class... ARGS>
2177bsl::pair<typename
2179 bool>
2181 const KEY& key,
2182 ARGS&&... args)
2183{
2184 bool notFound;
2185 bsl::size_t hashValue = d_hasher(key);
2186 bsl::size_t index = indexOfKey(&notFound, key, hashValue);
2187
2188 if (notFound) {
2189 ENTRY_UTIL::construct(d_entries_p + index,
2190 d_allocator_p,
2191 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
2192
2193 d_controls_p[index] = static_cast<bsl::uint8_t>(
2194 hashValue & k_HASHLET_MASK);
2195 ++d_size;
2196 }
2197
2198 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
2199 d_controls_p + index,
2200 d_capacity - index - 1),
2201 notFound);
2202}
2203
2204/// Note: `args` contains @ref piecewise_construct and `key`
2205template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2206template< class... ARGS>
2207bsl::pair<typename
2209 bool>
2211 BloombergLP::bslmf::MovableRef<KEY> key,
2212 ARGS&&... args)
2213{
2214 const KEY& k = key;
2215 bool notFound;
2216 bsl::size_t hashValue = d_hasher(k);
2217 bsl::size_t index = indexOfKey(&notFound, k, hashValue);
2218
2219 if (notFound) {
2220 ENTRY_UTIL::construct(d_entries_p + index,
2221 d_allocator_p,
2222 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
2223
2224 d_controls_p[index] = static_cast<bsl::uint8_t>(
2225 hashValue & k_HASHLET_MASK);
2226 ++d_size;
2227 }
2228 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
2229 d_controls_p + index,
2230 d_capacity - index - 1),
2231 notFound);
2232}
2233#endif
2234
2235 // Iterators
2236
2237template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2238inline
2241{
2242 if (d_size) {
2243 for (bsl::size_t i = 0; i < d_capacity; ++i) {
2244 if (0 == (d_controls_p[i] & GroupControl::k_EMPTY)) {
2245 return iterator(IteratorImp(d_entries_p + i,
2246 d_controls_p + i,
2247 d_capacity - i - 1)); // RETURN
2248 }
2249 }
2250 }
2251 return iterator();
2252}
2253
2254template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2255inline
2261
2262 // Aspects
2263
2264template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2265inline
2267 FlatHashTable& other)
2268{
2269 BSLS_ASSERT_SAFE(allocator() == other.allocator());
2270
2271 bslalg::SwapUtil::swap(&d_entries_p, &other.d_entries_p);
2272 bslalg::SwapUtil::swap(&d_controls_p, &other.d_controls_p);
2273 bslalg::SwapUtil::swap(&d_size, &other.d_size);
2274 bslalg::SwapUtil::swap(&d_capacity, &other.d_capacity);
2275 bslalg::SwapUtil::swap(&d_groupControlShift, &other.d_groupControlShift);
2276 bslalg::SwapUtil::swap(&d_hasher, &other.d_hasher);
2277 bslalg::SwapUtil::swap(&d_equal, &other.d_equal);
2278}
2279
2280// ACCESSORS
2281template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2282inline
2284 capacity() const
2285{
2286 return d_capacity;
2287}
2288
2289template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2290inline
2292 const KEY& key) const
2293{
2294 return find(key) != end();
2295}
2296
2297template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2298inline
2299const bsl::uint8_t *FlatHashTable<KEY,
2300 ENTRY,
2301 ENTRY_UTIL,
2302 HASH,
2303 EQUAL>::controls() const
2304{
2305 return d_controls_p;
2306}
2307
2308template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2309inline
2311 const KEY& key) const
2312{
2313 return contains(key) ? 1 : 0;
2314}
2315
2316template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2317inline
2319{
2320 return 0 == d_size;
2321}
2322
2323template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2324inline
2325const ENTRY *FlatHashTable<KEY,
2326 ENTRY,
2327 ENTRY_UTIL,
2328 HASH,
2329 EQUAL>::entries() const
2330{
2331 return d_entries_p;
2332}
2333
2334template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2335inline
2336bsl::pair<typename FlatHashTable<KEY,
2337 ENTRY,
2338 ENTRY_UTIL,
2339 HASH,
2340 EQUAL>::const_iterator,
2341 typename FlatHashTable<KEY,
2342 ENTRY,
2343 ENTRY_UTIL,
2344 HASH,
2345 EQUAL>::const_iterator>
2347 const KEY& key) const
2348{
2349 const_iterator cit1 = find(key);
2350 const_iterator cit2 = cit1;
2351 if (cit1 != end()) {
2352 ++cit2;
2353 }
2354 return bsl::make_pair(cit1, cit2);
2355}
2356
2357template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2358inline
2361{
2362 bsl::size_t index = findKey(key, d_hasher(key));
2363 if (index < d_capacity) {
2364 return const_iterator(IteratorImp(d_entries_p + index,
2365 d_controls_p + index,
2366 d_capacity - index - 1)); // RETURN
2367 }
2368 return end();
2369}
2370
2371template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2372inline
2374{
2375 return d_hasher;
2376}
2377
2378template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2379inline
2381{
2382 return d_equal;
2383}
2384
2385template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2386inline
2387float bdlc::FlatHashTable<KEY,
2388 ENTRY,
2389 ENTRY_UTIL,
2390 HASH,
2391 EQUAL>::load_factor() const
2392{
2393 return d_capacity > 0
2394 ? static_cast<float>(d_size) / static_cast<float>(d_capacity)
2395 : 0;
2396}
2397
2398template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2399inline
2400float bdlc::FlatHashTable<KEY,
2401 ENTRY,
2402 ENTRY_UTIL,
2403 HASH,
2404 EQUAL>::max_load_factor() const
2405{
2406 return static_cast<float>(k_MAX_LOAD_FACTOR_NUMERATOR)
2407 / static_cast<float>(k_MAX_LOAD_FACTOR_DENOMINATOR);
2408}
2409
2410template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2411inline
2413{
2414 return d_size;
2415}
2416
2417 // Iterators
2418
2419template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2420inline
2423{
2424 if (d_size) {
2425 for (bsl::size_t i = 0; i < d_capacity; ++i) {
2426 if (0 == (d_controls_p[i] & GroupControl::k_EMPTY)) {
2427 return const_iterator(
2428 IteratorImp(d_entries_p + i,
2429 d_controls_p + i,
2430 d_capacity - i - 1)); // RETURN
2431 }
2432 }
2433 }
2434 return const_iterator();
2435}
2436
2437template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2438inline
2441{
2442 return begin();
2443}
2444
2445template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2446inline
2452
2453template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2454inline
2460
2461 // Aspects
2462
2463template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2464inline
2470
2471} // close package namespace
2472
2473// FREE OPERATORS
2474template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2475bool bdlc::operator==(const FlatHashTable<KEY,
2476 ENTRY,
2477 ENTRY_UTIL,
2478 HASH,
2479 EQUAL>& lhs,
2480 const FlatHashTable<KEY,
2481 ENTRY,
2482 ENTRY_UTIL,
2483 HASH,
2484 EQUAL>& rhs)
2485{
2486 typedef typename FlatHashTable<KEY,
2487 ENTRY,
2488 ENTRY_UTIL,
2489 HASH,
2490 EQUAL>::const_iterator ConstIterator;
2491
2492 if (lhs.size() == rhs.size()) {
2493 ConstIterator lhsEnd = lhs.end();
2494 ConstIterator rhsEnd = rhs.end();
2495
2496 if (lhs.capacity() <= rhs.capacity()) {
2497 for (ConstIterator it = lhs.begin(); it != lhsEnd; ++it) {
2498 ConstIterator i = rhs.find(ENTRY_UTIL::key(*it));
2499 if (i == rhsEnd || *i != *it) {
2500 return false; // RETURN
2501 }
2502 }
2503 return true; // RETURN
2504 }
2505 else {
2506 for (ConstIterator it = rhs.begin(); it != rhsEnd; ++it) {
2507 ConstIterator i = lhs.find(ENTRY_UTIL::key(*it));
2508 if (i == lhsEnd || *i != *it) {
2509 return false; // RETURN
2510 }
2511 }
2512 return true; // RETURN
2513 }
2514 }
2515 return false;
2516}
2517
2518template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2519bool bdlc::operator!=(const FlatHashTable<KEY,
2520 ENTRY,
2521 ENTRY_UTIL,
2522 HASH,
2523 EQUAL>& lhs,
2524 const FlatHashTable<KEY,
2525 ENTRY,
2526 ENTRY_UTIL,
2527 HASH,
2528 EQUAL>& rhs)
2529{
2530 return !(lhs == rhs);
2531}
2532
2533// FREE FUNCTIONS
2534template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2535inline
2536void bdlc::swap(FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>& a,
2537 FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>& b)
2538{
2539 if (a.allocator() == b.allocator()) {
2540 a.swap(b);
2541
2542 return; // RETURN
2543 }
2544
2545 typedef FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL> Table;
2546
2547 Table futureA(b, a.allocator());
2548 Table futureB(a, b.allocator());
2549
2550 futureA.swap(a);
2551 futureB.swap(b);
2552}
2553
2554namespace bslma {
2555
2556template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2557struct UsesBslmaAllocator<bdlc::FlatHashTable<KEY,
2558 ENTRY,
2559 ENTRY_UTIL,
2560 HASH,
2561 EQUAL> > : bsl::true_type {
2562};
2563
2564} // close namespace bslma
2565
2566namespace bdlc {
2567
2568 // -----------------------------
2569 // struct FlatHashTable_ImplUtil
2570 // -----------------------------
2571
2572// PRIVATE CLASS METHODS
2573template <class ENTRY_TYPE>
2574inline
2575void FlatHashTable_ImplUtil::copyEntryAndControlArrays(
2576 ENTRY_TYPE *firstDestinationEntry,
2577 bsl::uint8_t *firstDestinationControl,
2578 const ENTRY_TYPE *firstSourceEntry,
2579 const ENTRY_TYPE *lastSourceEntry,
2580 const bsl::uint8_t *firstSourceControl,
2581 const bsl::uint8_t *lastSourceControl,
2582 bslma::Allocator *entryAllocator,
2583 bsl::false_type isBitwiseCopyable)
2584{
2585 (void) isBitwiseCopyable;
2586
2588
2589 bsl::memcpy(firstDestinationControl,
2590 firstSourceControl,
2591 bsl::distance(firstSourceControl, lastSourceControl) *
2592 sizeof(bsl::uint8_t));
2593
2594 const bsl::size_t numEntries = static_cast<bsl::size_t>(
2595 bsl::distance(firstSourceEntry, lastSourceEntry));
2596
2597 DestroyEntryArrayProctor<ENTRY_TYPE> destroyEntriesProctor(
2598 firstDestinationEntry,
2599 firstDestinationEntry,
2600 firstDestinationControl,
2601 firstDestinationControl);
2602
2603 for (bsl::size_t idx = 0; idx != numEntries; ++idx) {
2604 ENTRY_TYPE& destinationEntry = *(firstDestinationEntry + idx);
2605 const bsl::uint8_t& sourceControl = *(firstSourceControl + idx);
2606 const ENTRY_TYPE& sourceEntry = *(firstSourceEntry + idx);
2607
2608 if (0 == (sourceControl & GroupControl::k_EMPTY)) {
2610 &destinationEntry, entryAllocator, sourceEntry);
2611 }
2612
2613 destroyEntriesProctor.moveEnd(1);
2614 }
2615
2616 destroyEntriesProctor.release();
2617}
2618
2619template <class ENTRY_TYPE>
2620inline
2621void FlatHashTable_ImplUtil::copyEntryAndControlArrays(
2622 ENTRY_TYPE *firstDestinationEntry,
2623 bsl::uint8_t *firstDestinationControl,
2624 const ENTRY_TYPE *firstSourceEntry,
2625 const ENTRY_TYPE *lastSourceEntry,
2626 const bsl::uint8_t *firstSourceControl,
2627 const bsl::uint8_t *lastSourceControl,
2629 bsl::true_type isBitwiseCopyable)
2630{
2631 (void) isBitwiseCopyable;
2632
2634
2635 bsl::memcpy(firstDestinationControl,
2636 firstSourceControl,
2637 bsl::distance(firstSourceControl, lastSourceControl) *
2638 sizeof(bsl::uint8_t));
2639
2640#if defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION >= 80000
2641#pragma GCC diagnostic push
2642#pragma GCC diagnostic ignored "-Wclass-memaccess"
2643#endif
2644
2645 bsl::memcpy(firstDestinationEntry,
2646 firstSourceEntry,
2647 bsl::distance(firstSourceEntry, lastSourceEntry) *
2648 sizeof(ENTRY_TYPE));
2649
2650#if defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION >= 80000
2651#pragma GCC diagnostic pop
2652#endif
2653}
2654
2655template <class ENTRY_TYPE>
2656inline
2657void FlatHashTable_ImplUtil::destroyEntryArray(
2658 ENTRY_TYPE *firstEntry,
2659 ENTRY_TYPE *lastEntry,
2660 const bsl::uint8_t *firstControl,
2661 const bsl::uint8_t *lastControl,
2662 bsl::false_type triviallyDestructible)
2663{
2664 (void) triviallyDestructible;
2665
2666 ///Implementation Note
2667 ///-------------------
2668 // The implementation of this function uses the
2669 // 'FlatHashTable_GroupControl' facilities to bulk search through the
2670 // control range and look for entries that need to be destroyed. However,
2671 // the size of the ranges passed to this function are not always a multiple
2672 // of 'GroupControl::k_SIZE', and so a second loop is needed to
2673 // sequentially destroy the up-to 'GroupControl::k_SIZE - 1' number of
2674 // entries that cannot be destroyed as part of a bulk operation on
2675 // 'GroupControl::k_SIZE' elements of the entry range.
2676 //
2677 // It may be surprising that the size of these ranges is not always a
2678 // multiple of 'GroupControl::k_SIZE' despite the fact that the capacity of
2679 // a 'FlatHashTable' is always a power of 2. However, this operation can
2680 // be invoked midway through copying one entry array to another if copying
2681 // an entry throws and the already-copied elements need to then be
2682 // destroyed as part of cleaning up during exception handling.
2683
2684 static_cast<void>(lastControl); // silence unused variable warnings
2685
2686 const bsl::size_t numEntries =
2687 static_cast<bsl::size_t>(bsl::distance(firstEntry, lastEntry));
2688 const bsl::size_t numGroupedEntries =
2689 numEntries - (numEntries % GroupControl::k_SIZE);
2690
2691 for (bsl::size_t idx = 0;
2692 idx != numGroupedEntries;
2693 idx += GroupControl::k_SIZE) {
2694 GroupControl groupControl(firstControl + idx);
2695 bsl::uint32_t candidates = groupControl.inUse();
2696 while (candidates) {
2697 const int offset = bdlb::BitUtil::numTrailingUnsetBits(candidates);
2698 bslma::DestructionUtil::destroy(firstEntry + idx + offset);
2699 candidates = bdlb::BitUtil::withBitCleared(candidates, offset);
2700 }
2701 }
2702
2703 for (bsl::size_t idx = numGroupedEntries; idx != numEntries; ++idx) {
2704 ENTRY_TYPE& entry = *(firstEntry + idx);
2705 const bsl::uint8_t& control = *(firstControl + idx);
2706
2707 if (0 == (control & GroupControl::k_EMPTY)) {
2708 bslma::DestructionUtil::destroy(&entry);
2709 }
2710 }
2711}
2712
2713template <class ENTRY_TYPE>
2714inline
2715void FlatHashTable_ImplUtil::destroyEntryArray(
2716 ENTRY_TYPE *,
2717 ENTRY_TYPE *,
2718 const bsl::uint8_t *,
2719 const bsl::uint8_t *,
2720 bsl::true_type triviallyDestructible)
2721{
2722 (void) triviallyDestructible;
2723
2724 // Do nothing, in just the right way.
2725}
2726
2727// CLASS METHODS
2728template <class ENTRY_TYPE>
2729inline
2730void FlatHashTable_ImplUtil::copyEntryAndControlArrays(
2731 ENTRY_TYPE *firstDestinationEntry,
2732 bsl::uint8_t *firstDestinationControl,
2733 const ENTRY_TYPE *firstSourceEntry,
2734 const ENTRY_TYPE *lastSourceEntry,
2735 const bsl::uint8_t *firstSourceControl,
2736 const bsl::uint8_t *lastSourceControl,
2737 bslma::Allocator *entryAllocator)
2738{
2739 BSLS_ASSERT_SAFE(bsl::distance(firstSourceEntry, lastSourceEntry) ==
2740 bsl::distance(firstSourceControl, lastSourceControl));
2741
2742 FlatHashTable_ImplUtil::copyEntryAndControlArrays(
2743 firstDestinationEntry,
2744 firstDestinationControl,
2745 firstSourceEntry,
2746 lastSourceEntry,
2747 firstSourceControl,
2748 lastSourceControl,
2749 entryAllocator,
2751}
2752
2753template <class ENTRY_TYPE>
2754inline
2755void FlatHashTable_ImplUtil::destroyEntryArray(
2756 ENTRY_TYPE *firstEntry,
2757 ENTRY_TYPE *lastEntry,
2758 const bsl::uint8_t *firstControl,
2759 const bsl::uint8_t *lastControl)
2760{
2761 BSLS_ASSERT_SAFE(bsl::distance(firstEntry, lastEntry) ==
2762 bsl::distance(firstControl, lastControl));
2763
2764 ///Implementation Note
2765 ///-------------------
2766 // If a type is trivially copyable then it is also trivially destructible.
2767 // The type trait 'bslmf::IsTriviallyCopyable' is available in C++03
2768 // mode and later, however 'bsl::is_trivially_destructible' is only
2769 // available in C++11 and later and not always on clang. So, this utility
2770 // 'struct' uses bitwise copyability as a stand-in for trivial
2771 // destructibility in order to provide certain optimizations uniformly
2772 // across all C++ versions.
2773
2775 IsEntryTypeTriviallyDestructible;
2776
2777 FlatHashTable_ImplUtil::destroyEntryArray(
2778 firstEntry,
2779 lastEntry,
2780 firstControl,
2781 lastControl,
2782 IsEntryTypeTriviallyDestructible());
2783}
2784
2785 // ------------------------------------------------------
2786 // class FlatHashTable_ImplUtil::DestroyEntryArrayProctor
2787 // ------------------------------------------------------
2788
2789// CREATORS
2790template <class ENTRY_TYPE>
2791inline
2792FlatHashTable_ImplUtil::DestroyEntryArrayProctor<
2793 ENTRY_TYPE>::DestroyEntryArrayProctor(ENTRY_TYPE *firstEntry,
2794 ENTRY_TYPE *lastEntry,
2795 const bsl::uint8_t *firstControl,
2796 const bsl::uint8_t *lastControl)
2797: d_firstEntry_p(firstEntry)
2798, d_lastEntry_p(lastEntry)
2799, d_firstControl_p(firstControl)
2800, d_lastControl_p(lastControl)
2801{
2802}
2803
2804template <class ENTRY_TYPE>
2805inline
2806FlatHashTable_ImplUtil::DestroyEntryArrayProctor<
2807 ENTRY_TYPE>::~DestroyEntryArrayProctor()
2808{
2809 ImplUtil::destroyEntryArray(d_firstEntry_p,
2810 d_lastEntry_p,
2811 d_firstControl_p,
2812 d_lastControl_p);
2813}
2814
2815// MANIPULATORS
2816template <class ENTRY_TYPE>
2817inline
2818void FlatHashTable_ImplUtil::DestroyEntryArrayProctor<ENTRY_TYPE>::moveEnd(
2819 bsl::ptrdiff_t offset)
2820{
2821 d_lastEntry_p += offset;
2822 d_lastControl_p += offset;
2823}
2824
2825template <class ENTRY_TYPE>
2826inline
2827void FlatHashTable_ImplUtil::DestroyEntryArrayProctor<ENTRY_TYPE>::release()
2828{
2829 d_firstEntry_p = 0;
2830 d_lastEntry_p = 0;
2831 d_firstControl_p = 0;
2832 d_lastControl_p = 0;
2833}
2834
2835} // close package namespace
2836
2837
2838#endif // End C++11 code
2839
2840#endif // End C++11 code
2841
2842// ----------------------------------------------------------------------------
2843// Copyright 2020 Bloomberg Finance L.P.
2844// Copyright 2018 The Abseil Authors
2845//
2846// Licensed under the Apache License, Version 2.0 (the "License"); you may not
2847// use this file except in compliance with the License. You may obtain a copy
2848// of the License at
2849//
2850// http://www.apache.org/licenses/LICENSE-2.0
2851//
2852// Unless required by applicable law or agreed to in writing, software
2853// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2854// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2855// License for the specific language governing permissions and limitations
2856// under the License.
2857// ----------------------------- END-OF-FILE ----------------------------------
2858
2859/** @} */
2860/** @} */
2861/** @} */
Definition bdlc_flathashtable_groupcontrol.h:91
static const bsl::uint8_t k_EMPTY
Definition bdlc_flathashtable_groupcontrol.h:125
static const bsl::size_t k_SIZE
Definition bdlc_flathashtable_groupcontrol.h:127
Definition bdlc_flathashtable.h:245
FlatHashTable_IteratorImp & operator=(const FlatHashTable_IteratorImp &rhs)
Definition bdlc_flathashtable.h:1376
FlatHashTable_IteratorImp()
Definition bdlc_flathashtable.h:1344
void operator++()
Definition bdlc_flathashtable.h:1388
ENTRY & operator*() const
Definition bdlc_flathashtable.h:1409
Definition bdlc_flathashtable.h:326
void clear()
Definition bdlc_flathashtable.h:1875
bsl::size_t erase(const KEY &key)
Definition bdlc_flathashtable.h:1927
iterator erase(const_iterator first, const_iterator last)
const ENTRY * entries() const
Definition bdlc_flathashtable.h:2329
static const bsl::size_t k_MIN_CAPACITY
Definition bdlc_flathashtable.h:503
bsl::pair< iterator, bool > try_emplace(BloombergLP::bslmf::MovableRef< KEY > key, ARGS &&... args)
float max_load_factor() const
Definition bdlc_flathashtable.h:2404
const_iterator cbegin() const
Definition bdlc_flathashtable.h:2440
iterator erase(const_iterator position)
void swap(FlatHashTable &other)
Definition bdlc_flathashtable.h:2266
FlatHashTable(bsl::size_t capacity, const HASH &hash, const EQUAL &equal, bslma::Allocator *basicAllocator=0)
Definition bdlc_flathashtable.h:1632
FlatHashTable(bslmf::MovableRef< FlatHashTable > original)
Definition bdlc_flathashtable.h:1722
HASH hash_type
Definition bdlc_flathashtable.h:337
bsl::pair< iterator, bool > insert(const ENTRY &entry)
Definition bdlc_flathashtable.h:2050
EQUAL key_equal_type
Definition bdlc_flathashtable.h:338
static const bsl::size_t k_MAX_LOAD_FACTOR_NUMERATOR
Definition bdlc_flathashtable.h:508
void reset()
Definition bdlc_flathashtable.h:2154
bsl::pair< iterator, bool > emplace(ARGS &&... args)
iterator find(const KEY &key)
Definition bdlc_flathashtable.h:2036
iterator end()
Definition bdlc_flathashtable.h:2257
bsl::pair< const_iterator, const_iterator > equal_range(const KEY &key) const
Definition bdlc_flathashtable.h:2346
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASH, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< EQUAL, LOOKUP_KEY >::value, bsl::size_t >::type erase(LOOKUP_KEY &&key)
Definition bdlc_flathashtable.h:665
FlatHashTable & operator=(bslmf::MovableRef< FlatHashTable > rhs)
Definition bdlc_flathashtable.h:1837
bool empty() const
Definition bdlc_flathashtable.h:2318
bsl::pair< iterator, bool > try_emplace(const KEY &key, ARGS &&... args)
void insert(INPUT_ITERATOR first, INPUT_ITERATOR last)
Definition bdlc_flathashtable.h:2103
static const bsl::size_t k_MAX_LOAD_FACTOR_DENOMINATOR
Definition bdlc_flathashtable.h:513
ENTRY_UTIL entry_util_type
Definition bdlc_flathashtable.h:336
static const bsl::int8_t k_HASHLET_MASK
Definition bdlc_flathashtable.h:506
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASH, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< EQUAL, LOOKUP_KEY >::value, bsl::pair< const_iterator, const_iterator > >::type equal_range(const LOOKUP_KEY &key) const
Definition bdlc_flathashtable.h:972
bslma::Allocator * allocator() const
Return the allocator used by this hash table to supply memory.
Definition bdlc_flathashtable.h:2466
bsl::size_t capacity() const
Definition bdlc_flathashtable.h:2284
bslstl::ForwardIterator< const ENTRY, IteratorImp > const_iterator
Definition bdlc_flathashtable.h:343
bslstl::ForwardIterator< ENTRY, IteratorImp > iterator
Definition bdlc_flathashtable.h:341
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASH, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< EQUAL, LOOKUP_KEY >::value, iterator >::type find(const LOOKUP_KEY &key)
Definition bdlc_flathashtable.h:712
const bsl::uint8_t * controls() const
Definition bdlc_flathashtable.h:2303
ENTRY entry_type
Definition bdlc_flathashtable.h:335
ENTRY & operator[](BSLS_COMPILERFEATURES_FORWARD_REF(KEY_TYPE) key)
Definition bdlc_flathashtable.h:1852
const_iterator find(const KEY &key) const
Definition bdlc_flathashtable.h:2360
FlatHashTable(bslmf::MovableRef< FlatHashTable > original, bslma::Allocator *basicAllocator)
Definition bdlc_flathashtable.h:1744
KEY key_type
Definition bdlc_flathashtable.h:334
EQUAL key_eq() const
Definition bdlc_flathashtable.h:2380
bsl::pair< iterator, bool > insert(bslmf::MovableRef< ENTRY > entry)
Definition bdlc_flathashtable.h:2074
bool contains(const KEY &key) const
Definition bdlc_flathashtable.h:2291
const_iterator begin() const
Definition bdlc_flathashtable.h:2422
iterator begin()
Definition bdlc_flathashtable.h:2240
void reserve(bsl::size_t numEntries)
Definition bdlc_flathashtable.h:2135
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASH, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< EQUAL, LOOKUP_KEY >::value, bsl::pair< iterator, bool > >::type insertTransparent(LOOKUP_KEY &&key)
Definition bdlc_flathashtable.h:754
const_iterator cend() const
Definition bdlc_flathashtable.h:2448
bsl::size_t size() const
Return the number of entries in this table.
Definition bdlc_flathashtable.h:2412
bsl::size_t count(const KEY &key) const
Definition bdlc_flathashtable.h:2310
FlatHashTable & operator=(const FlatHashTable &rhs)
Definition bdlc_flathashtable.h:1824
~FlatHashTable()
Destroy this object and each of its entries.
Definition bdlc_flathashtable.h:1800
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASH, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< EQUAL, LOOKUP_KEY >::value, bsl::pair< iterator, iterator > >::type equal_range(const LOOKUP_KEY &key)
Definition bdlc_flathashtable.h:626
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASH, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< EQUAL, LOOKUP_KEY >::value, const_iterator >::type find(const LOOKUP_KEY &key) const
Definition bdlc_flathashtable.h:997
const_iterator end() const
Definition bdlc_flathashtable.h:2456
HASH hash_function() const
Definition bdlc_flathashtable.h:2373
float load_factor() const
Definition bdlc_flathashtable.h:2391
void rehash(bsl::size_t minimumCapacity)
Definition bdlc_flathashtable.h:2114
bsl::enable_if< BloombergLP::bslmf::IsTransparentPredicate< HASH, LOOKUP_KEY >::value &&BloombergLP::bslmf::IsTransparentPredicate< EQUAL, LOOKUP_KEY >::value, bsl::pair< iterator, bool > >::type try_emplace(LOOKUP_KEY &&key, ARGS &&... args)
Definition bdlc_flathashtable.h:866
FlatHashTable(const FlatHashTable &original, bslma::Allocator *basicAllocator=0)
Definition bdlc_flathashtable.h:1675
iterator erase(iterator position)
bsl::pair< iterator, iterator > equal_range(const KEY &key)
Definition bdlc_flathashtable.h:1894
Definition bslstl_pair.h:1280
static void swap(T *a, T *b)
Definition bslalg_swaputil.h:182
Definition bslma_allocator.h:545
virtual void deallocate(void *address)=0
virtual void * allocate(size_type size)=0
Definition bslma_deallocatorproctor.h:312
void release()
Definition bslma_deallocatorproctor.h:389
Definition bslma_destructorguard.h:132
Definition bslma_destructorproctor.h:259
Definition bslmf_movableref.h:752
Definition bslstl_forwarditerator.h:171
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
#define BSLS_ASSERT_OPT_UNREACHABLE(X)
Definition bsls_assert.h:2065
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2343
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2349
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
Definition bdlc_bitarray.h:506
void swap(BitArray &a, BitArray &b)
bool operator==(const BitArray &lhs, const BitArray &rhs)
bool operator!=(const BitArray &lhs, const BitArray &rhs)
ALLOCATOR const STRING_VIEW_LIKE_TYPE & rhs
Definition bslstl_string.h:3918
deque< VALUE_TYPE, ALLOCATOR >::size_type erase(deque< VALUE_TYPE, ALLOCATOR > &deq, const BDE_OTHER_TYPE &value)
Definition bslstl_deque.h:4424
ALLOCATOR & lhs
Definition bslstl_string.h:3917
T::iterator end(T &container)
Definition bslstl_iterator.h:1621
Definition baljsn_encoder_testtypes.h:76
Definition bdlbb_blob.h:579
static int numTrailingUnsetBits(unsigned int value)
Definition bdlb_bitutil.h:456
static unsigned int withBitCleared(unsigned int value, int index)
Definition bdlb_bitutil.h:571
static int log2(unsigned int value)
Definition bdlb_bitutil.h:340
static unsigned int roundUpToBinaryPower(unsigned int value)
Definition bdlb_bitutil.h:540
Definition bdlc_flathashtable.h:1099
Definition bslmf_enableif.h:530
Definition bslmf_integralconstant.h:261
static void construct(TARGET_TYPE *address, const ALLOCATOR &allocator)
Definition bslma_constructionutil.h:1244
static void destructiveMove(TARGET_TYPE *address, const ALLOCATOR &allocator, TARGET_TYPE *original)
Definition bslma_constructionutil.h:1296
Definition bslma_usesbslmaallocator.h:344
Definition bslmf_isbitwisecopyable.h:298
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
Definition bsls_objectbuffer.h:277
TYPE * address()
Definition bsls_objectbuffer.h:335
TYPE & object()
Definition bsls_objectbuffer.h:352