step20
Loading...
Searching...
No Matches
least_recently_used.hpp
Go to the documentation of this file.
1// Andrew Naplavkov
2
3#ifndef STEP20_LEAST_RECENTLY_USED_HPP
4#define STEP20_LEAST_RECENTLY_USED_HPP
5
6#include <list>
7#include <unordered_map>
8
10namespace detail {
11
12template <class Key,
13 class T,
14 class Hash = std::hash<Key>,
15 class KeyEqual = std::equal_to<Key>>
16class linked_hash_map {
17public:
18 using value_type = std::pair<const Key, T>;
19 using list_type = std::list<value_type>;
20 using iterator = typename list_type::iterator;
21 linked_hash_map() = default;
22 linked_hash_map(linked_hash_map&&) = default;
23 linked_hash_map& operator=(linked_hash_map&&) = default;
24 linked_hash_map(const linked_hash_map&) = delete;
25 linked_hash_map& operator=(const linked_hash_map&) = delete;
26 virtual ~linked_hash_map() = default;
27 auto size() const { return list_.size(); }
28 iterator begin() { return list_.begin(); }
29 iterator end() { return list_.end(); }
30 void transfer(iterator from, iterator to) { list_.splice(to, list_, from); }
31
32 iterator find(const Key& key)
33 {
34 auto it = map_.find(key);
35 return it == map_.end() ? list_.end() : it->second;
36 }
37
38 iterator erase(iterator it)
39 {
40 map_.erase(it->first);
41 return list_.erase(it);
42 }
43
44 template <class M>
45 std::pair<iterator, bool> emplace(iterator it, const Key& key, M&& val)
46 {
47 if (auto pos = find(key); pos != end())
48 return {pos, false};
49 it = list_.emplace(it, key, std::forward<M>(val));
50 try {
51 map_.emplace(key, it);
52 return {it, true};
53 }
54 catch (...) {
55 list_.erase(it);
56 throw;
57 }
58 }
59
60private:
61 list_type list_;
62 std::unordered_map<Key, iterator, Hash, KeyEqual> map_;
63};
64
65} // namespace detail
66
68template <class Key,
69 class T,
70 class Hash = std::hash<Key>,
71 class KeyEqual = std::equal_to<Key>>
72class cache {
73 detail::linked_hash_map<Key, T, Hash, KeyEqual> map_;
74 std::size_t capacity_;
75
76public:
77 explicit cache(std::size_t capacity) : capacity_(capacity) {}
78 cache(cache&&) = default;
79 cache& operator=(cache&&) = default;
80 cache(const cache&) = delete;
81 cache& operator=(const cache&) = delete;
82 virtual ~cache() = default;
83
85 const T* find(const Key& key)
86 {
87 auto it = map_.find(key);
88 if (it == map_.end())
89 return nullptr;
90 map_.transfer(it, map_.end());
91 return std::addressof(it->second);
92 }
93
96 void insert_or_assign(const Key& key, const T& val)
97 {
98 auto [it, success] = map_.emplace(map_.end(), key, val);
99 if (!success) {
100 map_.transfer(it, map_.end());
101 it->second = val;
102 return;
103 }
104 while (map_.size() > capacity_)
105 map_.erase(map_.begin());
106 }
107};
108
109} // namespace step20::least_recently_used
110
111#endif // STEP20_LEAST_RECENTLY_USED_HPP
An O(1) algorithm for implementing the LRU cache eviction scheme.
Definition least_recently_used.hpp:72
const T * find(const Key &key)
Definition least_recently_used.hpp:85
cache & operator=(cache &&)=default
cache & operator=(const cache &)=delete
void insert_or_assign(const Key &key, const T &val)
Definition least_recently_used.hpp:96
cache(std::size_t capacity)
Definition least_recently_used.hpp:77
Definition least_recently_used.hpp:9
To to(From &&from)
Definition to.hpp:13