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