Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
SynchronizedLRUCache.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Cache_SynchronizedLRUCache_h_
5#define _Stroika_Foundation_Cache_SynchronizedLRUCache_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <mutex>
10#include <shared_mutex>
11
12#include "Stroika/Foundation/Cache/LRUCache.h"
13
14/**
15 * \file
16 *
17 * \note Code-Status: <a href="Code-Status.md#Beta">Beta</a>
18 *
19 * TODO:
20 * @todo Get rid of copied/cloned CTORs (just for deduction guides) - and get the explicit deduction guides working
21 *
22 * @todo Add 'overrides' for Add/Remove methods - so those are safe too!
23 * and add more overloads (from base class) of Lookup
24 *
25 * @todo Copy CTOR should copy Stats as well (lopri)
26 */
27
29
30 /**
31 * \brief simple wrapper on LRUCache (with the same API) - but internally synchronized in a way that is
32 * more performant than using RWSyncrhonzied<LRUCache<...>>
33 *
34 * @see LRUCache<> - for unsynchronized base version
35 *
36 * \note \em Thread-Safety <a href="Thread-Safety.md#Internally-Synchronized-Thread-Safety">Internally-Synchronized-Thread-Safety</a>
37 */
38 template <typename KEY, typename VALUE, typename KEY_EQUALS_COMPARER = equal_to<KEY>, typename KEY_HASH_FUNCTION = nullptr_t, typename STATS_TYPE = Statistics::StatsType_DEFAULT>
39 class SynchronizedLRUCache : private LRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE> {
41
42 public:
43 using StatsType = typename inherited::StatsType;
44
45 public:
46 using KeyEqualsCompareFunctionType = typename inherited::KeyEqualsCompareFunctionType;
47
48 public:
49 /**
50 * @see LRUCache constructor for examples, or SynchronizedLRUCache_NoHash, SynchronizedLRUCache_WithHash
51 */
52 template <typename... ARGS>
55
56 public:
57 // @todo support - sb easy
58 nonvirtual SynchronizedLRUCache& operator= (const SynchronizedLRUCache&) = delete;
59
60 public:
61 /*
62 * Note: We choose to not hold any lock while filling the cache (fHoldWriteLockDuringCacheFill false by default).
63 * This is because typically, filling the cache will be slow (otherwise you wouldn't be us using a cache).
64 *
65 * But this has the downside, that you could try filling the cache multiple times with the same value.
66 *
67 * That's perfectly safe, but not speedy.
68 *
69 * Which is better depends on the likihood the caller will make multiple requests for the same non-existent value at
70 * the same time. If yes, you should set fHoldWriteLockDuringCacheFill. If no (or if you care more about being able to
71 * read the rest of the data and not having threads block needlessly for other values) set fHoldWriteLockDuringCacheFill false (default).
72 */
73 bool fHoldWriteLockDuringCacheFill{false};
74
75 public:
76 /**
77 * @see LRUCache::GetMaxCacheSize ()
78 */
79 nonvirtual size_t GetMaxCacheSize () const;
80
81 public:
82 /**
83 * @see LRUCache::SetMaxCacheSize ()
84 */
85 nonvirtual void SetMaxCacheSize (size_t maxCacheSize);
86
87 public:
88 /**
89 * @see LRUCache::GetStats ()
90 */
91 nonvirtual StatsType GetStats () const;
92
93 public:
94 /**
95 * @see LRUCache::GetKeyEqualsCompareFunction ()
96 */
97 nonvirtual KeyEqualsCompareFunctionType GetKeyEqualsCompareFunction () const;
98
99 public:
100 /**
101 * @see LRUCache::GetHashTableSize ()
102 */
103 nonvirtual size_t GetHashTableSize () const;
104
105 public:
106 /**
107 * @see LRUCache::GetKeyHashFunction ()
108 */
109 nonvirtual KEY_HASH_FUNCTION GetKeyHashFunction () const;
110
111 public:
112 /**
113 * @see LRUCache::clear ()
114 */
115 nonvirtual void clear ();
116 nonvirtual void clear (typename Common::ArgByValueType<KEY> key);
117 nonvirtual void clear (function<bool (typename Common::ArgByValueType<KEY>)> clearPredicate);
118
119 public:
120 /**
121 * \note - though this is not technically 'const' - it acts (from a thread safety point of view) as const, so its marked const
122 * @see LRUCache::Lookup ()
123 */
124 nonvirtual optional<VALUE> Lookup (typename Common::ArgByValueType<KEY> key) const;
125
126 public:
127 /**
128 * @see LRUCache::LookupValue ()
129 */
130 nonvirtual VALUE LookupValue (typename Common::ArgByValueType<KEY> key, const function<VALUE (typename Common::ArgByValueType<KEY>)>& valueFetcher);
131
132 public:
133 /**
134 * Add the given value to the cache. This is rarely directly used.
135 */
136 nonvirtual void Add (typename Common::ArgByValueType<KEY> key, typename Common::ArgByValueType<VALUE> value);
137
138 public:
139 /**
140 * @see LRUCache::Elements ()
141 */
142 nonvirtual Containers::Mapping<KEY, VALUE> Elements () const;
143
144 private:
145 mutable shared_timed_mutex fMutex_;
146 };
147
148 namespace Factory {
149 /**
150 * \note - no way to extract the KEY from the KEY_EQUALS_COMPARER, because this comparer might have templated operator(), such
151 * as String::EqualsComparer.
152 *
153 * \par Example Usage
154 * \code
155 * auto t0{Factory::SynchronizedLRUCache_NoHash<string, string>{}()};
156 * auto t1{Factory::SynchronizedLRUCache_NoHash<string, string>{}(3)};
157 * SynchronizedLRUCache t2{Factory::SynchronizedLRUCache_NoHash<String, string>{}(3, kStringCIComparer_)};
158 * \endcode
159 */
160 template <typename KEY, typename VALUE, typename STATS_TYPE = Statistics::StatsType_DEFAULT>
161 struct SynchronizedLRUCache_NoHash {
162 template <Common::IEqualsComparer<KEY> KEY_EQUALS_COMPARER = equal_to<KEY>>
163 auto operator() (size_t maxCacheSize = 1, const KEY_EQUALS_COMPARER& keyComparer = {}) const
164 {
165 return SynchronizedLRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, nullptr_t, STATS_TYPE>{maxCacheSize, keyComparer};
166 }
167 };
168
169 /**
170 * \par Example Usage
171 * \code
172 * auto t0{Factory::SynchronizedLRUCache_WithHash<string, string>{}(3, 3)};
173 * auto t1{Factory::SynchronizedLRUCache_WithHash<String, string>{}(3, 3, hashFunction)};
174 * SynchronizedLRUCache t2{Factory::SynchronizedLRUCache_WithHash<String, string>{}(3, equal_to<String>{}, 3)};
175 * SynchronizedLRUCache t3{Factory::SynchronizedLRUCache_WithHash<String, string, Statistics::Stats_Basic>{}(3, equal_to<String>{}, 3)}; // throw in stats object
176 * SynchronizedLRUCache t4{Factory::SynchronizedLRUCache_WithHash<String, string>{}(3, kStringCIComparer_, 3)}; // alt equality comparer
177 * \endcode
178 */
179 template <typename KEY, typename VALUE, typename STATS_TYPE = Statistics::StatsType_DEFAULT, typename DEFAULT_KEY_EQUALS_COMPARER = equal_to<KEY>>
180 struct SynchronizedLRUCache_WithHash {
181 template <typename KEY_HASH_FUNCTION = hash<KEY>>
182 auto operator() (size_t maxCacheSize, size_t hastTableSize, const KEY_HASH_FUNCTION& hashFunction = {}) const
183 {
184 Require (maxCacheSize >= hastTableSize);
185 return SynchronizedLRUCache<KEY, VALUE, DEFAULT_KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>{
186 maxCacheSize, DEFAULT_KEY_EQUALS_COMPARER{}, hastTableSize, hashFunction};
187 }
188 template <typename KEY_EQUALS_COMPARER, typename KEY_HASH_FUNCTION = hash<KEY>>
189 auto operator() (size_t maxCacheSize, const KEY_EQUALS_COMPARER& keyComparer, size_t hastTableSize,
190 const KEY_HASH_FUNCTION& hashFunction = {}) const
191 {
192 Require (maxCacheSize >= hastTableSize);
193 return SynchronizedLRUCache<KEY, VALUE, KEY_EQUALS_COMPARER, KEY_HASH_FUNCTION, STATS_TYPE>{maxCacheSize, keyComparer,
194 hastTableSize, hashFunction};
195 }
196 };
197
198 }
199
200}
201
202/*
203 ********************************************************************************
204 ***************************** Implementation Details ***************************
205 ********************************************************************************
206 */
207#include "SynchronizedLRUCache.inl"
208
209#endif /*_Stroika_Foundation_Cache_SynchronizedLRUCache_h_*/
LRUCache implements a simple least-recently-used caching strategy, with optional hashing (of keys) to...
Definition LRUCache.h:94
simple wrapper on LRUCache (with the same API) - but internally synchronized in a way that is more pe...
nonvirtual optional< VALUE > Lookup(typename Common::ArgByValueType< KEY > key) const
nonvirtual void SetMaxCacheSize(size_t maxCacheSize)
nonvirtual KEY_HASH_FUNCTION GetKeyHashFunction() const
nonvirtual Containers::Mapping< KEY, VALUE > Elements() const
nonvirtual KeyEqualsCompareFunctionType GetKeyEqualsCompareFunction() const
nonvirtual VALUE LookupValue(typename Common::ArgByValueType< KEY > key, const function< VALUE(typename Common::ArgByValueType< KEY >)> &valueFetcher)
nonvirtual void Add(typename Common::ArgByValueType< KEY > key, typename Common::ArgByValueType< VALUE > value)
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.
Definition TypeHints.h:32