ALib C++ Library
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
hashtable.inl
Go to the documentation of this file.
1
2//==================================================================================================
3/// \file
4/// This header-file is part of module \alib_containers of the \aliblong.
5///
6/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
7/// Published under \ref mainpage_license "Boost Software License".
8//==================================================================================================
9ALIB_EXPORT namespace alib { namespace containers {
10//==================================================================================================
11/// # Contents #
12/// \ref alib_ns_containers_hashtable_intro "1. Introduction" <br>
13/// \ref alib_ns_containers_hashtable_setandmap "2. Hash Sets vs. Hash Maps" <br>
14/// \ref alib_ns_containers_hashtable_single_multi "3. Single And Multiple Entries" <br>
15/// \ref alib_ns_containers_hashtable_rehashing "4. Re-Hashing" <br>
16/// \ref alib_ns_containers_hashtable_iterators "5. Iterators" <br>
17/// \ref alib_ns_containers_hashtable_hashcodes "6. Hash Codes" <br>
18/// &nbsp;&nbsp;\ref alib_ns_containers_hashtable_caching "6.1 Caching Hash Codes" <br>
19/// &nbsp;&nbsp;\ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Codes Pre-calculation" <br>
20/// &nbsp;&nbsp;\ref alib_ns_containers_hashtable_hashquality "6.3 Hash Codes Pre-calculation" <br>
21/// \ref alib_ns_containers_hashtable_memory "7. Memory Use" <br>
22/// \ref alib_ns_containers_hashtable_comparison "8. Comparison To Standard Library Hash-Types" <br>
23/// \ref alib_ns_containers_hashtable_referencedoc "Reference Documentation" <br>
24///
25/// \I{#############################################################################################}
26/// \anchor alib_ns_containers_hashtable_intro
27/// # 1. Introduction #
28/// This class implements a \https{hash table,en.wikipedia.org/wiki/Hash_table} that
29/// stores and retrieves objects very efficiently in respect to execution performance.
30/// All memory for the hash table and its entries are allocated using a template
31/// \alib{lang;Allocator;allocator type}.
32///
33/// Two type definitions based on this class exist, which change the set of template parameters
34/// of this type by providing reasonable replacements. These types are:
35/// - \alib{containers;HashMap} and
36/// - \alib{containers;HashSet}.
37///
38/// In many cases, the use of one of these definitions is more convenient than instantiating this
39/// type directly. The meaning of these types is discussed in the next section.
40///
41/// \I{#############################################################################################}
42/// \anchor alib_ns_containers_hashtable_setandmap
43/// # 2. Hash Sets vs. Hash Maps#
44/// A <em>"hash set"</em> is commonly understood as a type that contains custom values of
45/// #StoredType, which are also used as the key to finding such stored objects.
46/// <em>"Hash maps"</em> are hash tables that store objects of a custom #MappedType which are
47/// associated to a value of a key #KeyType. In this "mode" the key is not contained in the custom
48/// value.<br>
49/// The template parameters and implementation of this class supports both concepts and they are
50/// covered by the two provided alternative type definitions mentioned in the previous section.
51/// Furthermore, those go along well with what is found in the standard C++ library:
52///
53/// 1. \alib{containers;HashSet}
54/// Removes template parameter \p{TValueDescriptor} (by presetting it to a built-in helper-type)
55/// and instead denotes all three types, namely #StoredType, #KeyType and #MappedType to the
56/// same new template parameter \p{T}.
57/// Functors \p{THash} and \p{TEqual} consequently expect the \b %StoredType.<br>
58///
59/// This type definition is similar to what types <c>std::unordered_set</c> and
60/// <c>std::unordered_multiset</c> of the standard C++ class library provide.
61///
62/// 2. \alib{containers;HashMap}
63/// Removes template parameter \p{TValueDescriptor} (by presetting it to a built-in helper-type)
64/// and instead introduces template parameters \p{TKey} and \p{TMapped}.
65/// Here, only the <em>key-portion</em> is used for calculating hash values and testing elements
66/// for equality. The <em>mapped-portion</em> is the true custom type that is to be stored. <br>
67/// Consequently, \b %HashMap defines the #StoredType as <c>std::pair<TKey, TMapped></c>.<br>
68///
69/// The type definition is similar to what types <c>std::unordered_map</c> and
70/// <c>std::unordered_multimap</c> of the standard C++ class library provide.
71///
72/// To achieve this flexibility, template parameter \p{TValueDescriptor}, which is exposed as
73/// #DescriptorType, is constrained to have two methods \b Key() and \b Mapped() to extract
74/// a reference to the corresponding portions out of the stored value.
75///
76/// One of the advantages of this approach is that this type supports a third "mode", besides
77/// implementing <em>"hash sets"</em> and <em>"hash maps"</em>: Custom value type #StoredType
78/// may have a <em>key-portion</em> embedded, instead of using the complete type as a search key.<br>
79/// While there is no specific type definition for this "key-embedded mode" available, the using
80/// code needs to create a custom version of template parameter \p{TValueDescriptor}
81/// which enables the extraction of the key and mapped portions of the stored type.
82/// The following table summarizes this:
83///
84/// Working Mode | Type to Use | Value Descriptor Type
85/// ---------------------------|-------------------------------------|-------------------------
86/// Hash Set |\alib{containers;HashSet} (A type definition on \b %HashTable) | Automaticly chosen as built-in \alib{containers;TIdentDescriptor}
87/// Hash Map |\alib{containers;HashMap} (A type definition on \b %HashTable) | Automaticly chosen as built-in \alib{containers;TPairDescriptor}
88/// Hash Set with embedded Key |\alib{containers;HashTable} (The original type) | A <b>custom type</b> has to be provided
89///
90/// \note The hash-table implementations of the standard C++ library do not support a similar
91/// approach. While with the provision of customized hash- and comparison-functors, of course
92/// only a portion of a type stored in a set can be used for hashing and comparing, still the
93/// interface functions require to receive a "complete" instance, which then is often
94/// "nulled" or "empty" in respect to the fields that are not used for the key.<br>
95/// Because of this limitation, \alib introduces template parameter \p{TValueDescriptor} in
96/// addition to parameters \p{THash} and \p{TEqual}.
97///
98///
99/// As a sample for the advantage consider method
100/// #EmplaceIfNotExistent(const KeyType& key, TArgs&&... args).
101/// A corresponding method is found with type <c>std::unordered_map::try_emplace</c>, but not
102/// with <c>std::unordered_set</c>. In contrast with this implementation, the method
103/// is usable with <em>hash maps</em> as well as with <em>hash sets</em>!<br>
104/// The only precondition to the availability of this method, is that the #StoredType has to be
105/// constructible from the combined list of given arguments, hence the \p{KeyType} argument along
106/// with given arguments of variadic template types \p{TArgs}.
107/// The same is true for method #EmplaceOrAssign(const KeyType&, TArgs&&... args)
108///
109///
110/// The set of available interface methods slightly changes with the two operation modes:
111/// 1. <b>Hash Set Mode:</b><br>
112/// Method overload #EmplaceIfNotExistent(TArgs&&... args) is exclusively available with hash
113/// sets.<br>
114///
115/// 2. <b>Hash Map Mode:</b><br>
116/// The following method overloads are exclusively available with hash \b maps:
117/// - #InsertOrAssign(const KeyType&, MappedType&&)
118/// - #InsertOrAssign(const KeyType&, const MappedType&)
119/// - #InsertIfNotExistent(const KeyType&, MappedType&&)
120/// - #InsertIfNotExistent(const KeyType&, const MappedType&)
121/// <br><br>
122///
123/// In addition, the following method overloads of inner types are also exclusively available
124/// with hash \b maps.
125/// - \alib{containers::detail::HashTableBase;TIterator::Mapped}
126/// - \alib{containers::detail::HashTableBase;TLocalIterator::Mapped}
127/// - \alib{containers::HashTable;ElementHandle::Mapped}
128///
129/// A hint to restrictions is given with the documentation of each method of concern.
130/// Note that methods that expect a single #KeyType are usable with both operation modes, because
131/// with hash sets the key-type equals type #StoredType.
132///
133/// \note
134/// Technically, the availability of the methods is selected at compile-time.
135///
136/// \I{#############################################################################################}
137/// \anchor alib_ns_containers_hashtable_single_multi
138/// # 3. Single And Multiple Entries #
139/// The standard C++ library differentiates between hashing containers that accept only one
140/// element with a specific <em>key-portion</em> of the value (see <c>std::unordered_set</c> and
141/// <c>std::unordered_map</c>) and those that accept multiple insertions of objects with the
142/// same <em>key-portion</em> (see <c>std::unordered_multiset</c> <c>std::unordered_multimap</c>).
143///
144/// This library does \b not provide separate types and any instantiation of this class allows
145/// multiple entries. But this is rather an extension of functionality, than a restriction
146/// and does not impose a penalty on performance.
147///
148/// If unique entries are to be achieved, the user of the type has to make sure for herself that
149/// no multiple entries are inserted. This can be guaranteed, with the exclusive use of the
150/// following set of (partly overloaded) methods, which prevent the creation of multiple entries:
151///
152/// - #InsertUnique / #EmplaceUnique
153/// - #InsertOrAssign / #EmplaceOrAssign
154/// - #InsertIfNotExistent / #EmplaceIfNotExistent
155///
156/// In contrast to this, methods #Insert and #Emplace (and their overloads) will insert
157/// an equal value without giving further notice (for example, by providing a special return value
158/// that indicates if the inserted key existed before).<br>
159/// Method #EraseUnique(const KeyType&) is more efficient than #erase(const KeyType&)
160/// and a further advantage is that it asserts (in debug-compilations) that not more than one
161/// element is found in the table.
162///
163/// \note
164/// If uniqueness of key values is needed, it might be seen by the reader to be a "disadvantage"
165/// that the burden is on the user of the class to guarantee such uniqueness.
166/// However, such burden exists with the set-types of the standard library likewise:
167/// There, result values have to be evaluated to determine if an insertion was successful or not.
168/// The various smaller changes and extensions of the <c>std</c>-types with C++ 14 and 17 reflect
169/// the design problems of the approach to provide "unique" and "multi" types.
170///
171/// \note
172/// The approach that \alib takes here has three small benefits:
173/// 1. A user is free to choose a "mixed mode" by allowing duplicates of certain values (keys)
174/// and not allowing duplicates for others.
175/// While this can be achieved with <c>std::unordered_multimap/set</c> as well, a performance
176/// penalty is given, unless the extended interface of C++17 standard is used with great care.
177/// 2. The code is better readable, due to explicit naming of the invocations, in contrast
178/// to the need to knowing a container's type with each invocation.
179/// 3. The use of the type and this documentation is less confusing, because only one type exists.
180/// In contrast, the two types found in <c>std</c> have equally named methods that act
181/// differently and return different result types.
182///
183/// \I{#############################################################################################}
184/// \anchor alib_ns_containers_hashtable_rehashing
185/// # 4. Re-Hashing #
186/// A check for the need to perform re-hashing is made with every insertion of an element.
187/// The policy for re-hashing is described as follows:
188/// - With insertions, the new average bucket size is calculated as #Size divided by #BucketCount.
189/// - This value is compared with #MaxLoadFactor and if higher the number of buckets is increased.
190/// - When increased, the new minimum number of buckets is calculated as #Size divided by
191/// #BaseLoadFactor. Starting from this minimum, the effective number of buckets is chosen as a
192/// next higher prime number from a static table.
193/// - Automatic rehashes may be disabled by setting #MaxLoadFactor to a very high value, e.g.
194/// <c>std::numeric_limits<float>::max()</c>
195///
196/// The number of buckets is never decreased, unless method #Reset is invoked.
197///
198/// Manual re-hashing is not supported by design. In our view, with monotonic growth (or stability
199/// in size) and hence the absence of dynamic increase/decrease scenarios, manual rehashing is not
200/// needed. Only the base and maximum load factors are of concern, which both can be
201/// specified with \ref HashTable::HashTable "construction" and with methods #MaxLoadFactor
202/// respectively #MaxLoadFactor.<br>
203/// What can be done, however, is to use the method #MaxLoadFactor to "disable" rehashing
204/// temporarily and thus to allow an efficient mass insertion. Nevertheless, if the number of
205/// elements to be inserted is known upfront, the use of method #Reserve, respectively
206/// #ReserveRecyclables is the preferred approach.
207///
208/// \I{############################################################################################}
209/// \anchor alib_ns_containers_hashtable_iterators
210/// # 5. Iterators #
211/// ## 5.1 Iterator Types ##
212/// There are two types of iterators provided:
213/// - \alib{containers::HashTable;Iterator} and its constant sibling
214/// \alib{containers::HashTable;ConstIterator}, used to iterate over all elements of the
215/// hash table,
216/// - \alib{containers::HashTable;LocalIterator} and its constant sibling
217/// \alib{containers::HashTable;ConstLocalIterator} used to iterate over the elements
218/// of a certain bucket only.
219///
220/// Both types satisfy the C++ standard library concept
221/// \https{ForwardIterator,en.cppreference.com/w/cpp/named_req/ForwardIterator}.
222///
223/// ## 5.2 Validity Rules ##
224/// The following rules define the validity of existing iterator instances on table operations:
225/// - <b>Element \b Insertions:</b>
226/// - If no rehashing is performed (see previous section) all iterators remain valid.
227/// - If rehashing is performed, existing iterators become invalid in respect to allowance
228/// of increments and comparison. The elements that existing iterators referred to
229/// before the insertion remain valid. Consequently existing iterators may still be used
230/// to access the custom element value and modify the mapped portion of it.
231/// - <b>Element \b Removals:</b> <br>
232/// All existing iterators that referred to elements that have been removed become invalid.
233/// All others remain fully intact.<br>
234/// The order of the elements that are not erased is preserved, what makes it possible to
235/// erase individual elements while iterating through the container.
236///
237///
238///\I{#############################################################################################}
239/// \anchor alib_ns_containers_hashtable_hashcodes
240/// # 6. Hash Codes #
241///
242///\I{#############################################################################################}
243/// \anchor alib_ns_containers_hashtable_caching
244/// ## 6.1 Caching Hash Codes ##
245///
246/// Template parameter \p{THashCaching} may be used to control if hash codes are cached.
247/// Caching the hash codes increases the memory consumption of this class by <c>sizeof(size_t)</c>
248/// per inserted element. While this is only a small amount and memory consumption should not
249/// be a great concern when monotonic allocation is used, caching the hash codes may impose a
250/// reasonable performance impact. This impact depends on the performance of functor \p{THash}
251/// working on the <c>key-portion</c> of the inserted value.
252///
253/// The cached hash code is used when the table is
254/// \ref alib_ns_containers_hashtable_rehashing "re-hashed". In addition, the cached
255/// hash code is also used with almost all interface methods (insertion, deletion and search
256/// operations): If cached, any needed comparison of two elements will first compare the hash
257/// codes and only invoke templated functor \p{TEqual} if those match.
258///
259/// If template parameter \p{THashCaching} evaluates to <b>Caching::Auto</b> then this class
260/// defaults to use caching if type #KeyType is not arithmetic
261/// (using <c>std::is_arithmetic<TKey></c> for this check).<br>
262///
263/// The caching option of an instance of this class can be queried with enum #CachedHashCodes.
264///
265///
266///\I{#############################################################################################}
267/// \anchor alib_ns_containers_hashtable_hashprecalc
268/// ## 6.2 Hash Codes Pre-calculation ##
269/// The following overloaded methods accept parameter \p{hashCode} in addition to the parameters
270/// accepted by their corresponding base version:
271/// - #Find(const KeyType&, size_t)
272/// - #Insert(const T&, size_t)
273/// - #Insert(T&&, size_t)
274/// - #InsertUnique(T&&, size_t)
275/// - #InsertOrAssign(const KeyType&, MappedType&& mapped, size_t)
276/// - #InsertIfNotExistent(const KeyType&, MappedType&& mapped, size_t)
277/// - #InsertIfNotExistent(T&&, size_t )
278/// - #Extract(const KeyType&, size_t )
279/// - #Erase(const KeyType&, size_t )
280/// - #EraseUnique( const KeyType&, size_t )
281///
282/// The rationale for the provision of these methods is to allow to "pre-calculate" a key's hash
283/// code before invoking the method. This is efficient in situations where one or more subsequent
284/// operations with the same key are performed. For example:
285/// - Insertions of multiple objects with the same key.
286/// - Insertions of an object into multiple hash tables.
287/// - Situations where the result of a find operation may lead to further operations with the
288/// same object.
289///
290///\I{#############################################################################################}
291/// \anchor alib_ns_containers_hashtable_hashquality
292/// ## 6.3 Hash Code Quality ##
293/// To have hash tables perform in constant time <em>O(1)</em> in the average case, a well
294/// implemented calculation of hash-codes has to be provided for template type \p{TKey} with
295/// template functor \p{THash}. This is an obligation of the user of this type.
296///
297/// This \alibmod_nl supports the compiler-symbol \ref ALIB_DEBUG_CONTAINERS which enables extra
298/// features.
299/// The entities relevant for this type are:
300/// - \alib{containers;DbgGetHashTableDistribution},
301/// - \alib{containers;DbgDumpDistribution} and
302/// - \alib{containers;DbgDumpHashtable}.
303///
304/// These methods may be used to assert the quality of custom hash algorithms.
305///
306///\I{#############################################################################################}
307/// \anchor alib_ns_containers_hashtable_memory
308/// # 7. Memory Use #
309/// With template parameter \p{TRecycling} being either \alib{containers;Recycling;Private}
310/// (the default) or \alib{containers;Recycling;Shared}, the internal
311/// <em>"node objects"</em> are remembered when deleted, and "recycled" with future insertions.
312/// The rationale for this lies in the simple fact that memory cannot be returned to
313/// the monotonic allocator. The recycling mechanism is very lightweight and does not cost measurable
314/// performance. If it is assured that no deletions are made during the life-cycle of an instance,
315/// type \alib{containers;Recycling;None} may be used to eliminate this little overhead
316/// of recycling. This is why type-definition \alib{MonoAllocator} is recommended to be used
317/// with this container.
318///
319/// If the table is re-hashed, the former bucket list is likewise recycled and sliced into as many
320/// internal node objects as possible. The precondition for this is that the allocator
321/// interface method \alib{lang::Allocator;allowsMemSplit} returns \c true. This is true for type
322/// \b MonoAllocator.
323///
324/// With these two mechanisms in place, the use of monotonic allocation with this container
325/// is very safe in respect to avoid memory exhaustion.
326/// The use of this class, even in scenarios where a lot of (theoretically an endless amount of)
327/// erase and insert operations are performed, will not increase memory consumption, as long it is
328/// guaranteed that the overall size of the table is limited.<br>
329///
330/// If a maximum number of possible insertions is known, method #ReserveRecyclables might be used
331/// to allocate all needed memory at once. With that, a
332/// \alib{containers;MonoAllocator::TakeSnapshot;snapshot} of the allocator can be taken and
333/// later used to reset the allocator to the minimum that preserves all memory in the according
334/// hash table instance.<br>
335/// For advanced usage, it is advisable to fully understand the concept of monotonic allocation
336/// implemented with this module \alib_containers.
337///
338/// \I{############################################################################################}
339/// \anchor alib_ns_containers_hashtable_comparison
340/// # 8. Comparison To Standard Library Hash-Types #
341/// In the previous sections, it was already referred several times to types
342/// - <c>std::unordered_map</c>,
343/// - <c>std::unordered_multimap,</c>
344/// - <c>std::unordered_set</c> and
345/// - <c>std::unordered_multiset</c>
346///
347/// of the C++ standard library. The uses cases and features of these four compared to this type are
348/// generally the same and this type can be used to replace the standard tyes without general
349/// limitations and vice versa.
350///
351/// Then with C++17, the standard library was extended by a new set of types, namely
352/// - <c>std::pmr::unordered_map</c>,
353/// - <c>std::pmr::unordered_multimap,</c>
354/// - <c>std::pmr::unordered_set</c> and
355/// - <c>std::pmr::unordered_multiset</c>
356///
357/// which, likewise this type, may use monotonic allocation (for example, in combination with C++17
358/// type <c>std::pmr::monotonic_buffer_resource</c>).
359/// On the one hand, \alib in the past needed support of monotonic allocation already for
360/// C++ 11, and on the other hand, the C++17 library extensions follow slightly different design
361/// goals. Details of these were given in the previous section.
362///
363/// Besides these general differences, the specific similarities and differences can be summarized
364/// as follows:
365///
366/// - This \alib type does not distinguish sets and maps but provides a more flexible approach:
367/// Mapped types do not necessarily need to be build using a <c>std::pair</c> of key and value
368/// elements.
369/// For convenience, when the use of <c>std::pair</c> is suitable, type definition
370/// \alib{containers;HashMap} offers exactly this.
371/// - This \alib type does not distinguish sets/maps from multi-sets/maps.
372/// The rationale for this design decision has been described in section
373/// \ref alib_ns_containers_hashtable_single_multi "3. Single And Multiple Entries".
374/// - Almost all members of the four standard library types are implemented with this type
375/// in a very compatible fashion. The member names were translated from <em>lower_snake_case</em>
376/// to <em>UpperCamelCase</em> and then sometimes slightly changed.<br>
377/// C++17 extensions of the standard types were reflected.
378/// - Method #Find provides additional overloads that accept an externally (pre-) calculated
379/// hash code. This allows efficiently using the same key with a series of searches within
380/// different hash table instances. Note that C++20 offers a templated version of <c>find</c>,
381/// which allows performing the same optimization.
382/// - Erase methods that accept a #LocalIterator (bucket iterators) that are not available with
383/// the four standard library types, are provided with this type.
384/// - There is no <c>operator[]</c> defined. The rationale to omit this - at first sight convenient
385/// and intuitive - operator, is that it imposes insert operation even if used in r-value
386/// expressions. This is considered an unwanted side effect.
387/// - The caching of hash-codes can be controlled with this type, while it is an implementation
388/// dependent feature with the standard library.
389/// - The automatic increase (re-hashing) of the bucket number can be tweaked with
390/// constructor parameter \p{pBaseLoadFactor} (and method #BaseLoadFactor(float)), which is not
391/// specified with the standard library types.
392/// - Assignment <c>operator=</c> is not available with this implementation.
393/// If needed, such has to implemented by a user (full iteration with copying elements from one
394/// instance to another).
395///
396/// @see
397/// - Chapter \ref alib_contmono_containers_types of the joint Programmer's Manuals of modules
398/// \alib_containers and \alib_monomem.
399/// - Chapter \ref alib_threads_intro_assert_entry of the Programmer's Manual of module
400/// \alib_threads for information about debugging multithreaded access on instances of this
401/// type.
402///\I{#############################################################################################}
403/// \anchor alib_ns_containers_hashtable_referencedoc
404/// # Reference Documentation #
405/// @tparam TAllocator The \alib{lang;Allocator;allocator type} to use.
406/// @tparam TValueDescriptor Defines the #StoredType, #KeyType and #MappedType. Furthermore has to
407/// proving methods that to extract key- and mapped values out of the
408/// stored type.<br>
409/// For details on required type definitions and method signatures, see
410/// provided implementations
411/// \alib{containers;TIdentDescriptor} and
412/// \alib{containers;TPairDescriptor} as a sample.<br>
413/// The type is published as
414/// \alib{containers;HashTable::DescriptorType}.
415/// @tparam THash The hash functor applicable to the key-type defined by
416/// \p{TValueDescriptor}.
417/// Defaults to <c>std::hash<typename TValueDescriptor::KeyType></c>
418/// and is published as \alib{containers;HashTable::HashType}.
419/// @tparam TEqual The comparison functor on the key-type defined by \p{TValueDescriptor}.
420/// Defaults to <c>std::equal_to<typename TValueDescriptor::KeyType></c>
421/// and is published as \alib{containers;HashTable::EqualType}.
422/// @tparam THashCaching Determines if hash codes are cached when elements are inserted.
423/// Defaults to <b>Caching::Auto</b>, which enables caching if
424/// <c>std::is_arithmetic<TKey>::value</c> evaluates to \c false.
425/// @tparam TRecycling Denotes the type of recycling that is to be performed. Possible values
426/// are
427/// \alib{containers;Recycling;Private} (the default),
428/// \alib{containers;Recycling;Shared} or
429/// \alib{containers;Recycling;None}.
430//==================================================================================================
431template< typename TAllocator,
432 typename TValueDescriptor,
433 typename THash = std::hash <typename TValueDescriptor::KeyType>,
434 typename TEqual = std::equal_to<typename TValueDescriptor::KeyType>,
435 lang::Caching THashCaching = lang::Caching::Auto,
436 Recycling TRecycling = Recycling::Private >
437class HashTable : protected detail::HashTableBase<TAllocator,TValueDescriptor,THash,TEqual,THashCaching,TRecycling>
438{
439 public:
440 #if !DOXYGEN
441 #if ALIB_DEBUG_CRITICAL_SECTIONS
442 mutable lang::DbgCriticalSections dcs;
443 #define DCS ALIB_DCS_WITH(dcs)
444 #define DCSSHRD ALIB_DCS_SHARED_WITH(dcs)
445 #else
446 #define DCS
447 #define DCSSHRD
448 #endif
449 #endif
450
451 protected:
452 // protected shortcuts to parent and its types we need
453 #if !DOXYGEN
455 using Element = typename base::Element;
456 using Node = typename base::Node;
457 #endif
458
459 /// The recycler type.
460 using recyclerType= typename base::recyclerType;
461
462
463 public:
464
465 //################################################################################################
466 // Types and Constants
467 //################################################################################################
468 /// Type definition publishing template parameter \p{TAllocator}.
469 using AllocatorType = TAllocator;
470
471 /// Type definition publishing template parameter \p{TValueDescriptor}.
472 using DescriptorType= TValueDescriptor;
473
474 /// Type definition publishing the stored type of this container as defined with template
475 /// parameter \p{TValueDescriptor}.
476 using StoredType = typename TValueDescriptor::StoredType;
477
478 /// Type definition publishing the key type of this container as defined with template
479 /// parameter \p{TValueDescriptor}.
480 using KeyType = typename TValueDescriptor::KeyType;
481
482 /// Type definition publishing the map type of this container as defined with template
483 /// parameter \p{TValueDescriptor}.
484 using MappedType = typename TValueDescriptor::MappedType;
485
486 /// Type definition publishing template parameter \p{THash}.
487 using HashType = THash;
488
489 /// Type definition publishing template parameter \p{TEqual}.
490 using EqualType = TEqual;
491
492 /// Determines whether hash codes are stored with the elements.
493 /// It is done in case the given template parameter \p{THashCashing} equals
494 /// \alib{lang;Caching;Caching::Enabled} or if it equals \alib{lang;Caching;Caching::Auto}
495 /// and the #KeyType type is an arithmetic type.
496 /// @return \c true if hash codes are stored for reuse, \c false if not.
497 static constexpr bool IsCachingHashes() { return base::IsCachingHashes(); }
498
499 /// @return The enum element value of template parameter \p{TRecycling}.
500 static constexpr Recycling RecyclingTag() { return TRecycling; }
501
502 /// This type definition may be used to define an externally managed shared recycler,
503 /// which can be passed to the alternative constructor of this class when template
504 /// parameter \p{TRecycling} equals \alib{containers;Recycling;Shared}.
505 /// \see
506 /// Chapter \ref alib_contmono_containers_recycling_shared of the Programmer's Manual
507 /// for this \alibmod.
508 using SharedRecyclerType= typename base::SharedRecyclerType;
509
510
511 /// Determines whether the used recycler type is in fact recycling elements.
512 /// @return \c false if template parameter \p{TRecycling} equals
513 /// \alib{containers;Recycling;None}, \c true otherwise.
514 static constexpr bool IsRecycling() { return recyclerType::IsRecycling(); }
515
516 /// Denotes whether hash codes are cached or not.
517 static constexpr bool CachedHashCodes = base::Element::CachedHashCodes;
518
519 /// The mutable iterator exposed by this container.
520 using Iterator = typename base::template TIterator < StoredType>;
521
522 /// The constant iterator exposed by this container.
523 using ConstIterator = typename base::template TIterator <const StoredType>;
524
525 /// The mutable iterator for a single bucket exposed by this container.
526 using LocalIterator = typename base::template TLocalIterator < StoredType>;
527
528 /// The constant iterator for a single bucket exposed by this container.
529 using ConstLocalIterator = typename base::template TLocalIterator <const StoredType>;
530
531 /// A value of this type is returned with methods #Extract, which allows removing
532 /// an element from the hashtable, without deleting its allocated storage and destructing its
533 /// custom value.
534 ///
535 /// This handle allows writing access to the value of an extracted element.
536 /// In combination with methods #Insert(ElementHandle&) and #InsertIfNotExistent(ElementHandle&),
537 /// this supports changing parts of the element value, including the <em>key-portion</em> with
538 /// proper re-insertion.
539 ///
540 /// Objects of this type cannot be copied, but just moved.
542 {
543 #if !DOXYGEN
544 friend class HashTable;
545 #endif
546
547 private:
548 HashTable* table; ///< The table we belong to.
549 Element* element; ///< The extracted element.
550
551 /// Constructor setting fields #table and #element.
552 /// @param pTable The table we belong to.
553 /// @param pElement The extracted element.
554 ElementHandle( HashTable* pTable, Element* pElement )
555 : table ( pTable )
556 , element( pElement ) {}
557
558 public:
559 /// Move constructor setting the moved object to emtpy.
560 /// @param other The handle to move.
562 : table ( other.table )
563 , element( other.element ) { other.element= nullptr; }
564
565 /// Default constructor creating and empty handle.
567 : element( nullptr ) {}
568
569 /// Deleted copy constructor.
570 ElementHandle( ElementHandle& other ) =delete;
571
572 /// Deleted copy assignment operator.
573 ElementHandle& operator =( const ElementHandle& other ) =delete;
574
575 /// Move assignment. Disposes any current content, and moves \p{other} into this.
576 /// @param other The handle to move into this object.
577 /// @return A reference to <c>this</c>.
579 if( element != nullptr )
580 table->recyclerType::Recycle(element);
581 table = other.table;
582 element= other.element;
583 other.element= nullptr;
584
585 return *this;
586 }
587
588 /// Destructor. If this handle is not empty, the allocated storage of the
589 /// represented element is added to the list of recyclable objects.
590 ~ElementHandle() { if( element != nullptr ) table->recyclerType::Recycle(element); }
591
592 /// Determines if this is a "valid" handle.
593 /// @return Returns \c true if this objects represents a valid element, \c false
594 /// otherwise.
595 bool IsEmpty() const { return element == nullptr; }
596
597 /// Returns a mutable reference to this element's data.
598 /// Must not be invoked on empty instances.
599 /// @return Returns a mutable reference to value of the represented element.
600 StoredType& Value () const { return element->value; }
601
602 /// Returns a mutable reference to the <em>key-portion</em> of this element's data.
603 /// Must not be invoked on empty instances.
604 /// @return Returns a mutable reference to the <em>key-portion</em> of the represented
605 /// element.
606 KeyType& Key () const { return TValueDescriptor().Key( element->value ); }
607
608 /// Returns a mutable reference to the <em>mapped-portion</em> of this element's data.
609 /// Must not be invoked on empty instances.
610 /// @return Returns a mutable reference to the mapped object.
611 MappedType& Mapped () const { return TValueDescriptor().Mapped( element->value ); }
612
613 }; // class ElementHandle
614
615 //################################################################################################
616 // Construction/Destruction And Allocator Access
617 //################################################################################################
618
619 /// Constructor.
620 /// \note
621 /// This constructor is not available if the template argument \p{TRecycling} equals
622 /// \alib{containers;Recycling;Shared}.
623 ///
624 /// @tparam TRequires Defaulted template parameter. Must not be specified.
625 /// @param pAllocator The allocator to use.
626 /// @param pBaseLoadFactor The base load factor. Defaults to <c>1.0</c>.
627 /// @param pMaxLoadFactor The maximum load factor. Defaults to <c>2.0</c>.
628 template<bool TRequires= TRecycling!= Recycling::Shared>
629 requires TRequires
630 explicit
632 float pBaseLoadFactor = 1.0,
633 float pMaxLoadFactor = 2.0 )
634 : base( pAllocator, pBaseLoadFactor, pMaxLoadFactor )
636 , dcs("HashTable")
637 #endif
638 {}
639
640 /// Constructor.
641 /// \note
642 /// This constructor is not available if the template argument \p{TRecycling} equals
643 /// \alib{containers;Recycling;Shared} and the
644 /// if template argument \p{TAllocator} does not equal \alib{lang;HeapAllocator}
645 ///
646 ///
647 /// @tparam TRequires Defaulted template parameter. Must not be specified.
648 /// @param pBaseLoadFactor The base load factor. Defaults to <c>1.0</c>.
649 /// @param pMaxLoadFactor The maximum load factor. Defaults to <c>2.0</c>.
650 template<bool TRequires= TRecycling!= Recycling::Shared>
651 requires TRequires
652 explicit
653 HashTable( float pBaseLoadFactor = 1.0,
654 float pMaxLoadFactor = 2.0 )
655 : base( pBaseLoadFactor, pMaxLoadFactor )
657 , dcs("HashTable")
658 #endif
659 {}
660
661
662 /// Constructor taking a shared recycler.
663 /// @param pAllocator The allocator to use.
664 /// @param pSharedRecycler The shared recycler.
665 /// @param pBaseLoadFactor The base load factor. See method #BaseLoadFactor for details.
666 /// Defaults to <c>1.0</c>.
667 /// @param pMaxLoadFactor The maximum load factor. See method #MaxLoadFactor for details.
668 /// Defaults to <c>2.0</c>.
669 /// @tparam TSharedRecycler Used to select this constructor. Deduced by the compiler.
670 template<typename TSharedRecycler= SharedRecyclerType>
671 requires (!std::same_as<TSharedRecycler, void>)
673 TSharedRecycler& pSharedRecycler,
674 float pBaseLoadFactor = 1.0,
675 float pMaxLoadFactor = 2.0 )
676 : base( pAllocator, pSharedRecycler, pBaseLoadFactor, pMaxLoadFactor )
678 , dcs("HashTable")
679 #endif
680 {}
681
682 /// Constructor taking a shared recycler.
683 /// @param pSharedRecycler The shared recycler.
684 /// @param pBaseLoadFactor The base load factor. See method #BaseLoadFactor for details.
685 /// Defaults to <c>1.0</c>.
686 /// @param pMaxLoadFactor The maximum load factor. See method #MaxLoadFactor for details.
687 /// Defaults to <c>2.0</c>.
688 /// @tparam TSharedRecycler Used to select this constructor. Deduced by the compiler.
689 template<typename TSharedRecycler= SharedRecyclerType>
690 requires (!std::same_as<TSharedRecycler, void>)
691 HashTable( TSharedRecycler& pSharedRecycler,
692 float pBaseLoadFactor = 1.0,
693 float pMaxLoadFactor = 2.0 )
694 : base( pSharedRecycler, pBaseLoadFactor, pMaxLoadFactor )
696 , dcs("HashTable")
697 #endif
698 {}
699
700 /// Returns the allocator of this object. Usually the allocator might be used to perform
701 /// allocations in respect to data found in objects stored in this object.
702 /// However, such allowance is dependent on the use case and not part of this class's
703 /// contract.
704 ///
705 /// @return The allocator that was provided in the constructor.
706 AllocatorType& GetAllocator() noexcept { return base::base::GetAllocator(); }
707
708
709 //##############################################################################################
710 /// @name Size and Capacity
711 //##############################################################################################
712
713 /// Destructs and removes all elements from this hash table. The allocated space
714 /// of the elements will be preserved and "recycled" with future insertions.
715 void Clear() { DCS base::clear(); }
716
717 /// Same as clear, but does not recycle internal nodes. Furthermore, all recyclables
718 /// are deleted. The latter is done only if template parameter \p{TRecycling} is not
719 /// \alib{containers;Recycling;Shared}. In this case, the elements are still recycled.
720 ///
721 /// This method is useful with monotonic allocators, that can be reset as well, after
722 /// this instance is reset.
723 /// But, because the life-cycle of the monotonic allocator(s) used for insertions is not
724 /// under control of this object, it is the obligation of the caller to ensure that the
725 /// monotonic allocator is kept in sync with this object.
726 /// The following recipe shows a valid use:
727 /// - Construct a \b HashTable passing a \b MonoAllocator.
728 /// - Create a snapshot of the \b MonoAllocator.
729 /// - Use the \b HashTable.
730 /// - Reset the \b HashTable and right afterwards the \b MonoAllocator to the snapeshot taken.
731 void Reset() {
732 recyclerType oldRecycler(*this);
733 auto baseLoadFactor = base::baseLoadFactor;
734 auto maxLoadFactor = base::maxLoadFactor ;
735 auto& allocator = base::base::GetAllocator();
736 lang::Destruct(*this);
737 if constexpr ( std::same_as< typename base::recyclerType,
739 new (this) HashTable( oldRecycler, baseLoadFactor, maxLoadFactor );
740 else
741 new (this) HashTable( allocator, baseLoadFactor, maxLoadFactor );
742 }
743
744 /// Returns the number of stored elements. Note that this method runs in constant time, as
745 /// the number of elements is kept counted during operation.
746 /// @return The number of elements stored in the hash table.
747 integer Size() const noexcept { return base::size; }
748
749 /// Invokes #Size and compares result with \c 0.
750 /// @return \c true if this list is empty, \c false otherwise.
751 bool IsEmpty() const noexcept { return base::size == 0; }
752
753 /// Reserves space for at least the given number of elements.
754 /// This might re-hash this table.
755 /// \see Method #ReserveRecyclables.
756 /// @param qty The expected number or increase of elements to be stored in the hash table.
757 /// @param reference Denotes whether \p{expected} is meant as an absolute size or an increase.
758 void Reserve( integer qty, lang::ValueReference reference ) {DCS
759 float expectedSize= float( qty + (reference == lang::ValueReference::Relative ? Size()
760 : 0 ) );
761 return base::rehash( uinteger(std::ceil( expectedSize / base::baseLoadFactor)) );
762 }
763
764 /// Same as #Reserve but in addition also already allocates the required space for the number
765 /// of additional elements expected.
766 ///
767 /// @see Chapter \ref alib_contmono_containers_recycling_reserving of the Programmer's
768 /// Manual.
769 ///
770 /// @param qty The expected resulting number (or increase) of elements to be stored in
771 /// this container.
772 /// @param reference Denotes whether \p{qty} is meant as an absolute size or an
773 /// increase.
775 Reserve( qty, reference );
776 {DCS
777 auto requiredRecyclables= ( qty - (reference == lang::ValueReference::Absolute ? Size()
778 : 0 ) )
779 - base::recyclerType::Count();
780 if( requiredRecyclables > 0 )
781 recyclerType::Reserve( requiredRecyclables );
782 } }
783
784 /// Counts the number of currently allocated but unused (not contained) element nodes
785 /// that will be recycled with upcoming insertions.
786 ///
787 /// \note
788 /// This method is provided for completeness and unit-testing. It should not be of
789 /// relevance for common usage.<br>
790 /// Furthermore, this method is not available (aka does not compile) with instantiations
791 /// that specify template parameter \p{TRecycling} as \alib{containers;Recycling;None}.
792 ///
793 /// @return The number of removed and not yet recycled elements.
794 integer RecyclablesCount() const noexcept
795 {DCSSHRD return base::recyclerType::Count(); }
796
797 //##############################################################################################
798 /// @name Hash Policy
799 //##############################################################################################
800
801 /// Sets a new value for the "base load factor" used with this container.
802 /// The base load factor determines the minimum number of buckets
803 /// when re-hashing is performed.
804 ///
805 /// The formula to determine the minimum number of buckets is #Size divided by this factor.
806 /// A static table of prime numbers is searched for the next higher number and this value
807 /// is then used to determine the number of buckets.
808 ///
809 /// The default value for this factor is defined as <c>1.0</c> by the default value
810 /// of parameter \p{pBaseLoadFactor} of the constructor.
811 ///
812 /// \note
813 /// Invoking this method never triggers rehashing.
814 ///
815 /// \see
816 /// Overloaded method #BaseLoadFactor() and this class's documentation section
817 /// \ref alib_ns_containers_hashtable_rehashing "4. Re-Hashing".
818 ///
819 /// @param newBaseLoadFactor The new base load factor to use when a rehash is performed.
820 void BaseLoadFactor( float newBaseLoadFactor ) noexcept
821 { base::baseLoadFactor= newBaseLoadFactor; }
822
823 /// Returns the actual base load factor.
824 ///
825 /// \see
826 /// Overloaded method #BaseLoadFactor(float) and this class's documentation section
827 /// \ref alib_ns_containers_hashtable_rehashing "4. Re-Hashing".
828 ///
829 /// @return The current value of the base load factor.
830 float BaseLoadFactor() const noexcept { return base::baseLoadFactor; }
831
832
833 /// Sets a new value for the "maximum load factor" which is the average number of elements
834 /// per bucket.
835 ///
836 /// The default value for this factor is defined as <c>2.0</c> by the default value
837 /// of parameter \p{pMaxLoadFactor} of the constructor.
838 ///
839 /// \note
840 /// Invoking this method triggers rehashing, in case the hash table is not empty and
841 /// the new maximum load factor is below the current load factor of this container, which
842 /// equals #Size divided by #BucketCount.<br>
843 /// This method may be used to temporarily disable re-hashing by providing
844 /// <c>std::numeric_limits<float>::max()</c>.
845 ///
846 /// \see
847 /// Overloaded method #MaxLoadFactor() and this class's documentation section
848 /// \ref alib_ns_containers_hashtable_rehashing "4. Re-Hashing".
849 ///
850 /// @param newMaxLoadFactor The maximum load factor used to determine the need of re-hashing.
851 void MaxLoadFactor( float newMaxLoadFactor ) noexcept
852 { base::setMaxLoadFactor( newMaxLoadFactor ); }
853
854 /// Returns the actual maximum load factor.
855 ///
856 /// \see
857 /// Overloaded method #MaxLoadFactor(float) and this class's documentation section
858 /// \ref alib_ns_containers_hashtable_rehashing "4. Re-Hashing".
859 ///
860 /// @return The current value of the maximum load factor.
861 float MaxLoadFactor() const noexcept { return base::maxLoadFactor; }
862
863 //##############################################################################################
864 /// @name Bucket Interface
865 //##############################################################################################
866
867 /// Returns the number of "buckets" that this hash table currently uses.
868 ///
869 /// @return The size of the array of hash buckets.
870 uinteger BucketCount() const noexcept { return base::bucketCount; }
871
872 /// Returns the number of entries stored in the bucket with the given number.
873 ///
874 /// @param bucketNumber The number of the bucket to receive the size for.
875 /// @return The number of entries in the specified bucket.
876 uinteger BucketSize( uinteger bucketNumber ) const noexcept {DCSSHRD
877 ALIB_ASSERT_ERROR( bucketNumber < base::bucketCount, "MONOMEM/HASHTABLE",
878 "Bucket number out of range. {}>={}", bucketNumber, base::bucketCount )
879 return uinteger(base::buckets[bucketNumber].count());
880 }
881
882 /// Returns the number of the bucket corresponding to \p{key}.
883 ///
884 /// @param key The key to evaluate the bucket number for.
885 /// @return The bucket number that \p{key} is assigned to.
886 uinteger BucketNumber( const KeyType& key ) const noexcept
887 { return THash{}(key) % base::bucketCount; }
888
889 //##############################################################################################
890 /// @name Element Insertion
891 //##############################################################################################
892 /// See #Insert(StoredType&&) which is invoked with a copy of \p{value}.
893 ///
894 /// @param value A value to copy and insert.
895 /// @return An iterator referring to the element added.
897 { return Insert(value, THash{}(TValueDescriptor().Key(reinterpret_cast<StoredType&>(value)))); }
898
899 /// Overloaded version of method \alib{containers::HashTable;Insert(const StoredType&)} which
900 /// accepts the \p{hashCode} of the given \p{value} as a second parameter.
901 ///
902 /// @see Use cases of this method are discussed in reference documentation section
903 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
904 ///
905 /// @param value A value to copy and insert.
906 /// @param hashCode Pre-calculated hash code of \p{value}.
907 /// @return An iterator referring to the element added.
908 Iterator Insert( const StoredType& value, size_t hashCode )
909 { return Insert(value, hashCode ); }
910
911 /// Moves the given value into this table.<br>
912 /// Existing iterators remain valid.
913 ///
914 /// \note
915 /// The use of this method may insert elements sharing the same key as already existing
916 /// elements.
917 /// For more information, see
918 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
919 /// of the documentation of this class.
920 ///
921 /// @param value A rvalue reference of contained type \p{StoredType} to insert.
922 /// @return An iterator referring to the element added.
924 {
925 auto hashCode = THash{}( TValueDescriptor().Key( reinterpret_cast<StoredType&>(value)) );
926 return Insert( std::move(value), hashCode );
927 }
928
929 /// Overloaded version of method \alib{containers::HashTable;Insert(StoredType&&)} which
930 /// accepts the \p{hashCode} of the given \p{value} as a second parameter.
931 ///
932 /// @see Use cases of this method are discussed in reference documentation section
933 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
934 ///
935 /// @param value An rvalue reference of contained type \p{StoredType} to insert.
936 /// @param hashCode Pre-calculated hash code of \p{value}.
937 /// @return An iterator referring to the element added.
938 Iterator Insert( StoredType&& value, size_t hashCode ) {DCS
939 // Recycle node or create a new one
940 Element* element= base::allocElement(hashCode);
941
942 // placement-new
943 new ( &element->value ) StoredType ( std::move(value) );
944
945 // insert to hash table
946 base::increaseSize( 1 );
947 auto bucketIdx= base::insertInBucket( element, hashCode );
948 return Iterator( this, bucketIdx, element);
949 }
950
951 /// Inserts the element contained in the given \alib{containers::HashTable;ElementHandle}
952 /// into the hash table.
953 ///
954 /// \note
955 /// The use of this method may insert elements sharing the same key as already existing
956 /// elements.
957 /// For more information, see
958 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
959 /// of the documentation of this class.
960 ///
961 /// <p>
962 /// Objects of type \b ElementHandle objects may be received using overloaded methods
963 /// #Extract. The combination of \b %Extract and this method (as well as method
964 /// #InsertIfNotExistent(ElementHandle&) are the only way to change the <em>key-portion</em> of an
965 /// element without element destruction/re-construction.
966 ///
967 /// @param handle A reference to a handle to an element, previously received with #Extract.
968 /// @return On success, returns an iterator that refers to the inserted element.
969 /// On failure (if parameter \p{handle} was empty), the returned iterator equals #end.
970 Iterator Insert( ElementHandle& handle ) {DCS
971 if( handle.IsEmpty() )
972 return end();
973
974 base::increaseSize( 1 );
975 Element* element= handle.element;
976 auto hashCode= THash{}( TValueDescriptor().Key( element->value ));
977 element->fixHashCode( hashCode );
978 auto bucketIdx= base::insertInBucket( element, hashCode );
979 handle.element= nullptr;
980 return Iterator( this, bucketIdx, element );
981 }
982
983 /// See #InsertUnique(StoredType&&) which is invoked with a copy of \p{value}.
984 ///
985 /// @param value An element to insert whose <em>key-portion</em> has to be different to
986 /// all currently contained elements.
987 /// @return An iterator referring to the element added.
989 { return InsertUnique(std::move(StoredType( value )) ); }
990
991 /// Overloaded version of method
992 /// \alib{containers::HashTable;InsertUnique(const StoredType&)} which accepts the
993 /// \p{hashCode} of the given \p{key} as a second parameter.
994 ///
995 /// @see Use cases of this method are discussed in reference documentation section
996 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
997 ///
998 /// @param value An element to insert whose <em>key-portion</em> has to be different to
999 /// all currently contained elements.
1000 /// @param hashCode Pre-calculated hash code of \p{value}.
1001 /// @return An iterator referring to the element added.
1002 Iterator InsertUnique( const StoredType& value, size_t hashCode )
1003 { return InsertUnique( StoredType( value ), hashCode ); }
1004
1005 /// Moves the given value into this table without checking to place it in the right
1006 /// position in respect to existing elements with the same <em>key-portion</em>.
1007 ///
1008 /// \attention
1009 /// This method must only be used if the caller guarantees that no other element is
1010 /// currently stored in this container having an equal <em>key-portion</em>.
1011 /// In such situations, this method is very efficient.<br>
1012 /// If one exists already, this hash table is not considered in a consistent state
1013 /// after the operation. I.e., method #EqualRange will discontinue to function properly.
1014 ///
1015 /// \attention
1016 /// In debug-compilations an \alib_assertion is raised if an equal element exists.
1017 /// For this reason, performance differences to method #Insert will be seen only with
1018 /// release-compilations.
1019 ///
1020 /// \attention
1021 /// For more information, see
1022 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1023 /// of the documentation of this class.
1024 ///
1025 ///
1026 /// @param value An element to insert whose <em>key-portion</em> has to be different to
1027 /// all currently contained elements.
1028 /// @return An iterator referring to the element added.
1030 {
1031 auto hashCode = THash{}( TValueDescriptor().Key( reinterpret_cast<StoredType&>(value)) );
1032 return InsertUnique(std::move(value), hashCode );
1033 }
1034
1035 /// Overloaded version of method \alib{containers::HashTable;InsertUnique(StoredType&&)}
1036 /// which accepts the \p{hashCode} of the given \p{key} as a second parameter.
1037 ///
1038 /// @see Use cases of this method are discussed in reference documentation section
1039 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1040 ///
1041 /// @param value An element to insert whose <em>key-portion</em> has to be different to
1042 /// all currently contained elements.
1043 /// @param hashCode Pre-calculated hash code of \p{value}.
1044 /// @return An iterator referring to the element added.
1045 Iterator InsertUnique( StoredType&& value, size_t hashCode ) {DCS
1046 Element* element = base::allocElement( hashCode );
1047
1048 base::increaseSize( 1 );
1049 auto bucketIdx= hashCode % base::bucketCount;
1050 base::buckets[bucketIdx].pushFront( element );
1051
1052 new ( &element->value ) StoredType( std::move(value) );
1053
1054 #if ALIB_DEBUG
1055 //Check that this was the first of
1056 auto it= ConstLocalIterator( bucketIdx, base::buckets[bucketIdx].first() ); // cbegin(bucketIdx);
1057 ALIB_ASSERT( it.element == element, "MONOMEM/HASHTABLE" ) // has to be the first inserted
1058 while( ++it != cend(bucketIdx) ) {
1059 ALIB_ASSERT_ERROR( !base::areEqual(element, it.element ), "MONOMEM/HASHTABLE",
1060 "InsertUnique used while element with same key-portion existed!" )
1061 }
1062 #endif
1063
1064 return Iterator( this, bucketIdx, element);
1065 }
1066
1067
1068 /// See #InsertOrAssign(const KeyType&, MappedType&&) which is invoked with a copy of \p{mapped}.
1069 ///
1070 /// \par Availability
1071 /// This method is only available with
1072 /// \ref alib_ns_containers_hashtable_setandmap "hash map mode".
1073 ///
1074 /// @tparam TRequires Used to disable this method for instantiations of this
1075 /// template type with <em>hash set mode</em>.<br>
1076 /// Defaulted and must not be specified with invocations.
1077 /// @param key The key to use for search and insertion.
1078 /// @param mapped The mapped value to copy and then insert or assign.
1079 /// @return A pair containing an iterator referencing the element added.
1080 /// The bool component is \c true if the insertion took place and \c false if the
1081 /// assignment took place.
1082 template<typename TRequires= MappedType>
1083 requires(!std::same_as<TRequires, StoredType>)
1084 std::pair<Iterator, bool> InsertOrAssign( const KeyType& key, const MappedType& mapped)
1085 { return InsertOrAssign( key, MappedType(mapped) ); }
1086
1087 /// Replaces an existing, respectively inserts a new element into this hash table.
1088 ///
1089 /// \note
1090 /// This method allows preventing the insertion of double entries.
1091 /// For more information, see
1092 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1093 /// of the documentation of this class.
1094 ///
1095 /// \par Availability
1096 /// This method is only available with
1097 /// \ref alib_ns_containers_hashtable_setandmap "hash map mode".
1098 ///
1099 /// @tparam TRequires Used to disable this method for instantiations of this
1100 /// template type with <em>hash set mode</em>.<br>
1101 /// Defaulted and must not be specified with invocations.
1102 /// @param key The key to use for search and insertion.
1103 /// @param mapped The mapped value to insert or assign.
1104 /// @return A pair containing an iterator referring to the element added.
1105 /// The bool component is \c true if the insertion took place and \c false if the
1106 /// assignment took place.
1107 template<typename TRequires= MappedType>
1108 requires(!std::same_as<TRequires, StoredType>)
1109 std::pair<Iterator, bool> InsertOrAssign( const KeyType& key, MappedType&& mapped )
1110 { return InsertOrAssign( key, std::move(mapped), THash{}(key) ); }
1111
1112 /// Overloaded version of method
1113 /// \alib{containers::HashTable;InsertOrAssign(const KeyType&; MappedType&&)} which
1114 /// accepts the \p{hashCode} of the given \p{key} as a third parameter.
1115 ///
1116 /// @see Use cases of this method are discussed in reference documentation section
1117 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1118 ///
1119 /// \par Availability
1120 /// This method is only available with
1121 /// \ref alib_ns_containers_hashtable_setandmap "hash map mode".
1122 ///
1123 /// @tparam TRequires Used to disable this method for instantiations of this
1124 /// template type with <em>hash set mode</em>.<br>
1125 /// Defaulted and must not be specified with invocations.
1126 /// @param key The key to use for search and insertion.
1127 /// @param mapped The mapped value to insert or assign.
1128 /// @param hashCode Pre-calculated hash code of \p{key}.
1129 /// @return A pair containing an iterator referring to the element added.
1130 /// The bool component is \c true if the insertion took place and \c false if the
1131 /// assignment took place.
1132 template<typename TRequires= MappedType>
1133 requires(!std::same_as<TRequires, StoredType>)
1134 std::pair<Iterator, bool> InsertOrAssign( const KeyType& key, MappedType&& mapped, size_t hashCode )
1135 {DCS
1136 std::pair<Iterator, bool> result= base::insertOrGet( key, hashCode );
1137
1138 // if an existing element was found, we have to destruct the mapped value
1139 if( result.second == false )
1140 lang::Destruct( TValueDescriptor().Mapped( result.first.element->value ) );
1141
1142 // if otherwise a new element was inserted, we have to copy the key
1143 else
1144 new (&TValueDescriptor().Key( result.first.element->value )) KeyType( key );
1145
1146 // placement-new for the mapped object
1147 new ( &TValueDescriptor().Mapped( result.first.element->value ) ) MappedType( std::move( mapped) );
1148
1149 return result;
1150 }
1151
1152 /// See #InsertIfNotExistent(const KeyType&, MappedType&&) which is invoked with a copy of
1153 /// \p{mapped}.
1154 ///
1155 /// \par Availability
1156 /// This method is only available with
1157 /// \ref alib_ns_containers_hashtable_setandmap "hash map mode".
1158 ///
1159 /// @tparam TRequires Used to disable this method for instantiations of this
1160 /// template type with <em>hash set mode</em>.<br>
1161 /// Defaulted and must not be specified with invocations.
1162 /// @param key The key to use for search and insertion.
1163 /// @param mapped The mapped object to copy and insert if \p{key} is not existing.
1164 /// @return A pair containing an iterator referencing either the element found or the new
1165 /// element added. The bool component is \c true if the insertion took place and \c false
1166 /// if nothing was changed.
1167 template<typename TRequires= MappedType>
1168 requires(!std::same_as<TRequires, StoredType>)
1169 std::pair<Iterator, bool> InsertIfNotExistent( const KeyType& key, const MappedType& mapped)
1170 { return InsertIfNotExistent( key, MappedType(mapped) ); }
1171
1172 /// Overloaded version of method
1173 /// \alib{containers::HashTable;InsertIfNotExistent(const KeyType&,MappedType&&)} which
1174 /// accepts the \p{hashCode} of the given \p{key} as a third parameter.
1175 ///
1176 /// \par Availability
1177 /// This method is only available with
1178 /// \ref alib_ns_containers_hashtable_setandmap "hash map mode".
1179 ///
1180 /// @see Use cases of this method are discussed in reference documentation section
1181 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1182 ///
1183 /// @tparam TRequires Used to disable this method for instantiations of this
1184 /// template type with <em>hash set mode</em>.<br>
1185 /// Defaulted and must not be specified with invocations.
1186 /// @param key The key to use for search and insertion.
1187 /// @param hashCode Pre-calculated hash code of \p{key}.
1188 /// @param mapped The mapped value to insert if \p{key} is not existing.
1189 /// @return A pair containing an iterator referencing either the element found or the new
1190 /// element added. The bool component is \c true if the insertion took place and \c false
1191 /// if nothing was changed.
1192 template<typename TRequires= MappedType>
1193 requires(!std::same_as<TRequires, StoredType>)
1194 std::pair<Iterator, bool> InsertIfNotExistent( const KeyType& key, MappedType&& mapped, size_t hashCode)
1195 {DCS
1196 // search element
1197 std::pair<Iterator, bool> result= base::insertIfNotExists( key, hashCode );
1198
1199 // existed? Do nothing
1200 if( result.second == false )
1201 return result;
1202
1203 // placement-new for the key (using copy constructor)
1204 new (&TValueDescriptor().Key( result.first.element->value )) KeyType( key );
1205
1206 // placement-new for the mapped (using move constructor)
1207 new ( &TValueDescriptor().Mapped( result.first.element->value ) ) MappedType( std::move( mapped) );
1208
1209 return result;
1210 }
1211
1212 /// Inserts a new mapped object only if no other object is contained that is associated
1213 /// already with the same key as given \p{key}.
1214 ///
1215 /// \note
1216 /// This method allows preventing the insertion of double entries.
1217 /// For more information, see
1218 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1219 /// of the documentation of this class.
1220 ///
1221 /// \par Availability
1222 /// This method is only available with
1223 /// \ref alib_ns_containers_hashtable_setandmap "hash map mode".
1224 ///
1225 /// @tparam TRequires Used to disable this method for instantiations of this
1226 /// template type with <em>hash set mode</em>.<br>
1227 /// Defaulted and must not be specified with invocations.
1228 /// @param key The key to use for search and insertion.
1229 /// @param mapped The mapped value to insert if \p{key} is not existing.
1230 /// @return A pair containing an iterator referencing either the element found or the new
1231 /// element added. The bool component is \c true if the insertion took place and \c false
1232 /// if nothing was changed.
1233 template<typename TRequires= MappedType>
1234 requires(!std::same_as<TRequires, StoredType>)
1235 std::pair<Iterator, bool> InsertIfNotExistent( const KeyType& key, MappedType&& mapped)
1236 { return InsertIfNotExistent( key, std::move(mapped), THash{}(key) ); }
1237
1238 /// See #InsertIfNotExistent(StoredType&&) which is invoked with a copy of \p{value}.
1239 ///
1240 /// @param value The value to copy and insert.
1241 /// @return A pair containing an iterator referencing either the element found or the new
1242 /// element added. The bool component is \c true if the insertion took place and \c false
1243 /// if nothing was changed.
1244 std::pair<Iterator, bool> InsertIfNotExistent( const StoredType& value )
1245 { return InsertIfNotExistent( StoredType(value) ); }
1246
1247 /// Inserts a new mapped object only if no other object is contained that is associated
1248 /// already with the same key as given \p{key}.
1249 ///
1250 /// \note
1251 /// This method allows preventing the insertion of double entries.
1252 /// For more information, see
1253 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1254 /// of the documentation of this class.
1255 ///
1256 /// @param value A rvalue reference of a \p{StoredType} to insert.
1257 /// @return A pair containing an iterator referencing either the element found or the new
1258 /// element added.
1259 /// The bool component is \c true if the insertion took place and \c false if nothing
1260 /// was changed.
1261 std::pair<Iterator, bool> InsertIfNotExistent( StoredType&& value )
1262 {
1263 auto hashCode= THash{}( TValueDescriptor().Key(value) );
1264 return InsertIfNotExistent(std::move(value), hashCode);
1265 }
1266
1267 /// Overloaded version of method
1268 /// \alib{containers::HashTable;InsertIfNotExistent(StoredType&&)} which accepts the
1269 /// \p{hashCode} of the given \p{key} as a second parameter.
1270 ///
1271 /// @see Use cases of this method are discussed in reference documentation section
1272 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1273 ///
1274 /// @param value A rvalue reference of a \p{StoredType} to insert.
1275 /// @param hashCode Pre-calculated hash code of \p{value}.
1276 /// @return A pair containing an iterator referencing either the element found or the new
1277 /// element added.
1278 /// The bool component is \c true if the insertion took place and \c false if nothing
1279 /// was changed.
1280 std::pair<Iterator, bool> InsertIfNotExistent( StoredType&& value, size_t hashCode ) {DCS
1281 // search element
1282 std::pair<Iterator, bool> result= base::insertIfNotExists( TValueDescriptor().Key(value), hashCode );
1283
1284 // existed? Do nothing
1285 if( result.second == false )
1286 return result;
1287
1288 // placement-new for the value(using move constructor)
1289 new ( &result.first.element->value ) StoredType( std::move(value) );
1290
1291 return result;
1292 }
1293
1294 /// Inserts the element contained in the given \alib{containers::HashTable;ElementHandle} into
1295 /// this table, if no equal element exists. In the unsuccessful case, the given
1296 /// \b %ElementHandle remains set and can be reused.<br>
1297 ///
1298 /// Existing iterators remain valid.
1299 ///
1300 /// \note
1301 /// This method allows preventing the insertion of double entries.
1302 /// For more information, see
1303 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1304 /// of the documentation of this class.
1305 ///
1306 /// <p>
1307 /// \see
1308 /// Objects of type \b ElementHandle objects may be received using overloaded methods
1309 /// #Extract. The combination of \b %Extract and this method (as well as method
1310 /// #Insert(ElementHandle&) are the only way to change the <em>key-portion</em> of an element
1311 /// without element destruction/re-construction.
1312 ///
1313 /// @param handle A reference to a handle to an element, previously received with #Extract.
1314 /// @return If an empty handle is given, #end is returned.
1315 /// Otherwise, if no equal element existed, an iterator that refers to the inserted
1316 /// element is returned and the given \p{handle} is emptied.<br>
1317 /// If an equal element existed, the returned iterator refers to the existing element
1318 /// and the \p{handle} remains set (not empty).
1319 Iterator InsertIfNotExistent( ElementHandle& handle ) {DCS
1320 if( handle.IsEmpty() )
1321 return Iterator( this, base::bucketCount, nullptr ); //end();
1322
1323 Element* element = handle.element;
1324 auto hashCode = THash{}( TValueDescriptor().Key( handle.element->value ) );
1325 auto bucketIdx= hashCode % base::bucketCount;
1326
1327 Element* existing= base::findElement( hashCode, TValueDescriptor().Key( element->value ), hashCode );
1328 if ( existing != nullptr )
1329 return Iterator( this, bucketIdx, existing );
1330
1331 handle.element= nullptr;
1332 element->fixHashCode( hashCode ); // the key might have been changed outside
1333
1334 bucketIdx= base::increaseSize( 1, hashCode );
1335 base::buckets[bucketIdx].pushFront( element );
1336 return Iterator( this, bucketIdx, element);
1337 }
1338
1339 /// Constructs a new element within this container.
1340 ///
1341 /// \note
1342 /// The use of this method may insert elements sharing the same key as already existing
1343 /// elements.
1344 /// For more information, see
1345 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1346 /// of the documentation of this class.
1347 ///
1348 /// @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1349 /// @param args Variadic parameters to be forwarded to the constructor of the inserted
1350 /// instance of type #StoredType.
1351 /// @return An iterator referring to the element added.
1352 template<typename... TArgs>
1353 Iterator Emplace( TArgs&&... args ) {DCS
1354 // Recycle node or create a new one
1355 Element* element= base::allocElement( 0 );
1356
1357 // placement-new
1358 new ( &element->value ) StoredType( std::forward<TArgs>(args)... );
1359
1360 // fix the hash code which was not available at allocation, yet.
1361 auto hashCode= THash{}( TValueDescriptor().Key( element->value ));
1362 element->fixHashCode( hashCode );
1363
1364 // insert to hash table
1365 base::increaseSize( 1 );
1366 auto bucketIdx= base::insertInBucket( element, hashCode );
1367 return Iterator( this, bucketIdx, element);
1368 }
1369
1370 /// Constructs a value within this container without checking to place it in the right
1371 /// position in respect to existing elements with the same <em>key-portion</em>.
1372 ///
1373 /// \attention
1374 /// This method must only be used if the caller guarantees that no other element is
1375 /// currently stored in this container having an equal <em>key-portion</em>.
1376 /// In such situations, this method is very efficient.<br>
1377 /// If one exists already, this hash table is not considered in a consistent state
1378 /// after the operation. I.e., method #EqualRange will discontinue to function properly.
1379 ///
1380 /// \attention
1381 /// In debug-compilations, an \alib_assertion is raised if an equal element exists.
1382 /// For this reason, performance differences to method #Insert will be seen only with
1383 /// release-compilations.
1384 ///
1385 /// \attention
1386 /// For more information, see
1387 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1388 /// of the documentation of this class.
1389 ///
1390 /// @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1391 /// @param args Variadic parameters to be forwarded to the constructor of the
1392 /// element to insert whose <em>key-portion</em> has to be different to
1393 /// all currently contained elements.
1394 /// @return An iterator referring to the element added.
1395 template<typename... TArgs>
1396 Iterator EmplaceUnique( TArgs&&... args ) {DCS
1397 // Recycle node or create a new one
1398 Element* element= base::allocElement(0);
1399
1400 // placement-new
1401 new ( &element->value ) StoredType( std::forward<TArgs>(args)... );
1402
1403 // replace hash code (which is available only now)
1404 auto hashCode= THash{}( TValueDescriptor().Key( element->value ));
1405 element->fixHashCode( hashCode );
1406
1407
1408 // insert to hash table
1409 auto bucketIdx= base::increaseSize( 1, hashCode );
1410 base::buckets[bucketIdx].pushFront( element );
1411 auto result= Iterator( this, bucketIdx, element);
1412
1413 #if ALIB_DEBUG
1414 // Check that this was the first of
1415 auto it= ConstLocalIterator( result.bucketIdx, base::buckets[result.bucketIdx].first() ); // cbegin();
1416 ALIB_ASSERT( it.element == result.element, "MONOMEM/HASHTABLE" ) // has to be the first inserted
1417 while( ++it != ConstLocalIterator( result.bucketIdx, nullptr ) ) //cend(result.bucketIdx)
1418 ALIB_ASSERT_ERROR( !base::areEqual(result.element, it.element ), "MONOMEM/HASHTABLE",
1419 "EmplaceUnique used while element with same key-portion existed!" )
1420 #endif
1421
1422 return result;
1423 }
1424
1425#if DOXYGEN
1426 //==============================================================================================
1427 /// Replaces an existing, respectively constructs a new element within this container.
1428 ///
1429 /// \note
1430 /// This method allows preventing the insertion of double entries.
1431 /// For more information, see
1432 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1433 /// of the documentation of this class.
1434 ///
1435 /// \par Availability
1436 /// This method is available if this templated type is instantiated with
1437 /// \ref alib_ns_containers_hashtable_setandmap "hash map mode"
1438 /// or for hash sets that only define a subset of \p{StoredType} as a key type \p{TKey} and
1439 /// whose stored type \p{StoredType} is constructible if given a key value and the variadic
1440 /// template arguments.
1441 ///
1442 ///
1443 /// @tparam TRequires Used to disable this method where not available.<br>
1444 /// Defaulted and must not be specified with invocations.
1445 /// @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1446 /// @param key The key to use for search and insertion.
1447 /// @param args Variadic parameters to be forwarded to the constructor of the mapped object
1448 /// of type <c>\p{MappedType}</c>.
1449 /// @return A pair containing an iterator referring to the element added.
1450 /// The bool component is \c true if the insertion took place and \c false if the
1451 /// assignment took place.
1452 //==============================================================================================
1453 template<typename TRequires= MappedType, typename... TArgs>
1454 requires(!std::same_as<TRequires, StoredType>)
1455 std::pair<Iterator, bool> EmplaceOrAssign( const KeyType& key, TArgs&&... args);
1456#else
1457 template<typename TRequires= MappedType, typename... TArgs>
1458 requires(!std::same_as<TRequires, StoredType>)
1459 std::pair<Iterator, bool> EmplaceOrAssign( const KeyType& key, TArgs&&... args) {DCS
1460 // insert to hash table
1461 std::pair<Iterator, bool> result= base::insertOrGet( key, THash{}(key) );
1462
1463 // if an existing element was found, we have to destruct the currently mapped object
1464 if( result.second == false )
1465 lang::Destruct( TValueDescriptor().Mapped( result.first.element->value ) );
1466
1467 // if otherwise an insertion took place, we have to copy the key
1468 else
1469 new (&TValueDescriptor().Key( result.first.element->value )) KeyType( key );
1470
1471 // placement-new for the mapped object
1472 new ( &TValueDescriptor().Mapped( result.first.element->value )) MappedType( std::forward<TArgs>( args)... );
1473
1474 return result;
1475 }
1476
1477 // set mode
1478 template<typename TRequires= MappedType, typename... TArgs>
1479 requires( std::same_as<TRequires, StoredType>
1480 && std::is_constructible< StoredType,
1481 const KeyType&,
1482 TArgs&&... >::value )
1483 std::pair<Iterator, bool> EmplaceOrAssign( const KeyType& key, TArgs&&... args) {DCS
1484 // insert to hash table
1485 std::pair<Iterator, bool> result= base::insertOrGet( key, THash{}(key) );
1486
1487 // if an existing element was found, we have to destruct the whole object
1488 if( result.second == false )
1489 lang::Destruct( result.first.element->value );
1490
1491 // placement-new for the whole object
1492 new (&result.first.element->value) StoredType( key, std::forward<TArgs>( args)... );
1493
1494 return result;
1495 }
1496#endif
1497
1498 /// Inserts a new element only if no other element is contained equals to the one
1499 /// that is constructed by \p{args}.
1500 ///
1501 /// \note
1502 /// This method allows preventing the insertion of double entries.
1503 /// For more information, see
1504 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1505 /// of the documentation of this class.
1506 /// <p>
1507 /// \note
1508 /// For comparison, a local object of type #StoredType is constructed. In case an equal
1509 /// object exists, it is destructed. Otherwise it is moved into this container.
1510 ///
1511 /// \par Availability
1512 /// This method is available only if this templated type is instantiated with
1513 /// \ref alib_ns_containers_hashtable_setandmap "hash set mode". For <em>hash map mode</em>,
1514 /// use overloaded version #EmplaceIfNotExistent(const KeyType& key, TArgs&&... args).
1515 /// \par
1516 /// Furthermore it is available only if custom type \p{StoredType} has a move constructor.
1517 ///
1518 /// \attention
1519 /// If a move constructor exists, but is not duly defined, the method produces undefined
1520 /// behavior.<br>
1521 /// An alternative version that does not require a move constructor is found with
1522 /// #EmplaceIfNotExistent(const KeyType& key, TArgs&&... args). This can be used for hash sets
1523 /// that define a subset of \p{StoredType} as a key type \p{TKey} and whose stored type
1524 /// is constructible from a constant <em>key-portion</em> and the variadic template arguments.
1525 ///
1526 /// @tparam TRequires Used to disable this method where not available.
1527 /// @tparam TArgs Types of variadic parameters given with parameter \p{args}.<br>
1528 /// Defaulted and must not be specified with invocations.
1529 /// @param args Variadic parameters to be forwarded to the constructor of \p{StoredType}.
1530 /// @return A pair containing an iterator referencing either the element found or the new
1531 /// element added.
1532 /// The bool component is \c true if the insertion took place and \c false nothing
1533 /// was changed.
1534 template<typename TRequires= MappedType, typename... TArgs>
1535 requires ( std::same_as<TRequires, StoredType>
1536 && std::is_move_constructible<StoredType>::value )
1537 std::pair<Iterator, bool> EmplaceIfNotExistent( TArgs&&... args) {DCS
1538 StoredType value( std::forward<TArgs>( args)... );
1539
1540 // search element
1541 std::pair<Iterator, bool> result= base::insertIfNotExists( TValueDescriptor().Key(value),
1542 THash{}(TValueDescriptor().Key(value)) );
1543
1544 // existed? Do nothing
1545 if( result.second == false )
1546 return result;
1547
1548 // placement-new moving the locally created object
1549 new ( &result.first.element->value ) StoredType( std::move(value) );
1550
1551 return result;
1552 }
1553
1554#if DOXYGEN
1555 //==============================================================================================
1556 /// Inserts a new mapped object only if no other object is contained that is associated
1557 /// already with a key that equals the given \p{key}.
1558 ///
1559 /// \note
1560 /// This method allows preventing the insertion of double entries.
1561 /// For more information, see
1562 /// \ref alib_ns_containers_hashtable_single_multi "Single And Multiple Entries"
1563 /// of the documentation of this class.
1564 ///
1565 /// \par Availability
1566 /// This method is available if this templated type is instantiated with
1567 /// \ref alib_ns_containers_hashtable_setandmap "hash map mode"
1568 /// or for hash sets that only define a subset of \p{StoredType} as a key type \p{TKey} and
1569 /// whose stored type is constructible if given a key value and the variadic template
1570 /// arguments.
1571 ///
1572 /// @tparam TArgs Types of variadic parameters given with parameter \p{args}.
1573 /// @param key The key to use for search and insertion.
1574 /// @param args Variadic parameters to be forwarded to the constructor of the mapped object
1575 /// of type <c>\p{MappedType}</c>.
1576 /// @return A pair containing an iterator referencing either the element found or the new
1577 /// element added.
1578 /// The bool component is \c true if the insertion took place and \c false nothing
1579 /// was changed.
1580 //==============================================================================================
1581 template<typename... TArgs>
1582 std::pair<Iterator, bool> EmplaceIfNotExistent( const KeyType& key, TArgs&&... args);
1583#else
1584 template<typename... TArgs>
1585 requires( !std::is_constructible< StoredType, const KeyType&, TArgs&&... >::value )
1586 std::pair<Iterator, bool> EmplaceIfNotExistent( const KeyType& key, TArgs&&... args) {DCS
1587 // search element
1588 std::pair<Iterator, bool> result= base::insertIfNotExists( key, THash{}(key) );
1589
1590 // existed? Do nothing
1591 if( result.second == false )
1592 return result;
1593
1594 // placement-new for the key (using copy constructor)
1595 new (&TValueDescriptor().Key(result.first.element->value)) KeyType( key );
1596
1597 // placement-new for the mapped object (using custom constructor)
1598 new (&TValueDescriptor().Mapped(result.first.element->value)) MappedType( std::forward<TArgs>( args)... );
1599
1600 return result;
1601 }
1602
1603 template<typename... TArgs>
1604 requires(std::is_constructible< StoredType, const KeyType&, TArgs&&...>::value )
1605 std::pair<Iterator, bool> EmplaceIfNotExistent( const KeyType& key, TArgs&&... args) {DCS
1606 // search element
1607 std::pair<Iterator, bool> result= base::insertIfNotExists( key, THash{}(key) );
1608
1609 // existed? Do nothing
1610 if( result.second == false )
1611 return result;
1612
1613 // placement-new for the element passing key and args together
1614 new (&result.first.element->value) StoredType( key, std::forward<TArgs>( args)... );
1615
1616 return result;
1617 }
1618#endif
1619
1620 //##############################################################################################
1621 /// @name Element Search
1622 //##############################################################################################
1623 /// Returns an iterator pointing to the first element of equal key value.
1624 ///
1625 /// \note
1626 /// The iterator returned may be incremented. It is ensured that further elements contained
1627 /// in this hash table with the same key are consecutively following this first element
1628 /// returned. However, the iterator does \b not end with the last element of that key.
1629 ///
1630 /// \see
1631 /// Method #EqualRange, which also returns an iterator pointing behind the last element
1632 /// with that key.
1633 ///
1634 ///
1635 /// @param key The key to search for.
1636 /// @return An iterator pointing to the first element found with equal <em>key-portion</em>,
1637 /// respectively, one being equal to #end, if no element was found with \p{key}.
1638 Iterator Find( const KeyType& key ) {DCSSHRD
1639 auto hashCode = THash{}(key);
1640 auto bucketIdx= hashCode % base::bucketCount;
1641 Element* elem = base::findElement( bucketIdx, key, hashCode );
1642 return Iterator( this, elem == nullptr ? base::bucketCount : bucketIdx, elem );
1643 }
1644
1645 /// Searches an element.
1646 /// @param key The key to search for.
1647 /// @return An iterator pointing to the first element found with equal <em>key-portion</em>,
1648 /// respectively, one being equal to #end, if no element was found with \p{key}.
1649 ConstIterator Find( const KeyType& key ) const {DCSSHRD
1650 auto hashCode = THash{}(key);
1651 auto bucketIdx= hashCode % base::bucketCount;
1652 Element* elem = base::findElement( bucketIdx, key, hashCode );
1653 return ConstIterator( this, elem == nullptr ? base::bucketCount : bucketIdx, elem );
1654 }
1655
1656 /// Overloaded version of method \alib{containers::HashTable;Find(const KeyType&)} which
1657 /// accepts the \p{hashCode} of the given \p{key} as a second parameter.
1658 ///
1659 /// @see Use cases of this method are discussed in reference documentation section
1660 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1661 ///
1662 /// @param key The key to search for.
1663 /// @param hashCode Pre-calculated hash code of \p{key}.
1664 /// @return An iterator pointing to the first element found with equal <em>key-portion</em>,
1665 /// respectively, one being equal to #end, if no element was found with \p{key}.
1666 Iterator Find( const KeyType& key, size_t hashCode ) {DCSSHRD
1667 auto bucketIdx= hashCode % base::bucketCount;
1668 Element* elem = base::findElement( bucketIdx, key, hashCode );
1669 return Iterator( this, elem == nullptr ? base::bucketCount : bucketIdx, elem );
1670 }
1671
1672 /// Overloaded version of method \alib{containers::HashTable;Find(const KeyType&)const} which
1673 /// accepts the \p{hashCode} of the given \p{key} as a second parameter.
1674 ///
1675 /// @see Use cases of this method are discussed in reference documentation section
1676 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1677 ///
1678 /// @param key The key to search for.
1679 /// @param hashCode Pre-calculated hash code of \p{key}.
1680 /// @return An iterator pointing to the first element found with equal <em>key-portion</em>,
1681 /// respectively, one being equal to #end, if no element was found with \p{key}.
1682 ConstIterator Find( const KeyType& key, size_t hashCode ) const {DCSSHRD
1683 auto bucketIdx= hashCode % base::bucketCount;
1684 Element* elem = base::findElement( bucketIdx, key, hashCode );
1685 return ConstIterator( this, elem == nullptr ? base::bucketCount : bucketIdx, elem );
1686 }
1687
1688 /// Tests if an element with given \p{key} is stored in this container.
1689 /// @param key The key to search for.
1690 /// @return \c true if this hash table contains at least one element with given
1691 /// <em>key-portion</em> \p{key}, \c false otherwise.
1692 bool Contains( const KeyType& key ) const {DCSSHRD
1693 auto hashCode= THash{}(key);
1694 return base::findElement(hashCode % base::bucketCount, key, hashCode )
1695 != nullptr;
1696 }
1697
1698 /// Searches a key and returns a pair of iterators. The first is pointing to the first
1699 /// element of the range, the second is pointing to the first element past the range.
1700 ///
1701 /// If both iterators are equal, the range is empty (both iterators will be equal to #end).
1702 ///
1703 /// @param key The key to search for.
1704 /// @return A pair of iterators defining the range of elements with key \p{key}.
1705 std::pair<Iterator,Iterator> EqualRange(const KeyType& key )
1706 {DCSSHRD return base::findRange( key ); }
1707
1708 /// Searches a key and returns a pair of iterators. The first is pointing to the first
1709 /// element of the range, the second is pointing to the first element past the range.
1710 ///
1711 /// If both iterators are equal, the range is empty (both iterators will be equal to #end).
1712 ///
1713 /// @param key The key to search for.
1714 /// @return A pair of iterators defining the range of elements with key \p{key}.
1715 std::pair<ConstIterator,ConstIterator> EqualRange(const KeyType& key ) const
1716 {DCSSHRD return base::findRange( key ); }
1717
1718 //##############################################################################################
1719 /// @name Element Removal
1720 //##############################################################################################
1721 /// Extracts the first element found with the given key from the hash table and returns a
1722 /// handle to it.<br>
1723 /// Extracting an element invalidates only the iterators to the extracted element and preserves
1724 /// the relative order of the elements that are not extracted.
1725 ///
1726 /// Extracting and re-inserting nodes is the only way to change a key of an element without
1727 /// performing reallocation and or destruction/construction.
1728 ///
1729 /// @param key The key to search a first element for.
1730 /// @return A handle to an element that allows changes of the formerly stored value.
1731 /// Changes may include the <em>key-portion</em> of the data stored.
1732 /// Handles may be passed to one of the overloaded insert methods.
1733 /// If no element was found, the returned handle is empty.
1734 ElementHandle Extract(const KeyType& key ) { return Extract( key, THash{}(key) ); }
1735
1736 /// Overloaded version of method \alib{containers::HashTable;Extract(const KeyType&)} which
1737 /// accepts the \p{hashCode} of the given \p{key} as a second parameter.
1738 ///
1739 /// @see Use cases of this method are discussed in reference documentation section
1740 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1741 ///
1742 /// @param key The key to search a first element for.
1743 /// @param hashCode Pre-calculated hash code of \p{key}.
1744 /// @return A handle to an element that allows changes of the formerly stored value.
1745 /// Changes may include the <em>key-portion</em> of the data stored.
1746 /// Handles may be passed to one of the overloaded insert methods.
1747 /// If no element was found, the returned handle is empty.
1748 ElementHandle Extract(const KeyType& key, size_t hashCode ) {DCS
1749 Node* previous= base::findElementBefore( hashCode % base::bucketCount, hashCode, key );
1750 if( previous == nullptr )
1751 return ElementHandle(this, nullptr);
1752
1753 Element* element= previous->next();
1754 previous->removeNext();
1755 --base::size;
1756 return ElementHandle( this, element );
1757 }
1758
1759 /// Extracts the first element found with the given key from the hash table and returns a
1760 /// handle to it.<br>
1761 /// If the iterator was not valid (i.e., #end), the method has undefined behavior.
1762 /// With debug-builds an \alib_assertion is raised.
1763 ///
1764 /// Extracting a element invalidates only the iterators to the extracted element, and preserves
1765 /// the relative order of the elements that are not extracted.
1766 ///
1767 /// Extracting and re-inserting nodes is the only way to change a key of an element without
1768 /// performing reallocation and or destruction/construction.
1769 ///
1770 /// @param pos The position of the element to extract.
1771 /// @return A handle to an element that allows changes of the formerly stored value.
1772 /// Changes may include the <em>key-portion</em> of the data stored.
1773 /// Handles may be passed to one of the overloaded insert methods.
1774 /// If no element was found, the returned handle is empty.
1775 ElementHandle Extract( ConstIterator pos ) {DCS
1776 ALIB_ASSERT_ERROR( pos.element != nullptr
1777 && pos.table != nullptr ,
1778 "MONOMEM/HASHTABLE", "Illegal iterator." )
1779
1780 Node* previous= base::buckets[pos.bucketIdx].findLastBefore( pos.element );
1781 ALIB_ASSERT_ERROR( previous != nullptr, "MONOMEM/HASHTABLE",
1782 "Illegal iterator: Element not found." )
1783
1784 previous->removeNext();
1785 --base::size;
1786 return ElementHandle( this, pos.element );
1787 }
1788
1789 /// Erases all elements stored with the given key.
1790 ///
1791 /// @param key The key to search elements for deletion.
1792 /// @return The number of elements removed.
1793 integer erase(const KeyType& key ) { return Erase( key, THash{}(key) ); }
1794
1795 /// Overloaded version of method \alib{containers::HashTable;erase(const KeyType&)}
1796 /// which accepts the \p{hashCode} of the given \p{key} as a second parameter.
1797 ///
1798 /// @see Use cases of this method are discussed in reference documentation section
1799 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1800 ///
1801 /// @param key The key to search elements for deletion.
1802 /// @param hashCode Pre-calculated hash code of \p{key}.
1803 /// @return The number of elements removed.
1804 integer Erase(const KeyType& key, size_t hashCode ) {DCS
1805 // search start
1806 Node* beforeFirst= base::findElementBefore( hashCode % base::bucketCount, hashCode, key );
1807 if( beforeFirst == nullptr )
1808 return 0;
1809
1810 // search end
1811 Element* end= beforeFirst->next();
1812 while( end && base::areEqual( end, key, hashCode ) )
1813 end= end->next();
1814
1815 // erase and add to recycler
1816 auto result= base::recyclerType::RecycleList(beforeFirst->next(), end);
1817 beforeFirst->next( end );
1818
1819 base::size-= result.second;
1820 return result.second;
1821 }
1822
1823 /// Erases the unique element with the given key.
1824 ///
1825 /// \note
1826 /// This method is slightly more efficient than method #erase(const KeyType&), as it will
1827 /// not search for a next element with an equal key.<br>
1828 /// In debug-compilations, the method asserts that no second element with the same \p{key}
1829 /// is available.<br>
1830 /// If this table is supposed to
1831 /// \ref alib_ns_containers_hashtable_single_multi "store only unique elements", the
1832 /// use of this method is therefore recommended, as an assertions hints to an erroneous use
1833 /// of the insertion methods.
1834 ///
1835 /// @param key The key to search elements for deletion.
1836 /// @return \c true if an element was found and removed, \c false otherwise.
1837 bool EraseUnique( const KeyType& key ) { return EraseUnique( key, THash{}(key) ); }
1838
1839
1840 /// Overloaded version of method \alib{containers::HashTable;EraseUnique(const KeyType&)} which
1841 /// accepts the \p{hashCode} of the given \p{key} as a second parameter.
1842 ///
1843 /// @see Use cases of this method are discussed in reference documentation section
1844 /// \ref alib_ns_containers_hashtable_hashprecalc "6.2 Hash Code Pre-calculation".
1845 ///
1846 /// @param key The key to search elements for deletion.
1847 /// @param hashCode Pre-calculated hash code of \p{key}.
1848 /// @return \c true if an element was found and removed, \c false otherwise.
1849 bool EraseUnique( const KeyType& key, size_t hashCode ) {DCS
1850 Node* before= base::findElementBefore( hashCode % base::bucketCount, hashCode, key );
1851 if( before == nullptr )
1852 return false;
1853
1854 ALIB_ASSERT_ERROR( before->next()->next() == nullptr
1855 || !base::areEqual( before->next()->next(), key, hashCode ),
1856 "MONOMEM/HASHTABLE", "More than one element found matching the given key" )
1857
1858 Element* elem= before->removeNext();
1859 base::recyclerType::Recycle(elem);
1860
1861 --base::size;
1862 return true;
1863 }
1864
1865
1866 /// Removes an element specified by an iterator.<br>
1867 /// If the iterator was not valid (i.e #end), the method has undefined behavior.
1868 /// With debug-builds an \alib_assertion is raised.
1869 ///
1870 /// The order of the elements that are not erased is preserved, what makes it possible to
1871 /// erase individual elements while iterating through the container.
1872 ///
1873 /// @param pos The iterator to the element to remove.
1874 /// @return An iterator following the removed element.
1876 ALIB_ASSERT_ERROR( pos.element != nullptr
1877 && pos.table != nullptr ,
1878 "MONOMEM/HASHTABLE", "Illegal iterator." )
1879
1880 Iterator result( this, pos.bucketIdx, pos.element );
1881 ++result;
1882
1883 // search pointer to element before pos
1884 Node* previous= base::buckets[pos.bucketIdx].findLastBefore( pos.element );
1885 ALIB_ASSERT_ERROR( previous != nullptr, "MONOMEM/HASHTABLE",
1886 "Illegal iterator: Element not found." )
1887
1888
1889 Element* toDelete= previous->removeNext();
1890 base::recyclerType::Recycle(toDelete);
1891
1892 --base::size;
1893 return result;
1894 }
1895
1897 /// Removes all elements from the given position \p{start} to the element
1898 /// before given position \p{end}.
1899 ///
1900 /// The order of the elements that are not erased is preserved, what makes it possible to
1901 /// erase individual elements while iterating through the container.
1902 ///
1903 /// @param start The iterator to the element to remove.
1904 /// @param end The first element not to remove.
1905 /// @return An iterator following the last removed element.
1907 ALIB_ASSERT_ERROR( start.element != nullptr
1908 && start.table != nullptr ,
1909 "MONOMEM/HASHTABLE", "Illegal iterator." )
1910
1911 ALIB_ASSERT_ERROR( start.table == end.table, "MONOMEM/HASHTABLE",
1912 "Iterators are referring to different hash tables." )
1913
1914 if( start.element == end.element )
1915 return Iterator(this, start.bucketIdx, start.element );
1916
1917 // loop over all buckets in question
1918 for( uinteger bucketIdx= start.bucketIdx; bucketIdx <= end.bucketIdx; ++bucketIdx ) {
1919 // end of buckets? Return iterator that marks hashtable end
1920 if( bucketIdx == base::bucketCount )
1921 return HashTable::end();
1922
1923 // find the previous pointer to the start node:
1924 Node* previous;
1925 if( bucketIdx == start.bucketIdx ) { // With the first bucket in the loop, this has to be searched...
1926 // search pointer to element before start
1927 previous= base::buckets[start.bucketIdx].findLastBefore( start.element );
1928 ALIB_ASSERT_ERROR( previous != nullptr, "MONOMEM/HASHTABLE",
1929 "Illegal iterator: Element not found." )
1930 }
1931 else { // ...afterwards, its of course just the bucket that points to it
1932 if( base::buckets[bucketIdx].isEmpty() )
1933 continue;
1934 previous= &base::buckets[bucketIdx];
1935 }
1936
1937 // destruct either to end of list or to end-iterator element
1938 if ( bucketIdx < end.bucketIdx ) {
1939 base::size-= previous->count();
1940 base::recyclerType::RecycleList( previous->next() );
1941 previous->next( nullptr );
1942 } else {
1943 auto pair= base::recyclerType::RecycleList(previous->next(), end.element );
1944 previous->next( end.element );
1945 base::size-= pair.second;
1946
1947 return Iterator( this, bucketIdx, end.element );
1948 } } }
1950
1951
1952 /// Removes an element specified by a bucket iterator.
1953 /// Bucket iterators are receivable using overloaded methods #begin(uinteger) and
1954 /// \alib{containers::HashTable;cbegin(uinteger)const;cbegin(uinteger)}.
1955 ///
1956 /// The order of the elements that are not erased is preserved, what makes it possible to
1957 /// erase individual elements while iterating through the container.
1958 ///
1959 /// @param pos The iterator to the element to remove.
1960 /// @return An iterator following the removed element.
1962 ALIB_ASSERT_ERROR( pos.element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
1963
1964 LocalIterator result( pos.bucketIdx, pos.element->next() );
1965
1966 Element* element= pos.element;
1967 base::buckets[pos.bucketIdx].findAndRemove( element );
1968 base::recyclerType::Recycle( element);
1969 --base::size;
1970
1971 return result;
1972 }
1973
1974 /// Removes all element from the given bucket iterator position \p{start} to the element
1975 /// before given position \p{end}.
1976 ///
1977 /// The order of the elements that are not erased is preserved, what makes it possible to
1978 /// erase individual elements while iterating through the container.
1979 ///
1980 /// @param start The bucket iterator to the element to remove.
1981 /// @param end The bucket iterator to the first element not to remove.
1982 /// @return An iterator following the last removed element.
1984 ALIB_ASSERT_ERROR( start.element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
1985
1986 Node* previous= base::buckets[start.bucketIdx].findLastBefore( start.element );
1987 ALIB_ASSERT_ERROR( previous != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
1988 if( start.element == end.element )
1989 return LocalIterator( start.bucketIdx, start.element );
1990
1991 previous->next( end.element );
1992 auto pair= base::recyclerType::RecycleList( start.element, end.element );
1993
1994 base::size-= pair.second;
1995
1996 return LocalIterator( start.bucketIdx, end.element );
1997 }
1998
1999 //##############################################################################################
2000 /// @name std::iterator_traits Interface
2001 //##############################################################################################
2002
2003 /// Returns an iterator referring to a mutable element at the start of this table.
2004 /// @return The first of element in this container.
2005 Iterator begin() { return Iterator( this, 0 ); }
2006
2007 /// Returns an iterator referring to a mutable, non-existing element.
2008 /// @return The end of the list of elements in this container.
2009 Iterator end() { DCSSHRD return Iterator( this, base::bucketCount, nullptr ); }
2010
2011 /// Returns an iterator referring to a constant element at the start of this container.
2012 /// @return The first of element in this container.
2013 ConstIterator begin() const { return ConstIterator( this, 0 ); }
2014
2015 /// Returns an iterator referring to a constant, non-existing element.
2016 /// @return The end of the list of elements in this container.
2017 ConstIterator end() const {DCSSHRD return ConstIterator(this,base::bucketCount,nullptr); }
2018
2019 /// Returns an iterator referring to a constant element at the start of this container.
2020 /// @return The first of element in this container.
2021 ConstIterator cbegin() const { return ConstIterator( this, 0 ); }
2022
2023 /// Returns an iterator referring to a constant, non-existing element.
2024 /// @return The end of the list of elements in this container.
2025 ConstIterator cend() const {DCSSHRD return ConstIterator(this,base::bucketCount,nullptr); }
2026
2027 /// Returns an iterator referring to a mutable element at the start of bucket of index
2028 /// \p{bucketNumber}.
2029 /// @param bucketNumber The bucket to iterate on.
2030 /// @return The first element in bucket \p{bucketNumber}.
2031 LocalIterator begin( uinteger bucketNumber ) {DCSSHRD
2032 ALIB_ASSERT_ERROR( bucketNumber < base::bucketCount, "MONOMEM/HASHTABLE",
2033 "Bucket number out of range: {}>={}.", bucketNumber, base::bucketCount )
2034 return LocalIterator( bucketNumber, base::buckets[bucketNumber].first() );
2035 }
2036
2037 /// Returns an iterator referring to a constant, non-existing element in bucket of index
2038 /// \p{bucketNumber}.
2039 /// @param bucketNumber The bucket to iterate on.
2040 /// @return The end of the list of elements in bucket \p{bucketNumber}.
2041 LocalIterator end( uinteger bucketNumber ) {DCSSHRD
2042 ALIB_ASSERT_ERROR( bucketNumber < base::bucketCount, "MONOMEM/HASHTABLE",
2043 "Bucket number out of range: {}>={}.", bucketNumber, base::bucketCount )
2044 return LocalIterator( bucketNumber, nullptr );
2045 }
2046
2047 /// Returns an iterator referring to a mutable element at the start of bucket of index
2048 /// \p{bucketNumber}.
2049 /// @param bucketNumber The bucket to iterate on.
2050 /// @return The first element in bucket \p{bucketNumber}.
2051 ConstLocalIterator begin( uinteger bucketNumber ) const {DCSSHRD
2052 ALIB_ASSERT_ERROR( bucketNumber < base::bucketCount, "MONOMEM/HASHTABLE",
2053 "Bucket number out of range: {}>={}.", bucketNumber, base::bucketCount )
2054 return ConstLocalIterator( bucketNumber, base::buckets[bucketNumber].first() );
2055 }
2056
2057 /// Returns an iterator referring to a constant, non-existing element in bucket of index
2058 /// \p{bucketNumber}.
2059 /// @param bucketNumber The bucket to iterate on.
2060 /// @return The end of the list of elements in bucket \p{bucketNumber}.
2061 ConstLocalIterator end( uinteger bucketNumber ) const {DCSSHRD
2062 ALIB_ASSERT_ERROR( bucketNumber < base::bucketCount, "MONOMEM/HASHTABLE",
2063 "Bucket number out of range: {}>={}.", bucketNumber, base::bucketCount )
2064 return ConstLocalIterator( bucketNumber, nullptr );
2065 }
2066
2067 /// Returns an iterator referring to a mutable element at the start of bucket of index
2068 /// \p{bucketNumber}.
2069 /// @param bucketNumber The bucket to iterate on.
2070 /// @return The first element in bucket \p{bucketNumber}.
2071 ConstLocalIterator cbegin( uinteger bucketNumber ) const {DCSSHRD
2072 ALIB_ASSERT_ERROR( bucketNumber < base::bucketCount, "MONOMEM/HASHTABLE",
2073 "Bucket number out of range: {}>={}.", bucketNumber, base::bucketCount )
2074 return ConstLocalIterator( bucketNumber, base::buckets[bucketNumber].first() );
2075 }
2076
2077 /// Returns an iterator referring to a constant, non-existing element in bucket of index
2078 /// \p{bucketNumber}.
2079 /// @param bucketNumber The bucket to iterate on.
2080 /// @return The end of the list of elements in bucket \p{bucketNumber}.
2081 ConstLocalIterator cend( uinteger bucketNumber ) const {DCSSHRD
2082 ALIB_ASSERT_ERROR( bucketNumber < base::bucketCount, "MONOMEM/HASHTABLE",
2083 "Bucket number out of range: {}>={}.", bucketNumber, base::bucketCount )
2084 return ConstLocalIterator( bucketNumber, nullptr );
2085 }
2086}; // class Hashtable
2087
2088
2089//##################################################################################################
2090//##################################################################################################
2091// Debug Functions
2092//##################################################################################################
2093//##################################################################################################
2094#if ALIB_DEBUG_CONTAINERS
2095#include "ALib.Lang.CIFunctions.H"
2096/// Generates statistics on the given hash table. The meanings of the returned tuple are:
2097/// 0. The expected average size of a bucket (simply table size divided by number of buckets).
2098/// 1. The <em>standard deviation</em> of the buckets. The lower this value, the better
2099/// is the hash algorithm used. A value of <c>1.0</c> denotes the <em>gaussian distribution</em>
2100/// which indicates perfect randomness. However, this value is unlikely (impossible) to be
2101/// achieved.
2102/// 2. The minimum number of elements found in a bucket.
2103/// 3. The maximum number of elements found in a bucket.
2104///
2105/// \par Availability
2106/// Available only if the compiler-symbol \ref ALIB_DEBUG_CONTAINERS is set.
2107///
2108/// \see
2109/// Sibling namespace functions \alib{containers;DbgDumpDistribution} and
2110/// \alib{containers;DbgDumpHashtable} provided for debugging and optimization.
2111///
2112/// @tparam THashtable A specification of templated type \alib{containers;HashTable}.
2113/// Deduced by the compiler by given parameter \p{hashtable}.
2114/// @param hashtable The hashtable to investigate on.
2115/// @return The tuple as described above.
2116template<typename THashtable>
2117inline
2118std::tuple<double,double,integer,integer>
2119DbgGetHashTableDistribution(const THashtable& hashtable )
2120{
2121 auto qtyBuckets = hashtable.BucketCount();
2122 double averageExpected = double(hashtable.Size()) / double(qtyBuckets);
2123 uinteger minimum = std::numeric_limits<uinteger>::max();
2124 uinteger maximum = std::numeric_limits<uinteger>::min();
2125 double diffs = 0.0;
2126 integer sumCheck = 0;
2127 for( uinteger i= 0 ; i < qtyBuckets ; ++i )
2128 {
2129 auto bucketSize= hashtable.BucketSize( i );
2130 sumCheck+= bucketSize;
2131 if( minimum > bucketSize ) minimum= bucketSize;
2132 if( maximum < bucketSize ) maximum= bucketSize;
2133
2134 double diff= averageExpected - double(bucketSize);
2135 diffs+= diff > 0 ? diff : - diff;
2136 }
2137
2138 ALIB_ASSERT_ERROR( sumCheck == hashtable.Size(), "MONOMEM/HASHTABLE",
2139 "Error: Hashtable::Size() and sum of bucket sizes differ: {}!={}", hashtable.Size(),sumCheck )
2140 double deviation= diffs / double(qtyBuckets);
2141
2142 return std::make_tuple( averageExpected, deviation, minimum, maximum );
2143}
2144
2145
2146#include "ALib.Lang.CIMethods.H"
2147#endif //ALIB_DEBUG_CONTAINERS
2148
2149//==================================================================================================
2150//============================================= HashSet ============================================
2151//==================================================================================================
2152
2153/// This type definition is a shortcut to \alib{containers;HashTable}, usable if the full
2154/// portion of the data stored in the container is used for the comparison of values.
2155///
2156/// \note
2157/// As with this definition template type \p{TKey} equals stored type \p{StoredType}, methods of
2158/// target type \alib{containers;HashTable} that accept an object of template type
2159/// \b TKey expect an object of \p{StoredType} when this type is used.<br>
2160/// In case this is not wanted (or possible), and only the true key-portion should be expected
2161/// by interface functions such as \alib{containers;HashTable::Find}, the original
2162/// type has to be used. Here, typically template parameter \p{TValueDescriptor} can be
2163/// set to \alib{containers;TSubsetKeyDescriptor}.
2164///
2165/// \see
2166/// For a detailed description of this type, see original type
2167/// \alib{containers;HashTable}, as well as alternative type definition
2168/// \alib{containers;HashMap}.
2169///
2170/// @tparam TAllocator The \alib{lang;Allocator;allocator type} to use.
2171/// @tparam T The element type stored with this container.
2172/// This type is published as \alib{containers;HashTable::StoredType}
2173/// and type definition \alib{containers;HashTable::KeyType} becomes
2174/// a synonym.
2175/// @tparam THash The hash functor applicable to \p{T}.<br>
2176/// Defaults to <c>std::hash<T></c> and is published as
2177/// \alib{containers;HashTable::HashType}.
2178/// @tparam TEqual The comparison functor on \p{T}.<br>
2179/// Defaults to <c>std::equal_to<T></c> and is published as
2180/// \alib{containers;HashTable::EqualType}.
2181/// @tparam THashCaching Determines if hash codes are cached when elements are inserted.<br>
2182/// Defaults to <b>Caching::Auto</b>, which enables caching if
2183/// <c>std::is_arithmetic<StoredType>::value</c> evaluates to \c false.
2184/// @tparam TRecycling Denotes the type of recycling that is to be performed. Possible values are
2185/// \alib{containers;Recycling;None},
2186/// \alib{containers;Recycling;Private} (the default), or
2187/// \alib{containers;Recycling;Shared}.
2188template< typename TAllocator,
2189 typename T,
2190 typename THash = std::hash <T>,
2191 typename TEqual = std::equal_to<T>,
2192 lang::Caching THashCaching = lang::Caching::Auto,
2193 Recycling TRecycling = Recycling::Private >
2194using HashSet= HashTable< TAllocator,
2196 THash, TEqual,
2197 THashCaching,
2198 TRecycling >;
2199
2200//==================================================================================================
2201//============================================= HashMap ============================================
2202//==================================================================================================
2203
2204/// This type definition is a shortcut to \alib{containers;HashTable}, usable if data
2205/// stored in the container does not include a key-portion, and thus the key to the data
2206/// is to be separately defined.<br>
2207/// To achieve this, this type definition aggregates types \p{TKey} and \p{TMapped} into a
2208/// <c>std::pair<TKey,TMapped></c>. This is done using special value descriptor type
2209/// \alib{containers;TPairDescriptor}.
2210///
2211/// \see
2212/// For a detailed description of this type, see original type
2213/// \alib{containers;HashTable}, as well as alternative type definition
2214/// \alib{containers;HashSet}.
2215///
2216/// @tparam TAllocator The \alib{lang;Allocator;allocator type} to use.
2217/// @tparam TKey The type of the <em>key-portion</em> of the inserted data.<br>
2218/// This type is published as \alib{containers;HashTable::KeyType}.
2219/// @tparam TMapped The type of the <em>mapped-portion</em> of the inserted data.<br>
2220/// This type is published as \alib{containers;HashTable::MappedType}.
2221/// @tparam THash The hash functor applicable to \p{TKey}.<br>
2222/// Defaults to <c>std::hash<TKey></c> and is published as
2223/// \alib{containers;HashTable::HashType}.
2224/// @tparam TEqual The comparison functor on \p{TKey}.<br>
2225/// Defaults to <c>std::equal_to<TKey></c> and is published as
2226/// \alib{containers;HashTable::EqualType}.
2227/// @tparam THashCaching Determines if hash codes are cached when elements are inserted.<br>
2228/// Defaults to <b>Caching::Auto</b>, which enables caching if
2229/// <c>std::is_arithmetic<TKey>::value</c> evaluates to \c false.
2230/// @tparam TRecycling Denotes the type of recycling that is to be performed. Possible values are
2231/// \alib{containers;Recycling;None},
2232/// \alib{containers;Recycling;Private} (the default), or
2233/// \alib{containers;Recycling;Shared}.
2234template< typename TAllocator,
2235 typename TKey,
2236 typename TMapped,
2237 typename THash = std::hash <TKey>,
2238 typename TEqual = std::equal_to<TKey>,
2239 lang::Caching THashCaching = lang::Caching::Auto,
2240 Recycling TRecycling = Recycling::Private >
2241using HashMap= HashTable<TAllocator,
2243 THash,TEqual,
2244 THashCaching,
2245 TRecycling >;
2246
2247} // namespace alib[::containers]
2248
2249/// Type alias in namespace \b alib. See type definition \ref alib::containers::HashSet.
2250template< typename TAllocator,
2251 typename TValueDescriptor,
2252 typename THash = std::hash <typename TValueDescriptor::KeyType>,
2253 typename TEqual = std::equal_to<typename TValueDescriptor::KeyType>,
2254 lang::Caching THashCaching = lang::Caching::Auto,
2255 Recycling TRecycling = Recycling::Private >
2257
2258/// Type alias in namespace \b alib. See type definition \ref alib::containers::HashSet.
2259template< typename TAllocator,
2260 typename T,
2261 typename THash = std::hash <T>,
2262 typename TEqual = std::equal_to<T>,
2263 lang::Caching THashCaching = lang::Caching::Auto,
2264 Recycling TRecycling = Recycling::Private >
2266
2267/// Type alias in namespace \b alib.
2268template< typename TAllocator,
2269 typename TKey,
2270 typename TMapped,
2271 typename THash = std::hash <TKey>,
2272 typename TEqual = std::equal_to<TKey>,
2273 lang::Caching THashCaching = lang::Caching::Auto,
2274 Recycling TRecycling = Recycling::Private >
2276
2277} // namespace [alib]
2278
2279#if ALIB_DEBUG_CRITICAL_SECTIONS
2280# undef DCS
2281# undef DCSSHRD
2282#endif
ElementHandle & operator=(ElementHandle &&other)
HashTable * table
The table we belong to.
ElementHandle(ElementHandle &other)=delete
Deleted copy constructor.
ElementHandle(HashTable *pTable, Element *pElement)
ElementHandle()
Default constructor creating and empty handle.
Element * element
The extracted element.
ALIB_WARNINGS_IGNORE_NOTHING_RETURNED Iterator erase(ConstIterator start, ConstIterator end)
std::pair< Iterator, bool > InsertIfNotExistent(const KeyType &key, const MappedType &mapped)
HashTable(AllocatorType &pAllocator, TSharedRecycler &pSharedRecycler, float pBaseLoadFactor=1.0, float pMaxLoadFactor=2.0)
std::pair< Iterator, bool > EmplaceIfNotExistent(const KeyType &key, TArgs &&... args)
ConstIterator cend() const
typename TValueDescriptor::MappedType MappedType
typename base::recyclerType recyclerType
The recycler type.
HashTable(AllocatorType &pAllocator, float pBaseLoadFactor=1.0, float pMaxLoadFactor=2.0)
typename base::template TLocalIterator< const StoredType > ConstLocalIterator
The constant iterator for a single bucket exposed by this container.
std::pair< Iterator, bool > InsertIfNotExistent(const KeyType &key, MappedType &&mapped)
typename TValueDescriptor::StoredType StoredType
TValueDescriptor DescriptorType
Type definition publishing template parameter TValueDescriptor.
std::pair< Iterator, bool > InsertOrAssign(const KeyType &key, const MappedType &mapped)
integer Erase(const KeyType &key, size_t hashCode)
std::pair< Iterator, bool > InsertIfNotExistent(const KeyType &key, MappedType &&mapped, size_t hashCode)
std::pair< Iterator, bool > InsertOrAssign(const KeyType &key, MappedType &&mapped, size_t hashCode)
typename base::SharedRecyclerType SharedRecyclerType
TAllocator AllocatorType
Type definition publishing template parameter TAllocator.
std::pair< Iterator, bool > InsertOrAssign(const KeyType &key, MappedType &&mapped)
THash HashType
Type definition publishing template parameter THash.
typename TValueDescriptor::KeyType KeyType
typename base::template TIterator< StoredType > Iterator
The mutable iterator exposed by this container.
typename base::template TLocalIterator< StoredType > LocalIterator
The mutable iterator for a single bucket exposed by this container.
TEqual EqualType
Type definition publishing template parameter TEqual.
typename base::template TIterator< const StoredType > ConstIterator
The constant iterator exposed by this container.
HashTable(TSharedRecycler &pSharedRecycler, float pBaseLoadFactor=1.0, float pMaxLoadFactor=2.0)
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1065
#define ALIB_WARNINGS_RESTORE
Definition alib.inl:719
#define ALIB_EXPORT
Definition alib.inl:497
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
#define ALIB_WARNINGS_IGNORE_NOTHING_RETURNED
Definition alib.inl:695
#define ALIB_DEBUG_CRITICAL_SECTIONS
Definition prepro.dox.md:43
std::tuple< double, double, integer, integer > DbgGetHashTableDistribution(const THashtable &hashtable)
HashTable< TAllocator, TPairDescriptor< TKey, TMapped >, THash, TEqual, THashCaching, TRecycling > HashMap
HashTable< TAllocator, TIdentDescriptor< T >, THash, TEqual, THashCaching, TRecycling > HashSet
void Destruct(T &object)
Definition tmp.inl:82
Caching
Denotes if a cache mechanism is enabled or disabled.
@ Auto
Auto/default mode.
ValueReference
Denotes if a value is interpreted as an absolute or relative number.
@ Relative
Referring to a relative value.
@ Absolute
Referring to an absolute value.
containers::HashSet< TAllocator, T, THash, TEqual, THashCaching, TRecycling > HashSet
Type alias in namespace alib. See type definition alib::containers::HashSet.
containers::HashTable< TAllocator, TValueDescriptor, THash, TEqual, THashCaching, TRecycling > HashTable
Type alias in namespace alib. See type definition alib::containers::HashSet.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
containers::HashMap< TAllocator, TKey, TMapped, THash, TEqual, THashCaching, TRecycling > HashMap
Type alias in namespace alib.
containers::Recycling Recycling
Type alias in namespace alib.
Definition recycling.inl:35
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
float maxLoadFactor
The maximum quotient of size and bucketCount that triggers a rehash.
lang::SidiNodeBase< Element > Node
Type of a node in the List.
typename HTElementSelector< TValueDescriptor, THashCaching >::Type Element
The type stored in the bucket of class HashTable.
typename RecyclingSelector< TRecycling >::template Type< TAllocator, typename HTElementSelector< TValueDescriptor, THashCaching >::Type > base
Our base type.
float baseLoadFactor
The load factor that is set when the table is rehashed automatically.
TElement * removeNext() noexcept
Definition sidilist.inl:118