4#include "Stroika/Foundation/Containers/Common.h"
6#include "Stroika/Foundation/Cryptography/Digest/Hash.h"
16 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
17 struct LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::CacheIterator_ {
18 explicit CacheIterator_ (CacheElement_**
start, CacheElement_** end)
24 CacheIterator_& operator++ ()
27 Require (fCurV != fEndV);
29 if (fCur ==
nullptr) {
40 return fCur->fElement;
45 return &fCur->fElement;
47 bool operator== (
const CacheIterator_&
rhs)
const
49 return fCur ==
rhs.fCur;
53 CacheElement_** fCurV;
54 CacheElement_** fEndV;
63 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
64 struct LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::CacheElement_ {
65 CacheElement_* fNext{
nullptr};
66 CacheElement_* fPrev{
nullptr};
75 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
81 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
82 inline LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::LRUCache (
size_t maxCacheSize,
const KEY_EQUALS_COMPARER& keyEqualsComparer)
83 requires (same_as<KEY_HASH_FUNCTION, nullptr_t>)
85 , fKeyEqualsComparer_{keyEqualsComparer}
86 , fHashFunction_{nullptr}
88 , fCachedElts_First_{Memory::eUninitialized, 1}
89 , fCachedElts_Last_{Memory::eUninitialized, 1}
91 Require (maxCacheSize >= 1);
92 SetMaxCacheSize (maxCacheSize);
94 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
95 inline LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::LRUCache (
size_t maxCacheSize,
96 const KEY_EQUALS_COMPARER& keyEqualsComparer,
97 size_t hashTableSize,
const KEY_HASH_FUNCTION& hashFunction)
98 requires (not same_as<KEY_HASH_FUNCTION, nullptr_t>)
99 : fHashtableSize_{hashTableSize}
100 , fKeyEqualsComparer_{keyEqualsComparer}
101 , fHashFunction_{hashFunction}
102 , fCachedElts_BUF_{hashTableSize}
103 , fCachedElts_First_{Memory::eUninitialized, hashTableSize}
104 , fCachedElts_Last_{Memory::eUninitialized, hashTableSize}
106 Require (hashTableSize >= 1);
108 SetMaxCacheSize (maxCacheSize);
110 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
111 inline LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::LRUCache (
size_t maxCacheSize,
size_t hashTableSize,
112 const KEY_HASH_FUNCTION& hashFunction)
113 requires (not same_as<KEY_HASH_FUNCTION, nullptr_t>)
114 : LRUCache{maxCacheSize, KEY_EQUALS_COMPARER{}, hashTableSize, hashFunction}
117 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
118 inline LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::LRUCache (LRUCache&& from)
125 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
127 requires (same_as<KEY_HASH_FUNCTION, nullptr_t>)
128 : LRUCache{from.GetMaxCacheSize (), from.GetKeyEqualsCompareFunction ()}
131 for (CacheIterator_ i =
from.begin_ (); i !=
from.end_ (); ++i) {
133 Add ((*i)->fKey, (*i)->fValue);
137 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
140 :
LRUCache{
from.GetMaxCacheSize (),
from.GetKeyEqualsCompareFunction (),
from.GetHashTableSize (),
from.GetKeyHashFunction ()}
143 for (CacheIterator_ i = from.begin_ (); i != from.end_ (); ++i) {
145 Add ((*i)->fKey, (*i)->fValue);
149 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
150 inline auto LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::operator= (LRUCache&& rhs)
noexcept -> LRUCache&
152 IgnoreExceptionsForCall (
return operator= (rhs));
154 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
155 auto LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::operator= (
const LRUCache& rhs) -> LRUCache&
159 SetMaxCacheSize (rhs.GetMaxCacheSize ());
161 for (
const auto& i :
rhs.Elements ()) {
163 Add (*i.fKey, *i.fValue);
169 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
170 inline size_t LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::GetMaxCacheSize ()
const
173 return fHashtableSize_ * fCachedElts_BUF_[0].
size ();
175 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
182 for (
size_t hi = 0;
hi < fHashtableSize_; ++
hi) {
188 fCachedElts_BUF_[
hi][0].fPrev =
nullptr;
190 fCachedElts_BUF_[
hi][i].fNext = fCachedElts_First_[
hi] + (i + 1);
191 fCachedElts_BUF_[
hi][i + 1].fPrev = fCachedElts_First_[
hi] + (i);
197 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
201 return fKeyEqualsComparer_;
203 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
209 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
210 inline auto LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::GetHashTableSize () const ->
size_t
217 return fHashtableSize_;
220 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
221 inline auto LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::GetKeyHashFunction () const -> KEY_HASH_FUNCTION
224 return fHashFunction_;
226 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
232 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
242 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
246 for (
auto i = begin_ (); i != end_ (); ++i) {
252 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
261 Ensure (fKeyEqualsComparer_ (
key, (*v)->fKey));
264 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
270 *v = KeyValuePair_{
key, value};
272 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
278 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
279 inline size_t LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::H_ ([[maybe_unused]]
typename Common::ArgByValueType<KEY> k)
const
281 Assert (fHashtableSize_ >= 1);
286 return fHashFunction_ (k) % fHashtableSize_;
289 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
294 for (CacheIterator_ i = begin_ (); i != end_ (); ++i) {
296 result.
Add ((*i)->fKey, (*i)->fValue);
301 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
306 if (v.has_value ()) {
315 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
319 return CacheIterator_{std::begin (
ncThis->fCachedElts_First_), std::end (
ncThis->fCachedElts_First_)};
321 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
322 inline typename LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::CacheIterator_
323 LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::end_ ()
const
325 return CacheIterator_{
nullptr,
nullptr};
327 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
328 inline void LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::ShuffleToHead_ (
size_t chainIdx, CacheElement_* b)
330 Require (
chainIdx < fHashtableSize_);
333 Assert (
b->fPrev ==
nullptr);
336 CacheElement_*
prev =
b->fPrev;
339 prev->fNext =
b->fNext;
340 if (
b->fNext ==
nullptr) {
341 Assert (
b == fCachedElts_Last_[
chainIdx]);
345 b->fNext->fPrev =
prev;
356 Ensure (fCachedElts_Last_[
chainIdx] !=
nullptr and fCachedElts_Last_[
chainIdx]->fNext ==
nullptr);
358 fCachedElts_First_[
chainIdx]->fPrev ==
nullptr and fCachedElts_First_[
chainIdx]->fNext !=
nullptr);
360 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
361 inline void LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::ClearCache_ ()
363 for (
size_t hi = 0;
hi < fHashtableSize_; ++
hi) {
364 for (CacheElement_*
cur = fCachedElts_First_[
hi];
cur !=
nullptr;
cur =
cur->fNext) {
369 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
370 inline auto LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::LookupElement_ (
typename Common::ArgByValueType<KeyType> item)
371 -> optional<KeyValuePair_>*
373 size_t chainIdx = H_ (item);
374 Assert (0 <= chainIdx and chainIdx < fHashtableSize_);
375 for (CacheElement_* cur = fCachedElts_First_[chainIdx]; cur !=
nullptr; cur = cur->fNext) {
376 if (cur->fElement and fKeyEqualsComparer_ (cur->fElement->fKey, item)) {
377 ShuffleToHead_ (chainIdx, cur);
378 fStats_.IncrementHits ();
379 return &fCachedElts_First_[chainIdx]->fElement;
382 fStats_.IncrementMisses ();
385 template <
typename KEY,
typename VALUE,
typename KEY_EQUALS_COMPARER,
typename KEY_HASH_FUNCTION,
typename STATS_TYPE>
386 inline auto LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>::AddNew_ (
typename Common::ArgByValueType<KeyType> item)
387 -> optional<KeyValuePair_>*
389 size_t chainIdx = H_ (item);
390 Assert (0 <= chainIdx and chainIdx < fHashtableSize_);
391 ShuffleToHead_ (chainIdx, fCachedElts_Last_[chainIdx]);
392 return &fCachedElts_First_[chainIdx]->fElement;
#define RequireNotNull(p)
#define WeakAssert(c)
A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be t...
LRUCache implements a simple least-recently-used caching strategy, with optional hashing (of keys) to...
nonvirtual Containers::Mapping< KEY, VALUE > Elements() const
nonvirtual void Add(typename Common::ArgByValueType< KEY > key, typename Common::ArgByValueType< VALUE > value)
nonvirtual void SetMaxCacheSize(size_t maxCacheSize)
nonvirtual VALUE LookupValue(typename Common::ArgByValueType< KEY > key, const function< VALUE(typename Common::ArgByValueType< KEY >)> &valueFetcher)
nonvirtual optional< VALUE > Lookup(typename Common::ArgByValueType< KEY > key)
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
nonvirtual size_t size() const noexcept
nonvirtual void resize(size_t nElements)
conditional_t<(sizeof(CHECK_T)<=2 *sizeof(void *)) and is_trivially_copyable_v< CHECK_T >, CHECK_T, const CHECK_T & > ArgByValueType
This is an alias for 'T' - but how we want to pass it on stack as formal parameter.
CONTAINER::value_type * Start(CONTAINER &c)
For a contiguous container (such as a vector or basic_string) - find the pointer to the start of the ...