Caches 0.1.0
LRU/LFU/FIFO Caches library
Loading...
Searching...
No Matches
cache.hpp
Go to the documentation of this file.
1
5#ifndef CACHE_HPP
6#define CACHE_HPP
7
8#include "cache_policy.hpp"
9
10#include <algorithm>
11#include <cstddef>
12#include <functional>
13#include <limits>
14#include <memory>
15#include <mutex>
16#include <stdexcept>
17#include <unordered_map>
18
19namespace caches
20{
24template <typename V>
25using WrappedValue = std::shared_ptr<V>;
26
35template <typename Key, typename Value, template <typename> class Policy = NoCachePolicy,
36 typename HashMap = std::unordered_map<Key, WrappedValue<Value>>>
38{
39 public:
40 using map_type = HashMap;
41 using value_type = typename map_type::mapped_type;
42 using iterator = typename map_type::iterator;
43 using const_iterator = typename map_type::const_iterator;
44 using operation_guard = typename std::lock_guard<std::mutex>;
45 using on_erase_cb =
46 typename std::function<void(const Key &key, const value_type &value)>;
47
56 size_t max_size, const Policy<Key> policy = Policy<Key>{},
57 on_erase_cb on_erase = [](const Key &, const value_type &) {})
58 : cache_policy{policy}, max_cache_size{max_size}, on_erase_callback{on_erase}
59 {
60 if (max_cache_size == 0)
61 {
62 throw std::invalid_argument{"Size of the cache should be non-zero"};
63 }
64 }
65
66 ~fixed_sized_cache() noexcept
67 {
68 Clear();
69 }
70
76 void Put(const Key &key, const Value &value) noexcept
77 {
78 operation_guard lock{safe_op};
79 auto elem_it = FindElem(key);
80
81 if (elem_it == cache_items_map.end())
82 {
83 // add new element to the cache
84 if (cache_items_map.size() + 1 > max_cache_size)
85 {
86 auto disp_candidate_key = cache_policy.ReplCandidate();
87
88 Erase(disp_candidate_key);
89 }
90
91 Insert(key, value);
92 }
93 else
94 {
95 // update previous value
96 Update(key, value);
97 }
98 }
99
108 std::pair<value_type, bool> TryGet(const Key &key) const noexcept
109 {
110 operation_guard lock{safe_op};
111 const auto result = GetInternal(key);
112
113 return std::make_pair(result.second ? result.first->second : nullptr,
114 result.second);
115 }
116
125 value_type Get(const Key &key) const
126 {
127 operation_guard lock{safe_op};
128 auto elem = GetInternal(key);
129
130 if (elem.second)
131 {
132 return elem.first->second;
133 }
134 else
135 {
136 throw std::range_error{"No such element in the cache"};
137 }
138 }
139
146 bool Cached(const Key &key) const noexcept
147 {
148 operation_guard lock{safe_op};
149 return FindElem(key) != cache_items_map.cend();
150 }
151
156 std::size_t Size() const
157 {
158 operation_guard lock{safe_op};
159
160 return cache_items_map.size();
161 }
162
169 bool Remove(const Key &key)
170 {
171 operation_guard lock{safe_op};
172
173 auto elem = FindElem(key);
174
175 if (elem == cache_items_map.end())
176 {
177 return false;
178 }
179
180 Erase(elem);
181
182 return true;
183 }
184
185 protected:
186 void Clear()
187 {
188 operation_guard lock{safe_op};
189
190 std::for_each(begin(), end(),
191 [&](const std::pair<const Key, value_type> &el)
192 { cache_policy.Erase(el.first); });
193 cache_items_map.clear();
194 }
195
196 const_iterator begin() const noexcept
197 {
198 return cache_items_map.cbegin();
199 }
200
201 const_iterator end() const noexcept
202 {
203 return cache_items_map.cend();
204 }
205
206 protected:
207 void Insert(const Key &key, const Value &value)
208 {
209 cache_policy.Insert(key);
210 cache_items_map.emplace(std::make_pair(key, std::make_shared<Value>(value)));
211 }
212
213 void Erase(const_iterator elem)
214 {
215 cache_policy.Erase(elem->first);
216 on_erase_callback(elem->first, elem->second);
217 cache_items_map.erase(elem);
218 }
219
220 void Erase(const Key &key)
221 {
222 auto elem_it = FindElem(key);
223
224 Erase(elem_it);
225 }
226
227 void Update(const Key &key, const Value &value)
228 {
229 cache_policy.Touch(key);
230 cache_items_map[key] = std::make_shared<Value>(value);
231 }
232
233 const_iterator FindElem(const Key &key) const
234 {
235 return cache_items_map.find(key);
236 }
237
238 std::pair<const_iterator, bool> GetInternal(const Key &key) const noexcept
239 {
240 auto elem_it = FindElem(key);
241
242 if (elem_it != end())
243 {
244 cache_policy.Touch(key);
245 return {elem_it, true};
246 }
247
248 return {elem_it, false};
249 }
250
251 private:
252 map_type cache_items_map;
253 mutable Policy<Key> cache_policy;
254 mutable std::mutex safe_op;
255 std::size_t max_cache_size;
256 on_erase_cb on_erase_callback;
257};
258} // namespace caches
259
260#endif // CACHE_HPP
std::shared_ptr< V > WrappedValue
Wrapper over the given value type to allow safe returning of a value from the cache.
Definition: cache.hpp:25
Cache policy interface declaration.
Basic no caching policy class.
Definition: cache_policy.hpp:57
Fixed sized cache that can be used with different policy types (e.g. LRU, FIFO, LFU)
Definition: cache.hpp:38
void Put(const Key &key, const Value &value) noexcept
Put element into the cache.
Definition: cache.hpp:76
value_type Get(const Key &key) const
Get element from the cache if present.
Definition: cache.hpp:125
fixed_sized_cache(size_t max_size, const Policy< Key > policy=Policy< Key >{}, on_erase_cb on_erase=[](const Key &, const value_type &) {})
Fixed sized cache constructor.
Definition: cache.hpp:55
bool Remove(const Key &key)
Definition: cache.hpp:169
bool Cached(const Key &key) const noexcept
Check whether the given key is presented in the cache.
Definition: cache.hpp:146
std::pair< value_type, bool > TryGet(const Key &key) const noexcept
Try to get an element by the given key from the cache.
Definition: cache.hpp:108
std::size_t Size() const
Get number of elements in cache.
Definition: cache.hpp:156