Point Cloud Library (PCL)  1.15.1-dev
lru_cache.hpp
1 
2 #ifndef __PCL_OUTOFCORE_LRU_CACHE__
3 #define __PCL_OUTOFCORE_LRU_CACHE__
4 
5 #include <cstddef>
6 #include <cassert>
7 #include <list>
8 #include <map>
9 #include <utility>
10 
11 template<typename T>
13 {
14 public:
15 
16  virtual std::size_t
17  sizeOf () const
18  {
19  return sizeof (item);
20  }
21 
22  virtual
23  ~LRUCacheItem () = default;
24 
25  T item;
26  std::size_t timestamp;
27 };
28 
29 template<typename KeyT, typename CacheItemT>
30 class LRUCache
31 {
32 public:
33 
34  using KeyIndex = std::list<KeyT>;
35  using KeyIndexIterator = typename KeyIndex::iterator;
36  using Cache = std::map<KeyT, std::pair<CacheItemT, typename KeyIndex::iterator> >;
37 
38  LRUCache (std::size_t c) :
39  capacity_ (c)
40  {
41  assert(capacity_ != 0);
42  }
43 
44  bool
45  hasKey (const KeyT& k)
46  {
47  return (cache_.find (k) != cache_.end ());
48  }
49 
50  CacheItemT&
51  get (const KeyT& k)
52  {
53  // Get existing key
54  const auto it = cache_.find (k);
55  assert(it != cache_.end ());
56 
57  // Move key to MRU key index
58  key_index_.splice (key_index_.end (), key_index_, (*it).second.second);
59 
60  // Return the retrieved item
61  return it->second.first;
62  }
63 
64  void
65  touch (const KeyT& key)
66  {
67  // Get existing key
68  const auto it = cache_.find (key);
69  assert(it != cache_.end ());
70 
71  // Move key to MRU key index
72  key_index_.splice (key_index_.end (), key_index_, it->second.second);
73  }
74 
75  // Record a fresh key-value pair in the cache
76  bool
77  insert (const KeyT& key, const CacheItemT& value)
78  {
79  if (cache_.find (key) != cache_.end ())
80  {
81  touch (key);
82  return true;
83  }
84 
85  std::size_t size = size_;
86  std::size_t item_size = value.sizeOf ();
87  int evict_count = 0;
88 
89  // Get LRU key iterator
90  auto key_it = key_index_.begin ();
91 
92  while (size + item_size >= capacity_)
93  {
94  const auto cache_it = cache_.find (*key_it);
95 
96  // Get tail item (Least Recently Used)
97  std::size_t tail_timestamp = cache_it->second.first.timestamp;
98  std::size_t tail_size = cache_it->second.first.sizeOf ();
99 
100  // Check timestamp to see if we've completely filled the cache in one go
101  if (value.timestamp == tail_timestamp)
102  {
103  return false;
104  }
105 
106  size -= tail_size;
107  ++key_it;
108  ++evict_count;
109  }
110 
111  // Evict enough items to make room for the new item
112  evict (evict_count);
113 
114  size_ += item_size;
115 
116  // Insert most-recently-used key at the end of our key index
117  auto it = key_index_.insert (key_index_.end (), key);
118 
119  // Add to cache
120  cache_.insert (std::make_pair (key, std::make_pair (value, it)));
121 
122  return true;
123  }
124 
125  void
126  setCapacity (std::size_t capacity)
127  {
128  capacity_ = capacity;
129  }
130 
131  CacheItemT&
133  {
134  const auto it = cache_.find (key_index_.front ());
135  return it->second.first;
136  }
137 
138  std::size_t
139  sizeOf (const CacheItemT& value)
140  {
141  return value.sizeOf ();
142  }
143 
144  // Evict the least-recently-used item from the cache
145  bool
146  evict (int item_count=1)
147  {
148  for (int i=0; i < item_count; i++)
149  {
150  if (key_index_.empty ())
151  return false;
152 
153  // Get LRU item
154  const auto it = cache_.find (key_index_.front ());
155  assert(it != cache_.end());
156 
157  // Remove LRU item from cache and key index
158  size_ -= it->second.first.sizeOf ();
159  cache_.erase (it);
160  key_index_.pop_front ();
161  }
162 
163  return true;
164  }
165 
166  // Cache capacity in kilobytes
167  std::size_t capacity_;
168 
169  // Current cache size in kilobytes
170  std::size_t size_{0};
171 
172  // LRU key index LRU[0] ... MRU[N]
174 
175  // LRU cache
177 };
178 
179 #endif //__PCL_OUTOFCORE_LRU_CACHE__
bool insert(const KeyT &key, const CacheItemT &value)
Definition: lru_cache.hpp:77
std::list< KeyT > KeyIndex
Definition: lru_cache.hpp:34
bool hasKey(const KeyT &k)
Definition: lru_cache.hpp:45
std::size_t capacity_
Definition: lru_cache.hpp:167
void touch(const KeyT &key)
Definition: lru_cache.hpp:65
void setCapacity(std::size_t capacity)
Definition: lru_cache.hpp:126
KeyIndex key_index_
Definition: lru_cache.hpp:173
std::map< KeyT, std::pair< CacheItemT, typename KeyIndex::iterator > > Cache
Definition: lru_cache.hpp:36
typename KeyIndex::iterator KeyIndexIterator
Definition: lru_cache.hpp:35
std::size_t size_
Definition: lru_cache.hpp:170
LRUCache(std::size_t c)
Definition: lru_cache.hpp:38
std::size_t sizeOf(const CacheItemT &value)
Definition: lru_cache.hpp:139
CacheItemT & get(const KeyT &k)
Definition: lru_cache.hpp:51
CacheItemT & tailItem()
Definition: lru_cache.hpp:132
bool evict(int item_count=1)
Definition: lru_cache.hpp:146
Cache cache_
Definition: lru_cache.hpp:176
virtual ~LRUCacheItem()=default
std::size_t timestamp
Definition: lru_cache.hpp:26
virtual std::size_t sizeOf() const
Definition: lru_cache.hpp:17