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