ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
hashtablebase.inl
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-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8// Not exported
9#if ALIB_SIZEOF_INTEGER == 4
10 static constexpr int PRIME_TABLE_SIZE = 26;
11#elif ALIB_SIZEOF_INTEGER == 8
12 /// The size of the static table of prime numbers. Depends on the platform.
13 static constexpr int PRIME_TABLE_SIZE = 58;
14#else
15 #error "Unknown size of integer"
16#endif
17
18// forward declaration of HashTable
20template< typename TAllocator,
21 typename TValueDescriptor,
22 typename THash,
23 typename TEqual,
24 lang::Caching THashCaching,
25 Recycling TRecycling >
26class HashTable;
27}
28
30
31/// Table of prime numbers. The effective bucket size is chosen to be the first value found in
32/// this table that is equal or higher than the requested size.
34
35/// A dummy bucket used for nulled hash tables to avoid otherwise necessary checks.
36ALIB_DLL extern void* DUMMY_BUCKET;
37
38/// HashTable element type if hash codes are cached.
39/// @tparam TStored The custom data stored.
40template<typename TStored>
41struct HTElementCached : public lang::SidiNodeBase<HTElementCached<TStored>>
42{
43 /// Denotes that hash codes are cached.
44 static constexpr bool CachedHashCodes = 1;
45
46 /// The custom data stored in nodes of this table.
47 TStored value;
48
49 size_t hashCode; ///< The cached hash code.
50
51 /// Stores the given hash code when an element is recycled or extracted and changed.
52 /// @param pHashCode The new hash code to set for this (recycled) element.
53 void fixHashCode( size_t pHashCode ) { *const_cast<size_t*>(&hashCode)= pHashCode; }
54
55 /// Returns the cached hash code.
56 /// @return The hash code of this element.
57 size_t getCached() { return hashCode; }
58
59};
60
61/// HashTable element type if hash codes are not cached.
62/// @tparam TStored The custom data stored.
63template<typename TStored>
64struct HTElementUncached : public lang::SidiNodeBase<HTElementUncached<TStored>>
65{
66 /// Denotes that hash codes are not cached.
67 static constexpr bool CachedHashCodes = 0;
68
69 /// The custom data stored in nodes of this table.
70 TStored value;
71
72 /// Does nothing, parameter ignored.
73 /// @param pHashCode Ignored
74 void fixHashCode( size_t pHashCode ) { (void) pHashCode; }
75
76 /// Never called.
77 /// @return Undefined.
78 size_t getCached() { return 0; }
79};
80
81/// Node types used with #"HashTable".
82/// @tparam TValueDescriptor The descriptor of contained types provided with a template parameter
83/// of the \b HashTable.
84/// @tparam THashCaching A template parameter of the \b HashTable that determines whether
85/// hash values are cached or not.
86template<typename TValueDescriptor, lang::Caching THashCaching>
88{
89 /// @return \c true, if the selected #".Type" caches hash values, otherwise \c false.
90 static constexpr bool IsCachingHashes() {
91 return THashCaching == lang::Caching::Enabled
92 || ( THashCaching == lang::Caching::Auto
93 && !std::is_arithmetic<typename TValueDescriptor::KeyType>::value );
94 }
95
96 /// The type stored in a hash table's bucket list.
97 using Type= std::conditional_t< IsCachingHashes(),
98 HTElementCached <typename TValueDescriptor::StoredType>,
100};
101
102//==================================================================================================
103/// Base struct of #"HashTable" providing internals.
104/// \note
105/// The separation of the internals of class \b HashTable to this type in namespace \b detail
106/// has no benefit on compilation speed or other positive "technical" effect, nor is it a matter
107/// of software design.<br>
108/// A user of derived class #"HashTable" finds all interface methods and types
109/// in one place, which is not cluttered by the documentation of the internals found here.
110/// Otherwise, the separation is exclusively supporting source code organization.
111///
112/// @see For a description of the template parameters and a general introduction to
113/// this module's hash table implementation, see the
114/// #"alib_ns_containers_hashtable_referencedoc;reference documentation"
115/// of class \b HashTable.
116//==================================================================================================
117template< typename TAllocator,
118 typename TValueDescriptor,
119 typename THash,
120 typename TEqual,
121 lang::Caching THashCaching,
122 Recycling TRecycling >
124: RecyclingSelector<TRecycling>:: template Type< TAllocator,
125 typename HTElementSelector<TValueDescriptor, THashCaching>::Type >
126{
127 /// Our base type.
128 using base= typename RecyclingSelector<TRecycling>:: template Type< TAllocator,
130
131 /// Type definition publishing template parameter \p{T}.
132 using T = typename TValueDescriptor::StoredType;
133
134 /// Type definition publishing template parameter \p{TKey}.
135 using TKey = typename TValueDescriptor::KeyType;
136
137 /// Type definition publishing template parameter \p{TKey}.
138 using TMapped = typename TValueDescriptor::MappedType;
139
140
141 /// Determines whether hash codes are stored with the elements.
142 /// It is done in case the given template parameter \p{THashCashing} equals
143 /// #"Caching::Enabled" or if it equals #"Caching::Auto"
144 /// and the key type is an arithmetic type.
145 /// @return \c true if hash codes are stored for reuse, \c false if not.
148
149 /// The type stored in the bucket of class \b HashTable.
151
152
153 //################################################################################################
154 // ### Types and Constants
155 //################################################################################################
156
157 /// Type of a single linked node list.
158 using recyclerType= typename RecyclingSelector<TRecycling>:: template Type< TAllocator,
160
161 /// This type definition may be used to define an externally managed shared recycler,
162 /// which can be passed to the alternative constructor of this class when template
163 /// parameter \p{TRecycling} equals #"Recycling::Shared".
164 /// \see
165 /// Chapter #"alib_contmono_containers_recycling_shared" of the Programmer's Manual
166 /// for this \alibmod.
168 :: template HookType<TAllocator,
170
171
172 /// Type of a single linked node list.
174
175 /// Type of a node in the \b List.
177
178
179 //################################################################################################
180 // ### internal helpers
181 //################################################################################################
182
183 /// Either returns the cached hash code or calculates it.
184 /// @param elem The element to receive the hashcode for.
185 /// @return The hash code of the given element.
186 static size_t getHashCode(Element* elem) {
187 if constexpr ( Element::CachedHashCodes )
188 return elem->getCached();
189 else
190 return THash{}( TValueDescriptor().Key( elem->value ) );
191 }
192
193 /// Returns either a recycled or newly allocated element.
194 /// @param hashCode The hashCode of the new element. Used only in cached case.
195 /// @return A pointer to the element created or recycled.
196 Element* allocElement( const size_t hashCode ) {
197 Element* elem= recyclerType::Get();
198 elem->fixHashCode( hashCode );
199 return elem;
200 }
201
202 //################################################################################################
203 // std::iterator_traits types.
204 //################################################################################################
205
206 /// Templated implementation of \c std::iterator_traits.
207 /// Will be exposed by derived class's definitions #"HashTable::Iterator" and
208 /// #"HashTable::ConstIterator".
209 ///
210 /// As the name of the class indicates, this iterator satisfies the C++ standard library concept
211 /// \https{ForwardIterator,en.cppreference.com/w/cpp/named_req/ForwardIterator}.
212 ///
213 /// @tparam TConstOrMutable A constant or mutable version of the parent's template type
214 /// \p{TMapped}.
215 template<typename TConstOrMutable>
217 {
218 #if !DOXYGEN
219 friend struct HashTableBase;
220 friend class containers::HashTable<TAllocator, TValueDescriptor,THash,TEqual,THashCaching,TRecycling>;
221 #endif
222
223 /// Const or mutable version of HashTableBase.
224 using THashtable = std::conditional_t< !std::is_const_v< TConstOrMutable>,
226 const HashTableBase >;
227 using iterator_category = std::forward_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
228 using value_type = TMapped ; ///< Implementation of <c>std::iterator_traits</c>.
229 using difference_type = integer ; ///< Implementation of <c>std::iterator_traits</c>.
230 using pointer = TConstOrMutable* ; ///< Implementation of <c>std::iterator_traits</c>.
231 using reference = TConstOrMutable& ; ///< Implementation of <c>std::iterator_traits</c>.
232
233 protected:
234 /// The pointer to the hash table.
236
237 /// The actual bucket index.
239
240 /// The pointer to the actual element.
242
243
244 /// Internal constructor. Searches the first element, starting with given bucket
245 /// number.
246 /// @param pTable Pointer to the hash table.
247 /// @param pBbucketIx The bucket index.
248 TIterator( THashtable* pTable, uinteger pBbucketIx )
249 : table(pTable) {
250 while( pBbucketIx < pTable->bucketCount ) {
251 if( !pTable->buckets[pBbucketIx].isEmpty() ) {
252 bucketIdx= pBbucketIx;
253 element = pTable->buckets[pBbucketIx].first();
254 return;
255 }
256 ++pBbucketIx;
257 }
258 bucketIdx= pBbucketIx;
259 element = nullptr;
260 }
261
262 /// Internal constructor creating a specific iterator.
263 /// @param pTable Pointer to the hash table.
264 /// @param pBbucketIx The bucket index.
265 /// @param pElement Pointer to the current element.
266 TIterator( THashtable* pTable, uinteger pBbucketIx, Element* pElement)
267 : table ( pTable )
268 , bucketIdx( pBbucketIx )
269 , element ( pElement ) {}
270
271 /// Moves an iterator with a nulled element pointer to the next element.
272 void repair() {
274 if( !table->buckets[bucketIdx].isEmpty() ) {
275 element= table->buckets[bucketIdx].first();
276 return;
277 } }
278
279
280 public:
281 /// Default constructor. Keeps everything uninitialized.
282 TIterator() =default;
283
284 /// Copy constructor (default).
285 /// @param other The iterator to assign from.
286 TIterator( const TIterator& other) =default;
287
288
289 /// Copy assignment (default).
290 /// @param other The iterator to assign from.
291 /// @return A reference to this object.
292 TIterator& operator=( const TIterator& other ) =default;
293
294
295 /// Copy constructor accepting a mutable iterator.
296 /// Available only for the constant version of this iterator.
297 /// @tparam TMutable The type of this constructor's argument.
298 /// @param mutableIt Mutable iterator to copy from.
299 template<typename TMutable>
300 requires std::same_as<TMutable, TIterator<T>>
301 TIterator( const TMutable& mutableIt )
302 : table ( mutableIt.table )
303 , bucketIdx( mutableIt.bucketIdx )
304 , element ( mutableIt.element ) {}
305
306 //########################## To satisfy concept of InputIterator ########################
307
308 /// Prefix increment operator.
309 /// @return A reference to this object.
311 if(element->hasNext()) {
312 element= element->next();
313 return *this;
314 }
315
317 if( !table->buckets[bucketIdx].isEmpty() ) {
318 element= table->buckets[bucketIdx].first();
319 return *this;
320 } }
321
322 element= nullptr;
323 return *this;
324 }
325
326 /// Postfix increment operator.
327 /// @return An iterator value that is not increased, yet.
329 auto result= TIterator( *this);
330 ++(*this);
331 return result;
332 }
333
334 /// Comparison operator.
335 /// @param other The iterator to compare ourselves to.
336 /// @return \c true if this and the given iterator are pointing to the same element,
337 /// \c false otherwise.
338 bool operator==( TIterator other) const { return element == other.element; }
339
340 /// Comparison operator.
341 /// @param other The iterator to compare ourselves to.
342 /// @return \c true if this and given iterator are not equal, \c false otherwise.
343 bool operator!=( TIterator other) const { return !(*this == other); }
344
345
346 //############################## access to templated members #############################
347
348 /// Retrieves the stored object that this iterator references.
349 /// @return A reference to the stored object.
350 TConstOrMutable& operator*() const {
351 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
352 return element->value;
353 }
354
355 /// Retrieves a pointer to the stored object that this iterator references.
356 /// @return A pointer to the stored object.
357 TConstOrMutable* operator->() const {
358 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
359 return &element->value;
360 }
361
362 /// Retrieves the stored object that this iterator references.
363 /// @return A reference to the stored object.
364 TConstOrMutable& Value() const {
365 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
366 return element->value;
367 }
368
369 /// Retrieves the key-portion of the stored object that this iterator references.
370 /// @return A reference to the key-portion of the stored object.
371 const TKey& Key() const {
372 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
373 return TValueDescriptor().Key( element->value );
374 }
375
376 /// Retrieves the mapped-portion of the stored object that this iterator references.
377 /// This method is an alias to <c>operator*</c>
378 /// @return A reference to the mapped-portion of the stored object.
379 TMapped& Mapped() const {
380 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
381 return TValueDescriptor().Mapped( element->value );
382 }
383
384 }; // class TIterator
385
386
387 /// Templated implementation of \c std::iterator_traits.
388 /// Will be exposed by derived class's definitions
389 /// #"HashTable::LocalIterator" and
390 /// #"HashTable::ConstLocalIterator".
391 ///
392 /// As the name of the class indicates, this iterator satisfies the C++ standard library concept
393 /// \https{ForwardIterator,en.cppreference.com/w/cpp/named_req/ForwardIterator}.
394 ///
395 /// @tparam TConstOrMutable A constant or mutable version of template parameter \p{T}.
396 template<typename TConstOrMutable>
398 {
399 #if !DOXYGEN
400 friend struct HashTableBase;
401 friend class containers::HashTable<TAllocator,TValueDescriptor,THash,TEqual,THashCaching,TRecycling>;
402 #endif
403
404 using iterator_category = std::forward_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
405 using value_type = TConstOrMutable ; ///< Implementation of <c>std::iterator_traits</c>.
406 using difference_type = integer ; ///< Implementation of <c>std::iterator_traits</c>.
407 using pointer = TConstOrMutable* ; ///< Implementation of <c>std::iterator_traits</c>.
408 using reference = TConstOrMutable& ; ///< Implementation of <c>std::iterator_traits</c>.
409
410 protected:
411 /// The pointer to the actual element.
413
414 /// The index of the bucket that this iterator works on.
416
417 public:
418 /// Default constructor.
420
421 /// Copy constructor (default).
422 /// @param other The iterator to assign from.
423 TLocalIterator( const TLocalIterator& other ) =default;
424
425 /// Copy constructor accepting a mutable iterator.
426 /// Available only for the constant version of this iterator.
427 /// @tparam TMutable The type of this constructor's argument.
428 /// @param mutableIt Mutable iterator to copy from.
429 template<typename TMutable>
430 requires std::same_as<TMutable, TLocalIterator<T>>
431 TLocalIterator( const TMutable& mutableIt )
432 : element ( mutableIt.element )
433 , bucketIdx( mutableIt.bucketIdx ) {}
434
435 /// Constructor.
436 /// @param pBucketIdx Index of the bucket this iterator works on.
437 /// @param pElement Pointer to current element.
438 explicit TLocalIterator( uinteger pBucketIdx, Element* pElement )
439 : element (pElement )
440 , bucketIdx(pBucketIdx) {}
441
442 /// Copy assignment (default).
443 /// @param other The iterator to assign from.
444 /// @return A reference to this object.
445 TLocalIterator& operator =( const TLocalIterator& other) =default;
446
447 //########################## To satisfy concept of InputIterator ########################
448
449 /// Prefix increment operator.
450 /// @return A reference to this object.
452 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
453 element= element->next();
454 return *this;
455 }
456
457 /// Postfix increment operator.
458 /// @return An iterator value that is not increased, yet.
460 auto result= TLocalIterator( *this);
461 ++(*this);
462 return result;
463 }
464
465 /// Comparison operator.
466 /// @param other The iterator to compare ourselves to.
467 /// @return \c true if this and the given iterator are pointing to the same element,
468 /// \c false otherwise.
469 bool operator==( TLocalIterator other) const {
470 return element == other.element
471 && bucketIdx == other.bucketIdx;
472 }
473
474 /// Comparison operator.
475 /// @param other The iterator to compare ourselves to.
476 /// @return \c true if this and given iterator are not equal, \c false otherwise.
477 bool operator!=( TLocalIterator other) const { return !(*this == other); }
478
479 //############################## access to templated members #############################
480
481 /// Retrieves the stored object that this iterator references.
482 /// @return A reference to the stored object.
483 TConstOrMutable& operator*() const {
484 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
485 return element->value;
486 }
487
488 /// Retrieves a pointer to the stored object that this iterator references.
489 /// @return A pointer to the stored object.
490 TConstOrMutable* operator->() const {
491 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
492 return &element->value;
493 }
494
495 /// Retrieves the stored object that this iterator references.
496 /// @return A reference to the stored object.
497 TConstOrMutable& Value() const {
498 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
499 return element->value;
500 }
501
502 /// Retrieves the key-portion of the stored object that this iterator references.
503 /// @return A reference to the key-portion of the stored object.
504 const TKey& Key() const {
505 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
506 return TValueDescriptor().Key( element->value );
507 }
508
509 /// Retrieves the stored object that this iterator references.<br>
510 /// This method is an alias to <c>operator*</c>
511 /// @return A reference to the mapped-portion of the stored object.
512 TMapped& Mapped() const {
513 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
514 return TValueDescriptor().Mapped( element->value );
515 }
516 }; // class TLocalIterator
517
518
519 //################################################################################################
520 // Fields
521 //################################################################################################
522 /// The number of buckets managed by this tree.
524
525 /// The list of buckets.
527
528 /// The load factor that is set when the table is rehashed automatically.
530
531 /// The maximum quotient of #"HashTableBase::size" and #"HashTableBase::bucketCount" that
532 /// triggers a rehash.
534
535 /// The number of elements stored.
537
538 /// Calculated once with rehash. Product of #maxLoadFactor and #bucketCount.
540
541
542 //################################################################################################
543 // ### mini helpers
544 //################################################################################################
545
546 /// Compares two elements. If cached mode, the hash code is compared before the keys.
547 /// @param lhs The first node to compare.
548 /// @param rhs The second node to compare.
549 /// @return The result of the comparison.
550 bool areEqual( Element* lhs, Element* rhs ) const {
551 return ( !Element::CachedHashCodes || ( getHashCode(lhs) == getHashCode(rhs) ) )
552 && TEqual{}( TValueDescriptor().Key( lhs->value ),
553 TValueDescriptor().Key( rhs->value ) );
554 }
555
556 /// Compares a key and a node. If cached mode, the hash codes are compared before the
557 /// keys.
558 /// @param elem The element to compare.
559 /// @param key The key to compare.
560 /// @param keyHashCode The hash code of \p{key}.
561 /// @return The result of the comparison.
562 bool areEqual( Element* elem, const TKey& key, size_t keyHashCode ) const {
563 return ( !Element::CachedHashCodes || ( keyHashCode == getHashCode(elem) ) )
564 && TEqual{}( TValueDescriptor().Key( elem->value ), key );
565 }
566
567 /// Searches the first element equal to \p{key} in bucket \p{bucketIdx}.
568 ///
569 /// @param bucketIdx The bucket number to search in (hash code divided by #bucketCount).
570 /// @param key The <em>key-portion</em> of the element to search.
571 /// @param keyHashCode The hash code of \p{key}.
572 /// @return A pointer to the element searched, respectively \c nullptr if not found.
573 Element* findElement( uinteger bucketIdx, const TKey& key, size_t keyHashCode ) const {
574 Node* result= buckets[bucketIdx].first();
575 while( result) {
576 if( areEqual( static_cast<Element*>(result), key, keyHashCode ) )
577 return static_cast<Element*>(result);
578
579 result= result->next();
580 }
581 return nullptr;
582 }
583
584 /// Searches the predecessor of the first element equal to \p{key} in bucket \p{bucketIdx}.
585 ///
586 /// @param bucketIdx The bucket number to search in (hash code divided by #bucketCount).
587 /// @param key The <em>key-portion</em> of the element to search.
588 /// @param keyHashCode The hash code of \p{key}.
589 /// @return A pointer to the element before the searched one, respectively \c nullptr if not
590 /// found.
591 Node* findElementBefore( uinteger bucketIdx, size_t keyHashCode, const TKey& key ) const {
592 Node* result= &buckets[bucketIdx];
593
594 while( result->hasNext() && !areEqual( result->next(), key, keyHashCode ) )
595 result= result->next();
596
597 return result->hasNext() ? result : nullptr;
598 }
599
600 /// Inserts the given element into the bucket.
601 /// If an element of the same key exists, then the element is put in front of that element.
602 /// Otherwise it is added to the start of the bucket.
603 /// @param element The element to insert to its bucket.
604 /// @param hashCode The hash code of parameter \p{element}.
605 /// @return The bucket number that the element was inserted to.
606 uinteger insertInBucket( Element* element, const size_t hashCode ) {
607 auto bucketIdx= hashCode % bucketCount;
608 Node* previous= findElementBefore( bucketIdx, hashCode, TValueDescriptor().Key( element->value ) );
609 if( previous == nullptr )
610 previous= &buckets[bucketIdx];
611
612 previous->addBehind( element );
613 return bucketIdx;
614 }
615
616 /// Increases field #size and checks for a rehash.
617 ///
618 /// @param increase The amount to increase.
619 /// @param hashCode A hashCode that caller might want to have converted into a new
620 /// actual bucket index.
621 /// @return The bucket index of \p{hashCode}.
622 size_t increaseSize( integer increase, const size_t hashCode= 0 ) {
623 size+= increase;
624 if( size >=sizeLimitToRehash )
625 rehash( (std::max)( uinteger( float(size) / baseLoadFactor ), bucketCount + 1 ) );
626
627 return hashCode % bucketCount;
628 }
629
630 /// Constructor.
631 /// @param pAllocator The allocator to use.
632 /// @param pBaseLoadFactor The base load factor.
633 /// @param pMaxLoadFactor The maximum load factor.
634 HashTableBase( TAllocator& pAllocator,
635 float pBaseLoadFactor,
636 float pMaxLoadFactor )
637 : recyclerType ( pAllocator )
638 , baseLoadFactor( pBaseLoadFactor )
639 , maxLoadFactor ( pMaxLoadFactor )
640 , size ( 0 ) {
641 buckets = reinterpret_cast<FwdList*>(&detail::DUMMY_BUCKET);
642 bucketCount = 1;
643 size = 0;
645 }
646
647 /// Constructor omitting an allocator.
648 /// Only applicable if the allocator type is default-constructible, i.e., with class
649 /// #"HeapAllocator".
650 /// @param pBaseLoadFactor The base load factor.
651 /// @param pMaxLoadFactor The maximum load factor.
652 /// @tparam TIf Defaulted, must not be given.
653 template<typename TIf= TAllocator>
654 requires std::is_default_constructible_v<TIf>
655 HashTableBase( float pBaseLoadFactor,
656 float pMaxLoadFactor )
657 : baseLoadFactor( pBaseLoadFactor )
658 , maxLoadFactor ( pMaxLoadFactor )
659 , size ( 0 ) {
660 buckets = reinterpret_cast<FwdList*>(&detail::DUMMY_BUCKET);
661 bucketCount = 1;
662 size = 0;
664 }
665
666 /// Constructor taking a shared recycler.
667 /// @param pSharedRecycler The shared recycler hook.
668 /// @param pBaseLoadFactor The base load factor.
669 /// @param pMaxLoadFactor The maximum load factor.
670 /// @tparam TSharedRecycler Used to select this constructor. Deduced by the compiler.
671 template<typename TSharedRecycler= SharedRecyclerType, typename TIf=TAllocator>
672 requires (!std::same_as<TSharedRecycler , void>)
673 HashTableBase( TSharedRecycler& pSharedRecycler,
674 float pBaseLoadFactor = 1.0,
675 float pMaxLoadFactor = 2.0 )
676 : recyclerType ( pSharedRecycler )
677 , baseLoadFactor( pBaseLoadFactor )
678 , maxLoadFactor ( pMaxLoadFactor )
679 , size ( 0 ) {
680 buckets = reinterpret_cast<FwdList*>(&detail::DUMMY_BUCKET);
681 bucketCount = 1;
682 size = 0;
684 }
685
686 /// Destructor. Destructs all elements in this object.
687 /// Deletes recyclables, buckets and bucket array.
689 if ( buckets == reinterpret_cast<FwdList*>( &detail::DUMMY_BUCKET ) )
690 return;
691
692 // destruct entry data and delete entry objects
693 for( uinteger bucketIdx= 0 ; bucketIdx < bucketCount ; ++bucketIdx ) {
694 Element* first= buckets[bucketIdx].first();
695 if ( first != nullptr )
696 recyclerType::DisposeList(first);
697 }
698
699 // free bucket array
700 recyclerType::template DisposeChunk<FwdList>(buckets, bucketCount );
701 }
702
703 //################################################################################################
704 // ### method implementations
705 //################################################################################################
706
707 /// Destructs and removes all entries from this hash table.
708 void clear() {
709 if( size == 0 )
710 return;
711
712 // destruct and recycle entries
713 for( uinteger bucketIdx= 0 ; bucketIdx < bucketCount ; ++bucketIdx )
714 if ( buckets[bucketIdx].first() ) {
715 recyclerType::RecycleList( buckets[bucketIdx].first() );
716 buckets[bucketIdx].reset();
717 }
718
719 size= 0;
720 }
721
722
723 /// Changes the maximum load factor value and invokes #rehash providing the actual bucket
724 /// count as the minimum bucket count that is to be chosen.
725 /// @param pMaxLoadFactor The maximum load factor used to determine the need of re-hashing.
726 void setMaxLoadFactor( float pMaxLoadFactor ) {
727 maxLoadFactor= pMaxLoadFactor;
728 if( bucketCount > 1 )
730 }
731
732 /// Changes the number of buckets to be at least the higher value of
733 /// a) the given \p{newMinBucketCount}, and<br>
734 /// b) the quotient of the current size and the maximum load factor.
735 ///
736 /// The result of the above, is increased to the next higher prime number.
737 /// Rehash is only performed if bucket size increases. It never is decreased.
738 ///
739 /// @param newMinBucketCount The minimum new bucket count requested.
740 void rehash( uinteger newMinBucketCount ) {
741 // smaller than before?
742 if( newMinBucketCount <= bucketCount )
743 return;
744
745 const auto oldBucketCount= bucketCount;
746
747 // adjust requested bucket count to the maximum load factor
748 newMinBucketCount= (std::max)( newMinBucketCount, uinteger(float(size) / maxLoadFactor) );
749
750 // adjust requested bucket count to next higher prime value
751 {
752 int idx= 0;
753 while( detail::PRIME_NUMBERS[idx] < newMinBucketCount )
754 ++idx;
756 }
757
758 ALIB_ASSERT_ERROR( bucketCount > oldBucketCount, "MONOMEM/HASHTABLE",
759 "Internal error: Rehashing to equal or smaller bucket count." )
760
761 // store new rehash trigger
763
764 // collect elements
765 FwdList elements;
766 for( uinteger bucketIdx= 0 ; bucketIdx < oldBucketCount ; ++bucketIdx ) {
767 Element* first= buckets[bucketIdx].first();
768 if( first != nullptr )
769 elements.pushFront( first, buckets[bucketIdx].findLast() );
770 }
771
772
773 // create a new data array
774 FwdList* oldData = buckets;
775
776 buckets= base::AI().template NewArray<FwdList>(bucketCount);
777
778 // re-insert objects
779 Element* actual= elements.first();
780 while( actual != nullptr ) {
781 Element* next= actual->next();
782 insertInBucket( actual, getHashCode(actual) );
783 actual= next;
784 }
785
786 // recycle old array and data (make future nodes elements out of it)
787 // But this must only be done with MonoAllocator and if ALIB_DEBUG_MEMORY is not set.
788 // (This is ensured by 'TAllocator::allowsMemSplit()')
789 if ( oldData != reinterpret_cast<FwdList*>( &detail::DUMMY_BUCKET ) )
790 recyclerType::template RecycleChunk<FwdList>( oldData, oldBucketCount );
791 }
792
793 /// Searches the first and last element stored according to given \p{key}.
794 /// Returns a pare of iterators that define a range containing all elements with key
795 /// \p{key} of the container.<br>
796 /// Parameter \p{resultStart} is set to the first element of the matching range and
797 /// parameter \p{resultEnd} is set to point past the last element of the range.
798 ///
799 /// If no element with key \p{key} is found, both iterators are set to \b end.
800 ///
801 /// @param key The <em>key-portion</em> of the elements to find.
802 /// @return A pair of iterators defining the range of elements with key \p{key}.
803 std::pair<TIterator<T>,TIterator<T>> findRange( const TKey& key ) {
804 const auto hashCode= THash{}(key);
805 auto bucketIdx= hashCode % bucketCount;
806 Element* element= findElement( bucketIdx, key, hashCode );
807 if( element == nullptr )
808 return std::make_pair( TIterator<T>( this, bucketCount, nullptr ),
809 TIterator<T>( this, bucketCount, nullptr ) );
810
811 auto result= std::make_pair( TIterator<T>( this, bucketIdx, element ),
812 TIterator<T>( this, bucketIdx, element ) );
813 for(;;) {
814 ++result.second;
815 if( result.second.element == nullptr
816 || !areEqual( result.second.element, key, hashCode ) )
817 return result;
818 }
819
820 }
821
822 /// Searches (a first) element with the given key.
823 /// If not found, an invalid iterator to the bucket is returned with a nulled element pointer.
824 /// Before this counter #size is increased and, if a load limit is reached, a re-hash is
825 /// performed.
826 ///
827 /// If otherwise an element was found, its valid iterator is returned.
828 ///
829 /// Note: Used by #"HashTable::EmplaceIfNotExistent(const KeyType&, TArgs &&...);*".
830 ///
831 /// @param key The key to the (first) element to find.
832 /// @param hashCode The hash code of parameter \p{key}.
833 /// @return A pair of an iterator referring to the found or inserted element and a boolean
834 /// that is \c true if the insertion took place and \c false nothing was changed.
835 std::pair<TIterator<T>, bool> insertIfNotExists( const TKey& key, size_t hashCode ) {
836 auto bucketIdx= hashCode % bucketCount;
837 Element* element = findElement( bucketIdx, key, hashCode );
838 if (element != nullptr )
839 return std::make_pair(TIterator<T>( this, bucketIdx, element ), false);
840
841 bucketIdx= increaseSize( 1, hashCode );
842
843 Element* newElement= allocElement( hashCode );
844 buckets[bucketIdx].pushFront( newElement );
845 return std::make_pair(TIterator<T>( this, bucketIdx, newElement ) , true);
846 }
847
848 /// Inserts the topmost recyclable element if no element with the same key-portion of its value
849 /// exists.
850 ///
851 /// @param key Pointer to the key to search elements for deletion.
852 /// @param hashCode The hash code of parameter \p{key}.
853 /// @return A pair containing an iterator referring to the element added.
854 /// The bool component is \c true if the insertion took place and \c false if a new
855 /// element was created.
856 std::pair<TIterator<T>, bool> insertOrGet( const TKey& key, size_t hashCode ) {
857 // find (first) element with same key in bucket
858 auto bucketIdx= hashCode % bucketCount;
859 auto* elem= findElement( bucketIdx, key, hashCode );
860 if( elem != nullptr )
861 return std::make_pair( TIterator<T>( this, bucketIdx, elem ), false);
862
863 // create new element
864 bucketIdx= increaseSize( 1, hashCode );
865 Element* newElem= allocElement( hashCode );
866 buckets[bucketIdx].pushFront( newElem );
867 return std::make_pair(TIterator<T>( this, bucketIdx, newElem ), true);
868 }
869
870}; // HashTableBase
871
872} // namespace [alib::containers::detail]
#define ALIB_DLL
Definition alib.inl:573
#define ALIB_EXPORT
Definition alib.inl:562
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
TIterator()=default
Default constructor. Keeps everything uninitialized.
TIterator & operator=(const TIterator &other)=default
std::forward_iterator_tag iterator_category
Implementation of std::iterator_traits.
TMapped value_type
Implementation of std::iterator_traits.
TIterator(THashtable *pTable, uinteger pBbucketIx)
TIterator(const TIterator &other)=default
TConstOrMutable * pointer
Implementation of std::iterator_traits.
std::conditional_t< !std::is_const_v< TConstOrMutable >, HashTableBase, const HashTableBase > THashtable
Const or mutable version of HashTableBase.
TIterator(THashtable *pTable, uinteger pBbucketIx, Element *pElement)
THashtable * table
The pointer to the hash table.
Element * element
The pointer to the actual element.
void repair()
Moves an iterator with a nulled element pointer to the next element.
integer difference_type
Implementation of std::iterator_traits.
TConstOrMutable & reference
Implementation of std::iterator_traits.
TConstOrMutable value_type
Implementation of std::iterator_traits.
integer difference_type
Implementation of std::iterator_traits.
TLocalIterator & operator=(const TLocalIterator &other)=default
TLocalIterator(const TLocalIterator &other)=default
Element * element
The pointer to the actual element.
TConstOrMutable & reference
Implementation of std::iterator_traits.
uinteger bucketIdx
The index of the bucket that this iterator works on.
std::forward_iterator_tag iterator_category
Implementation of std::iterator_traits.
TLocalIterator(uinteger pBucketIdx, Element *pElement)
TConstOrMutable * pointer
Implementation of std::iterator_traits.
static constexpr int PRIME_TABLE_SIZE
The size of the static table of prime numbers. Depends on the platform.
Detail namespace of module ALib Containers.
void * DUMMY_BUCKET
A dummy bucket used for nulled hash tables to avoid otherwise necessary checks.
const uinteger PRIME_NUMBERS[PRIME_TABLE_SIZE]
Caching
Denotes if a cache mechanism is enabled or disabled.
@ Enabled
Caching is enabled.
@ Auto
Auto/default mode.
containers::HashTable< TAllocator, TValueDescriptor, THash, TEqual, THashCaching, TRecycling > HashTable
Type alias in namespace alib. See type definition #"alib::containers::HashSet".
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
TStored value
The custom data stored in nodes of this table.
static constexpr bool CachedHashCodes
Denotes that hash codes are cached.
std::conditional_t< IsCachingHashes(), HTElementCached< typename TValueDescriptor::StoredType >, HTElementUncached< typename TValueDescriptor::StoredType > > Type
The type stored in a hash table's bucket list.
TStored value
The custom data stored in nodes of this table.
static constexpr bool CachedHashCodes
Denotes that hash codes are not cached.
HashTableBase(TSharedRecycler &pSharedRecycler, float pBaseLoadFactor=1.0, float pMaxLoadFactor=2.0)
typename TValueDescriptor::KeyType TKey
Type definition publishing template parameter TKey.
void clear()
Destructs and removes all entries from this hash table.
void rehash(uinteger newMinBucketCount)
Element * allocElement(const size_t hashCode)
HashTableBase(float pBaseLoadFactor, float pMaxLoadFactor)
lang::SidiListHook< Element > FwdList
Type of a single linked node list.
bool areEqual(Element *lhs, Element *rhs) const
static size_t getHashCode(Element *elem)
typename HTElementSelector< TValueDescriptor, THashCaching >::Type Element
The type stored in the bucket of class HashTable.
uinteger insertInBucket(Element *element, const size_t hashCode)
integer size
The number of elements stored.
uinteger bucketCount
The number of buckets managed by this tree.
typename TValueDescriptor::MappedType TMapped
Type definition publishing template parameter TKey.
typename TValueDescriptor::StoredType T
Type definition publishing template parameter T.
void setMaxLoadFactor(float pMaxLoadFactor)
float baseLoadFactor
The load factor that is set when the table is rehashed automatically.
std::pair< TIterator< T >, bool > insertOrGet(const TKey &key, size_t hashCode)
integer sizeLimitToRehash
Calculated once with rehash. Product of maxLoadFactor and bucketCount.
typename RecyclingSelector< TRecycling >::template Type< TAllocator, typename HTElementSelector< TValueDescriptor, THashCaching >::Type > base
Our base type.
HashTableBase(TAllocator &pAllocator, float pBaseLoadFactor, float pMaxLoadFactor)
Node * findElementBefore(uinteger bucketIdx, size_t keyHashCode, const TKey &key) const
Element * findElement(uinteger bucketIdx, const TKey &key, size_t keyHashCode) const
size_t increaseSize(integer increase, const size_t hashCode=0)
typename RecyclingSelector< TRecycling >::template Type< TAllocator, typename HTElementSelector< TValueDescriptor, THashCaching >::Type > recyclerType
Type of a single linked node list.
lang::SidiNodeBase< Element > Node
Type of a node in the List.
FwdList * buckets
The list of buckets.
std::pair< TIterator< T >, bool > insertIfNotExists(const TKey &key, size_t hashCode)
typename detail::RecyclingSelector< TRecycling > ::template HookType< TAllocator, typename HTElementSelector< TValueDescriptor, THashCaching >::Type > SharedRecyclerType
std::pair< TIterator< T >, TIterator< T > > findRange(const TKey &key)
bool areEqual(Element *elem, const TKey &key, size_t keyHashCode) const
TElement * first() const noexcept
Definition sidilist.inl:216
void pushFront(TElement *elem) noexcept
Definition sidilist.inl:220
TElement * addBehind(TElement *elem) noexcept
Definition sidilist.inl:140
void next(SidiNodeBase *p)
Definition sidilist.inl:93