Vanetza
 
Loading...
Searching...
No Matches
lru_cache.hpp
1#ifndef LRU_CACHE_HPP_CII58WXX
2#define LRU_CACHE_HPP_CII58WXX
3
4#include <cassert>
5#include <functional>
6#include <list>
7#include <unordered_map>
8
9namespace vanetza
10{
11
12/**
13 * \brief Least-Recently-Used cache
14 *
15 * If an entry is accessed which is not yet cached, it will created
16 * by invocation of the generator function.
17 *
18 * \tparam KEY key type
19 * \tparam VALUE value_type, i.e. type of cache entries
20 * \tparam GENERATOR generator function for creating values from key
21 */
22template<typename KEY, typename VALUE, typename GENERATOR = std::function<VALUE(const KEY&)>>
24{
25public:
26 using generator = GENERATOR;
27 using key_type = KEY;
28 using value_type = VALUE;
29
30 /**
31 * \param g user-defined generator function
32 * \param capacity maximum number of cache entries
33 */
34 LruCache(generator g, std::size_t capacity) :
35 m_generator(g),
36 m_capacity(capacity)
37 {
38 }
39
40 /**
41 * \brief Access a cache entry
42 *
43 * If cache entry does not yet exist it will be created.
44 * The least recently accessed entry might get dropped.
45 *
46 * \param key identifier of cache entry
47 * \return cached value
48 */
49 value_type& operator[](const key_type& key)
50 {
51 auto found = m_cache.find(key);
52 if (found == m_cache.end()) {
53 return add(key);
54 } else {
55 return refresh(found);
56 }
57 }
58
59private:
60 using list_type = std::list<key_type>;
61 using entry_type = std::pair<value_type, typename list_type::iterator>;
62 using map_type = std::unordered_map<key_type, entry_type>;
63
64 value_type& add(const key_type& k)
65 {
66 if (m_cache.size() >= m_capacity) {
67 remove();
68 }
69
70 m_index.emplace_front(k);
71 entry_type entry = std::make_pair(m_generator(k), m_index.begin());
72 auto insertion = m_cache.insert(std::make_pair(k, std::move(entry)));
73 assert(insertion.second == true);
74 return insertion.first->second.first;
75 }
76
77 value_type& refresh(typename map_type::iterator found)
78 {
79 m_index.splice(m_index.begin(), m_index, found->second.second);
80 assert(m_index.begin() == found->second.second);
81 return found->second.first;
82 }
83
84 void remove()
85 {
86 if (!m_index.empty()) {
87 m_cache.erase(m_index.back());
88 m_index.pop_back();
89 }
90 }
91
92 generator m_generator;
93 std::size_t m_capacity;
94 list_type m_index;
95 map_type m_cache;
96};
97
98} // namespace vanetza
99
100#endif /* LRU_CACHE_HPP_CII58WXX */
101
Least-Recently-Used cache.
Definition: lru_cache.hpp:24
value_type & operator[](const key_type &key)
Access a cache entry.
Definition: lru_cache.hpp:49
LruCache(generator g, std::size_t capacity)
Definition: lru_cache.hpp:34