14 #include <shared_mutex>
15 #include <unordered_map>
23 template <
typename key_t,
typename value_t>
26 using LoadFn = std::function<std::shared_ptr<value_t>(
const key_t&)>;
39 std::shared_ptr<value_t>
Get(
const key_t& key);
52 typedef typename std::pair<key_t, std::shared_ptr<value_t>>
54 typedef typename std::list<key_value_pair_t>::iterator list_iterator_t;
57 const size_t max_num_elems_;
60 std::list<key_value_pair_t> elems_list_;
63 std::unordered_map<key_t, list_iterator_t> elems_map_;
70 template <
typename key_t,
typename value_t>
73 using LoadFn = std::function<std::shared_ptr<value_t>(
const key_t&)>;
82 bool Exists(
const key_t& key)
const;
86 std::shared_ptr<value_t>
Get(
const key_t& key);
90 bool Evict(
const key_t& key);
101 std::promise<std::shared_ptr<value_t>>
promise;
102 std::shared_future<std::shared_ptr<value_t>>
future;
117 template <
typename key_t,
typename value_t>
120 using LoadFn = std::function<std::shared_ptr<value_t>(
const key_t&)>;
138 std::shared_ptr<value_t>
Get(
const key_t& key);
151 typedef typename std::pair<key_t, std::shared_ptr<value_t>>
153 typedef typename std::list<key_value_pair_t>::iterator list_iterator_t;
155 const size_t max_num_bytes_;
159 std::list<key_value_pair_t> elems_list_;
162 std::unordered_map<key_t, std::pair<list_iterator_t, size_t>> elems_map_;
172 template <
typename key_t,
typename value_t>
174 : max_num_elems_(max_num_elems), load_fn_(
std::move(load_fn)) {
176 CHECK_GT(max_num_elems, 0);
179 template <
typename key_t,
typename value_t>
181 return elems_map_.size();
184 template <
typename key_t,
typename value_t>
186 return max_num_elems_;
189 template <
typename key_t,
typename value_t>
191 return elems_map_.find(key) != elems_map_.end();
194 template <
typename key_t,
typename value_t>
196 const auto it = elems_map_.find(key);
197 if (it == elems_map_.end()) {
198 auto it = elems_map_.find(key);
199 elems_list_.emplace_front(key, load_fn_(key));
200 if (it != elems_map_.end()) {
201 elems_list_.erase(it->second);
202 elems_map_.erase(it);
204 it = elems_map_.emplace_hint(it, key, elems_list_.begin());
205 if (elems_map_.size() > max_num_elems_) {
208 return it->second->second;
210 elems_list_.splice(elems_list_.begin(), elems_list_, it->second);
211 return it->second->second;
215 template <
typename key_t,
typename value_t>
217 const auto it = elems_map_.find(key);
218 if (it != elems_map_.end()) {
219 elems_list_.erase(it->second);
220 elems_map_.erase(it);
226 template <
typename key_t,
typename value_t>
228 if (!elems_list_.empty()) {
229 auto last = elems_list_.end();
231 elems_map_.erase(last->first);
232 elems_list_.pop_back();
236 template <
typename key_t,
typename value_t>
242 template <
typename key_t,
typename value_t>
244 const size_t max_num_elems,
LoadFn load_fn)
245 : load_fn_(load_fn), cache_(max_num_elems, [](const key_t&) {
246 return std::make_shared<Entry>();
251 template <
typename key_t,
typename value_t>
253 std::shared_lock lock(cache_mutex_);
254 return cache_.NumElems();
257 template <
typename key_t,
typename value_t>
259 std::shared_lock lock(cache_mutex_);
260 return cache_.MaxNumElems();
263 template <
typename key_t,
typename value_t>
265 std::shared_lock lock(cache_mutex_);
266 return cache_.Exists(key);
269 template <
typename key_t,
typename value_t>
272 bool should_load =
false;
273 std::shared_ptr<Entry> entry;
274 std::shared_future<std::shared_ptr<value_t>> shared_future;
277 std::unique_lock lock(cache_mutex_);
278 entry = cache_.Get(key);
279 if (entry ==
nullptr) {
282 shared_future = entry->future;
283 if (!entry->is_loading) {
285 entry->is_loading =
true;
291 entry->promise.set_value(CHECK_NOTNULL(load_fn_(key)));
294 std::unique_lock lock(cache_mutex_);
296 entry->promise.set_exception(std::current_exception());
300 return shared_future.get();
303 template <
typename key_t,
typename value_t>
305 std::unique_lock lock(cache_mutex_);
306 return cache_.Evict(key);
309 template <
typename key_t,
typename value_t>
311 std::unique_lock lock(cache_mutex_);
315 template <
typename key_t,
typename value_t>
317 std::unique_lock lock(cache_mutex_);
318 return cache_.Clear();
321 template <
typename key_t,
typename value_t>
323 const size_t max_num_bytes,
LoadFn load_fn)
324 : max_num_bytes_(max_num_bytes),
326 load_fn_(
std::move(load_fn)) {
328 CHECK_GT(max_num_bytes, 0);
331 template <
typename key_t,
typename value_t>
333 return elems_map_.size();
336 template <
typename key_t,
typename value_t>
341 template <
typename key_t,
typename value_t>
343 return max_num_bytes_;
346 template <
typename key_t,
typename value_t>
348 return elems_map_.find(key) != elems_map_.end();
351 template <
typename key_t,
typename value_t>
354 const auto it = elems_map_.find(key);
355 if (it == elems_map_.end()) {
356 std::shared_ptr<value_t> value = load_fn_(key);
357 const size_t num_bytes = value->NumBytes();
358 auto it = elems_map_.find(key);
359 elems_list_.emplace_front(key, std::move(value));
360 if (it != elems_map_.end()) {
361 elems_list_.erase(it->second.first);
362 elems_map_.erase(it);
364 it = elems_map_.emplace_hint(
367 num_bytes_ += num_bytes;
368 while (num_bytes_ > max_num_bytes_ && elems_map_.size() > 1) {
372 return it->second.first->second;
374 elems_list_.splice(elems_list_.begin(), elems_list_, it->second.first);
375 return it->second.first->second;
379 template <
typename key_t,
typename value_t>
381 const auto it = elems_map_.find(key);
382 if (it != elems_map_.end()) {
383 num_bytes_ -= it->second.second;
384 elems_list_.erase(it->second.first);
385 elems_map_.erase(it);
391 template <
typename key_t,
typename value_t>
393 if (!elems_list_.empty()) {
394 auto last = elems_list_.end();
396 const auto it = elems_map_.find(last->first);
397 num_bytes_ -= it->second.second;
398 CHECK_GE(num_bytes_, 0);
399 elems_map_.erase(it);
400 elems_list_.pop_back();
404 template <
typename key_t,
typename value_t>
407 size_t& num_bytes = elems_map_.at(key).second;
408 num_bytes_ -= num_bytes;
409 CHECK_GE(num_bytes_, 0);
410 num_bytes = Get(key)->NumBytes();
411 num_bytes_ += num_bytes;
413 while (num_bytes_ > max_num_bytes_ && elems_map_.size() > 1) {
418 template <
typename key_t,
typename value_t>
LRUCache(size_t max_num_elems, LoadFn load_fn)
std::function< std::shared_ptr< value_t >(const key_t &)> LoadFn
std::shared_ptr< value_t > Get(const key_t &key)
size_t MaxNumElems() const
bool Evict(const key_t &key)
bool Exists(const key_t &key) const
std::shared_ptr< value_t > Get(const key_t &key)
void UpdateNumBytes(const key_t &key)
bool Evict(const key_t &key)
std::function< std::shared_ptr< value_t >(const key_t &)> LoadFn
size_t MaxNumElems() const
bool Exists(const key_t &key) const
size_t MaxNumBytes() const
MemoryConstrainedLRUCache(size_t max_num_bytes, LoadFn load_fn)
std::shared_ptr< value_t > Get(const key_t &key)
bool Exists(const key_t &key) const
std::shared_mutex cache_mutex_
std::function< std::shared_ptr< value_t >(const key_t &)> LoadFn
ThreadSafeLRUCache(size_t max_num_elems, LoadFn load_fn)
bool Evict(const key_t &key)
LRUCache< key_t, Entry > cache_
size_t MaxNumElems() const
CLOUDVIEWER_HOST_DEVICE Pair< First, Second > make_pair(const First &_first, const Second &_second)
std::promise< std::shared_ptr< value_t > > promise
std::shared_future< std::shared_ptr< value_t > > future