ALib C++ Library
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 \ref mainpage_license "Boost Software 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 \alib{containers;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 \alib{containers;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 \alib{containers;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/// \ref 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 /// \alib{lang;Caching;Caching::Enabled} or if it equals \alib{lang;Caching;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 \alib{containers;Recycling;Shared}.
164 /// \see
165 /// Chapter \ref 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 \alib{containers::HashTable;Iterator} and
208 /// \alib{containers::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 /// \alib{containers::HashTable;LocalIterator} and
390 /// \alib{containers::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 #size and #bucketCount that triggers a rehash.
533
534 /// The number of elements stored.
536
537 /// Calculated once with rehash. Product of #maxLoadFactor and #bucketCount.
539
540
541 //################################################################################################
542 // ### mini helpers
543 //################################################################################################
544
545 /// Compares two elements. If cached mode, the hash code is compared before the keys.
546 /// @param lhs The first node to compare.
547 /// @param rhs The second node to compare.
548 /// @return The result of the comparison.
549 bool areEqual( Element* lhs, Element* rhs ) const {
550 return ( !Element::CachedHashCodes || ( getHashCode(lhs) == getHashCode(rhs) ) )
551 && TEqual{}( TValueDescriptor().Key( lhs->value ),
552 TValueDescriptor().Key( rhs->value ) );
553 }
554
555 /// Compares a key and a node. If cached mode, the hash codes are compared before the
556 /// keys.
557 /// @param elem The element to compare.
558 /// @param key The key to compare.
559 /// @param keyHashCode The hash code of \p{key}.
560 /// @return The result of the comparison.
561 bool areEqual( Element* elem, const TKey& key, size_t keyHashCode ) const {
562 return ( !Element::CachedHashCodes || ( keyHashCode == getHashCode(elem) ) )
563 && TEqual{}( TValueDescriptor().Key( elem->value ), key );
564 }
565
566 /// Searches the first element equal to \p{key} in bucket \p{bucketIdx}.
567 ///
568 /// @param bucketIdx The bucket number to search in (hash code divided by #bucketCount).
569 /// @param key The <em>key-portion</em> of the element to search.
570 /// @param keyHashCode The hash code of \p{key}.
571 /// @return A pointer to the element searched, respectively \c nullptr if not found.
572 Element* findElement( uinteger bucketIdx, const TKey& key, size_t keyHashCode ) const {
573 Node* result= buckets[bucketIdx].first();
574 while( result) {
575 if( areEqual( static_cast<Element*>(result), key, keyHashCode ) )
576 return static_cast<Element*>(result);
577
578 result= result->next();
579 }
580 return nullptr;
581 }
582
583 /// Searches the predecessor of the first element equal to \p{key} in bucket \p{bucketIdx}.
584 ///
585 /// @param bucketIdx The bucket number to search in (hash code divided by #bucketCount).
586 /// @param key The <em>key-portion</em> of the element to search.
587 /// @param keyHashCode The hash code of \p{key}.
588 /// @return A pointer to the element before the searched one, respectively \c nullptr if not
589 /// found.
590 Node* findElementBefore( uinteger bucketIdx, size_t keyHashCode, const TKey& key ) const {
591 Node* result= &buckets[bucketIdx];
592
593 while( result->hasNext() && !areEqual( result->next(), key, keyHashCode ) )
594 result= result->next();
595
596 return result->hasNext() ? result : nullptr;
597 }
598
599 /// Inserts the given element into the bucket.
600 /// If an element of the same key exists, then the element is put in front of that element.
601 /// Otherwise it is added to the start of the bucket.
602 /// @param element The element to insert to its bucket.
603 /// @param hashCode The hash code of parameter \p{element}.
604 /// @return The bucket number that the element was inserted to.
605 uinteger insertInBucket( Element* element, const size_t hashCode ) {
606 auto bucketIdx= hashCode % bucketCount;
607 Node* previous= findElementBefore( bucketIdx, hashCode, TValueDescriptor().Key( element->value ) );
608 if( previous == nullptr )
609 previous= &buckets[bucketIdx];
610
611 previous->addBehind( element );
612 return bucketIdx;
613 }
614
615 /// Increases field #size and checks for a rehash.
616 ///
617 /// @param increase The amount to increase.
618 /// @param hashCode A hashCode that caller might want to have converted into a new
619 /// actual bucket index.
620 /// @return The bucket index of \p{hashCode}.
621 size_t increaseSize( integer increase, const size_t hashCode= 0 ) {
622 size+= increase;
623 if( size >=sizeLimitToRehash )
624 rehash( (std::max)( uinteger( float(size) / baseLoadFactor ), bucketCount + 1 ) );
625
626 return hashCode % bucketCount;
627 }
628
629 /// Constructor.
630 /// @param pAllocator The allocator to use.
631 /// @param pBaseLoadFactor The base load factor.
632 /// @param pMaxLoadFactor The maximum load factor.
633 HashTableBase( TAllocator& pAllocator,
634 float pBaseLoadFactor,
635 float pMaxLoadFactor )
636 : recyclerType ( pAllocator )
637 , baseLoadFactor( pBaseLoadFactor )
638 , maxLoadFactor ( pMaxLoadFactor )
639 , size ( 0 ) {
640 buckets = reinterpret_cast<FwdList*>(&detail::DUMMY_BUCKET);
641 bucketCount = 1;
642 size = 0;
644 }
645
646 /// Constructor omitting an allocator.
647 /// Only applicable if the allocator type is default-constructible, i.e., with class
648 /// \alib{lang;HeapAllocator}.
649 /// @param pBaseLoadFactor The base load factor.
650 /// @param pMaxLoadFactor The maximum load factor.
651 /// @tparam TIf Defaulted, must not be given.
652 template<typename TIf= TAllocator>
653 requires std::is_default_constructible_v<TIf>
654 HashTableBase( float pBaseLoadFactor,
655 float pMaxLoadFactor )
656 : baseLoadFactor( pBaseLoadFactor )
657 , maxLoadFactor ( pMaxLoadFactor )
658 , size ( 0 ) {
659 buckets = reinterpret_cast<FwdList*>(&detail::DUMMY_BUCKET);
660 bucketCount = 1;
661 size = 0;
663 }
664
665 /// Constructor taking a shared recycler.
666 /// @param pSharedRecycler The shared recycler hook.
667 /// @param pBaseLoadFactor The base load factor.
668 /// @param pMaxLoadFactor The maximum load factor.
669 /// @tparam TSharedRecycler Used to select this constructor. Deduced by the compiler.
670 template<typename TSharedRecycler= SharedRecyclerType, typename TIf=TAllocator>
671 requires (!std::same_as<TSharedRecycler , void>)
672 HashTableBase( TSharedRecycler& pSharedRecycler,
673 float pBaseLoadFactor = 1.0,
674 float pMaxLoadFactor = 2.0 )
675 : recyclerType ( pSharedRecycler )
676 , baseLoadFactor( pBaseLoadFactor )
677 , maxLoadFactor ( pMaxLoadFactor )
678 , size ( 0 ) {
679 buckets = reinterpret_cast<FwdList*>(&detail::DUMMY_BUCKET);
680 bucketCount = 1;
681 size = 0;
683 }
684
685 /// Destructor. Destructs all elements in this object.
686 /// Deletes recyclables, buckets and bucket array.
688 if ( buckets == reinterpret_cast<FwdList*>( &detail::DUMMY_BUCKET ) )
689 return;
690
691 // destruct entry data and delete entry objects
692 for( uinteger bucketIdx= 0 ; bucketIdx < bucketCount ; ++bucketIdx ) {
693 Element* first= buckets[bucketIdx].first();
694 if ( first != nullptr )
695 recyclerType::DisposeList(first);
696 }
697
698 // free bucket array
699 recyclerType::template DisposeChunk<FwdList>(buckets, bucketCount );
700 }
701
702 //################################################################################################
703 // ### method implementations
704 //################################################################################################
705
706 /// Destructs and removes all entries from this hash table.
707 void clear() {
708 if( size == 0 )
709 return;
710
711 // destruct and recycle entries
712 for( uinteger bucketIdx= 0 ; bucketIdx < bucketCount ; ++bucketIdx )
713 if ( buckets[bucketIdx].first() ) {
714 recyclerType::RecycleList( buckets[bucketIdx].first() );
715 buckets[bucketIdx].reset();
716 }
717
718 size= 0;
719 }
720
721
722 /// Changes the maximum load factor value and invokes #rehash providing the actual bucket
723 /// count as the minimum bucket count that is to be chosen.
724 /// @param pMaxLoadFactor The maximum load factor used to determine the need of re-hashing.
725 void setMaxLoadFactor( float pMaxLoadFactor ) {
726 maxLoadFactor= pMaxLoadFactor;
727 if( bucketCount > 1 )
729 }
730
731 /// Changes the number of buckets to be at least the higher value of
732 /// a) the given \p{newMinBucketCount}, and<br>
733 /// b) the quotient of the current size and the maximum load factor.
734 ///
735 /// The result of the above, is increased to the next higher prime number.
736 /// Rehash is only performed if bucket size increases. It never is decreased.
737 ///
738 /// @param newMinBucketCount The minimum new bucket count requested.
739 void rehash( uinteger newMinBucketCount ) {
740 // smaller than before?
741 if( newMinBucketCount <= bucketCount )
742 return;
743
744 const auto oldBucketCount= bucketCount;
745
746 // adjust requested bucket count to the maximum load factor
747 newMinBucketCount= (std::max)( newMinBucketCount, uinteger(float(size) / maxLoadFactor) );
748
749 // adjust requested bucket count to next higher prime value
750 {
751 int idx= 0;
752 while( detail::PRIME_NUMBERS[idx] < newMinBucketCount )
753 ++idx;
755 }
756
757 ALIB_ASSERT_ERROR( bucketCount > oldBucketCount, "MONOMEM/HASHTABLE",
758 "Internal error: Rehashing to equal or smaller bucket count." )
759
760 // store new rehash trigger
762
763 // collect elements
764 FwdList elements;
765 for( uinteger bucketIdx= 0 ; bucketIdx < oldBucketCount ; ++bucketIdx ) {
766 Element* first= buckets[bucketIdx].first();
767 if( first != nullptr )
768 elements.pushFront( first, buckets[bucketIdx].findLast() );
769 }
770
771
772 // create a new data array
773 FwdList* oldData = buckets;
774
775 buckets= base::AI().template NewArray<FwdList>(bucketCount);
776
777 // re-insert objects
778 Element* actual= elements.first();
779 while( actual != nullptr ) {
780 Element* next= actual->next();
781 insertInBucket( actual, getHashCode(actual) );
782 actual= next;
783 }
784
785 // recycle old array and data (make future nodes elements out of it)
786 // But this must only be done with MonoAllocator and if ALIB_DEBUG_MEMORY is not set.
787 // (This is ensured by 'TAllocator::allowsMemSplit()')
788 if ( oldData != reinterpret_cast<FwdList*>( &detail::DUMMY_BUCKET ) )
789 recyclerType::template RecycleChunk<FwdList>( oldData, oldBucketCount );
790 }
791
792 /// Searches the first and last element stored according to given \p{key}.
793 /// Returns a pare of iterators that define a range containing all elements with key
794 /// \p{key} of the container.<br>
795 /// Parameter \p{resultStart} is set to the first element of the matching range and
796 /// parameter \p{resultEnd} is set to point past the last element of the range.
797 ///
798 /// If no element with key \p{key} is found, both iterators are set to \b end.
799 ///
800 /// @param key The <em>key-portion</em> of the elements to find.
801 /// @return A pair of iterators defining the range of elements with key \p{key}.
802 std::pair<TIterator<T>,TIterator<T>> findRange( const TKey& key ) {
803 const auto hashCode= THash{}(key);
804 auto bucketIdx= hashCode % bucketCount;
805 Element* element= findElement( bucketIdx, key, hashCode );
806 if( element == nullptr )
807 return std::make_pair( TIterator<T>( this, bucketCount, nullptr ),
808 TIterator<T>( this, bucketCount, nullptr ) );
809
810 auto result= std::make_pair( TIterator<T>( this, bucketIdx, element ),
811 TIterator<T>( this, bucketIdx, element ) );
812 for(;;) {
813 ++result.second;
814 if( result.second.element == nullptr
815 || !areEqual( result.second.element, key, hashCode ) )
816 return result;
817 }
818
819 }
820
821 /// Searches (a first) element with the given key.
822 /// If not found, an invalid iterator to the bucket is returned with a nulled element pointer.
823 /// Before this counter #size is increased and, if a load limit is reached, a re-hash is
824 /// performed.
825 ///
826 /// If otherwise an element was found, its valid iterator is returned.
827 ///
828 /// Note: Used by \alib{containers;HashMap::EmplaceIfNotExistent}.
829 ///
830 /// @param key The key to the (first) element to find.
831 /// @param hashCode The hash code of parameter \p{key}.
832 /// @return A pair of an iterator referring to the found or inserted element and a boolean
833 /// that is \c true if the insertion took place and \c false nothing was changed.
834 std::pair<TIterator<T>, bool> insertIfNotExists( const TKey& key, size_t hashCode ) {
835 auto bucketIdx= hashCode % bucketCount;
836 Element* element = findElement( bucketIdx, key, hashCode );
837 if (element != nullptr )
838 return std::make_pair(TIterator<T>( this, bucketIdx, element ), false);
839
840 bucketIdx= increaseSize( 1, hashCode );
841
842 Element* newElement= allocElement( hashCode );
843 buckets[bucketIdx].pushFront( newElement );
844 return std::make_pair(TIterator<T>( this, bucketIdx, newElement ) , true);
845 }
846
847 /// Inserts the topmost recyclable element if no element with the same key-portion of its value
848 /// exists.
849 ///
850 /// @param key Pointer to the key to search elements for deletion.
851 /// @param hashCode The hash code of parameter \p{key}.
852 /// @return A pair containing an iterator referring to the element added.
853 /// The bool component is \c true if the insertion took place and \c false if a new
854 /// element was created.
855 std::pair<TIterator<T>, bool> insertOrGet( const TKey& key, size_t hashCode ) {
856 // find (first) element with same key in bucket
857 auto bucketIdx= hashCode % bucketCount;
858 auto* elem= findElement( bucketIdx, key, hashCode );
859 if( elem != nullptr )
860 return std::make_pair( TIterator<T>( this, bucketIdx, elem ), false);
861
862 // create new element
863 bucketIdx= increaseSize( 1, hashCode );
864 Element* newElem= allocElement( hashCode );
865 buckets[bucketIdx].pushFront( newElem );
866 return std::make_pair(TIterator<T>( this, bucketIdx, newElem ), true);
867 }
868
869}; // HashTableBase
870
871} // namespace [alib::containers::detail]
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)
std::conditional_t< !std::is_const_v< TConstOrMutable >, HashTableBase, const HashTableBase > THashtable
Const or mutable version of HashTableBase.
TIterator(const TIterator &other)=default
TConstOrMutable * pointer
Implementation of std::iterator_traits.
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.
#define ALIB_DLL
Definition alib.inl:503
#define ALIB_EXPORT
Definition alib.inl:497
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
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.
ALIB_DLL const uinteger PRIME_NUMBERS[PRIME_TABLE_SIZE]
ALIB_DLL void * DUMMY_BUCKET
A dummy bucket used for nulled hash tables to avoid otherwise necessary checks.
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.
float maxLoadFactor
The maximum quotient of size and bucketCount that triggers a rehash.
lang::SidiNodeBase< Element > Node
Type of a node in the List.
typename 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)
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)
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.
std::pair< TIterator< T >, bool > insertOrGet(const TKey &key, size_t hashCode)
integer sizeLimitToRehash
Calculated once with rehash. Product of maxLoadFactor and bucketCount.
HashTableBase(float pBaseLoadFactor, float pMaxLoadFactor)
typename detail::RecyclingSelector< TRecycling > ::template HookType< TAllocator, typename HTElementSelector< TValueDescriptor, THashCaching >::Type > SharedRecyclerType
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
typename RecyclingSelector< TRecycling >::template Type< TAllocator, typename HTElementSelector< TValueDescriptor, THashCaching >::Type > recyclerType
Type of a single linked node list.
HashTableBase(TSharedRecycler &pSharedRecycler, float pBaseLoadFactor=1.0, float pMaxLoadFactor=2.0)
size_t increaseSize(integer increase, const size_t hashCode=0)
FwdList * buckets
The list of buckets.
std::pair< TIterator< T >, bool > insertIfNotExists(const TKey &key, size_t hashCode)
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:218
void pushFront(TElement *elem) noexcept
Definition sidilist.inl:222
TElement * addBehind(TElement *elem) noexcept
Definition sidilist.inl:142
void next(SidiNodeBase *p)
Definition sidilist.inl:95