BDE 4.14.0 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 `flat_hash_map`.
36///
37/// # Classes {#bdlc_flathashtable-classes}
38///
39/// - bdlc::FlatHashTable: open-addressed hash table like Abseil `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 `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 `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 `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>
188#include <bslmf_movableref.h>
189#include <bslmf_util.h> // 'forward(V)'
190
191#include <bsls_assert.h>
193#include <bsls_keyword.h>
194#include <bsls_objectbuffer.h>
195#include <bsls_performancehint.h>
196#include <bsls_platform.h>
197#include <bsls_types.h>
198#include <bsls_util.h> // 'forward<T>(V)'
199
200#include <bsl_cstddef.h>
201#include <bsl_cstdint.h>
202#include <bsl_cstring.h>
203#include <bsl_iterator.h>
204#include <bsl_limits.h>
205#include <bsl_type_traits.h>
206#include <bsl_utility.h>
207
208#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
209// Include version that can be compiled with C++03
210// Generated on Tue Feb 13 09:14:21 2024
211// Command line: sim_cpp11_features.pl bdlc_flathashtable.h
212# define COMPILING_BDLC_FLATHASHTABLE_H
214# undef COMPILING_BDLC_FLATHASHTABLE_H
215#else
216
217
218namespace bdlc {
219
220// FORWARD DECLARATIONS
221struct FlatHashTable_ImplUtil;
222
223template <class ENTRY>
224class FlatHashTable_IteratorImp;
225
226template <class ENTRY>
227bool operator==(const class FlatHashTable_IteratorImp<ENTRY>&,
229
230 // ===============================
231 // class FlatHashTable_IteratorImp
232 // ===============================
233
234/// This class implements the methods required by `bsl::ForwardIterator` to
235/// provide forward iterators. As such, an instance of this class
236/// represents a position within a flat hash table. This class uses no
237/// features of the `ENTRY` type except for addresses of `ENTRY` objects.
238template <class ENTRY>
240{
241 // PRIVATE TYPES
243
244 // DATA
245 ENTRY *d_entries_p;
246 const bsl::uint8_t *d_controls_p;
247 bsl::size_t d_additionalLength;
248
249 // FRIENDS
250 friend bool operator==<>(const FlatHashTable_IteratorImp&,
252
253 public:
254 // CREATORS
255
256 /// Create a `FlatHashTable_IteratorImp` having the default,
257 /// non-dereferencable value.
259
260 /// Create a `FlatHashTable_IteratorImp` referencing the first element
261 /// of the specified `entries` and `controls`, which have the specified
262 /// `additionalLength` values. The behavior is undefined unless
263 /// `entries` points to at least `1 + additionalLength` entry values and
264 /// `controls` points to at least
265 /// `1 + additionalLength + ControlGroup::k_SIZE` control values.
266 FlatHashTable_IteratorImp(ENTRY *entries,
267 const bsl::uint8_t *controls,
268 bsl::size_t additionalLength);
269
270 /// Create a `FlatHashTable_IteratorImp` having the same value as the
271 /// specified `original`.
273
275 // Destroy this object.
276
277 // MANIPULATORS
278
279 /// Assign to this `FlatHashTable_IteratorImp` the value of the
280 /// specified `rhs`.
282
283 /// Advance the `FlatHashTable_IteratorImp` to the next present element
284 /// in the underlying flat hash table. If there is no such element,
285 /// assign this object to `FlatHashTable_InteratorImp()`. The behavior
286 /// is undefined unless this `FlatHashTable_IteratorImp` refers to a
287 /// valid element of the underlying sequence.
288 void operator++();
289
290 // ACCESSORS
291
292 /// Return a reference to the element referred to by this
293 /// `FlatHashTable_IteratorImp`. The behavior is undefined unless this
294 /// `FlatHashTable_IteratorImp() != *this`.
295 ENTRY& operator*() const;
296};
297
298// FREE OPERATORS
299
300/// Return true if the specified `a` and `b` are equal. Two
301/// `FlatHashTable_IteratorImp` objects are equal if they both refer to the
302/// same element of the underlying flat hash table, or are both not
303/// dereferenceable. The behavior is undefined unless `a` and `b` refer to
304/// the same `FlatHashTable`.
305template <class ENTRY>
306bool operator==(const FlatHashTable_IteratorImp<ENTRY>& a,
308
309 // ===================
310 // class FlatHashTable
311 // ===================
312
313/// This class template provides a flat hash table implementation useful for
314/// implementing a flat hash set and flat hash map.
315template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
317{
318 // PRIVATE TYPES
322
323 public:
324 // TYPES
325 typedef KEY key_type;
326 typedef ENTRY entry_type;
327 typedef ENTRY_UTIL entry_util_type;
328 typedef HASH hash_type;
329 typedef EQUAL key_equal_type;
330
331 typedef typename bslstl::ForwardIterator<ENTRY,
333 typedef typename bslstl::ForwardIterator<const ENTRY,
335
336 private:
337 // DATA
338 ENTRY *d_entries_p; // entries of this table
339 bsl::uint8_t *d_controls_p; // control values of this table
340 bsl::size_t d_size; // number of active values
341 bsl::size_t d_capacity; // size of values array
342 int d_groupControlShift; // number of bits to shift hash
343 HASH d_hasher; // hashing functor
344 EQUAL d_equal; // equality functor
345 bslma::Allocator *d_allocator_p; // allocator
346
347 // PRIVATE CLASS METHODS
348
349 /// Return the index of the first available entry indicated by the
350 /// specified `controls` at or after the specified `index`, assuming
351 /// `controls` has the specified `capacity`. The behavior is undefined
352 /// unless `index < capacity` and `controls` has at least `capacity`
353 /// entries.
354 static bsl::size_t findAvailable(bsl::uint8_t *controls,
355 bsl::size_t index,
356 bsl::size_t capacity);
357
358 // PRIVATE MANIPULATORS
359
360 /// Load `true` into the specified `notFound` if there is no entry in
361 /// this table having the specified `key` with the specified
362 /// `hashValue`, and `false` otherwise. Return the index of the entry
363 /// within `d_entries_p` which contains the `key` if such an entry
364 /// exists, otherwise insert an entry with value obtained from
365 /// `ENTRY_UTIL::construct` and return the index of this entry. This
366 /// method rehashes the table if the `key` was not present and the
367 /// addition of an entry would cause the load factor to exceed
368 /// `max_load_factor()`. The behavior is undefined unless
369 /// `hashValue == d_hasher(key)`.
370 bsl::size_t indexOfKey(bool *notFound,
371 const KEY& key,
372 bsl::size_t hashValue);
373
374 /// Change the capacity of this table to the specified `newCapacity`,
375 /// and redistribute all the contained elements into the new sequence of
376 /// entries, according to their hash values. The behavior is undefined
377 /// unless `0 < newCapacity` and `newCapacity` satisfies all class
378 /// invariants.
379 void rehashRaw(bsl::size_t newCapacity);
380
381 // PRIVATE ACCESSORS
382
383 /// Return the index of the entry within `d_entries_p` containing the
384 /// specified `key`, which has the specified `hashValue`, or
385 /// `d_capacity` if the `key` is not present. The behavior is undefined
386 /// unless `hashValue == d_hasher(key)`.
387 bsl::size_t findKey(const KEY& key, bsl::size_t hashValue) const;
388
389 /// Return the minimum capacity that satisfies all class invariants, and
390 /// is at least the specified `minimumCapacity`.
391 bsl::size_t minimumCompliantCapacity(bsl::size_t minimumCapacity) const;
392
393 // NOT IMPLEMENTED
395
396 public:
397 // PUBLIC CLASS DATA
398 static const bsl::size_t k_MIN_CAPACITY = 2 * GroupControl::k_SIZE;
399 // min. non-zero capacity
400
401 static const bsl::int8_t k_HASHLET_MASK = 0x7f; // hashlet = hash & MASK
402
403 static const bsl::size_t k_MAX_LOAD_FACTOR_NUMERATOR = 7;
404 // numerator of fraction
405 // that specifies the
406 // maximum load factor
407
408 static const bsl::size_t k_MAX_LOAD_FACTOR_DENOMINATOR = 8;
409 // denominator of
410 // fraction that
411 // specifies the maximum
412 // load factor
413
414 // CREATORS
415
416 /// Create an empty table having at least the specified `capacity`, that
417 /// will use the specified `hash` to generate hash values for the keys
418 /// of the entries contained in this table, and the specified `equal` to
419 /// verify that the keys of the two entries are the same. Optionally
420 /// specify a `basicAllocator` used to supply memory. If
421 /// `basicAllocator` is 0, the currently installed default allocator is
422 /// used. If `0 == capacity`, no memory is allocated and the object is
423 /// defined to be in the "zero-capacity" state.
425 const HASH& hash,
426 const EQUAL& equal,
427 bslma::Allocator *basicAllocator = 0);
428
429 /// Create a table having the same value, hasher, and key-equality
430 /// comparator as the specified `original`. Optionally specify a
431 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
432 /// the currently installed default allocator is used.
434 bslma::Allocator *basicAllocator = 0);
435
436 /// Create an table having the same value as the specified `original`
437 /// object by moving (in constant time) the contents of `original` to
438 /// the new table. Use a copy of `original.hash_function()` to generate
439 /// hash values for the keys of the entries contained in this table.
440 /// Use a copy of `original.key_eq()` to verify that two keys are equal.
441 /// The allocator associated with `original` is propagated for use in
442 /// the newly-created table. `original` is left in a (valid)
443 /// unspecified state.
445
446 /// Create a table having the same value, hasher, and key-equality
447 /// comparator as the specified `original` object by moving the contents
448 /// of `original` to the new table, and using the specified
449 /// `basicAllocator` to supply memory. Use a copy of
450 /// `original.hash_function()` to generate hash values for the entries
451 /// contained in this table. Use a copy of `original.key_eq()` to
452 /// verify that the keys of two entries are equal. This method requires
453 /// that the (template parameter) type `ENTRY` be `move-insertable` into
454 /// this `FlatHashTable`. If `basicAllocator` is 0, the currently
455 /// installed default allocator is used. If `original` and the newly
456 /// created object have the same allocator then the value of `original`
457 /// becomes unspecified but valid, and no exceptions will be thrown;
458 /// otherwise `original` is unchanged (and an exception may be thrown).
460 bslma::Allocator *basicAllocator);
461
462 /// Destroy this object and each of its entries.
464
465 // MANIPULATORS
466
467 /// Assign to this object the value, hasher, and key-equality functor of
468 /// the specified `rhs` object and return a reference offering
469 /// modifiable access to this object.
471
472 /// Assign to this object the value, hash function, and key-equality
473 /// comparator of the specified `rhs` object and return a reference
474 /// offering modifiable access to this object. The entries of `rhs` are
475 /// moved (in constant time) to this object if the two have the same
476 /// allocator, otherwise entries from `rhs` are moved into this table.
477 /// In either case, `rhs` is left in a valid but unspecified state. If
478 /// an exception is thrown, this object is left in a valid but
479 /// unspecified state.
481
482 /// If an entry with the specified `key` is not already present in this
483 /// table, insert an entry having the value defined by
484 /// `ENTRY_UTIL::construct`; otherwise, this method has no effect.
485 /// Return an iterator referring to the (possibly newly inserted) object
486 /// in this table with the `key`.
487 template <class KEY_TYPE>
489
490 /// Remove all entries from this table. Note that this table will be
491 /// empty after calling this method, but allocated memory may be
492 /// retained for future use. See the `capacity` method.
493 void clear();
494
495 /// Return a pair of iterators providing modifiable access to the
496 /// sequence of objects in this flat hash table having the specified
497 /// `key`, where the first iterator is positioned at the start of the
498 /// sequence, and the second is positioned one past the end of the
499 /// sequence. If this table contains no object having `key`, then the
500 /// two returned iterators will have the same value, `end()`. Note that
501 /// since each key in a flat hash table is unique, the returned range
502 /// contains at most one element.
504
505#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
506 /// Create an `ENTRY` object from the specified `args`, and attempt to
507 /// add it to this flat hash table. Return a `bsl::pair` containing an
508 /// iterator to the newly inserted object and `true` if the element was
509 /// added. If an entry with the same key already exists in this flat
510 /// hash table, return an iterator to that entry and `false`. This
511 /// method requires that the `ENTRY` be `copy-constructible`.
512 template< class... ARGS>
514#endif
515
516 /// Remove from this table the object having the specified `key`, if it
517 /// exists, and return 1; otherwise (there is no object with a key equal
518 /// to `key` in this table) return 0 with no other effect. This method
519 /// invalidates all iterators, and references to the removed element.
520 bsl::size_t erase(const KEY& key);
521
523 /// Remove from this table the object at the specified `position`, and
524 /// return an iterator referring to the element immediately following
525 /// the removed element, or to the past-the-end position if the removed
526 /// element was the last element in the sequence of elements maintained
527 /// by this table. This method invalidates all iterators, and
528 /// references to the removed element. The behavior is undefined unless
529 /// `position` refers to an object in this table.
531
532 /// Remove from this table the objects starting at the specified `first`
533 /// position up to, but not including, the specified `last` position,
534 /// and return `last`. This method invalidates all iterators, and
535 /// references to the removed element. The behavior is undefined unless
536 /// `first` and `last` either refer to elements in this table or are the
537 /// `end` iterator, and the `first` position is at or before the `last`
538 /// position in the iteration sequence provided by this container.
540
541 /// Return an iterator providing modifiable access to the object in this
542 /// flat hash table with a key equal to the specified `key`, if such an
543 /// entry exists, and `end()` otherwise.
544 iterator find(const KEY& key);
545
546#if defined(BSLS_PLATFORM_CMP_SUN) && BSLS_PLATFORM_CMP_VERSION < 0x5130
547 template <class ENTRY_TYPE>
549 BSLS_COMPILERFEATURES_FORWARD_REF(ENTRY_TYPE) entry)
550#else
551 /// Insert the specified `entry` into this table if the key of the
552 /// `entry` does not already exist in this table; otherwise, this method
553 /// has no effect. Return a `pair` whose `first` member is an iterator
554 /// referring to the (possibly newly inserted) object in this table
555 /// whose key is the equal to that of the object to be inserted, and
556 /// whose `second` member is `true` if a new entry was inserted, and
557 /// `false` if a entry having an equal key was already present. Bitwise
558 /// movable types that are not bitwise copyable will be copied (to avoid
559 /// confusion with regard to calling the `entry` destructor after this
560 /// call).
561 template <class ENTRY_TYPE>
565#endif
566 {
567 // Note that some compilers require functions declared with 'enable_if'
568 // to be defined inline.
569
570 bool notFound;
571 bsl::size_t hashValue = d_hasher(ENTRY_UTIL::key(entry));
572 bsl::size_t index = indexOfKey(&notFound,
573 ENTRY_UTIL::key(entry),
574 hashValue);
575
576 if (notFound) {
577 ENTRY_UTIL::construct(
578 d_entries_p + index,
579 d_allocator_p,
580 BSLS_COMPILERFEATURES_FORWARD(ENTRY_TYPE, entry));
581
582 d_controls_p[index] = static_cast<bsl::uint8_t>(
583 hashValue & k_HASHLET_MASK);
584
585 ++d_size;
586 }
587
588 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
589 d_controls_p + index,
590 d_capacity - index - 1),
591 notFound);
592 }
593
594 /// Create an object for each iterator in the range starting at the
595 /// specified `first` iterator and ending immediately before the
596 /// specified `last` iterator, by converting from the object referred to
597 /// by each iterator. Insert into this table each such object whose key
598 /// is not already contained. The (template parameter) type
599 /// `INPUT_ITERATOR` shall meet the requirements of an input iterator
600 /// defined in the C++11 standard [24.2.3] providing access to values of
601 /// a type convertible to `ENTRY`. The behavior is undefined unless
602 /// `first` and `last` refer to a sequence of valid values where `first`
603 /// is at a position at or before `last`.
604 template <class INPUT_ITERATOR>
605 void insert(INPUT_ITERATOR first, INPUT_ITERATOR last);
606
607 /// Change the capacity of this table to at least the specified
608 /// `minimumCapacity`, and redistribute all the contained elements into
609 /// a new sequence of entries, according to their hash values. If
610 /// `0 == minimumCapacity` and `0 == size()`, the table is returned to
611 /// the zero-capacity state. On return, `load_factor()` is less than or
612 /// equal to `max_load_factor()` and all iterators, pointers, and
613 /// references to elements of this `FlatHashTable` are invalidated.
614 void rehash(bsl::size_t minimumCapacity);
615
616 /// Change the capacity of this table to at least a capacity that can
617 /// accommodate the specified `numEntries` (accounting for the load
618 /// factor invariant), and redistribute all the contained elements into
619 /// a new sequence of entries, according to their hash values. If
620 /// `0 == numEntries` and `0 == size()`, the table is returned to the
621 /// zero-capacity state. After this call, `load_factor()` will be less
622 /// than or equal to `max_load_factor()`. Note that this method is
623 /// effectively equivalent to:
624 /// @code
625 /// rehash(bsl::ceil(numEntries / max_load_factor()))
626 /// @endcode
627 void reserve(bsl::size_t numEntries);
628
629 /// Remove all entries from this table and release all memory from this
630 /// table, returning the table to the zero-capacity state.
631 void reset();
632
633#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
634 /// If a key equivalent to the specified `key` already exists in this
635 /// map, return a pair containing an iterator referring to the existing
636 /// item, and `false`. Otherwise, insert into this map a newly-created
637 /// `ENTRY` object, constructed from `key` and the specified `args`, and
638 /// return a pair containing an iterator referring to the newly-created
639 /// entry and `true`. This method requires that the (template
640 /// parameter) types `KEY` and `VALUE` are `emplace-constructible` from
641 /// `key` and `args` respectively. For C++03, `VALUE` must also be
642 /// `copy-constructible`.
643 template< class... ARGS>
644 bsl::pair<iterator, bool> try_emplace(const KEY& key, ARGS&&... args);
645
646 /// If a key equivalent to the specified `key` already exists in this
647 /// map, return a pair containing an iterator referring to the existing
648 /// item, and `false`. Otherwise, insert into this map a newly-created
649 /// `ENTRY` object, constructed from `std::forward<KEY>(key)` and the
650 /// specified `args`, and return a pair containing an iterator referring
651 /// to the newly-created entry and `true`. This method requires that
652 /// the (template parameter) types `KEY` and `VALUE` are
653 /// `emplace-constructible` from `key` and `args` respectively. For
654 /// C++03, `VALUE` must also be `copy-constructible`.
655 template <class... ARGS>
657 BloombergLP::bslmf::MovableRef<KEY> key,
658 ARGS&&... args);
659#endif
660
661 // Iterators
662
663 /// Return an iterator representing the beginning of the sequence of
664 /// entries held by this container.
666
667 /// Return an iterator representing one past the end of the sequence of
668 /// entries held by this container.
670
671 // Aspects
672
673 /// Efficiently exchange the value of this table with the value of the
674 /// specified `other` table. This method provides the no-throw
675 /// exception-safety guarantee. The behavior is undefined unless this
676 /// array was created with the same allocator as `other`.
677 void swap(FlatHashTable& other);
678
679 // ACCESSORS
680
681 /// Return the number of elements this table could hold if the load
682 /// factor were 1.
683 bsl::size_t capacity() const;
684
685 /// Return `true` if this table contains an entry having the specified
686 /// `key`, and `false` otherwise.
687 bool contains(const KEY& key) const;
688
689 /// Return the address of the first element of the underlying array of
690 /// control values in this table, or 0 if this table is in the
691 /// zero-capacity state. An element of this array has the value
692 /// `FlatHashTable_GroupControl::k_EMPTY`,
693 /// `FlatHashTable_GroupControl::k_ERASED`, or a seven bit hashlet value
694 /// for the in-use position (the highest-order bit is unset).
695 const bsl::uint8_t *controls() const;
696
697 /// Return the number of objects contained within this table having the
698 /// specified `key`. Note that since a table maintains unique keys, the
699 /// returned value will be either 0 or 1.
700 bsl::size_t count(const KEY& key) const;
701
702 /// Return `true` if this table contains no entries, and `false`
703 /// otherwise.
704 bool empty() const;
705
706 /// Return the address of the first element of the underlying array of
707 /// entries in this table, or 0 if this table is in the zero-capacity
708 /// state. The behavior is undefined unless the address is verified
709 /// in-use through use of the `controls` array before dereferencing an
710 /// entry in this array.
711 const ENTRY *entries() const;
712
713 /// Return a pair of iterators providing non-modifiable access to the
714 /// sequence of objects in this table having the specified `key`, where
715 /// the first iterator is positioned at the start of the sequence, and
716 /// the second is positioned one past the end of the sequence. If this
717 /// table contains no objects having `key`, then the two returned
718 /// iterators will have the same value, `end()`. Note that since a
719 /// table maintains unique keys, the range will contain at most one
720 /// entry.
722 const KEY& key) const;
723
724 /// Return an iterator representing the position of the entry in this
725 /// flat hash table having the specified `key`, or `end()` if no such
726 /// entry exists in this table.
727 const_iterator find(const KEY& key) const;
728
729 /// Return (a copy of) the unary hash functor used by this flat hash
730 /// table to generate a hash value (of type `bsl::size_t) for a `KEY'
731 /// object.
732 HASH hash_function() const;
733
734 /// Return (a copy of) the binary key-equality functor used by this flat
735 /// hash table that returns `true` if two `KEY` objects are equal, and
736 /// `false` otherwise.
737 EQUAL key_eq() const;
738
739 /// Return the current ratio between the number of elements in this
740 /// table and its capacity.
741 float load_factor() const;
742
743 /// Return the maximum load factor allowed for this table. Note that if
744 /// an insert operation would cause the load factor to exceed the
745 /// `max_load_factor`, that same insert operation will increase the
746 /// capacity and rehash the entries of the container (see `insert` and
747 /// `rehash`). Note that the value returned by `max_load_factor` is
748 /// implementation dependent and cannot be changed by the user.
749 float max_load_factor() const;
750
751 /// Return the number of entries in this table.
752 bsl::size_t size() const;
753
754 // Iterators
755
757
758 /// Return an iterator representing the beginning of the sequence of
759 /// entries held by this container.
761
763
764 /// Return an iterator representing one past the end of the sequence of
765 /// entries held by this container.
767
768 // Aspects
769
770 /// Return the allocator used by this hash table to supply memory.
772};
773
774// FREE OPERATORS
775
776/// Return `true` if the specified `lhs` and `rhs` objects have the same
777/// value, and `false` otherwise. Two `FlatHashTable` objects have the same
778/// value if they have the same number of entries, and for each entry that
779/// is contained in `lhs` there is a entry contained in `rhs` having the
780/// same value. Note that this method requires the (template parameter)
781/// type `ENTRY` to be equality-comparable.
782template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
785
786/// Return `true` if the specified `lhs` and `rhs` objects do not have the
787/// same value, and `false` otherwise. Two `FlatHashTable` objects do not
788/// have the same value if they do not have the same number of entries, or
789/// that for some entry contained in `lhs` there is not a entry in `rhs`
790/// having the same value. Note that this method requires the (template
791/// parameter) type `ENTRY` to be equality-comparable.
792template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
795
796// FREE FUNCTIONS
797
798/// Exchange the values of the specified `a` and `b` objects. This function
799/// provides the no-throw exception-safety guarantee if the two objects were
800/// created with the same allocator and the basic guarantee otherwise.
801template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
804
805 // =============================
806 // struct FlatHashTable_ImplUtil
807 // =============================
808
809/// This component-private, utility `struct` provides a namespace for a
810/// suite of operations used in the implementation of the `FlatHashTable`
811/// class template.
813
814 private:
815 // PRIVATE TYPES
817
818 /// This component-private, mechanism class template provides a proctor
819 /// that, unless its `release` method has been previously invoked, on
820 /// destruction automatically destroys the populated `ENTRY_TYPE`
821 /// elements of an `ENTRY_TYPE` array supplied on construction as
822 /// indicated by a "control" byte array supplied on construction.
823 template <class ENTRY_TYPE>
824 class DestroyEntryArrayProctor;
825
826 // PRIVATE CLASS METHODS
827
828 /// Copy the specified range `[firstSourceControl, lastSourceControl)`
829 /// to the array specified by `firstDestinationControl`, and copy each
830 /// element in the specified range `[firstSourceEntry, lastSourceEntry)`
831 /// at the same index as each byte in the range '[firstSourceControl,
832 /// lastSourceControl)' that has its most-significant bit unset, to the
833 /// corresponding location in the contiguous storage for `ENTRY_TYPE`
834 /// objects specified by `firstDestinationEntry`. Use the specified
835 /// `entryAllocator` as the object allocator for each newly-constructed
836 /// `ENTRY_TYPE` object if `ENTRY_TYPE` is allocator-aware. If
837 /// `entryAllocator` is 0, the currently-installed default allocator is
838 /// used. No exception is thrown if the specified `ENTRY_TYPE` is
839 /// nothrow-copyable, otherwise an exception may be thrown. The
840 /// behavior is undefined unless
841 /// `bslmf::IsBitwiseCopyable<ENTRY_TYPE>::value` is equal to the
842 /// `value` member of the type of the specified `tag`,
843 /// `firstDestinationEntry` is a pointer to the first byte of
844 /// uninitialized and correctly aligned storage for at least
845 /// `bsl::distance(firstSourceEntry, lastSourceEntry)` `ENTRY_TYPE`
846 /// objects, `firstDestinationControl` is a pointer to the first byte of
847 /// `bsl::distance(firstSourceEntry, lastSourceEntry)` bytes of
848 /// uninitialized storage, the range '[firstSourceEntry,
849 /// lastSourceEntry)' denotes a contiguous array of storage for
850 /// optionally-constructed `ENTRY_TYPE` objects, the range
851 /// `[firstSourceControl, lastSourceControl)` denotes a contiguous array
852 /// of `bsl::uint8_t` objects, an `ENTRY_TYPE` object exists at the same
853 /// index in the `[firstSourceEntry, lastSourceEntry)` storage range as
854 /// each byte in the range `[firstControlEntry, lastControlEntry)` that
855 /// has its most significant bit unset, and
856 /// `bsl::distance(firstSourceEntry, lastSourceEntry)` is equal to
857 /// `bsl::distance(firstSourceControl, lastSourceControl)`.
858 template <class ENTRY_TYPE>
859 static void copyEntryAndControlArrays(
860 ENTRY_TYPE *firstDestinationEntry,
861 bsl::uint8_t *firstDestinationControl,
862 const ENTRY_TYPE *firstSourceEntry,
863 const ENTRY_TYPE *lastSourceEntry,
864 const bsl::uint8_t *firstSourceControl,
865 const bsl::uint8_t *lastSourceControl,
866 bslma::Allocator *entryAllocator,
867 bsl::false_type bitwiseCopyable);
868 template <class ENTRY_TYPE>
869 static void copyEntryAndControlArrays(
870 ENTRY_TYPE *firstDestinationEntry,
871 bsl::uint8_t *firstDestinationControl,
872 const ENTRY_TYPE *firstSourceEntry,
873 const ENTRY_TYPE *lastSourceEntry,
874 const bsl::uint8_t *firstSourceControl,
875 const bsl::uint8_t *lastSourceControl,
876 bslma::Allocator *entryAllocator,
877 bsl::true_type bitwiseCopyable);
878
879
880 /// Destroy each entry object in the storage specified by the range
881 /// `[firstEntry, lastEntry)` if the most-significant bit is unset in
882 /// the corresponding element in the specified range
883 /// `[firstControl, lastControl)` (i.e., the most-significant bit of the
884 /// element in the "control" array that has the same index as the
885 /// element in the "entry" array is unset). No exception is thrown.
886 /// The behavior is undefined unless
887 /// `bslmf::IsTriviallyDestructible<ENTRY_TYPE>::value` is equal to the
888 /// `value` member of the type of the specified `tag`, the range
889 /// `[firstEntry, lastEntry)` denotes a contiguous array of storage for
890 /// optionally-constructed `ENTRY_TYPE` objects, the range
891 /// `[firstControl, lastControl)` denotes a contiguous array of
892 /// `bsl::uint8_t` objects, the two arrays have the same number of
893 /// elements, and an `ENTRY_TYPE` object exists at the same index in the
894 /// `[firstEntry, lastEntry)` storage range for each element in the
895 /// `[firstControl, lastControl)` range that has its first bit unset.
896 template <class ENTRY_TYPE>
897 static void destroyEntryArray(ENTRY_TYPE *firstEntry,
898 ENTRY_TYPE *lastEntry,
899 const bsl::uint8_t *firstControl,
900 const bsl::uint8_t *lastControl,
901 bsl::false_type triviallyDestructible);
902 template <class ENTRY_TYPE>
903 static void destroyEntryArray(ENTRY_TYPE *firstEntry,
904 ENTRY_TYPE *lastEntry,
905 const bsl::uint8_t *firstControl,
906 const bsl::uint8_t *lastControl,
907 bsl::true_type triviallyDestructible);
908
909 public:
910 // CLASS METHODS
911
912 /// Copy the specified range `[firstSourceControl, lastSourceControl)`
913 /// to the array specified by `firstDestinationControl`, and copy each
914 /// element in the specified range `[firstSourceEntry, lastSourceEntry)`
915 /// at the same index as each byte in the range '[firstSourceControl,
916 /// lastSourceControl)' that has its most-significant bit unset, to the
917 /// corresponding location in the contiguous storage for `ENTRY_TYPE`
918 /// objects specified by `firstDestinationEntry`. Use the specified
919 /// `entryAllocator` as the object allocator for each newly-constructed
920 /// `ENTRY_TYPE` object if `ENTRY_TYPE` is allocator-aware. If
921 /// `entryAllocator` is 0, the currently-installed default allocator is
922 /// used. No exception is thrown if the specified `ENTRY_TYPE` is
923 /// nothrow-copyable, otherwise an exception may be thrown. The
924 /// behavior is undefined unless `firstDestinationEntry` is a pointer to
925 /// the first byte of uninitialized and correctly aligned storage for at
926 /// least `bsl::distance(firstSourceEntry, lastSourceEntry)`
927 /// `ENTRY_TYPE` objects, `firstDestinationControl` is a pointer to the
928 /// first byte of `bsl::distance(firstSourceEntry, lastSourceEntry)`
929 /// bytes of uninitialized storage, the range '[firstSourceEntry,
930 /// lastSourceEntry)' denotes a contiguous array of storage for
931 /// optionally-constructed `ENTRY_TYPE` objects, the range
932 /// `[firstSourceControl, lastSourceControl)` denotes a contiguous array
933 /// of `bsl::uint8_t` objects, an `ENTRY_TYPE` object exists at the same
934 /// index in the `[firstSourceEntry, lastSourceEntry)` storage range as
935 /// each byte in the range `[firstControlEntry, lastControlEntry)` that
936 /// has its most significant bit unset, and
937 /// `bsl::distance(firstSourceEntry, lastSourceEntry)` is equal to
938 /// `bsl::distance(firstSourceControl, lastSourceControl)`.
939 template <class ENTRY_TYPE>
940 static void
941 copyEntryAndControlArrays(ENTRY_TYPE *firstDestinationEntry,
942 bsl::uint8_t *firstDestinationControl,
943 const ENTRY_TYPE *firstSourceEntry,
944 const ENTRY_TYPE *lastSourceEntry,
945 const bsl::uint8_t *firstSourceControl,
946 const bsl::uint8_t *lastSourceControl,
947 bslma::Allocator *entryAllocator);
948
949 /// Destroy each entry object in the storage specified by the range
950 /// `[firstEntry, lastEntry)` if the most-significant bit is unset in
951 /// the corresponding element in the specified range '[firstControl,
952 /// lastControl)' (i.e., the most-significant bit of the element in the
953 /// "control" array that has the same index as the element in the
954 /// "entry" array is unset). No exception is thrown. The behavior is
955 /// undefined unless the range `[firstEntry, lastEntry)` denotes a
956 /// contiguous array of storage for optionally-constructed `ENTRY_TYPE`
957 /// objects, the range `[firstControl, lastControl)` denotes a
958 /// contiguous array of `bsl::uint8_t` objects, the two arrays have the
959 /// same number of elements, and an `ENTRY_TYPE` object exists at the
960 /// same index in the `[firstEntry, lastEntry)` storage range for each
961 /// element in the `[firstControl, lastControl)` range that has its
962 /// first bit unset.
963 template <class ENTRY_TYPE>
964 static void destroyEntryArray(ENTRY_TYPE *firstEntry,
965 ENTRY_TYPE *lastEntry,
966 const bsl::uint8_t *firstControl,
967 const bsl::uint8_t *lastControl);
968};
969
970 // ======================================================
971 // class FlatHashTable_ImplUtil::DestroyEntryArrayProctor
972 // ======================================================
973
974/// This component-private, mechanism class template provides a proctor
975/// that, unless its `release` method has been previously invoked, on
976/// destruction automatically destroys the populated `ENTRY_TYPE` elements
977/// of an `ENTRY_TYPE` array supplied on construction as indicated by a
978/// "control" byte array supplied on construction.
979template <class ENTRY_TYPE>
980class FlatHashTable_ImplUtil::DestroyEntryArrayProctor {
981
982 // PRIVATE TYPES
983 typedef FlatHashTable_GroupControl GroupControl;
984 typedef FlatHashTable_ImplUtil ImplUtil;
985
986 // DATA
987
988 // pointer to first element of entry array
989 ENTRY_TYPE *d_firstEntry_p;
990
991 // pointer to one-past-the-end of entry array
992 ENTRY_TYPE *d_lastEntry_p;
993
994 // pointer to first element of control array
995 const bsl::uint8_t *d_firstControl_p;
996
997 // pointer to one-past-the-end of control array
998 const bsl::uint8_t *d_lastControl_p;
999
1000 // NOT IMPLEMENTED
1001 DestroyEntryArrayProctor(const DestroyEntryArrayProctor&);
1002 DestroyEntryArrayProctor& operator=(const DestroyEntryArrayProctor&);
1003
1004 public:
1005 // CREATORS
1006
1007 /// Create a new `DestroyEntryArrayProctor` object for the contiguous
1008 /// `ENTRY_TYPE` storage delimited by the range specified by
1009 /// `[firstEntry, lastEntry)` controlled by the bytes in the range
1010 /// specified by `[firstControl, lastControl)`. The behavior is
1011 /// undefined unless 'bsl::distance(firstEntry, lastEntry) ==
1012 /// bsl::distance(`firstControl, lastControl)`. Note that these ranges
1013 /// may be valid sub-ranges (or "views") of larger arrays, and these
1014 /// sub-ranges can be grown or shrunk by `moveEnd`.
1015 DestroyEntryArrayProctor(ENTRY_TYPE *firstEntry,
1016 ENTRY_TYPE *lastEntry,
1017 const bsl::uint8_t *firstControl,
1018 const bsl::uint8_t *lastControl);
1019
1020 /// Destroy this object and each object in the entry storage array held
1021 /// by this object where the most-significant bit of the corresponding
1022 /// element in the control array held by this object is unset.
1023 ~DestroyEntryArrayProctor();
1024
1025 // MANIPULATORS
1026
1027 /// Move the end of the entry and control ranges held by this object by
1028 /// the specified `offset`.
1029 void moveEnd(bsl::ptrdiff_t offset);
1030
1031 /// Release the entry and control ranges held by this object from
1032 /// management by this object, and set this object's held entry and
1033 /// control arrays to the corresponding empty arrays. If the entry and
1034 /// control arrays held by this object are empty, this method has no
1035 /// effect.
1036 void release();
1037};
1038
1039// ============================================================================
1040// INLINE DEFINITIONS
1041// ============================================================================
1042
1043 // -------------------------------
1044 // class FlatHashTable_IteratorImp
1045 // -------------------------------
1046
1047// CREATORS
1048template <class ENTRY>
1049inline
1051: d_entries_p(0)
1052, d_controls_p(0)
1053, d_additionalLength(0)
1054{
1055}
1056
1057template <class ENTRY>
1058inline
1060 ENTRY *entries,
1061 const bsl::uint8_t *controls,
1062 bsl::size_t additionalLength)
1063: d_entries_p(entries)
1064, d_controls_p(controls)
1065, d_additionalLength(additionalLength)
1066{
1067}
1068
1069template <class ENTRY>
1070inline
1072 const FlatHashTable_IteratorImp& original)
1073: d_entries_p(original.d_entries_p)
1074, d_controls_p(original.d_controls_p)
1075, d_additionalLength(original.d_additionalLength)
1076{
1077}
1078
1079// MANIPULATORS
1080template <class ENTRY>
1081inline
1083 const FlatHashTable_IteratorImp& rhs)
1084{
1085 d_entries_p = rhs.d_entries_p;
1086 d_controls_p = rhs.d_controls_p;
1087 d_additionalLength = rhs.d_additionalLength;
1088
1089 return *this;
1090}
1091
1092template <class ENTRY>
1093inline
1095{
1096 BSLS_ASSERT_SAFE(d_entries_p);
1097 BSLS_ASSERT_SAFE(d_controls_p);
1098
1099 while (d_additionalLength) {
1100 ++d_entries_p;
1101 ++d_controls_p;
1102 --d_additionalLength;
1103 if (0 == (*d_controls_p & 0x80)) {
1104 return; // RETURN
1105 }
1106 }
1107
1108 d_entries_p = 0;
1109 d_controls_p = 0;
1110}
1111
1112// ACCESSORS
1113template <class ENTRY>
1114inline
1116{
1117 BSLS_ASSERT_SAFE(d_entries_p);
1118 BSLS_ASSERT_SAFE(d_controls_p);
1119
1120 return *d_entries_p;
1121}
1122
1123} // close package namespace
1124
1125// FREE OPERATORS
1126template <class ENTRY>
1127inline
1128bool bdlc::operator==(const FlatHashTable_IteratorImp<ENTRY>& a,
1129 const FlatHashTable_IteratorImp<ENTRY>& b)
1130{
1131 return a.d_entries_p == b.d_entries_p
1132 && a.d_controls_p == b.d_controls_p
1133 && a.d_additionalLength == b.d_additionalLength;
1134}
1135
1136namespace bdlc {
1137
1138 // -------------------
1139 // class FlatHashTable
1140 // -------------------
1141
1142// PRIVATE CLASS METHODS
1143template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1144bsl::size_t FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>::findAvailable(
1145 bsl::uint8_t *controls,
1146 bsl::size_t index,
1147 bsl::size_t capacity)
1148{
1149 BSLS_ASSERT_SAFE(index < capacity);
1150
1151 for (bsl::size_t i = 0; i < capacity; i += GroupControl::k_SIZE) {
1152 bsl::uint8_t *controlStart = controls + index;
1153
1154 GroupControl groupControl(controlStart);
1155 bsl::uint32_t candidates = groupControl.available();
1156
1157 if (candidates) {
1158 return index
1159 + bdlb::BitUtil::numTrailingUnsetBits(candidates); // RETURN
1160 }
1161
1162 index = (index + GroupControl::k_SIZE) & (capacity - 1);
1163 }
1164
1165 BSLS_ASSERT_OPT(false && "execution should never reach this location");
1166 return capacity;
1167}
1168
1169// PRIVATE MANIPULATORS
1170template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1171bsl::size_t FlatHashTable<KEY,
1172 ENTRY,
1173 ENTRY_UTIL,
1174 HASH,
1175 EQUAL>::indexOfKey(bool *notFound,
1176 const KEY& key,
1177 bsl::size_t hashValue)
1178{
1179 BSLS_ASSERT_SAFE(hashValue == d_hasher(key));
1180
1181 bsl::size_t index = findKey(key, hashValue);
1182
1183 if (index == d_capacity) {
1184 *notFound = true;
1185
1186 if (d_size >= k_MAX_LOAD_FACTOR_NUMERATOR
1187 * (d_capacity / k_MAX_LOAD_FACTOR_DENOMINATOR)) {
1188 rehashRaw(d_capacity > 0 ? 2 * d_capacity : k_MIN_CAPACITY);
1189 }
1190
1191 index = (hashValue >> d_groupControlShift) * GroupControl::k_SIZE;
1192 index = findAvailable(d_controls_p, index, d_capacity);
1193 }
1194 else {
1195 *notFound = false;
1196 }
1197
1198 return index;
1199}
1200
1201template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1202void FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>::rehashRaw(
1203 bsl::size_t newCapacity)
1204{
1205 BSLS_ASSERT_SAFE( 0 < newCapacity);
1206 BSLS_ASSERT_SAFE(newCapacity == minimumCompliantCapacity(newCapacity));
1207
1208 FlatHashTable tmp(newCapacity,
1209 d_hasher,
1210 d_equal,
1211 d_allocator_p);
1212
1213 for (bsl::size_t i = 0; i < d_capacity; i += GroupControl::k_SIZE) {
1214 bsl::uint8_t *controlStart = d_controls_p + i;
1215 ENTRY *entryStart = d_entries_p + i;
1216
1217 GroupControl groupControl(controlStart);
1218 bsl::uint32_t candidates = groupControl.inUse();
1219 while (candidates) {
1220 int offset = bdlb::BitUtil::numTrailingUnsetBits(candidates);
1221 ENTRY *entry = entryStart + offset;
1222
1223 // create a destructor proctor for the element to be moved
1224 bslma::DestructorProctor<ENTRY> proctor(entry);
1225
1226 // perform book-keeping for the destruction
1227 *(controlStart + offset) = GroupControl::k_ERASED;
1228 --d_size;
1229
1230 // place the element in the new container
1231 bsl::size_t hashValue = tmp.d_hasher(ENTRY_UTIL::key(*entry));
1232 bsl::size_t index = (hashValue >> tmp.d_groupControlShift)
1233 * GroupControl::k_SIZE;
1234
1235 index = findAvailable(tmp.d_controls_p, index, tmp.d_capacity);
1236
1237 bslma::ConstructionUtil::destructiveMove(tmp.d_entries_p + index,
1238 tmp.d_allocator_p,
1239 entry);
1240
1241 // release destructor proctor
1242 proctor.release();
1243
1244 tmp.d_controls_p[index] = static_cast<bsl::uint8_t>(
1245 hashValue & k_HASHLET_MASK);
1246
1247 ++tmp.d_size;
1248
1249 candidates = bdlb::BitUtil::withBitCleared(candidates, offset);
1250 }
1251 }
1252
1253 d_allocator_p->deallocate(d_entries_p);
1254 d_allocator_p->deallocate(d_controls_p);
1255
1256 d_entries_p = 0;
1257 d_controls_p = 0;
1258 d_capacity = 0;
1259 d_groupControlShift = 0;
1260
1261 bslalg::SwapUtil::swap(&d_entries_p, &tmp.d_entries_p);
1262 bslalg::SwapUtil::swap(&d_controls_p, &tmp.d_controls_p);
1263 bslalg::SwapUtil::swap(&d_size, &tmp.d_size);
1264 bslalg::SwapUtil::swap(&d_capacity, &tmp.d_capacity);
1265 bslalg::SwapUtil::swap(&d_groupControlShift, &tmp.d_groupControlShift);
1266}
1267
1268// PRIVATE ACCESSORS
1269template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1270bsl::size_t FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>::findKey(
1271 const KEY& key,
1272 bsl::size_t hashValue) const
1273{
1274 BSLS_ASSERT_SAFE(hashValue == d_hasher(key));
1275
1276 bsl::size_t index = (hashValue >> d_groupControlShift)
1277 * GroupControl::k_SIZE;
1278 bsl::uint8_t hashlet = static_cast<bsl::uint8_t>(
1279 hashValue & k_HASHLET_MASK);
1280
1281 for (bsl::size_t i = 0; i < d_capacity; i += GroupControl::k_SIZE) {
1282 bsl::uint8_t *controlStart = d_controls_p + index;
1283 ENTRY *entryStart = d_entries_p + index;
1284
1285 GroupControl groupControl(controlStart);
1286 bsl::uint32_t candidates = groupControl.match(hashlet);
1287 while (candidates) {
1288 int offset = bdlb::BitUtil::numTrailingUnsetBits(candidates);
1289
1290 ENTRY *entry = entryStart + offset;
1291
1293 d_equal(ENTRY_UTIL::key(*entry), key))) {
1294 return index + offset; // RETURN
1295 }
1296 candidates = bdlb::BitUtil::withBitCleared(candidates, offset);
1297 }
1298 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(groupControl.neverFull())) {
1299 break;
1300 }
1301
1302 index = (index + GroupControl::k_SIZE) & (d_capacity - 1);
1303 }
1304
1305 return d_capacity;
1306}
1307
1308template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1309bsl::size_t FlatHashTable<KEY,
1310 ENTRY,
1311 ENTRY_UTIL,
1312 HASH,
1313 EQUAL>::minimumCompliantCapacity(
1314 bsl::size_t minimumCapacity) const
1315{
1316 bsl::size_t minForEntries = ((d_size + k_MAX_LOAD_FACTOR_NUMERATOR - 1)
1317 / k_MAX_LOAD_FACTOR_NUMERATOR)
1318 * k_MAX_LOAD_FACTOR_DENOMINATOR;
1319
1320 bsl::size_t capacity = minimumCapacity >= minForEntries
1321 ? minimumCapacity
1322 : minForEntries;
1323
1324 if (0 < capacity) {
1325 capacity = capacity > k_MIN_CAPACITY
1326 ? static_cast<bsl::size_t>(bdlb::BitUtil::roundUpToBinaryPower(
1327 static_cast<bsl::uint64_t>(capacity)))
1328 : k_MIN_CAPACITY;
1329 }
1330
1331 return capacity;
1332}
1333
1334// CREATORS
1335template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1336inline
1338 bsl::size_t capacity,
1339 const HASH& hash,
1340 const EQUAL& equal,
1341 bslma::Allocator *basicAllocator)
1342: d_entries_p(0)
1343, d_controls_p(0)
1344, d_size(0)
1345, d_capacity(0)
1346, d_groupControlShift(0)
1347, d_hasher(hash)
1348, d_equal(equal)
1349, d_allocator_p(bslma::Default::allocator(basicAllocator))
1350{
1351 if (0 < capacity) {
1352 d_capacity = capacity > k_MIN_CAPACITY
1353 ? static_cast<bsl::size_t>(bdlb::BitUtil::roundUpToBinaryPower(
1354 static_cast<bsl::uint64_t>(capacity)))
1356
1357 d_groupControlShift = static_cast<int>(
1358 sizeof(bsl::size_t) * 8
1359 - bdlb::BitUtil::log2(static_cast<bsl::uint64_t>(
1360 d_capacity
1362
1363 ENTRY *entries = static_cast<ENTRY *>(
1364 d_allocator_p->allocate(d_capacity * sizeof(ENTRY)));
1365
1367 d_allocator_p);
1368
1369 d_controls_p = static_cast<bsl::uint8_t *>(
1370 d_allocator_p->allocate(d_capacity));
1371 bsl::memset(d_controls_p, GroupControl::k_EMPTY, d_capacity);
1372
1373 proctor.release();
1374 d_entries_p = entries;
1375 }
1376}
1377
1378template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1379inline
1381 const FlatHashTable& original,
1382 bslma::Allocator *basicAllocator)
1383: d_entries_p(0)
1384, d_controls_p(0)
1385, d_size(0)
1386, d_capacity(0)
1387, d_groupControlShift(0)
1388, d_hasher(original.hash_function())
1389, d_equal(original.key_eq())
1390, d_allocator_p(bslma::Default::allocator(basicAllocator))
1391{
1392 if (0 != original.d_capacity) {
1393 bsl::uint8_t *const controls = static_cast<bsl::uint8_t *>(
1394 d_allocator_p->allocate(original.d_capacity));
1396 controls,
1397 d_allocator_p);
1398
1399 ENTRY *const entries = static_cast<ENTRY *>(
1400 d_allocator_p->allocate(original.d_capacity * sizeof(ENTRY)));
1402 entries,
1403 d_allocator_p);
1404
1405 ImplUtil::copyEntryAndControlArrays(
1406 entries,
1407 controls,
1408 original.d_entries_p,
1409 original.d_entries_p + original.d_capacity,
1410 original.d_controls_p,
1411 original.d_controls_p + original.d_capacity,
1412 d_allocator_p);
1413
1414 entriesProctor.release();
1415 controlsProctor.release();
1416
1417 d_entries_p = entries;
1418 d_controls_p = controls;
1419 d_size = original.d_size;
1420 d_capacity = original.d_capacity;
1421 d_groupControlShift = original.d_groupControlShift;
1422 }
1423}
1424
1425template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1426inline
1429: d_entries_p(bslmf::MovableRefUtil::access(original).d_entries_p)
1430, d_controls_p(bslmf::MovableRefUtil::access(original).d_controls_p)
1431, d_size(bslmf::MovableRefUtil::access(original).d_size)
1432, d_capacity(bslmf::MovableRefUtil::access(original).d_capacity)
1433, d_groupControlShift(
1434 bslmf::MovableRefUtil::access(original).d_groupControlShift)
1435, d_hasher(bslmf::MovableRefUtil::access(original).d_hasher)
1436, d_equal(bslmf::MovableRefUtil::access(original).d_equal)
1437, d_allocator_p(bslmf::MovableRefUtil::access(original).d_allocator_p)
1438{
1439 FlatHashTable& reference = original;
1440
1441 reference.d_entries_p = 0;
1442 reference.d_controls_p = 0;
1443 reference.d_size = 0;
1444 reference.d_capacity = 0;
1445 reference.d_groupControlShift = 0;
1446}
1447
1448template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1451 bslma::Allocator *basicAllocator)
1452: d_entries_p(0)
1453, d_controls_p(0)
1454, d_size(0)
1455, d_capacity(0)
1456, d_groupControlShift(0)
1457, d_hasher(bslmf::MovableRefUtil::access(original).d_hasher)
1458, d_equal(bslmf::MovableRefUtil::access(original).d_equal)
1459, d_allocator_p(bslma::Default::allocator(basicAllocator))
1460{
1461 FlatHashTable& reference = original;
1462 if (d_allocator_p == reference.d_allocator_p) {
1463 bslalg::SwapUtil::swap(&d_entries_p, &reference.d_entries_p);
1464 bslalg::SwapUtil::swap(&d_controls_p, &reference.d_controls_p);
1465 bslalg::SwapUtil::swap(&d_size, &reference.d_size);
1466 bslalg::SwapUtil::swap(&d_capacity, &reference.d_capacity);
1467 bslalg::SwapUtil::swap(&d_groupControlShift,
1468 &reference.d_groupControlShift);
1469 }
1470 else if (reference.d_capacity) {
1471 bsl::uint8_t *const controls = static_cast<bsl::uint8_t *>(
1472 d_allocator_p->allocate(reference.d_capacity));
1474 controls,
1475 d_allocator_p);
1476
1477 ENTRY *const entries = static_cast<ENTRY *>(
1478 d_allocator_p->allocate(reference.d_capacity * sizeof(ENTRY)));
1480 entries,
1481 d_allocator_p);
1482
1483 ImplUtil::copyEntryAndControlArrays(
1484 entries,
1485 controls,
1486 reference.d_entries_p,
1487 reference.d_entries_p + reference.d_capacity,
1488 reference.d_controls_p,
1489 reference.d_controls_p + reference.d_capacity,
1490 d_allocator_p);
1491
1492 entriesProctor.release();
1493 controlsProctor.release();
1494
1495 d_entries_p = entries;
1496 d_controls_p = controls;
1497 d_size = reference.d_size;
1498 d_capacity = reference.d_capacity;
1499 d_groupControlShift = reference.d_groupControlShift;
1500 }
1501}
1502
1503template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1504inline
1506{
1508 (d_capacity == 0 && d_groupControlShift == 0) ||
1509 (d_groupControlShift ==
1510 static_cast<int>(sizeof(bsl::size_t) * 8 -
1511 bdlb::BitUtil::log2(static_cast<bsl::uint64_t>(
1512 d_capacity / GroupControl::k_SIZE)))));
1513
1514 if (0 != d_entries_p) {
1515 ImplUtil::destroyEntryArray(d_entries_p,
1516 d_entries_p + d_capacity,
1517 d_controls_p,
1518 d_controls_p + d_capacity);
1519
1520 d_allocator_p->deallocate(d_entries_p);
1521 d_allocator_p->deallocate(d_controls_p);
1522 }
1523}
1524
1525// MANIPULATORS
1526template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1527inline
1530 const FlatHashTable& rhs)
1531{
1532 if (this != &rhs) {
1533 FlatHashTable tmp(rhs, d_allocator_p);
1534 swap(tmp);
1535 }
1536 return *this;
1537}
1538
1539template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1540inline
1544{
1545 FlatHashTable& reference = rhs;
1546 if (this != &reference) {
1548 d_allocator_p);
1549 swap(table);
1550 }
1551 return *this;
1552}
1553
1554template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1555template <class KEY_TYPE>
1556inline
1559{
1560 bool notFound;
1561 bsl::size_t hashValue = d_hasher(key);
1562 bsl::size_t index = indexOfKey(&notFound, key, hashValue);
1563
1564 if (notFound) {
1565 ENTRY_UTIL::constructFromKey(d_entries_p + index,
1566 d_allocator_p,
1567 BSLS_COMPILERFEATURES_FORWARD(KEY_TYPE, key));
1568
1569 d_controls_p[index] = static_cast<bsl::uint8_t>(
1570 hashValue & k_HASHLET_MASK);
1571
1572 ++d_size;
1573 }
1574
1575 return d_entries_p[index];
1576}
1577
1578template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1579inline
1581{
1582 ImplUtil::destroyEntryArray(d_entries_p,
1583 d_entries_p + d_capacity,
1584 d_controls_p,
1585 d_controls_p + d_capacity);
1586
1587 if (d_controls_p) {
1588 bsl::memset(d_controls_p, GroupControl::k_EMPTY, d_capacity);
1589 }
1590
1591 d_size = 0;
1592}
1593
1594template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1595inline
1596bsl::pair<
1600{
1601 iterator it1 = find(key);
1602 if (it1 == end()) {
1603 return bsl::make_pair(it1, it1); // RETURN
1604 }
1605 iterator it2 = it1;
1606 ++it2;
1607 return bsl::make_pair(it1, it2);
1608}
1609
1610#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1611template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1612template< class... ARGS>
1613inline
1614bsl::pair<typename
1616 bool>
1618{
1620 ENTRY_UTIL::construct(value.address(),
1621 d_allocator_p,
1622 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
1623
1625 return this->insert(bslmf::MovableRefUtil::move(value.object()));
1626}
1627#endif
1628
1629
1630template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1631inline
1633 const KEY& key)
1634{
1635 iterator it = find(key);
1636 if (it == end()) {
1637 return 0; // RETURN
1638 }
1639 erase(it);
1640 return 1;
1641}
1642
1643template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1644inline
1647 typename FlatHashTable<KEY,
1648 ENTRY,
1649 ENTRY_UTIL,
1650 HASH,
1651 EQUAL>::const_iterator position)
1652{
1653 BSLS_ASSERT_SAFE(position != end());
1654
1655 bsl::size_t index = &*position - d_entries_p;
1656 bslma::DestructionUtil::destroy(d_entries_p + index);
1657 d_controls_p[index] = GroupControl::k_ERASED;
1658 --d_size;
1659
1660 if (d_size) {
1661 for (bsl::size_t i = index + 1; i < d_capacity; ++i) {
1662 if (0 == (d_controls_p[i] & GroupControl::k_EMPTY)) {
1663 return iterator(IteratorImp(d_entries_p + i,
1664 d_controls_p + i,
1665 d_capacity - i - 1)); // RETURN
1666 }
1667 }
1668 }
1669 return iterator();
1670}
1671
1672template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1673inline
1676 typename FlatHashTable<KEY,
1677 ENTRY,
1678 ENTRY_UTIL,
1679 HASH,
1680 EQUAL>::iterator position)
1681{
1682 // Note that this overload is necessary to avoid ambiguity when the key is
1683 // a table iterator.
1684
1685 BSLS_ASSERT_SAFE(position != end());
1686
1687 bsl::size_t index = &*position - d_entries_p;
1688 bslma::DestructionUtil::destroy(d_entries_p + index);
1689 d_controls_p[index] = GroupControl::k_ERASED;
1690 --d_size;
1691
1692 if (d_size) {
1693 for (bsl::size_t i = index + 1; i < d_capacity; ++i) {
1694 if (0 == (d_controls_p[i] & GroupControl::k_EMPTY)) {
1695 return iterator(IteratorImp(d_entries_p + i,
1696 d_controls_p + i,
1697 d_capacity - i - 1)); // RETURN
1698 }
1699 }
1700 }
1701 return iterator();
1702}
1703
1704template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1707 typename FlatHashTable<KEY,
1708 ENTRY,
1709 ENTRY_UTIL,
1710 HASH,
1711 EQUAL>::const_iterator first,
1712 typename FlatHashTable<KEY,
1713 ENTRY,
1714 ENTRY_UTIL,
1715 HASH,
1716 EQUAL>::const_iterator last)
1717{
1718 iterator rv;
1719 {
1720 if (last != end()) {
1721 bsl::size_t index = &*last - d_entries_p;
1722 rv = iterator(IteratorImp(d_entries_p + index,
1723 d_controls_p + index,
1724 d_capacity - index - 1));
1725 }
1726 else {
1727 rv = end();
1728 }
1729 }
1730
1731 for (; first != last; ++first) {
1732 erase(first);
1733 }
1734
1735 return rv;
1736}
1737
1738template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1739inline
1742{
1743 bsl::size_t index = findKey(key, d_hasher(key));
1744 if (index < d_capacity) {
1745 return iterator(IteratorImp(d_entries_p + index,
1746 d_controls_p + index,
1747 d_capacity - index - 1)); // RETURN
1748 }
1749 return end();
1750}
1751
1752template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1753template <class INPUT_ITERATOR>
1754inline
1756 INPUT_ITERATOR first,
1757 INPUT_ITERATOR last)
1758{
1759 for (; first != last; ++first) {
1760 insert(*first);
1761 }
1762}
1763
1764template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1765inline
1767 bsl::size_t minimumCapacity)
1768{
1769 minimumCapacity = minimumCompliantCapacity(minimumCapacity);
1770
1771 if (0 < minimumCapacity) {
1772 rehashRaw(minimumCapacity);
1773 }
1774 else {
1775 d_allocator_p->deallocate(d_entries_p);
1776 d_allocator_p->deallocate(d_controls_p);
1777
1778 d_entries_p = 0;
1779 d_controls_p = 0;
1780 d_capacity = 0;
1781 d_groupControlShift = 0;
1782 }
1783}
1784
1785template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1786inline
1788 bsl::size_t numEntries)
1789{
1790 if (0 == d_capacity && 0 == numEntries) {
1791 // From DRQS 167247593, 'reserve(0)' on an empty container is a
1792 // performance concern.
1793
1794 return; // RETURN
1795 }
1796
1797 bsl::size_t minForEntries = ((numEntries + k_MAX_LOAD_FACTOR_NUMERATOR - 1)
1798 / k_MAX_LOAD_FACTOR_NUMERATOR)
1799 * k_MAX_LOAD_FACTOR_DENOMINATOR;
1800
1801 rehash(minForEntries);
1802}
1803
1804template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1805inline
1807{
1808 if (0 != d_entries_p) {
1809 ImplUtil::destroyEntryArray(d_entries_p,
1810 d_entries_p + d_capacity,
1811 d_controls_p,
1812 d_controls_p + d_capacity);
1813
1814 d_allocator_p->deallocate(d_entries_p);
1815 d_allocator_p->deallocate(d_controls_p);
1816
1817 d_entries_p = 0;
1818 d_controls_p = 0;
1819 d_capacity = 0;
1820 d_size = 0;
1821 d_groupControlShift = 0;
1822 }
1823}
1824
1825#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
1826/// Note: `args` contains `key`
1827template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1828template< class... ARGS>
1829bsl::pair<typename
1831 bool>
1833 const KEY& key,
1834 ARGS&&... args)
1835{
1836 bool notFound;
1837 bsl::size_t hashValue = d_hasher(key);
1838 bsl::size_t index = indexOfKey(&notFound, key, hashValue);
1839
1840 if (notFound) {
1841 ENTRY_UTIL::construct(d_entries_p + index,
1842 d_allocator_p,
1843 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
1844
1845 d_controls_p[index] = static_cast<bsl::uint8_t>(
1846 hashValue & k_HASHLET_MASK);
1847 ++d_size;
1848 }
1849
1850 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
1851 d_controls_p + index,
1852 d_capacity - index - 1),
1853 notFound);
1854}
1855
1856/// Note: `args` contains `key`
1857template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1858template< class... ARGS>
1859bsl::pair<typename
1861 bool>
1863 BloombergLP::bslmf::MovableRef<KEY> key,
1864 ARGS&&... args)
1865{
1866 const KEY& k = key;
1867 bool notFound;
1868 bsl::size_t hashValue = d_hasher(k);
1869 bsl::size_t index = indexOfKey(&notFound, k, hashValue);
1870
1871 if (notFound) {
1872 ENTRY_UTIL::construct(d_entries_p + index,
1873 d_allocator_p,
1874 BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
1875
1876 d_controls_p[index] = static_cast<bsl::uint8_t>(
1877 hashValue & k_HASHLET_MASK);
1878 ++d_size;
1879 }
1880 return bsl::pair<iterator, bool>(IteratorImp(d_entries_p + index,
1881 d_controls_p + index,
1882 d_capacity - index - 1),
1883 notFound);
1884}
1885#endif
1886
1887 // Iterators
1888
1889template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1890inline
1893{
1894 if (d_size) {
1895 for (bsl::size_t i = 0; i < d_capacity; ++i) {
1896 if (0 == (d_controls_p[i] & GroupControl::k_EMPTY)) {
1897 return iterator(IteratorImp(d_entries_p + i,
1898 d_controls_p + i,
1899 d_capacity - i - 1)); // RETURN
1900 }
1901 }
1902 }
1903 return iterator();
1904}
1905
1906template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1907inline
1913
1914 // Aspects
1915
1916template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1917inline
1919 FlatHashTable& other)
1920{
1921 BSLS_ASSERT_SAFE(allocator() == other.allocator());
1922
1923 bslalg::SwapUtil::swap(&d_entries_p, &other.d_entries_p);
1924 bslalg::SwapUtil::swap(&d_controls_p, &other.d_controls_p);
1925 bslalg::SwapUtil::swap(&d_size, &other.d_size);
1926 bslalg::SwapUtil::swap(&d_capacity, &other.d_capacity);
1927 bslalg::SwapUtil::swap(&d_groupControlShift, &other.d_groupControlShift);
1928 bslalg::SwapUtil::swap(&d_hasher, &other.d_hasher);
1929 bslalg::SwapUtil::swap(&d_equal, &other.d_equal);
1930}
1931
1932// ACCESSORS
1933template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1934inline
1936 capacity() const
1937{
1938 return d_capacity;
1939}
1940
1941template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1942inline
1944 const KEY& key) const
1945{
1946 return find(key) != end();
1947}
1948
1949template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1950inline
1951const bsl::uint8_t *FlatHashTable<KEY,
1952 ENTRY,
1953 ENTRY_UTIL,
1954 HASH,
1955 EQUAL>::controls() const
1956{
1957 return d_controls_p;
1958}
1959
1960template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1961inline
1963 const KEY& key) const
1964{
1965 return contains(key) ? 1 : 0;
1966}
1967
1968template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1969inline
1971{
1972 return 0 == d_size;
1973}
1974
1975template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1976inline
1977const ENTRY *FlatHashTable<KEY,
1978 ENTRY,
1979 ENTRY_UTIL,
1980 HASH,
1981 EQUAL>::entries() const
1982{
1983 return d_entries_p;
1984}
1985
1986template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
1987inline
1988bsl::pair<typename FlatHashTable<KEY,
1989 ENTRY,
1990 ENTRY_UTIL,
1991 HASH,
1992 EQUAL>::const_iterator,
1993 typename FlatHashTable<KEY,
1994 ENTRY,
1995 ENTRY_UTIL,
1996 HASH,
1997 EQUAL>::const_iterator>
1999 const KEY& key) const
2000{
2001 const_iterator cit1 = find(key);
2002 const_iterator cit2 = cit1;
2003 if (cit1 != end()) {
2004 ++cit2;
2005 }
2006 return bsl::make_pair(cit1, cit2);
2007}
2008
2009template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2010inline
2013{
2014 bsl::size_t index = findKey(key, d_hasher(key));
2015 if (index < d_capacity) {
2016 return const_iterator(IteratorImp(d_entries_p + index,
2017 d_controls_p + index,
2018 d_capacity - index - 1)); // RETURN
2019 }
2020 return end();
2021}
2022
2023template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2024inline
2026{
2027 return d_hasher;
2028}
2029
2030template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2031inline
2033{
2034 return d_equal;
2035}
2036
2037template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2038inline
2039float bdlc::FlatHashTable<KEY,
2040 ENTRY,
2041 ENTRY_UTIL,
2042 HASH,
2043 EQUAL>::load_factor() const
2044{
2045 return d_capacity > 0
2046 ? static_cast<float>(d_size) / static_cast<float>(d_capacity)
2047 : 0;
2048}
2049
2050template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2051inline
2052float bdlc::FlatHashTable<KEY,
2053 ENTRY,
2054 ENTRY_UTIL,
2055 HASH,
2056 EQUAL>::max_load_factor() const
2057{
2058 return static_cast<float>(k_MAX_LOAD_FACTOR_NUMERATOR)
2059 / static_cast<float>(k_MAX_LOAD_FACTOR_DENOMINATOR);
2060}
2061
2062template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2063inline
2065{
2066 return d_size;
2067}
2068
2069 // Iterators
2070
2071template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2072inline
2075{
2076 if (d_size) {
2077 for (bsl::size_t i = 0; i < d_capacity; ++i) {
2078 if (0 == (d_controls_p[i] & GroupControl::k_EMPTY)) {
2079 return const_iterator(
2080 IteratorImp(d_entries_p + i,
2081 d_controls_p + i,
2082 d_capacity - i - 1)); // RETURN
2083 }
2084 }
2085 }
2086 return const_iterator();
2087}
2088
2089template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2090inline
2093{
2094 return begin();
2095}
2096
2097template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2098inline
2104
2105template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2106inline
2112
2113 // Aspects
2114
2115template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2116inline
2122
2123} // close package namespace
2124
2125// FREE OPERATORS
2126template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2127bool bdlc::operator==(const FlatHashTable<KEY,
2128 ENTRY,
2129 ENTRY_UTIL,
2130 HASH,
2131 EQUAL>& lhs,
2132 const FlatHashTable<KEY,
2133 ENTRY,
2134 ENTRY_UTIL,
2135 HASH,
2136 EQUAL>& rhs)
2137{
2138 typedef typename FlatHashTable<KEY,
2139 ENTRY,
2140 ENTRY_UTIL,
2141 HASH,
2142 EQUAL>::const_iterator ConstIterator;
2143
2144 if (lhs.size() == rhs.size()) {
2145 ConstIterator lhsEnd = lhs.end();
2146 ConstIterator rhsEnd = rhs.end();
2147
2148 if (lhs.capacity() <= rhs.capacity()) {
2149 for (ConstIterator it = lhs.begin(); it != lhsEnd; ++it) {
2150 ConstIterator i = rhs.find(ENTRY_UTIL::key(*it));
2151 if (i == rhsEnd || *i != *it) {
2152 return false; // RETURN
2153 }
2154 }
2155 return true; // RETURN
2156 }
2157 else {
2158 for (ConstIterator it = rhs.begin(); it != rhsEnd; ++it) {
2159 ConstIterator i = lhs.find(ENTRY_UTIL::key(*it));
2160 if (i == lhsEnd || *i != *it) {
2161 return false; // RETURN
2162 }
2163 }
2164 return true; // RETURN
2165 }
2166 }
2167 return false;
2168}
2169
2170template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2171bool bdlc::operator!=(const FlatHashTable<KEY,
2172 ENTRY,
2173 ENTRY_UTIL,
2174 HASH,
2175 EQUAL>& lhs,
2176 const FlatHashTable<KEY,
2177 ENTRY,
2178 ENTRY_UTIL,
2179 HASH,
2180 EQUAL>& rhs)
2181{
2182 return !(lhs == rhs);
2183}
2184
2185// FREE FUNCTIONS
2186template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2187inline
2188void bdlc::swap(FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>& a,
2189 FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL>& b)
2190{
2191 if (a.allocator() == b.allocator()) {
2192 a.swap(b);
2193
2194 return; // RETURN
2195 }
2196
2197 typedef FlatHashTable<KEY, ENTRY, ENTRY_UTIL, HASH, EQUAL> Table;
2198
2199 Table futureA(b, a.allocator());
2200 Table futureB(a, b.allocator());
2201
2202 futureA.swap(a);
2203 futureB.swap(b);
2204}
2205
2206namespace bslma {
2207
2208template <class KEY, class ENTRY, class ENTRY_UTIL, class HASH, class EQUAL>
2209struct UsesBslmaAllocator<bdlc::FlatHashTable<KEY,
2210 ENTRY,
2211 ENTRY_UTIL,
2212 HASH,
2213 EQUAL> > : bsl::true_type {
2214};
2215
2216} // close namespace bslma
2217
2218namespace bdlc {
2219
2220 // -----------------------------
2221 // struct FlatHashTable_ImplUtil
2222 // -----------------------------
2223
2224// PRIVATE CLASS METHODS
2225template <class ENTRY_TYPE>
2226inline
2227void FlatHashTable_ImplUtil::copyEntryAndControlArrays(
2228 ENTRY_TYPE *firstDestinationEntry,
2229 bsl::uint8_t *firstDestinationControl,
2230 const ENTRY_TYPE *firstSourceEntry,
2231 const ENTRY_TYPE *lastSourceEntry,
2232 const bsl::uint8_t *firstSourceControl,
2233 const bsl::uint8_t *lastSourceControl,
2234 bslma::Allocator *entryAllocator,
2235 bsl::false_type isBitwiseCopyable)
2236{
2237 (void) isBitwiseCopyable;
2238
2240
2241 bsl::memcpy(firstDestinationControl,
2242 firstSourceControl,
2243 bsl::distance(firstSourceControl, lastSourceControl) *
2244 sizeof(bsl::uint8_t));
2245
2246 const bsl::size_t numEntries = static_cast<bsl::size_t>(
2247 bsl::distance(firstSourceEntry, lastSourceEntry));
2248
2249 DestroyEntryArrayProctor<ENTRY_TYPE> destroyEntriesProctor(
2250 firstDestinationEntry,
2251 firstDestinationEntry,
2252 firstDestinationControl,
2253 firstDestinationControl);
2254
2255 for (bsl::size_t idx = 0; idx != numEntries; ++idx) {
2256 ENTRY_TYPE& destinationEntry = *(firstDestinationEntry + idx);
2257 const bsl::uint8_t& sourceControl = *(firstSourceControl + idx);
2258 const ENTRY_TYPE& sourceEntry = *(firstSourceEntry + idx);
2259
2260 if (0 == (sourceControl & GroupControl::k_EMPTY)) {
2262 &destinationEntry, entryAllocator, sourceEntry);
2263 }
2264
2265 destroyEntriesProctor.moveEnd(1);
2266 }
2267
2268 destroyEntriesProctor.release();
2269}
2270
2271template <class ENTRY_TYPE>
2272inline
2273void FlatHashTable_ImplUtil::copyEntryAndControlArrays(
2274 ENTRY_TYPE *firstDestinationEntry,
2275 bsl::uint8_t *firstDestinationControl,
2276 const ENTRY_TYPE *firstSourceEntry,
2277 const ENTRY_TYPE *lastSourceEntry,
2278 const bsl::uint8_t *firstSourceControl,
2279 const bsl::uint8_t *lastSourceControl,
2281 bsl::true_type isBitwiseCopyable)
2282{
2283 (void) isBitwiseCopyable;
2284
2286
2287 bsl::memcpy(firstDestinationControl,
2288 firstSourceControl,
2289 bsl::distance(firstSourceControl, lastSourceControl) *
2290 sizeof(bsl::uint8_t));
2291
2292#if defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION >= 80000
2293#pragma GCC diagnostic push
2294#pragma GCC diagnostic ignored "-Wclass-memaccess"
2295#endif
2296
2297 bsl::memcpy(firstDestinationEntry,
2298 firstSourceEntry,
2299 bsl::distance(firstSourceEntry, lastSourceEntry) *
2300 sizeof(ENTRY_TYPE));
2301
2302#if defined(BSLS_PLATFORM_CMP_GNU) && BSLS_PLATFORM_CMP_VERSION >= 80000
2303#pragma GCC diagnostic pop
2304#endif
2305}
2306
2307template <class ENTRY_TYPE>
2308inline
2309void FlatHashTable_ImplUtil::destroyEntryArray(
2310 ENTRY_TYPE *firstEntry,
2311 ENTRY_TYPE *lastEntry,
2312 const bsl::uint8_t *firstControl,
2313 const bsl::uint8_t *lastControl,
2314 bsl::false_type triviallyDestructible)
2315{
2316 (void) triviallyDestructible;
2317
2318 ///Implementation Note
2319 ///-------------------
2320 // The implementation of this function uses the
2321 // 'FlatHashTable_GroupControl' facilities to bulk search through the
2322 // control range and look for entries that need to be destroyed. However,
2323 // the size of the ranges passed to this function are not always a multiple
2324 // of 'GroupControl::k_SIZE', and so a second loop is needed to
2325 // sequentially destroy the up-to 'GroupControl::k_SIZE - 1' number of
2326 // entries that cannot be destroyed as part of a bulk operation on
2327 // 'GroupControl::k_SIZE' elements of the entry range.
2328 //
2329 // It may be surprising that the size of these ranges is not always a
2330 // multiple of 'GroupControl::k_SIZE' despite the fact that the capacity of
2331 // a 'FlatHashTable' is always a power of 2. However, this operation can
2332 // be invoked midway through copying one entry array to another if copying
2333 // an entry throws and the already-copied elements need to then be
2334 // destroyed as part of cleaning up during exception handling.
2335
2336 static_cast<void>(lastControl); // silence unused variable warnings
2337
2338 const bsl::size_t numEntries =
2339 static_cast<bsl::size_t>(bsl::distance(firstEntry, lastEntry));
2340 const bsl::size_t numGroupedEntries =
2341 numEntries - (numEntries % GroupControl::k_SIZE);
2342
2343 for (bsl::size_t idx = 0;
2344 idx != numGroupedEntries;
2345 idx += GroupControl::k_SIZE) {
2346 GroupControl groupControl(firstControl + idx);
2347 bsl::uint32_t candidates = groupControl.inUse();
2348 while (candidates) {
2349 const int offset = bdlb::BitUtil::numTrailingUnsetBits(candidates);
2350 bslma::DestructionUtil::destroy(firstEntry + idx + offset);
2351 candidates = bdlb::BitUtil::withBitCleared(candidates, offset);
2352 }
2353 }
2354
2355 for (bsl::size_t idx = numGroupedEntries; idx != numEntries; ++idx) {
2356 ENTRY_TYPE& entry = *(firstEntry + idx);
2357 const bsl::uint8_t& control = *(firstControl + idx);
2358
2359 if (0 == (control & GroupControl::k_EMPTY)) {
2360 bslma::DestructionUtil::destroy(&entry);
2361 }
2362 }
2363}
2364
2365template <class ENTRY_TYPE>
2366inline
2367void FlatHashTable_ImplUtil::destroyEntryArray(
2368 ENTRY_TYPE *,
2369 ENTRY_TYPE *,
2370 const bsl::uint8_t *,
2371 const bsl::uint8_t *,
2372 bsl::true_type triviallyDestructible)
2373{
2374 (void) triviallyDestructible;
2375
2376 // Do nothing, in just the right way.
2377}
2378
2379// CLASS METHODS
2380template <class ENTRY_TYPE>
2381inline
2382void FlatHashTable_ImplUtil::copyEntryAndControlArrays(
2383 ENTRY_TYPE *firstDestinationEntry,
2384 bsl::uint8_t *firstDestinationControl,
2385 const ENTRY_TYPE *firstSourceEntry,
2386 const ENTRY_TYPE *lastSourceEntry,
2387 const bsl::uint8_t *firstSourceControl,
2388 const bsl::uint8_t *lastSourceControl,
2389 bslma::Allocator *entryAllocator)
2390{
2391 BSLS_ASSERT_SAFE(bsl::distance(firstSourceEntry, lastSourceEntry) ==
2392 bsl::distance(firstSourceControl, lastSourceControl));
2393
2394 FlatHashTable_ImplUtil::copyEntryAndControlArrays(
2395 firstDestinationEntry,
2396 firstDestinationControl,
2397 firstSourceEntry,
2398 lastSourceEntry,
2399 firstSourceControl,
2400 lastSourceControl,
2401 entryAllocator,
2403}
2404
2405template <class ENTRY_TYPE>
2406inline
2407void FlatHashTable_ImplUtil::destroyEntryArray(
2408 ENTRY_TYPE *firstEntry,
2409 ENTRY_TYPE *lastEntry,
2410 const bsl::uint8_t *firstControl,
2411 const bsl::uint8_t *lastControl)
2412{
2413 BSLS_ASSERT_SAFE(bsl::distance(firstEntry, lastEntry) ==
2414 bsl::distance(firstControl, lastControl));
2415
2416 ///Implementation Note
2417 ///-------------------
2418 // If a type is trivially copyable then it is also trivially destructible.
2419 // The type trait 'bslmf::IsTriviallyCopyable' is available in C++03
2420 // mode and later, however 'bsl::is_trivially_destructible' is only
2421 // available in C++11 and later and not always on clang. So, this utility
2422 // 'struct' uses bitwise copyability as a stand-in for trivial
2423 // destructibility in order to provide certain optimizations uniformly
2424 // across all C++ versions.
2425
2427 IsEntryTypeTriviallyDestructible;
2428
2429 FlatHashTable_ImplUtil::destroyEntryArray(
2430 firstEntry,
2431 lastEntry,
2432 firstControl,
2433 lastControl,
2434 IsEntryTypeTriviallyDestructible());
2435}
2436
2437 // ------------------------------------------------------
2438 // class FlatHashTable_ImplUtil::DestroyEntryArrayProctor
2439 // ------------------------------------------------------
2440
2441// CREATORS
2442template <class ENTRY_TYPE>
2443inline
2444FlatHashTable_ImplUtil::DestroyEntryArrayProctor<
2445 ENTRY_TYPE>::DestroyEntryArrayProctor(ENTRY_TYPE *firstEntry,
2446 ENTRY_TYPE *lastEntry,
2447 const bsl::uint8_t *firstControl,
2448 const bsl::uint8_t *lastControl)
2449: d_firstEntry_p(firstEntry)
2450, d_lastEntry_p(lastEntry)
2451, d_firstControl_p(firstControl)
2452, d_lastControl_p(lastControl)
2453{
2454}
2455
2456template <class ENTRY_TYPE>
2457inline
2458FlatHashTable_ImplUtil::DestroyEntryArrayProctor<
2459 ENTRY_TYPE>::~DestroyEntryArrayProctor()
2460{
2461 ImplUtil::destroyEntryArray(d_firstEntry_p,
2462 d_lastEntry_p,
2463 d_firstControl_p,
2464 d_lastControl_p);
2465}
2466
2467// MANIPULATORS
2468template <class ENTRY_TYPE>
2469inline
2470void FlatHashTable_ImplUtil::DestroyEntryArrayProctor<ENTRY_TYPE>::moveEnd(
2471 bsl::ptrdiff_t offset)
2472{
2473 d_lastEntry_p += offset;
2474 d_lastControl_p += offset;
2475}
2476
2477template <class ENTRY_TYPE>
2478inline
2479void FlatHashTable_ImplUtil::DestroyEntryArrayProctor<ENTRY_TYPE>::release()
2480{
2481 d_firstEntry_p = 0;
2482 d_lastEntry_p = 0;
2483 d_firstControl_p = 0;
2484 d_lastControl_p = 0;
2485}
2486
2487} // close package namespace
2488
2489
2490#endif // End C++11 code
2491
2492#endif
2493
2494// ----------------------------------------------------------------------------
2495// Copyright 2020 Bloomberg Finance L.P.
2496// Copyright 2018 The Abseil Authors
2497//
2498// Licensed under the Apache License, Version 2.0 (the "License"); you may not
2499// use this file except in compliance with the License. You may obtain a copy
2500// of the License at
2501//
2502// http://www.apache.org/licenses/LICENSE-2.0
2503//
2504// Unless required by applicable law or agreed to in writing, software
2505// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2506// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2507// License for the specific language governing permissions and limitations
2508// under the License.
2509// ----------------------------- END-OF-FILE ----------------------------------
2510
2511/** @} */
2512/** @} */
2513/** @} */
Definition bdlc_flathashtable_groupcontrol.h:91
static const bsl::uint8_t k_EMPTY
Definition bdlc_flathashtable_groupcontrol.h:124
static const bsl::size_t k_SIZE
Definition bdlc_flathashtable_groupcontrol.h:126
Definition bdlc_flathashtable.h:240
FlatHashTable_IteratorImp & operator=(const FlatHashTable_IteratorImp &rhs)
Definition bdlc_flathashtable.h:1082
FlatHashTable_IteratorImp()
Definition bdlc_flathashtable.h:1050
void operator++()
Definition bdlc_flathashtable.h:1094
ENTRY & operator*() const
Definition bdlc_flathashtable.h:1115
Definition bdlc_flathashtable.h:317
void clear()
Definition bdlc_flathashtable.h:1580
bsl::size_t erase(const KEY &key)
Definition bdlc_flathashtable.h:1632
iterator erase(const_iterator first, const_iterator last)
const ENTRY * entries() const
Definition bdlc_flathashtable.h:1981
static const bsl::size_t k_MIN_CAPACITY
Definition bdlc_flathashtable.h:398
bsl::pair< iterator, bool > try_emplace(BloombergLP::bslmf::MovableRef< KEY > key, ARGS &&... args)
float max_load_factor() const
Definition bdlc_flathashtable.h:2056
const_iterator cbegin() const
Definition bdlc_flathashtable.h:2092
iterator erase(const_iterator position)
void swap(FlatHashTable &other)
Definition bdlc_flathashtable.h:1918
FlatHashTable(bsl::size_t capacity, const HASH &hash, const EQUAL &equal, bslma::Allocator *basicAllocator=0)
Definition bdlc_flathashtable.h:1337
FlatHashTable(bslmf::MovableRef< FlatHashTable > original)
Definition bdlc_flathashtable.h:1427
HASH hash_type
Definition bdlc_flathashtable.h:328
EQUAL key_equal_type
Definition bdlc_flathashtable.h:329
static const bsl::size_t k_MAX_LOAD_FACTOR_NUMERATOR
Definition bdlc_flathashtable.h:403
void reset()
Definition bdlc_flathashtable.h:1806
bsl::pair< iterator, bool > emplace(ARGS &&... args)
iterator find(const KEY &key)
Definition bdlc_flathashtable.h:1741
iterator end()
Definition bdlc_flathashtable.h:1909
bsl::pair< const_iterator, const_iterator > equal_range(const KEY &key) const
Definition bdlc_flathashtable.h:1998
FlatHashTable & operator=(bslmf::MovableRef< FlatHashTable > rhs)
Definition bdlc_flathashtable.h:1542
bool empty() const
Definition bdlc_flathashtable.h:1970
bsl::pair< iterator, bool > try_emplace(const KEY &key, ARGS &&... args)
void insert(INPUT_ITERATOR first, INPUT_ITERATOR last)
Definition bdlc_flathashtable.h:1755
static const bsl::size_t k_MAX_LOAD_FACTOR_DENOMINATOR
Definition bdlc_flathashtable.h:408
ENTRY_UTIL entry_util_type
Definition bdlc_flathashtable.h:327
static const bsl::int8_t k_HASHLET_MASK
Definition bdlc_flathashtable.h:401
bsl::enable_if< bsl::is_convertible< ENTRY_TYPE, ENTRY >::value, bsl::pair< iterator, bool > >::type insert(BSLS_COMPILERFEATURES_FORWARD_REF(ENTRY_TYPE) entry)
Definition bdlc_flathashtable.h:564
bslma::Allocator * allocator() const
Return the allocator used by this hash table to supply memory.
Definition bdlc_flathashtable.h:2118
bsl::size_t capacity() const
Definition bdlc_flathashtable.h:1936
bslstl::ForwardIterator< const ENTRY, IteratorImp > const_iterator
Definition bdlc_flathashtable.h:334
bslstl::ForwardIterator< ENTRY, IteratorImp > iterator
Definition bdlc_flathashtable.h:332
const bsl::uint8_t * controls() const
Definition bdlc_flathashtable.h:1955
ENTRY entry_type
Definition bdlc_flathashtable.h:326
ENTRY & operator[](BSLS_COMPILERFEATURES_FORWARD_REF(KEY_TYPE) key)
Definition bdlc_flathashtable.h:1557
const_iterator find(const KEY &key) const
Definition bdlc_flathashtable.h:2012
FlatHashTable(bslmf::MovableRef< FlatHashTable > original, bslma::Allocator *basicAllocator)
Definition bdlc_flathashtable.h:1449
KEY key_type
Definition bdlc_flathashtable.h:325
EQUAL key_eq() const
Definition bdlc_flathashtable.h:2032
bool contains(const KEY &key) const
Definition bdlc_flathashtable.h:1943
const_iterator begin() const
Definition bdlc_flathashtable.h:2074
iterator begin()
Definition bdlc_flathashtable.h:1892
void reserve(bsl::size_t numEntries)
Definition bdlc_flathashtable.h:1787
const_iterator cend() const
Definition bdlc_flathashtable.h:2100
bsl::size_t size() const
Return the number of entries in this table.
Definition bdlc_flathashtable.h:2064
bsl::size_t count(const KEY &key) const
Definition bdlc_flathashtable.h:1962
FlatHashTable & operator=(const FlatHashTable &rhs)
Definition bdlc_flathashtable.h:1529
~FlatHashTable()
Destroy this object and each of its entries.
Definition bdlc_flathashtable.h:1505
const_iterator end() const
Definition bdlc_flathashtable.h:2108
HASH hash_function() const
Definition bdlc_flathashtable.h:2025
float load_factor() const
Definition bdlc_flathashtable.h:2043
void rehash(bsl::size_t minimumCapacity)
Definition bdlc_flathashtable.h:1766
FlatHashTable(const FlatHashTable &original, bslma::Allocator *basicAllocator=0)
Definition bdlc_flathashtable.h:1380
iterator erase(iterator position)
bsl::pair< iterator, iterator > equal_range(const KEY &key)
Definition bdlc_flathashtable.h:1599
Definition bslstl_pair.h:1210
static void swap(T *a, T *b)
Definition bslalg_swaputil.h:194
Definition bslma_allocator.h:457
virtual void deallocate(void *address)=0
virtual void * allocate(size_type size)=0
Definition bslma_deallocatorproctor.h:312
void release()
Definition bslma_deallocatorproctor.h:384
Definition bslma_destructorguard.h:132
Definition bslma_destructorproctor.h:259
Definition bslmf_movableref.h:751
Definition bslstl_forwarditerator.h:169
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1762
#define BSLS_ASSERT_OPT(X)
Definition bsls_assert.h:1856
#define BSLS_COMPILERFEATURES_FORWARD_REF(T)
Definition bsls_compilerfeatures.h:2012
#define BSLS_COMPILERFEATURES_FORWARD(T, V)
Definition bsls_compilerfeatures.h:2018
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
Definition bdlc_bitarray.h:503
void swap(BitArray &a, BitArray &b)
bool operator==(const BitArray &lhs, const BitArray &rhs)
bool operator!=(const BitArray &lhs, const BitArray &rhs)
deque< VALUE_TYPE, ALLOCATOR >::size_type erase(deque< VALUE_TYPE, ALLOCATOR > &deq, const BDE_OTHER_TYPE &value)
Definition bslstl_deque.h:4126
T::iterator end(T &container)
Definition bslstl_iterator.h:1523
Definition balxml_encoderoptions.h:68
Definition bdlbb_blob.h:576
static int numTrailingUnsetBits(unsigned int value)
Definition bdlb_bitutil.h:462
static unsigned int withBitCleared(unsigned int value, int index)
Definition bdlb_bitutil.h:581
static int log2(unsigned int value)
Definition bdlb_bitutil.h:338
static unsigned int roundUpToBinaryPower(unsigned int value)
Definition bdlb_bitutil.h:550
Definition bdlc_flathashtable.h:812
Definition bslmf_enableif.h:525
Definition bslmf_integralconstant.h:244
static void construct(TARGET_TYPE *address, const ALLOCATOR &allocator)
Definition bslma_constructionutil.h:1243
static void destructiveMove(TARGET_TYPE *address, const ALLOCATOR &allocator, TARGET_TYPE *original)
Definition bslma_constructionutil.h:1295
Definition bslma_usesbslmaallocator.h:343
Definition bslmf_isbitwisecopyable.h:298
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
Definition bsls_objectbuffer.h:276
TYPE * address()
Definition bsls_objectbuffer.h:334
TYPE & object()
Definition bsls_objectbuffer.h:351