ALib C++ Library
Library Version: 2402 R1
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_monomem of the \aliblong.
4 *
5 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6 * Published under \ref mainpage_license "Boost Software License".
7 **************************************************************************************************/
8#ifndef HPP_ALIB_MONOMEM_DETAIL_HASHTABLEBASE
9#define HPP_ALIB_MONOMEM_DETAIL_HASHTABLEBASE 1
10
11#if !defined(HPP_ALIB_MONOMEM_HASHTABLE)
12# error "ALib sources with ending '.inl' must not be included from outside."
13#endif
14#if !defined (HPP_ALIB_MONOMEM_FWDS)
15# include "alib/monomem/fwds.hpp"
16#endif
17#if !defined (HPP_ALIB_MONOMEM_MONOALLOCATOR)
19#endif
20
21#if !defined(HPP_ALIB_LANG_SIDILIST)
22# include "alib/lang/sidilist.hpp"
23#endif
24
25#if !defined (HPP_ALIB_MONOMEM_DETAIL_RECYCLER)
27#endif
28
29#if !defined(HPP_ALIB_LANG_TMP) && !defined(ALIB_DOX)
30# include "alib/lang/tmp.hpp"
31#endif
32
33#if ALIB_STRINGS && ALIB_ENUMS
34# if !defined(HPP_ALIB_LANG_COMMONENUMS)
36# endif
37#else
38# if !defined(HPP_ALIB_LANG_COMMONENUMS_DEFS)
40# endif
41#endif
42
43#if !defined (_GLIBCXX_ALGORITHM) && !defined(_ALGORITHM_)
44# include <algorithm>
45#endif
46
47namespace alib { namespace monomem {
48
49/**
50 * Details of namespace #alib::monomem.
51 */
52namespace detail {
53
54
55#if ALIB_SIZEOF_INTEGER == 4
56 static constexpr int primeTableSize = 26;
57#elif ALIB_SIZEOF_INTEGER == 8
58 /** The size of the static table of prime numbers. Depends on the platform. */
59 static constexpr int primeTableSize = 58;
60#else
61 #error "Unknown size of integer"
62#endif
63
64/** Table of prime numbers. The effective bucket size is chosen to be the first value found in
65 * this table that is equal or higher than the requested size. */
69
70/** A dummy bucket used for nulled hash tables to avoid otherwise necessary checks. */
71ALIB_API extern void* dummyBucket;
72
73// #################################################################################################
74// ### Struct HashTableElement
75// #################################################################################################
76
77/** Type used by \alib{monomem::detail;HashTableBase::Element} if hash codes are cached. */
78template<typename T, typename TStored>
79struct HashTableElementCached : public lang::SidiNodeBase<HashTableElementCached<T,TStored>>
80{
81 /** Deleted default destructor. (Needed to avoid warning with msc). */
83
84 /** TMP constant that denotes that hash codes are cached. */
85 static constexpr bool CachedHashCodes = 1;
86
87 /** The custom data stored in nodes of this table. */
88 union
89 {
90 TStored value; ///< The value as seen internally.
91 T valueExternal; ///< The value as seen externally.
92 };
93
94 size_t hashCode; ///< The cached hash code.
95
96 /** Stores the given hash code when an element is recycled or extracted and changed.
97 * @param pHashCode The new hash code to set for this (recycled) element. */
98 void fixHashCode( size_t pHashCode )
99 {
100 *const_cast<size_t*>(&hashCode)= pHashCode;
101 }
102
103 /** Returns the cached hash code.
104 * @return The hash code of this element. */
105 size_t getCached()
106 {
107 return hashCode;
108 }
109
110 /** Invokes the destructor of templated custom member \p{TStored}. */
111 void destruct()
112 {
113 value.~TStored();
114 }
115
116};
117
118/** Type used by \alib{monomem::detail;HashTableBase::Element} if hash codes are \b not cached. */
119template<typename T, typename TStored>
120struct HashTableElementUncached : public lang::SidiNodeBase<HashTableElementUncached<T,TStored>>
121{
122 /** Deleted default constructor. (Needed to avoid warning with msc). */
124
125 /** TMP constant that denotes that hash codes are not cached. */
126 static constexpr bool CachedHashCodes = 0;
127
128 /** The custom data stored in nodes of this table. */
129 union
130 {
131 T valueExternal; ///< The value as seen externally.
132 TStored value; ///< The value as seen internally.
133 };
134
135
136 /** Does nothing, parameter ignored.
137 * @param pHashCode Ignored */
138 void fixHashCode( size_t pHashCode ) { (void) pHashCode; }
139
140 /** Never called.
141 * @return Undefined. */
142 size_t getCached() { return 0; }
143
144 /** Invokes the destructor of templated custom member \p{TStored}. */
145 void destruct()
146 {
147 value.~TStored();
148 }
149
150};
151
152/**
153 * Helper struct used to determine the node type of \alib{monomem;detail::HashTableBase}.
154 *
155 * Type definition #type equals \alib{monomem;detail::HashTableElementUncached} in case
156 * \p{THashCashing} equals \alib{lang;Caching;Caching::Enabled} or \alib{lang;Caching;Caching::Auto} and \p{TKey} is
157 * an arithmetic type.<br>
158 * Otherwise, \alib{monomem;detail::HashTableElementCached} is chosen.
159 */
160template<typename T, typename TStored,typename TKey,lang::Caching THashCaching>
162{
163 /** The element type that the hash table uses.
164 * Results from values given for \p{THashCaching} and \p{TKey}. */
166 || ( THashCaching == lang::Caching::Auto
167 && !std::is_arithmetic<TKey>::value ),
168 detail::HashTableElementCached <T ALIB_COMMA TStored>,
170};
171
172
173/**
174 * Partially specialized helper struct used to determine the recycler type for struct
175 * \alib{monomem;detail::HashTableBase}.
176 */
177template<typename T,typename TStored,typename TKey,lang::Caching THashCaching, typename TRecycling>
179{
180};
181
182#if !defined(ALIB_DOX)
183template<typename T,typename TStored,typename TKey,lang::Caching THashCaching>
184struct HashTableRecycler<T,TStored,TKey,THashCaching,Recycling::Private>
186
187template<typename T,typename TStored,typename TKey,lang::Caching THashCaching>
188struct HashTableRecycler<T,TStored,TKey,THashCaching,Recycling::Shared >
189{ using type= detail::RecyclerShared <typename HashTableElementType<T,TStored,TKey,THashCaching>::type >; };
190
191template<typename T,typename TStored,typename TKey,lang::Caching THashCaching>
192struct HashTableRecycler<T,TStored,TKey,THashCaching,Recycling::None >
193{ using type= detail::RecyclerVoid <typename HashTableElementType<T,TStored,TKey,THashCaching>::type >; };
194#endif
195
196
197/** ************************************************************************************************
198 * Base struct of \alib{monomem;HashTable} providing internals.
199 * \note
200 * The separation of the internals of class \b HashTable to this type in namespace \b detail
201 * has no benefit on compilation speed or other positive "technical" effect, nor is it a matter
202 * of software design.<br>
203 * A user of derived class \alib{monomem;HashTable} finds all interface methods and types
204 * in one place, which is not cluttered by the documentation of the internals found here.
205 * Otherwise, the separation is exclusively supporting source code organization.
206 *
207 *
208 * @tparam T See
209 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
210 * of class \b HashTable.
211 * @tparam TStored See
212 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
213 * of class \b HashTable.
214 * @tparam TKey See
215 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
216 * of class \b HashTable.
217 * @tparam TIfMapped See
218 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
219 * of class \b HashTable.
220 * @tparam THash See
221 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
222 * of class \b HashTable.
223 * @tparam TEqual See
224 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
225 * of class \b HashTable.
226 * @tparam TAccess See
227 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
228 * of class \b HashTable.
229 * @tparam THashCaching See
230 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
231 * of class \b HashTable.
232 * @tparam TRecycling See
233 * \ref alib_ns_monomem_hashtable_referencedoc "reference documentation"
234 * of class \b HashTable.
235 **************************************************************************************************/
236template< typename T,
237 typename TStored,
238 typename TKey,
239 typename TIfMapped,
240 typename THash,
241 typename TEqual,
242 typename TAccess,
243 lang::Caching THashCaching,
244 typename TRecycling >
246{
247// #################################################################################################
248// ### Types and Constants
249// #################################################################################################
250 /**
251 * This is an empty struct used as type #TMapped within this class, respectively type
252 * \alib{monomem;HashTable::MappedType}, in the case that template parameter \p{TIfMapped}
253 * is given as <c>void</c>.
254 */
256 {};
257
258 /** The recycler. Its type depends on template parameter \p{TRecycling}. */
260
261 /** Equals template parameter \p{TIfMapped} in case this is not <c>void</c>, and helper
262 * struct \alib{monomem::detail::HashTableBase;NO_MAPPING} if it is. */
263 using TMapped= ATMP_IF_T_F( ATMP_EQ(TIfMapped, void), NO_MAPPING, TIfMapped );
264
265 /** The type stored in bucket #List. */
267
268 /** Type of a single linked node list. */
270
271 /** Type of a node in the \b List. */
273
274
275// #################################################################################################
276// ### internal helpers
277// #################################################################################################
278
279 /** Return the <em>key-portion</em> of a given element.
280 * @param element The element to receive the value from.
281 * @return The key value of the element. */
282 static TKey& keyPortion ( Element* element )
283 {
284 return TAccess().Key( element->value );
285 }
286
287 /** Return the <em>mapped-portion</em> of a given element.
288 * @param element The element to receive the value from.
289 * @return The key value of the element. */
290 static TMapped& mappedPortion( Element* element )
291 {
292 return TAccess().Mapped( element->value );
293 }
294
295 /** Either returns the cached hash code or calculates it.
296 * @param elem The element to receive the hashcode for.
297 * @return The hash code of the given element. */
298 static size_t getHashCode(Element* elem)
299 {
300 if constexpr ( Element::CachedHashCodes )
301 return elem->getCached();
302 else
303 return THash() ( keyPortion( elem ) );
304 }
305
306 /** Returns either a recycled or newly allocated element.
307 * @param hashCode The hashCode of the new element. Used only in cached case.
308 * @return A pointer to the element created or recycled. */
309 Element* allocElement( const size_t hashCode )
310 {
311 Element* elem= recycler.get();
312 if( elem == nullptr )
313 elem= allocator->Alloc<Element>();
314
315 elem->fixHashCode( hashCode );
316 return elem;
317 }
318
319// #################################################################################################
320// std::iterator_traits types.
321// #################################################################################################
322
323 /** ********************************************************************************************
324 * Templated implementation of \c std::iterator_traits.
325 * Will be exposed by derived class's definitions \alib{monomem::HashTable;Iterator} and
326 * \alib{monomem::HashTable;ConstIterator}.
327 *
328 * As the name of the class indicates, this iterator satisfies the C++ standard library concept
329 * \https{ForwardIterator,en.cppreference.com/w/cpp/named_req/ForwardIterator}.
330 *
331 * @tparam TConstOrMutable A constant or mutable version of the parent's template type
332 * \p{TMapped}.
333 **********************************************************************************************/
334 template<typename TConstOrMutable>
336 {
337 #if !defined(ALIB_DOX)
338 friend struct HashTableBase;
339 friend class HashTable<T,TStored,TKey,TIfMapped,THash,TEqual,TAccess,THashCaching,TRecycling>;
340 #endif
341
342 /** Const or mutable version of HashTableBase. */
344 const HashTableBase );
345 using iterator_category = std::forward_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
346 using value_type = TMapped ; ///< Implementation of <c>std::iterator_traits</c>.
347 using difference_type = integer ; ///< Implementation of <c>std::iterator_traits</c>.
348 using pointer = TConstOrMutable* ; ///< Implementation of <c>std::iterator_traits</c>.
349 using reference = TConstOrMutable& ; ///< Implementation of <c>std::iterator_traits</c>.
350
351 protected:
352 /** The pointer to the hash table. */
354
355 /** The actual bucket index. */
357
358 /** The pointer to the actual element. */
360
361
362 /** Internal constructor. Searches the first element, starting with given bucket
363 * number.
364 * @param pTable Pointer to the hash table.
365 * @param pBbucketIx The bucket index.
366 */
367 TIterator( THashtable* pTable, uinteger pBbucketIx )
368 : table(pTable)
369 {
370 while( pBbucketIx < pTable->bucketCount )
371 {
373 if( !pTable->buckets[pBbucketIx].isEmpty() )
374 {
375 bucketIdx= pBbucketIx;
376 element = pTable->buckets[pBbucketIx].first();
377 return;
378 }
379 ++pBbucketIx;
381 }
382 bucketIdx= pBbucketIx;
383 element = nullptr;
384 }
385
386 /** Internal constructor creating a specific iterator.
387 * @param pTable Pointer to the hash table.
388 * @param pBbucketIx The bucket index.
389 * @param pElement Pointer to the current element.
390 */
391 TIterator( THashtable* pTable, uinteger pBbucketIx, Element* pElement)
392 : table ( pTable )
393 , bucketIdx( pBbucketIx )
394 , element ( pElement )
395 {}
396
397 /** Moves an iterator with a nulled element pointer to the next element. */
398 void repair()
399 {
401 while( ++bucketIdx < table->bucketCount )
402 if( !table->buckets[bucketIdx].isEmpty() )
403 {
404 element= table->buckets[bucketIdx].first();
405 return;
406 }
408 }
409
410
411 public:
412 /** Default constructor. Keeps everything uninitialized. */
413 TIterator() = default;
414
415 /** Copy constructor (default).
416 * @param other The iterator to assign from. */
417 TIterator( const TIterator& other) = default;
418
419
420 /** Copy assignment (default).
421 * @param other The iterator to assign from.
422 * @return A reference to this object. */
423 TIterator& operator=( const TIterator& other ) = default;
424
425
426 #if defined(ALIB_DOX)
427 /** Copy constructor accepting a mutable iterator.
428 * Available only for the constant version of this iterator.
429 * @tparam TMutable The type of this constructor's argument.
430 * @param mutableIt Mutable iterator to copy from. */
431 ATMP_SELECT_IF_1TP( typename TMutable, ATMP_EQ( TMutable, TIterator<T> ) )
432 TIterator( const TMutable& mutableIt );
433 #else
434 ATMP_SELECT_IF_1TP( typename TMutable, ATMP_EQ( TMutable, TIterator<T> ) )
435 TIterator( const TMutable& mutableIt )
436 : table ( mutableIt.table )
437 , bucketIdx( mutableIt.bucketIdx )
438 , element ( mutableIt.element )
439 {}
440 #endif
441
442 //#################### To satisfy concept of InputIterator ####################
443
444 /** Prefix increment operator.
445 * @return A reference to this object. */
447 {
448 if(element->hasNext())
449 {
450 element= element->next();
451 return *this;
452 }
453
454 while( ++bucketIdx < table->bucketCount )
455 {
457 if( !table->buckets[bucketIdx].isEmpty() )
458 {
459 element= table->buckets[bucketIdx].first();
460 return *this;
461 }
463 }
464
465 element= nullptr;
466 return *this;
467 }
468
469 /** Postfix increment operator.
470 * @return An iterator value that is not increased, yet. */
472 {
473 auto result= TIterator( *this);
474 ++(*this);
475 return result;
476 }
477
478 /** Comparison operator.
479 * @param other The iterator to compare ourselves to.
480 * @return \c true if this and the given iterator are pointing to the same element,
481 * \c false otherwise. */
482 bool operator==( TIterator other) const
483 {
484 return element == other.element;
485 }
486
487 /** Comparison operator.
488 * @param other The iterator to compare ourselves to.
489 * @return \c true if this and given iterator are not equal, \c false otherwise. */
490 bool operator!=( TIterator other) const
491 {
492 return !(*this == other);
493 }
494
495
496 // ############ access to templated members ############
497
498 /** Retrieves the stored object that this iterator references.
499 * @return A reference to the stored object. */
500 TConstOrMutable& operator*() const
501 {
502 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
503 return element->valueExternal;
504 }
505
506 /** Retrieves a pointer to the stored object that this iterator references.
507 * @return A pointer to the stored object. */
508 TConstOrMutable* operator->() const
509 {
510 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
511 return &element->valueExternal;
512 }
513
514 /** Retrieves the stored object that this iterator references.
515 * @return A reference to the stored object. */
516 TConstOrMutable& Value() const
517 {
518 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
519 return element->valueExternal;
520 }
521
522 /** Retrieves the key-portion of the stored object that this iterator references.
523 * @return A reference to the key-portion of the stored object. */
524 const TKey& Key() const
525 {
526 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
527 return keyPortion( element );
528 }
529
530 /** Retrieves the mapped-portion of the stored object that this iterator references.
531 * This method is an alias to <c>operator*</c>
532 *
533 * \par Availability
534 * This method is only available with
535 * \ref alib_ns_monomem_hashtable_setandmap "hash map mode".
536 *
537 * @return A reference to the mapped-portion of the stored object. */
538 template<typename TEnableIf= TMapped>
539 ATMP_T_IF(TMapped&, !ATMP_EQ( TEnableIf, void ))
540 Mapped() const
541 {
542 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
543 return mappedPortion( element );
544 }
545
546 }; // class TIterator
547
548
549 /** ********************************************************************************************
550 * Templated implementation of \c std::iterator_traits.
551 * Will be exposed by derived class's definitions
552 * \alib{monomem::HashTable;LocalIterator} and \alib{monomem::HashTable;ConstLocalIterator}.
553 *
554 * As the name of the class indicates, this iterator satisfies the C++ standard library concept
555 * \https{ForwardIterator,en.cppreference.com/w/cpp/named_req/ForwardIterator}.
556 *
557 * @tparam TConstOrMutable A constant or mutable version of
558 * \alib{monomem::detail;HashTableBase::TMapped}.
559 **********************************************************************************************/
560 template<typename TConstOrMutable>
562 {
563 #if !defined(ALIB_DOX)
564 friend struct HashTableBase;
565 friend class HashTable<T,TStored,TKey,TIfMapped,THash,TEqual,TAccess,THashCaching,TRecycling>;
566 #endif
567
568 using iterator_category = std::forward_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
569 using value_type = TConstOrMutable ; ///< Implementation of <c>std::iterator_traits</c>.
570 using difference_type = integer ; ///< Implementation of <c>std::iterator_traits</c>.
571 using pointer = TConstOrMutable* ; ///< Implementation of <c>std::iterator_traits</c>.
572 using reference = TConstOrMutable& ; ///< Implementation of <c>std::iterator_traits</c>.
573
574 protected:
575 /** The pointer to the actual element. */
577
578 /** The index of the bucket that this iterator works on. */
580
581 public:
582 /** Default constructor. */
585
586 /** Copy constructor (default).
587 * @param other The iterator to assign from. */
588 TLocalIterator( const TLocalIterator& other ) = default;
589
590 #if defined(ALIB_DOX)
591 /** Copy constructor accepting a mutable iterator.
592 * Available only for the constant version of this iterator.
593 * @tparam TMutable The type of this constructor's argument.
594 * @param mutableIt Mutable iterator to copy from. */
595 ATMP_SELECT_IF_1TP( typename TMutable, ATMP_EQ( TMutable, TLocalIterator<T> ) )
596 TLocalIterator( const TMutable& mutableIt );
597 #else
598 ATMP_SELECT_IF_1TP( typename TMutable, ATMP_EQ( TMutable, TLocalIterator<T> ) )
599 TLocalIterator( const TMutable& mutableIt )
600 : element ( mutableIt.element )
601 , bucketIdx( mutableIt.bucketIdx )
602 {}
603 #endif
604
605 /** Constructor.
606 * @param pBucketIdx Index of the bucket this iterator works on.
607 * @param pElement Pointer to current element.
608 */
609 explicit TLocalIterator( uinteger pBucketIdx, Element* pElement )
610 : element (pElement )
611 , bucketIdx(pBucketIdx)
612 {}
613
614 /** Copy assignment (default).
615 * @param other The iterator to assign from.
616 * @return A reference to this object. */
617 TLocalIterator& operator=( const TLocalIterator& other) = default;
618
619 // ################### To satisfy concept of InputIterator ####################
620
621 /** Prefix increment operator.
622 * @return A reference to this object. */
624 {
625 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
626 element= element->next();
627 return *this;
628 }
629
630 /** Postfix increment operator.
631 * @return An iterator value that is not increased, yet. */
633 {
634 auto result= TLocalIterator( *this);
635 ++(*this);
636 return result;
637 }
638
639 /** Comparison operator.
640 * @param other The iterator to compare ourselves to.
641 * @return \c true if this and the given iterator are pointing to the same element,
642 * \c false otherwise. */
643 bool operator==( TLocalIterator other) const
644 {
645 return element == other.element
646 && bucketIdx == other.bucketIdx;
647 }
648
649 /** Comparison operator.
650 * @param other The iterator to compare ourselves to.
651 * @return \c true if this and given iterator are not equal, \c false otherwise. */
652 bool operator!=( TLocalIterator other) const
653 {
654 return !(*this == other);
655 }
656
657 // ############ access to templated members ############
658
659 /** Retrieves the stored object that this iterator references.
660 * @return A reference to the stored object. */
661 TConstOrMutable& operator*() const
662 {
663 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
664 return element->valueExternal;
665 }
666
667 /** Retrieves a pointer to the stored object that this iterator references.
668 * @return A pointer to the stored object. */
669 TConstOrMutable* operator->() const
670 {
671 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
672 return &element->valueExternal;
673 }
674
675 /** Retrieves the stored object that this iterator references.
676 * @return A reference to the stored object. */
677 TConstOrMutable& Value() const
678 {
679 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
680 return element->valueExternal;
681 }
682
683 /** Retrieves the key-portion of the stored object that this iterator references.
684 * @return A reference to the key-portion of the stored object. */
685 const TKey& Key() const
686 {
687 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
688 return keyPortion( element );
689 }
690
691 /** Retrieves the stored object that this iterator references.<br>
692 * This method is an alias to <c>operator*</c>
693 *
694 * \par Availability
695 * This method is only available with
696 * \ref alib_ns_monomem_hashtable_setandmap "hash map mode".
697 *
698 * @return A reference to the mapped-portion of the stored object. */
699 template<typename TEnableIf= TMapped>
700 ATMP_T_IF(TMapped&, !ATMP_EQ( TEnableIf, void ))
701 Mapped() const
702 {
703 ALIB_ASSERT_ERROR( element != nullptr, "MONOMEM/HASHTABLE", "Illegal iterator." )
704 return mappedPortion( element );
705 }
706 }; // class TLocalIterator
707
708
709// #################################################################################################
710// Fields
711// #################################################################################################
712 /** The allocator assigned. */
714
715 /** The number of buckets managed by this tree. */
717
718 /** The list of buckets. */
720
721 /** The load factor that is set when the table is rehashed automatically. */
723
724 /** The maximum quotient of #size and #bucketCount that triggers a rehash. */
726
727 /** The number of elements stored. */
729
730 /** Calculated once with rehash. Product of #maxLoadFactor and #bucketCount. */
732
733
734 /** ********************************************************************************************
735 * Constructor.
736 * @param pAllocator The monotonic allocator to use.
737 * @param pBaseLoadFactor The base load factor.
738 * @param pMaxLoadFactor The maximum load factor.
739 **********************************************************************************************/
741 float pBaseLoadFactor,
742 float pMaxLoadFactor )
743 : allocator ( pAllocator )
744 , baseLoadFactor( pBaseLoadFactor )
745 , maxLoadFactor ( pMaxLoadFactor )
746 , size ( 0 )
747 {
748 buckets = reinterpret_cast<List*>(&detail::dummyBucket);
749 bucketCount = 1;
750 size = 0;
752 }
753
754 /** ********************************************************************************************
755 * Constructor taking a shared recycler.
756 * @param pAllocator The monotonic allocator to use.
757 * @param pRecycler The shared recycler.
758 * @param pBaseLoadFactor The base load factor.
759 * @param pMaxLoadFactor The maximum load factor.
760 **********************************************************************************************/
762 List& pRecycler,
763 float pBaseLoadFactor = 1.0,
764 float pMaxLoadFactor = 2.0 )
765 : recycler ( pRecycler )
766 , allocator ( pAllocator )
767 , baseLoadFactor( pBaseLoadFactor )
768 , maxLoadFactor ( pMaxLoadFactor )
769 , size ( 0 )
770 {
771 buckets = reinterpret_cast<List*>(&detail::dummyBucket);
772 bucketCount = 1;
773 size = 0;
775 }
776
777
778
779// #################################################################################################
780// ### mini helpers
781// #################################################################################################
782
783 /**
784 * Compares two elements. If cached mode, the hash code is compared prior to the keys.
785 * @param lhs The first node to compare.
786 * @param rhs The second node to compare.
787 * @return The result of the comparison.
788 */
789 bool areEqual( Element* lhs, Element* rhs ) const
790 {
791 return ( !Element::CachedHashCodes || ( getHashCode(lhs) == getHashCode(rhs) ) )
792 && TEqual()( keyPortion( lhs ), keyPortion( rhs ) );
793 }
794
795 /**
796 * Compares a key and a node. If cached mode, the hash codes are compared prior to the
797 * keys.
798 * @param elem The element to compare.
799 * @param key The key to compare.
800 * @param keyHashCode The hash code of \p{key}.
801 * @return The result of the comparison.
802 */
803 bool areEqual( Element* elem, const TKey& key, size_t keyHashCode ) const
804 {
805 return ( !Element::CachedHashCodes || ( keyHashCode == getHashCode(elem) ) )
806 && TEqual() ( keyPortion( elem ), key );
807 }
808
809 /**
810 * Searches the first element equal to \p{key} in bucket \p{bucketIdx}.
811 *
812 * @param bucketIdx The bucket number to search in (hash code divided by #bucketCount).
813 * @param key The <em>key-portion</em> of the element to search.
814 * @param keyHashCode The hash code of \p{key}.
815 * @return A pointer to the element searched, respectively \c nullptr if not found.
816 */
817 Element* findElement( uinteger bucketIdx, const TKey& key, size_t keyHashCode ) const
818 {
820 Node* result= buckets[bucketIdx].first();
821 while( result)
822 {
823 if( areEqual( static_cast<Element*>(result), key, keyHashCode ) )
824 return static_cast<Element*>(result);
825
826 result= result->next();
827 }
828 return nullptr;
830 }
831
832 /**
833 * Searches the predecessor of the first element equal to \p{key} in bucket \p{bucketIdx}.
834 *
835 * @param bucketIdx The bucket number to search in (hash code divided by #bucketCount).
836 * @param key The <em>key-portion</em> of the element to search.
837 * @param keyHashCode The hash code of \p{key}.
838 * @return A pointer to the element before the searched one, respectively \c nullptr if not
839 * found.
840 */
841 Node* findElementBefore( uinteger bucketIdx, size_t keyHashCode, const TKey& key ) const
842 {
844 Node* result= &buckets[bucketIdx].hook;
846
847 while( result->hasNext() && !areEqual( result->next(), key, keyHashCode ) )
848 result= result->next();
849
850 return result->hasNext() ? result : nullptr;
851 }
852
853 /**
854 * Inserts the given element into the bucket.
855 * If an element of the same key exists, then the element is put in front of that element.
856 * Otherwise it is added to the start of the bucket.
857 * @param element The element to insert to its bucket.
858 * @param hashCode The hash code of parameter \p{element}.
859 * @return The bucket number that the element was inserted to.
860 */
861 uinteger insertInBucket( Element* element, const size_t hashCode )
862 {
863 auto bucketIdx= hashCode % bucketCount;
864 Node* previous= findElementBefore( bucketIdx, hashCode, keyPortion(element) );
866 if( previous == nullptr )
867 previous= &buckets[bucketIdx].hook;
869
870 previous->addBehind( element );
871 return bucketIdx;
872 }
873
874 /**
875 * Increases field #size and checks for a rehash.
876 *
877 * @param increase The amount to increase.
878 * @param hashCode A hashCode that caller might want to have converted into a new
879 * actual bucket index.
880 * @return The bucket index of \p{hashCode}.
881 */
882 size_t increaseSize( integer increase, const size_t hashCode= 0 )
883 {
884 size+= increase;
885 if( size >=sizeLimitToRehash )
886 rehash( (std::max)( uinteger( float(size) / baseLoadFactor ), bucketCount + 1 ) );
887
888 return hashCode % bucketCount;
889 }
890
891// #################################################################################################
892// ### method implementations
893// #################################################################################################
894
895 /** ********************************************************************************************
896 * Destructs and removes all entries from this hash table.
897 **********************************************************************************************/
898 void clear()
899 {
900 if( size == 0 )
901 return;
902
903 // destruct and recycle entries
904 for( uinteger bucketIdx= 0 ; bucketIdx < bucketCount ; ++bucketIdx )
905 {
907 Element* first= buckets[bucketIdx].first();
908 if( first != nullptr )
909 {
910 first->destruct();
911 Element* last = first;
912 while( last->hasNext() )
913 {
914 last= last->next();
915 last->destruct();
916 }
917 recycler.recycle( first, last );
918 buckets[bucketIdx].reset();
919 }
921 }
922
923 size= 0;
924 }
925
926
927 /** ********************************************************************************************
928 * Resets this object. Invokes #clear to destruct all keys and values and disposes all
929 * allocated internal management data.
930 **********************************************************************************************/
931 void reset()
932 {
933 clear();
934 buckets = reinterpret_cast<List*>(&detail::dummyBucket);
935 bucketCount = 1;
936 size = 0;
938 recycler.disposeRecyclablesIfPrivate();
939 }
940
941 /** ********************************************************************************************
942 * Changes the maximum load factor value and invokes #rehash providing the actual bucket
943 * count as the minimum bucket count that is to be chosen.
944 * @param pMaxLoadFactor The maximum load factor used to determine the need of re-hashing.
945 **********************************************************************************************/
946 void setMaxLoadFactor( float pMaxLoadFactor )
947 {
948 maxLoadFactor= pMaxLoadFactor;
949 if( bucketCount > 1 )
951 }
952
953 /** ********************************************************************************************
954 * Changes the number of buckets to be at least the higher value of
955 * a) the given \p{newMinBucketCount}, and<br>
956 * b) the quotient of the current size and the maximum load factor.
957 *
958 * The result of the above, is increased to the next higher prime number.
959 * Rehash is only performed if bucket size increases. It never is decreased.
960 *
961 * @param newMinBucketCount The minimum new bucket count requested.
962 **********************************************************************************************/
963 void rehash( uinteger newMinBucketCount )
964 {
965 // smaller than before?
966 if( newMinBucketCount <= bucketCount )
967 return;
968
969 auto oldBucketCount= bucketCount;
970
971 // adjust requested bucket count to the maximum load factor
972 newMinBucketCount= (std::max)( newMinBucketCount,
973 static_cast<uinteger>( static_cast<float>(size) / maxLoadFactor ) );
974
975 // adjust requested bucket count to next higher prime value
976 {
978 int idx= 0;
979 while( detail::primeNumbers[idx] < newMinBucketCount )
980 ++idx;
983 }
984
985 ALIB_ASSERT_ERROR( bucketCount > oldBucketCount, "MONOMEM/HASHTABLE",
986 "Internal error: Rehashing to equal or smaller bucket count." )
987
988 // store new rehash trigger
990
991 // collect elements
992 List elements;
993 for( uinteger bucketIdx= 0 ; bucketIdx < oldBucketCount ; ++bucketIdx )
994 {
996 Element* first= buckets[bucketIdx].first();
997 if( first != nullptr )
998 elements.pushFront( first, buckets[bucketIdx].findLast() );
1000 }
1001
1002
1003 // create a new data array
1004 List* oldData = buckets;
1005
1007
1008 // re-insert objects
1009 Element* actual= elements.first();
1010 while( actual != nullptr )
1011 {
1012 Element* next= actual->next();
1013 insertInBucket( actual, getHashCode(actual) );
1014 actual= next;
1015 }
1016
1017 // recycle old data (make future nodes elements out of it)
1018 if( oldData != reinterpret_cast<List*>( &detail::dummyBucket ) )
1019 {
1020 recycler.template recycleChunk<List>( oldData, oldBucketCount );
1021 }
1022 }
1023
1024 /** ********************************************************************************************
1025 * Searches the first and last element stored according to given \p{key}.
1026 * Returns a pare of iterators that define a range containing all elements with key
1027 * \p{key} of the container.<br>
1028 * Parameter \p{resultStart} is set to the first element of the matching range and
1029 * parameter \p{resultEnd} is set to point past the last element of the range.
1030 *
1031 * If no element with key \p{key} is found, both iterators are set to \b end.
1032 *
1033 * @param key The <em>key-portion</em> of the elements to find.
1034 * @return A pair of iterators defining the range of elements with key \p{key}.
1035 **********************************************************************************************/
1036 std::pair<TIterator<T>,TIterator<T>> findRange( const TKey& key )
1037 {
1038 const auto hashCode= THash()(key);
1039 auto bucketIdx= hashCode % bucketCount;
1040 Element* element= findElement( bucketIdx, key, hashCode );
1041 if( element == nullptr )
1042 return std::make_pair( TIterator<T>( this, bucketCount, nullptr ),
1043 TIterator<T>( this, bucketCount, nullptr ) );
1044
1045 auto result= std::make_pair( TIterator<T>( this, bucketIdx, element ),
1046 TIterator<T>( this, bucketIdx, element ) );
1047 for(;;)
1048 {
1049 ++result.second;
1050 if( result.second.element == nullptr
1051 || !areEqual( result.second.element, key, hashCode ) )
1052 return result;
1053 }
1054
1055 }
1056
1057 /** ********************************************************************************************
1058 * Searches (a first) element with the given key.
1059 * If not found, an invalid iterator to the bucket is returned with a nulled element pointer.
1060 * Prior to this counter #size is increased and, if a load limit is reached, a re-hash is
1061 * performed.
1062 *
1063 * If otherwise an element was found, its valid iterator is returned.
1064 *
1065 * Note: Used by \alib{monomem;HashMap::EmplaceIfNotExistent}.
1066 *
1067 * @param key The key to the (first) element to find.
1068 * @param hashCode The hash code of parameter \p{key}.
1069 * @return A pair of an iterator referring to the found or inserted element and a boolean
1070 * that is \c true if the insertion took place and \c false nothing was changed.
1071 **********************************************************************************************/
1072 std::pair<TIterator<T>, bool> insertIfNotExists( const TKey& key, size_t hashCode )
1073 {
1074 auto bucketIdx= hashCode % bucketCount;
1075 Element* element= findElement( bucketIdx, key, hashCode );
1076 if (element != nullptr )
1077 return std::make_pair(TIterator<T>( this, bucketIdx, element ), false);
1078
1080 bucketIdx= increaseSize( 1, hashCode );
1081
1082 Element* newElement= allocElement( hashCode );
1083 buckets[bucketIdx].pushFront( newElement );
1084 return std::make_pair(TIterator<T>( this, bucketIdx, newElement ) , true);
1086 }
1087
1088 /** ********************************************************************************************
1089 * Inserts the topmost recyclable element if no element with the same key-portion of its value
1090 * exists.
1091 *
1092 * @param key Pointer to the key to search elements for deletion.
1093 * @param hashCode The hash code of parameter \p{key}.
1094 * @return A pair containing an iterator referring to the element added.
1095 * The bool component is \c true if the insertion took place and \c false if a new
1096 * element was created.
1097 **********************************************************************************************/
1098 std::pair<TIterator<T>, bool> insertOrGet( const TKey& key, size_t hashCode )
1099 {
1100 // find (first) element with same key in bucket
1101 auto bucketIdx= hashCode % bucketCount;
1102 auto* elem= findElement( bucketIdx, key, hashCode );
1103 if( elem != nullptr )
1104 return std::make_pair( TIterator<T>( this, bucketIdx, elem ), false);
1105
1106 // create new element
1107 bucketIdx= increaseSize( 1, hashCode );
1108 Element* newElem= allocElement( hashCode );
1110 buckets[bucketIdx].pushFront( newElem );
1112 return std::make_pair(TIterator<T>( this, bucketIdx, newElem ), true);
1113 }
1114
1115}; // HashTableBase
1116
1117}}} // namespace [alib::monomem::detail]
1118
1119
1120#endif // HPP_ALIB_MONOMEM_DETAIL_HASHTABLEBASE
ALIB_FORCE_INLINE char * Alloc(size_t size, size_t alignment)
T * EmplaceArray(TSize length, TArgs &&... args)
TIterator(THashtable *pTable, uinteger pBbucketIx, Element *pElement)
ATMP_IF_T_F(!ATMP_IS_CONST(TConstOrMutable), HashTableBase, const HashTableBase) THashtable
TIterator(THashtable *pTable, uinteger pBbucketIx)
TMapped value_type
Implementation of std::iterator_traits.
std::forward_iterator_tag iterator_category
Implementation of std::iterator_traits.
TIterator & operator=(const TIterator &other)=default
TIterator(const TIterator &other)=default
TConstOrMutable * pointer
Implementation of std::iterator_traits.
integer difference_type
Implementation of std::iterator_traits.
TConstOrMutable & reference
Implementation of std::iterator_traits.
TLocalIterator(const TLocalIterator &other)=default
TConstOrMutable value_type
Implementation of std::iterator_traits.
TLocalIterator & operator=(const TLocalIterator &other)=default
TLocalIterator(uinteger pBucketIdx, Element *pElement)
std::forward_iterator_tag iterator_category
Implementation of std::iterator_traits.
TConstOrMutable * pointer
Implementation of std::iterator_traits.
integer difference_type
Implementation of std::iterator_traits.
TConstOrMutable & reference
Implementation of std::iterator_traits.
#define ATMP_IF_T_F( Cond, T, F)
Definition tmp.hpp:54
#define ATMP_IS_CONST(T)
Definition tmp.hpp:25
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:715
#define ALIB_API
Definition alib.hpp:538
#define ATMP_EQ( T, TEqual)
Definition tmp.hpp:32
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:644
#define ATMP_SELECT_IF_1TP(TParam, ...)
Definition tmp.hpp:57
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:53
@ Enabled
Caching is enabled.
@ Auto
Auto/default mode.
ALIB_WARNINGS_RESTORE ALIB_API void * dummyBucket
static constexpr int primeTableSize
ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE ALIB_API const uinteger primeNumbers[primeTableSize]
Definition alib.cpp:57
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.hpp:289
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:286
void pushFront(TElement *elem)
Definition sidilist.hpp:247
TElement * first() const
Definition sidilist.hpp:240
void next(SidiNodeBase *p)
Definition sidilist.hpp:107
TElement * addBehind(TElement *elem)
Definition sidilist.hpp:154
Element * findElement(uinteger bucketIdx, const TKey &key, size_t keyHashCode) const
static TMapped & mappedPortion(Element *element)
bool areEqual(Element *lhs, Element *rhs) const
ATMP_IF_T_F(ATMP_EQ(TIfMapped, void), NO_MAPPING, TIfMapped) TMapped
std::pair< TIterator< T >, bool > insertIfNotExists(const TKey &key, size_t hashCode)
HashTableRecycler< T, TStored, TKey, THashCaching, TRecycling >::type recycler
static TKey & keyPortion(Element *element)
HashTableBase(MonoAllocator *pAllocator, float pBaseLoadFactor, float pMaxLoadFactor)
size_t increaseSize(integer increase, const size_t hashCode=0)
HashTableBase(MonoAllocator *pAllocator, List &pRecycler, float pBaseLoadFactor=1.0, float pMaxLoadFactor=2.0)
typename HashTableElementType< T, TStored, TKey, THashCaching >::type Element
void rehash(uinteger newMinBucketCount)
std::pair< TIterator< T >, TIterator< T > > findRange(const TKey &key)
Element * allocElement(const size_t hashCode)
std::pair< TIterator< T >, bool > insertOrGet(const TKey &key, size_t hashCode)
static size_t getHashCode(Element *elem)
uinteger insertInBucket(Element *element, const size_t hashCode)
void setMaxLoadFactor(float pMaxLoadFactor)
Node * findElementBefore(uinteger bucketIdx, size_t keyHashCode, const TKey &key) const
bool areEqual(Element *elem, const TKey &key, size_t keyHashCode) const
T valueExternal
The value as seen externally.
TStored value
The value as seen internally.
ATMP_IF_T_F( THashCaching==lang::Caching::Enabled||( THashCaching==lang::Caching::Auto &&!std::is_arithmetic< TKey >::value), detail::HashTableElementCached< T ALIB_COMMA TStored >, detail::HashTableElementUncached< T ALIB_COMMA TStored >) type
TStored value
The value as seen internally.