ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
lrucachetable.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of module \alib_containers of the \aliblong.
4///
5/// \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8#ifndef HPP_ALIB_MONOMEM_CONTAINERS_LRUCACHETABLE
9#define HPP_ALIB_MONOMEM_CONTAINERS_LRUCACHETABLE 1
10#pragma once
12ALIB_ASSERT_MODULE(CONTAINERS)
13#include "alib/lang/tmp.hpp"
17#include <limits>
18#include <functional>
19namespace alib { namespace containers {
20
21/// This type implements a container used for caching objects. When its #Size reaches its #Capacity,
22/// one of the least recently used (LRU) objects is replaced with the next insertion of a non-cached
23/// object.
24///
25/// This implementation uses an array of lists. The lists are forward lists of cached elements
26/// sorted by their insertion time, with the latest insertion in the front.
27/// The list (within the array of lists) used to store and later search an object, is chosen by
28/// the hash value of its key, modulo the number of lists in place.
29/// Both, the size of the lists as well the number of lists (the size of the array) can be chosen
30/// on construction or with method #Reserve.
31/// The memory needed for all entries (and the array of pointers to the start of the list)
32/// is allocated once, when the capacity is set. Generic allocation options (heap-, monotonic-
33/// and pool allocation) are given with template parameter \p{TAllocator}.<br>
34/// Together with the custom data, the hashcode of the key of the data is stored with each element.
35/// This can reduce search time dramatically in some cases, because the equal functor is invoked
36/// only if two objects have the same hashcode.
37///
38/// This design has the following consequences:
39/// - The maximum amount of objects stored, equals the product of the size of the hash-array
40/// and the maximum size of the list.
41/// - The maximum number of comparisons performed before a cache miss is detected, equals
42/// the maximum size of the lists.
43/// - The \b last recently used object is always found with only one comparison. The probability
44/// that other previously used objects (the second last, third last, etc) are likewise found
45/// with only one comparison, rises with the size of the array of lists.
46/// - This container does not necessarily free the least recently used object with the insertion
47/// of an unknown one. Instead, the least recently used object of those cached objects whose hash
48/// function leads to the same list index is freed.
49///
50/// As a sample, two reasonable use cases taken from \alib should be quickly discussed:
51/// 1. Class \alib{files;OwnerAndGroupResolver} of camp \alib_files:
52/// - The type translates owner and group IDs of files to corresponding owner and group names.
53/// - For this, the OS has to be called.
54/// - If for example a directory listing similar to bash command <c>ls -la</c> is to be printed,
55/// the entries in a directory usually share the same owner with very few exceptions.
56/// This is true for home directories inside <c>/home</c> as well as for system directories
57/// like <c>/usr/bin</c>.
58/// - A perfect exception is directory <c>/home</c> itself. Here, every subfolder belongs to a
59/// different owner.
60///
61/// This sample shows that already a very small cache capacity can dramatically decrease the
62/// number of calls to the OS. On the other hand, in the case of the exceptional folders, still
63/// the number of searches performed before a cache-miss is detected is limited to the length
64/// of the lists and not to the total capacity.
65/// The default capacity of the \b %LRUCacheTable chosen by class \b OwnerAndGroupResolver is
66/// <c>6 x 6</c> and can be changed with
67/// \alib{files::OwnerAndGroupResolver;SetOwnerCacheCapacity} and
68/// \alib{files::OwnerAndGroupResolver;SetGroupCacheCapacity}.
69/// 2. Camp \alib_alox:
70/// - With each log operation the placement of the call in a sourcefile (\alib{lox;Scope})
71/// is evaluated to resolve the resulting
72/// \"\ref alib_mod_alox_tak_terminology_domains "Log Domain"\".
73/// - For this, the source file name given by the C++ preprocessor, is to be parsed.
74/// - \alox uses an \b %LRUCacheTable to avoid parsing repetitive scopes.
75/// - It is very much depending on the use case of logging, how often repetitive scopes occur.
76/// For example if verbose logging is active, series of log statements comming from the same
77/// code entity should be expected. If logging is limited and furthermore logging is made
78/// in parallel by multiple threads, then the scopes should be rather mixed, but still
79/// resulting from a limited number of files during a certain period of execution time.
80///
81/// The default capacity of the \b %LRUCacheTable chosen by \alib is likewise <c>4 x 6</c>
82/// and can be changed with \alib{lox;Lox::SetFileNameCacheCapacity}.
83///
84/// Choosing the right values for the two dimensions of the capacity, depends on different
85/// factors of the specific use case, and in most cases cannot be chosen to be perfect in
86/// all situations. Among the things to consider are:
87/// - The costs of creating a new object.
88/// - The cost of comparing two keys.
89/// - The statistical distribution of requests on (subsequent) objects. In cases of even
90/// distribution, the use of this type can become counter-productive!
91/// - Potential memory constraints of the target platform, which may limit the capacity to set.
92///
93/// The stored type is not restricted in respect to complexity or construction, destruction, copy
94/// and move semantics, etc. This is reached by deferring construction to
95/// the caller of method #Try, who, in case of a cache miss, is obligated to duly use a
96/// C++ placement-new to construct an entry.
97///
98/// This class provides a forward-iterator type that fetches all currently cached elements.
99/// While this in most cases is not needed, the central interface method #Try also returns an
100/// iterator. While this iterator is always valid, a second returned value indicates whether also
101/// the element the iterator points to is valid. This distinction is necessary, because this
102/// container only reserves memory for the cached element, but it does not construct one.
103/// To support elegant construction of elements, the iterator class provides method
104/// \alib{containers::LRUCacheTable::TForwardIterator;Construct}.
105/// Furthermore, methods
106/// \alib{containers::LRUCacheTable::TForwardIterator;Key} and
107/// \alib{containers::LRUCacheTable::TForwardIterator;Mapped} allow access to the stored types.
108///
109/// @see
110/// - Type definitions \alib{containers;LRUCacheSet} and
111/// \alib{containers;LRUCacheMap} based on this type.
112/// - The approach to distinguish between "sets", "maps" and "sets with embedded keys" are
113/// the same with class \b %HashTable. Therefore, the
114/// \ref alib_ns_containers_hashtable_setandmap "documentation of class HashTable", which introduces
115/// the same template parameter \p{TValueDescriptor} and also provides similar type definitions
116/// \b %HashSet and \b %HashMap, is very helpful to understanding the concept of this type.
117///
118///
119/// @tparam TAllocator The allocator type to use, as prototyped with \alib{lang;Allocator}.
120/// @tparam TValueDescriptor Defines the #StoredType, #KeyType, and #MappedType. Furthermore has to
121/// provide methods that extract the key and the mapped value from the
122/// stored type.<br>
123/// For details on required type definitions and method signatures, see
124/// provided implementations
125/// \alib{containers;TIdentDescriptor} and
126/// \alib{containers;TPairDescriptor} as a sample.<br>
127/// The type is published as #DescriptorType.
128/// @tparam THash The hash functor applicable to the key-type defined by
129/// \p{TValueDescriptor}.<br>
130/// Defaults to <c>std::hash<typename TValueDescriptor::KeyType></c>
131/// and is published as #HashType.
132/// @tparam TEqual The comparison functor on the key-type defined by
133/// \p{TValueDescriptor}.<br>
134/// Defaults to <c>std::equal_to<typename TValueDescriptor::KeyType></c>
135/// and is published as #EqualType.
136template< typename TAllocator,
137 typename TValueDescriptor,
138 typename THash = std::hash <typename TValueDescriptor::KeyType>,
139 typename TEqual = std::equal_to<typename TValueDescriptor::KeyType> >
140class LRUCacheTable : public lang::AllocatorMember<TAllocator>
141#if ALIB_DEBUG_CRITICAL_SECTIONS
143#endif
144{
145 protected:
146 /// The allocator type that \p{TAllocator} specifies.
148
149 public:
150 /// Type definition publishing template parameter \p{TAllocator}.
151 using AllocatorType = TAllocator;
152
153 /// Type definition publishing template parameter \p{TValueDescriptor}.
154 using DescriptorType = TValueDescriptor;
155
156 /// Type definition publishing the stored type of this container as defined with template
157 /// parameter \p{TValueDescriptor}.
158 using StoredType = typename TValueDescriptor::StoredType;
159
160 /// Type definition publishing the key type of this container as defined with template
161 /// parameter \p{TValueDescriptor}.
162 using KeyType = typename TValueDescriptor::KeyType;
163
164 /// Type definition publishing the map type of this container as defined with template
165 /// parameter \p{TValueDescriptor}.
166 using MappedType = typename TValueDescriptor::MappedType;
167
168 /// Type definition publishing template parameter \p{THash}.
169 using HashType = THash;
170
171 /// Type definition publishing template parameter \p{TEqual}.
172 using EqualType = TEqual;
173
174 protected:
175 /// The node type of the cache lists.
176 struct Entry : public lang::SidiNodeBase<Entry>
177 {
178 size_t hashCode; ///< This entries hash code (calculated once on insertion)
179 StoredType data; ///< The data cached.
180 };
181
182 /// Shortcut to a forward list
184
185 /// Pointer to reserved memory for elements. Size is #capacityLists x #capacityEntries.
187
188 /// The next element to use with a cache-miss on a list that is not of full length, yet.
190
191 /// Array of size #capacityLists that holds the list..
193
194 /// The number of LRU-lists.
196
197 /// The number of entries collected in each LRU-list.
199
200 //================================================================================================
201 //=== Iterator implementation
202 //================================================================================================
203
204 //==============================================================================================
205 /// Templated implementation of \c std::iterator_traits.
206 /// Will be exposed by outer class's definitions
207 /// \alib{containers::LRUCacheTable;Iterator} and
208 /// \alib{containers::LRUCacheTable;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 #StoredType.
214 //==============================================================================================
215 template<typename TConstOrMutable>
217 {
218 #if !DOXYGEN
219 friend class LRUCacheTable;
220 #endif
221
222 using iterator_category = std::forward_iterator_tag; ///< Implementation of <c>std::iterator_traits</c>.
223 using value_type = TConstOrMutable ; ///< Implementation of <c>std::iterator_traits</c>.
224 using difference_type = integer ; ///< Implementation of <c>std::iterator_traits</c>.
225 using pointer = TConstOrMutable* ; ///< Implementation of <c>std::iterator_traits</c>.
226 using reference = TConstOrMutable& ; ///< Implementation of <c>std::iterator_traits</c>.
227
228 protected:
229 /// The pointer to the actual cache entry.
231
232 /// The pointer to the actual cache entry.
234
235 /// The actual list.
237
238 public:
239 /// Default constructor.
242
243 /// Copy constructor (default).
244 /// @param other The iterator to assign from.
245 TForwardIterator( const TForwardIterator& other ) = default;
246
247 #if DOXYGEN
248 /// Copy constructor accepting a mutable iterator.
249 /// Available only for the constant version of this iterator.
250 /// @tparam TMutable The type of this constructor's argument.
251 /// @param mutableIt Mutable iterator to copy from.
252 TForwardIterator( const TMutable& mutableIt );
253 #else
254 ATMP_SELECT_IF_1TP( typename TMutable, ATMP_EQ( TMutable, TForwardIterator<StoredType> ) )
255 TForwardIterator( const TMutable& mutableIt )
256 : entry ( mutableIt.entry ) {}
257 #endif
258
259 /// Constructor that explicitly sets a valid iterator.
260 /// @param pEntry Pointer to a valid element.
261 /// @param pTable The cache table we belong to.
262 /// @param pListIdx The index of the list that \p{pEntry} belongs to.
263 explicit
264 TForwardIterator( Entry* pEntry, LRUCacheTable* pTable, integer pListIdx )
265 : entry (pEntry)
266 , table (pTable)
267 , listIdx(pListIdx) {}
268
269
270 /// Constructor.
271 /// @param pTable The cache table we belong to.
272 /// @param pListIdx The index of the list to start with.
273 explicit
275 : table (pTable)
276 {
277 while( pListIdx < pTable->capacityLists )
278 {
280 if( !pTable->lists[pListIdx].isEmpty() )
281 {
282 listIdx= pListIdx;
283 entry = pTable->lists[pListIdx].first();
284 return;
285 }
286 ++pListIdx;
288 }
289 listIdx= pListIdx;
290 entry = nullptr;
291 }
292
293 /// Copy assignment (default).
294 /// @param other The iterator to assign from.
295 /// @return A reference to this object.
296 TForwardIterator& operator=( const TForwardIterator& other) = default;
297
298 // ################### To satisfy concept of InputIterator ####################
299
300 /// Prefix increment operator.
301 /// @return A reference to this object.
303 {
305 ALIB_ASSERT_ERROR( entry != nullptr, "MONOMEM/LRUCACHE", "Illegal iterator." )
306 entry= entry->next();
307 while( entry == nullptr && ++listIdx < table->capacityLists )
309
310 return *this;
312 }
313
314 /// Postfix increment operator.
315 /// @return An iterator value that is not increased, yet.
317 {
318 auto result= TForwardIterator( *this);
319 ++(*this);
320 return result;
321 }
322
323 /// Comparison operator.
324 /// @param other The iterator to compare ourselves to.
325 /// @return \c true if this and the given iterator are pointing to the same entry,
326 /// \c false otherwise.
327 bool operator==( TForwardIterator other) const
328 {
329 return entry == other.entry;
330 }
331
332 /// Comparison operator.
333 /// @param other The iterator to compare ourselves to.
334 /// @return \c true if this and given iterator are not equal, \c false otherwise.
335 bool operator!=( TForwardIterator other) const
336 {
337 return !(*this == other);
338 }
339
340 // ############ access to templated members ############
341
342 /// Retrieves the stored object that this iterator references.
343 /// @return A reference to the stored object.
344 TConstOrMutable& operator*() const
345 {
346 ALIB_ASSERT_ERROR( entry != nullptr, "MONOMEM/LRUCACHE", "Illegal iterator." )
347 return entry->data;
348 }
349
350 /// Retrieves a pointer to the stored object that this iterator references.
351 /// @return A pointer to the stored object.
352 TConstOrMutable* operator->() const
353 {
354 ALIB_ASSERT_ERROR( entry != nullptr, "MONOMEM/LRUCACHE", "Illegal iterator." )
355 return &entry->data;
356 }
357
358 /// Helper method that performs a placement-new on the data this iterator refers to.
359 /// This method can be used if method #Try indicates a cache miss.
360 ///@tparam TArgs Types of variadic parameters given with parameter \p{args}.
361 ///@param args Variadic parameters to be forwarded to the constructor of the inserted
362 /// instance of type #StoredType.
363 ///@return A reference to the just constructed object.
364 template<typename... TArgs>
365 TConstOrMutable& Construct( TArgs&&... args ) const
366 {
367 ALIB_ASSERT_ERROR( entry != nullptr, "MONOMEM/LRUCACHE", "Illegal iterator." )
368 return *new( &entry->data ) TConstOrMutable(std::forward<TArgs>(args)...);
369 }
370
371 /// Retrieves the stored object that this iterator references.
372 /// @return A reference to the stored object.
373 TConstOrMutable& Value() const
374 {
375 ALIB_ASSERT_ERROR( entry != nullptr, "MONOMEM/LRUCACHE", "Illegal iterator." )
376 return entry->data;
377 }
378
379 /// Retrieves the key-portion of the stored object that this iterator references.
380 /// @return A reference to the key-portion of the stored object.
381 const KeyType& Key() const
382 {
383 ALIB_ASSERT_ERROR( entry != nullptr, "MONOMEM/LRUCACHE", "Illegal iterator." )
384 return TValueDescriptor().Key(entry->data);
385 }
386
387 /// Retrieves the stored object that this iterator references.<br>
388 /// This method is an alias to <c>operator*</c>
389 /// @return A reference to the mapped-portion of the stored object.
391 {
392 ALIB_ASSERT_ERROR( entry != nullptr, "MONOMEM/LRUCACHE", "Illegal iterator." )
393 return TValueDescriptor().Mapped(entry->data);
394 }
395 }; // class TForwardIterator
396
397 public:
398 /// The mutable iterator over the cache entries.
399 using Iterator = TForwardIterator < StoredType>;
400
401 /// The constant iterator over the cache entries.
402 using ConstIterator = TForwardIterator <const StoredType>;
403
404 /// Returns an iterator referring to a mutable entry at the start of this cache.
405 /// @return The first of entry in this container.
406 Iterator begin() { return Iterator ( this, 0 ); }
407
408 /// Returns an iterator referring to a mutable, non-existing entry.
409 /// @return The end of the list of entries in this container.
410 Iterator end() { return Iterator ( this, (std::numeric_limits<integer>::max)() ); }
411
412 /// Returns an iterator referring to a constant entry at the start of this container.
413 /// @return The first of entry in this container.
414 ConstIterator begin() const { return ConstIterator( this, 0 ); }
415
416 /// Returns an iterator referring to a constant, non-existing entry.
417 /// @return The end of the list of entries in this container.
418 ConstIterator end() const { return ConstIterator( this, (std::numeric_limits<integer>::max)() ); }
419
420 /// Returns an iterator referring to a constant entry at the start of this container.
421 /// @return The first of entry in this container.
422 ConstIterator cbegin() const { return ConstIterator( this, 0 ); }
423
424 /// Returns an iterator referring to a constant, non-existing entry.
425 /// @return The end of the list of entries in this container.
426 ConstIterator cend() const { return ConstIterator( this, (std::numeric_limits<integer>::max)() ); }
427
428
429 /// Constructor taking an allocator as well as the sizes forming the capacity of the cache.
430 /// If one of the size parameters is \c 0, no pre-allocation is deferred and #Reserve has
431 /// to be invoked before using this type.
432 /// @param pAllocator The allocator type to use.
433 /// @param tableSize The number of LRU-lists.
434 /// @param listSize The (maximum) size of each list.
435 LRUCacheTable(TAllocator& pAllocator, integer tableSize, integer listSize )
436 : allocBase (pAllocator)
438 ,lang::DbgCriticalSections("LRUCacheTable")
439 #endif
440 , elementPool (nullptr)
441 , nextPoolElement (nullptr)
442 , capacityLists (0)
443 , capacityEntries (0) { Reserve( tableSize, listSize ); }
444
445 /// Constructor omitting the allocator, usable only with heap allocation
446 /// If one of the size parameters is \c 0, no pre-allocation is deferred and #Reserve has
447 /// to be invoked before using this type.
448 /// @param tableSize The number of LRU-lists.
449 /// @param listSize The (maximum) size of each list.
450 LRUCacheTable(integer tableSize, integer listSize )
451 :
453 lang::DbgCriticalSections("LRUCacheTable"),
454 #endif
455 elementPool (nullptr)
456 , nextPoolElement (nullptr)
457 , capacityLists (0)
458 , capacityEntries (0) { Reserve( tableSize, listSize ); }
459
460 /// Destructor. Calls the destructor of each cached value.
462 {
463 if( Capacity() == 0 )
464 return;
465 Clear();
466 allocBase::AI().template FreeArray<Entry >(elementPool, Capacity() );
467 allocBase::AI().template FreeArray<ForwardList>(lists , capacityLists );
468 }
469
470 /// Returns the number of lists used for the cache.
471 /// (Given with construction or a later invocation of method #Reserve.)
472 /// @return This caches' size.
474
475 /// Returns the maximum number of entries held in each list.
476 /// (Given with construction or a later invocation of method #Reserve.)
477 /// @return This caches' size.
479
480 /// Returns the product of #CapacityLists and #CapacityEntries.
481 /// (Both given with construction or a later invocation of method #Reserve.)
482 /// @return This caches' size.
484
485 /// Counts the number of stored elements (operates in O(N)).
486 /// @return The number of elements stored in the cache.
487 integer Size() const noexcept
489 integer result= 0;
490 for (int i = 0; i < capacityLists; ++i)
491 result+= lists[i].count();
492 return result;
493 }
494
495 /// Changes the size of this cache.
496 /// @param newQtyLists The number of LRU-lists to use.
497 /// @param newQtyEntriesPerList The maximum length of each LRU-list list.
498 void Reserve( integer newQtyLists, integer newQtyEntriesPerList )
499 {
500 if( CapacityLists() == newQtyLists
501 && CapacityEntries() == newQtyEntriesPerList )
502 return;
503
504 Clear();
506 auto newCapacity= newQtyLists * newQtyEntriesPerList;
507 if( Capacity() != newCapacity)
508 {
509 if( Capacity() != 0 )
510 allocBase::AI(). template FreeArray<Entry>(elementPool, Capacity());
511
512 elementPool = newCapacity ? allocBase::AI(). template AllocArray<Entry>(newCapacity)
513 : nullptr;
514 }
515
516 if( capacityLists != newQtyLists)
517 {
518 if( capacityLists )
519 allocBase::AI(). template FreeArray<ForwardList>(lists, capacityLists );
520 lists= newQtyLists ? allocBase::AI(). template AllocArray<ForwardList>(newQtyLists)
521 : nullptr;
522
524 for( integer i = 0; i < newQtyLists; ++i )
525 lists[i].reset();
527 }
528
529 capacityLists= newQtyLists;
530 capacityEntries= newQtyEntriesPerList;
532 }
533
534 /// Clears this cache.
535 void Clear()
536 {ALIB_DCS
538 for (integer i = 0; i < capacityLists; ++i)
539 {
540 auto* elem= lists[i].first();
541 while(elem)
542 {
543 lang::Destruct(elem->data);
544 elem= elem->next();
545 }
546 lists[i].reset();
547 }
550 }
551
552 /// Retrieves a value through this cache. The following cases can occur:
553 /// 1. No element with matching \p{key} is found in the cache while not all elements
554 /// of #elementPool are used, yet. In this case the next entry is taken from the pool, and
555 /// the entry is added to the front of the list.
556 /// 2. No element is found while all elements of the #elementPool have been inserted into the
557 /// list already. In this case the last entry of the list is removed, the destructor is
558 /// called on its contents, and the entry is moved to the front of the list.
559 /// 3. The element with matching \p{key} is found. In this case, the entry is moved to the start
560 /// of the list (if not already there).
561 ///
562 /// In cases 1. and 2., this method returns \c false in the first element of the result pair,
563 /// which tells the caller that the value found in the second element has to be constructed.
564 /// This can be done using convenient method
565 /// \alib{containers::LRUCacheTable::TForwardIterator;Construct;Iterator::Construct}.
566 /// Note that besides operator*
567 /// \alib{containers::LRUCacheTable::TForwardIterator;operator*}, the iterator type
568 /// offers methods
569 /// \alib{containers::LRUCacheTable::TForwardIterator;Key} and
570 /// \alib{containers::LRUCacheTable::TForwardIterator;Mapped} to directly access
571 /// corresponding portions of the stored value.
572 ///
573 /// @param key The key value to search for.
574 /// @return A pair of a boolean and an iterator. If the boolean value is \c true, a cached
575 /// entry was found and can be used. If it is \c false, the iterator is valid but
576 /// its data is not! In this case, the caller has to use a placement-new on the
577 /// address of the data receivable with the iterator. This might best be done by
578 /// calling \ref Iterator::Construct.
579 [[nodiscard]]
580 std::pair<bool, Iterator> Try(const KeyType& key)
581 {ALIB_DCS
582 ALIB_ASSERT_ERROR(Capacity() > 0, "MONOMEM", "Capacity of LRUCacheTable equals 0 (not set).")
583
584 // start the search below with the first element
585 const size_t keyHash = THash{}(key);
586 const integer listIdx = integer(keyHash % size_t(capacityLists));
588 auto& list = lists[listIdx];
590 Entry* prev2 = nullptr;
591 Entry* prev1 = reinterpret_cast<Entry*>(&list);
592 Entry* actual = list.first();
593 integer cnt = 0;
594
595
596 while( actual != nullptr )
597 {
598 if ( actual->hashCode == keyHash
599 && TEqual{}(TValueDescriptor().Key(actual->data), key) )
600 {
601 // Move the accessed item to the front
602 if (prev1 != nullptr)
603 {
604 prev1->next( actual->next() );
605 actual->next( list.next() );
606 list.next( actual );
607 }
608 return std::make_pair(true, Iterator(actual, this, listIdx ));
609 }
610 prev2= prev1;
611 prev1= actual;
612 actual= actual->next();
613 ++cnt;
614 }
615
616 // Value not found
617
618 // cache is full? -> take the last entry, change it and push it to the front.
619 if( cnt == capacityEntries )
620 {
621 prev2->next( nullptr );
622 prev1->data.~StoredType();
623 prev1->hashCode= keyHash;
624 prev1->next( list.next() );
625 list.next( prev1 );
626 return std::make_pair(false, Iterator(list.first(), this, listIdx ));
627 }
628
629 // cache not full yet -> Create new entry
631 Entry* newEntry= nextPoolElement++;
632 newEntry->hashCode= keyHash;
634 newEntry->next(list.next());
635 list.next(newEntry);
636 return std::make_pair(false, Iterator(list.first(), this, listIdx ));
637 }
638
639}; // struct LRUCacheTable
640
641
642
643/// This type definition is a shortcut to \alib{containers;LRUCacheTable}, usable if data
644/// stored in the container does not include a key-portion, and thus the key to the data
645/// retrievable from the cache has to be separately defined.<br>
646/// To achieve this, this type definition aggregates types \p{TKey} and \p{TMapped} into a
647/// <c>std::pair<TKey,TMapped></c>. This is done using special value descriptor type
648/// \alib{containers;TPairDescriptor}.
649///
650/// \see
651/// For a detailed description of this type, see original type
652/// \alib{containers;LRUCacheTable}, as well as alternative type definition
653/// \alib{containers;LRUCacheSet}.
654///
655/// @tparam TAllocator The allocator type to use, as prototyped with \alib{lang;Allocator}.
656/// @tparam TKey The type of the <em>key-portion</em> of the inserted data.<br>
657/// This type is published as \alib{containers;LRUCacheTable::KeyType}.
658/// @tparam TMapped The type of the <em>mapped-portion</em> of the inserted data.<br>
659/// This type is published as
660/// \alib{containers;LRUCacheTable::MappedType}.
661/// @tparam THash The hash functor applicable to \p{TKey}.<br>
662/// Defaults to <c>std::hash<TKey></c> and is published as
663/// \alib{containers;LRUCacheTable::HashType}.
664/// @tparam TEqual The comparison functor on \p{TKey}.<br>
665/// Defaults to <c>std::equal_to<TKey></c> and is published as
666/// \alib{containers;LRUCacheTable::EqualType}.
667template< typename TAllocator,
668 typename TKey, typename TMapped,
669 typename THash = std::hash <TKey>,
670 typename TEqual = std::equal_to<TKey> >
671using LRUCacheMap = LRUCacheTable< TAllocator,
673 THash, TEqual >;
674
675/// This type definition is a shortcut to \alib{containers;LRUCacheTable}, usable if the full
676/// portion of the data stored in the container is used for the comparison of values.
677///
678/// \note
679/// As with this definition template type \p{TKey} equals stored type \p{T}, methods of
680/// target type \alib{containers;LRUCacheTable} that accept an object of template type
681/// \b TKey expect an object of \p{T} when this type type defintion is used.<br>
682/// In case this is not wanted (or possible), and only the true key-portion should be expected
683/// by interface functions such as \alib{containers;LRUCacheTable::Try}, the underlying
684/// original type \alib{containers;LRUCacheTable}) has to be used.
685///
686/// \see
687/// For a detailed description of this type, see original type
688/// \alib{containers;LRUCacheTable}, as well as alternative type definition
689/// \alib{containers;LRUCacheMap}.
690///
691/// @tparam TAllocator The allocator type to use, as prototyped with \alib{lang;Allocator}.
692/// @tparam T The element type stored with this container.
693/// This type is published as
694/// \alib{containers;LRUCacheTable::StoredType} and type definition
695/// \alib{containers;LRUCacheTable::KeyType} becomes a synonym.
696/// @tparam THash The hash functor applicable to \p{T}. If \c void is given, no hashing
697/// is performed.<br>
698/// Defaults to <c>std::hash<T></c> and is published as
699/// \alib{containers;LRUCacheTable::HashType}.
700/// @tparam TEqual The comparison functor on \p{TKey}.<br>
701/// Defaults to <c>std::equal_to<TKey></c> and is published as
702/// \alib{containers;LRUCacheTable::EqualType}.
703template< typename TAllocator,
704 typename T,
705 typename THash = std::hash <T>,
706 typename TEqual = std::equal_to<T> >
707using LRUCacheSet = LRUCacheTable< TAllocator,
709 THash, TEqual >;
710
711} // namespace alib[::containers]
712
713/// Type alias in namespace \b alib.
714template< typename TAllocator,
715 typename TValueDescriptor,
716 typename THash = std::hash <typename TValueDescriptor::KeyType>,
717 typename TEqual = std::equal_to<typename TValueDescriptor::KeyType> >
719
720
721/// Type alias in namespace \b alib.
722template< typename TAllocator,
723 typename TKey, typename TMapped,
724 typename THash = std::hash <TKey>,
725 typename TEqual = std::equal_to<TKey> >
728
729/// Type alias in namespace \b alib.
730template< typename TAllocator,
731 typename T,
732 typename THash = std::hash <T>,
733 typename TEqual = std::equal_to<T> >
736 THash, TEqual >;
737} // namespace [alib]
738
739#endif // HPP_ALIB_MONOMEM_CONTAINERS_LRUCACHETABLE
740
LRUCacheTable * table
The pointer to the actual cache entry.
TConstOrMutable & Construct(TArgs &&... args) const
TConstOrMutable value_type
Implementation of std::iterator_traits.
std::forward_iterator_tag iterator_category
Implementation of std::iterator_traits.
bool operator!=(TForwardIterator other) const
TForwardIterator(LRUCacheTable *pTable, integer pListIdx)
TForwardIterator & operator=(const TForwardIterator &other)=default
bool operator==(TForwardIterator other) const
Entry * entry
The pointer to the actual cache entry.
TForwardIterator(Entry *pEntry, LRUCacheTable *pTable, integer pListIdx)
TConstOrMutable * pointer
Implementation of std::iterator_traits.
integer difference_type
Implementation of std::iterator_traits.
TConstOrMutable & reference
Implementation of std::iterator_traits.
TForwardIterator(const TForwardIterator &other)=default
LRUCacheTable(integer tableSize, integer listSize)
TAllocator AllocatorType
Type definition publishing template parameter TAllocator.
typename TValueDescriptor::MappedType MappedType
void Reserve(integer newQtyLists, integer newQtyEntriesPerList)
integer Size() const noexcept
THash HashType
Type definition publishing template parameter THash.
typename TValueDescriptor::KeyType KeyType
Entry * elementPool
Pointer to reserved memory for elements. Size is capacityLists x capacityEntries.
LRUCacheTable(TAllocator &pAllocator, integer tableSize, integer listSize)
~LRUCacheTable()
Destructor. Calls the destructor of each cached value.
ForwardList * lists
Array of size capacityLists that holds the list..
integer capacityLists
The number of LRU-lists.
TEqual EqualType
Type definition publishing template parameter TEqual.
void Clear()
Clears this cache.
std::pair< bool, Iterator > Try(const KeyType &key)
Entry * nextPoolElement
The next element to use with a cache-miss on a list that is not of full length, yet.
TForwardIterator< StoredType > Iterator
The mutable iterator over the cache entries.
TValueDescriptor DescriptorType
Type definition publishing template parameter TValueDescriptor.
integer capacityEntries
The number of entries collected in each LRU-list.
typename TValueDescriptor::StoredType StoredType
TForwardIterator< const StoredType > ConstIterator
The constant iterator over the cache entries.
#define ALIB_DCS
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:223
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ATMP_EQ( T, TEqual)
Definition tmp.hpp:27
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:760
#define ATMP_SELECT_IF_1TP(TParam, ...)
Definition tmp.hpp:58
#define ALIB_DCS_SHARED
#define ALIB_DEBUG_CRITICAL_SECTIONS
Definition prepro.md:44
static ALIB_FORCE_INLINE void Destruct(T &object)
Definition alib.cpp:69
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:273
The node type of the cache lists.
size_t hashCode
This entries hash code (calculated once on insertion)
AllocatorInterface< TAllocator > AI() const noexcept
ALIB_FORCE_INLINE DbgCriticalSections(const char *name)
void reset() noexcept
Resets this list to zero elements.
Definition sidilist.hpp:224
TElement * first() const noexcept
Definition sidilist.hpp:229
bool isEmpty() const noexcept
Definition sidilist.hpp:221
void next(SidiNodeBase *p)
Definition sidilist.hpp:101