Cosmetics.
[LibreOffice.git] / include / o3tl / lru_map.hxx
blob54378a319ece5082555fd9ed629ea2755710c373
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #ifndef INCLUDED_O3TL_LRU_MAP_HXX
12 #define INCLUDED_O3TL_LRU_MAP_HXX
14 #include <cassert>
15 #include <list>
16 #include <unordered_map>
18 namespace o3tl
21 /** LRU map
23 * Similar to unordered_map (it actually uses it) with additionally functionality
24 * which removes the entries that have been "least recently used" when the size
25 * hits the specified capacity.
27 * It only implements the minimal methods needed and the implementation is NOT
28 * thread safe.
30 * The implementation is as simple as possible but it still uses O(1) complexity
31 * for most of the operations with a combination unordered map and linked list.
33 **/
34 template<typename Key, typename Value, class KeyHash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
35 class lru_map final
37 public:
38 typedef typename std::pair<Key, Value> key_value_pair_t;
40 private:
41 typedef std::list<key_value_pair_t> list_t;
42 typedef typename list_t::iterator list_iterator_t;
43 typedef typename list_t::const_iterator list_const_iterator_t;
45 typedef std::unordered_map<Key, list_iterator_t, KeyHash, KeyEqual> map_t;
46 typedef typename map_t::iterator map_iterator_t;
47 typedef typename map_t::const_iterator map_const_iterator_t;
49 list_t mLruList;
50 map_t mLruMap;
51 const size_t mMaxSize;
53 void checkLRU()
55 if (mLruMap.size() > mMaxSize)
57 // remove from map
58 mLruMap.erase(mLruList.back().first);
59 // remove from list
60 mLruList.pop_back();
64 public:
65 typedef list_iterator_t iterator;
66 typedef list_const_iterator_t const_iterator;
68 // a size of 0 effectively disables the LRU cleanup code
69 lru_map(size_t nMaxSize)
70 : mMaxSize(nMaxSize ? nMaxSize : std::min(mLruMap.max_size(), mLruList.max_size()))
72 ~lru_map()
74 // Some code .e.g. SalBitmap likes to remove itself from a cache during it's destructor, which means we
75 // get calls into lru_map while we are in destruction, so use the swap-and-clear idiom to avoid those problems.
76 mLruMap.clear();
77 list_t aLruListTemp;
78 aLruListTemp.swap(mLruList);
81 void insert(key_value_pair_t& rPair)
83 map_iterator_t i = mLruMap.find(rPair.first);
85 if (i == mLruMap.end()) // doesn't exist -> add to queue and map
87 // add to front of the list
88 mLruList.push_front(rPair);
89 // add the list position (iterator) to the map
90 auto it = mLruList.begin();
91 mLruMap[it->first] = it;
92 checkLRU();
94 else // already exists -> replace value
96 // replace value
97 i->second->second = rPair.second;
98 // bring to front of the lru list
99 mLruList.splice(mLruList.begin(), mLruList, i->second);
103 void insert(key_value_pair_t&& rPair)
105 map_iterator_t i = mLruMap.find(rPair.first);
107 if (i == mLruMap.end()) // doesn't exist -> add to list and map
109 // add to front of the list
110 mLruList.push_front(std::move(rPair));
111 // add the list position (iterator) to the map
112 auto it = mLruList.begin();
113 mLruMap[it->first] = it;
114 checkLRU();
116 else // already exists -> replace value
118 // replace value
119 i->second->second = std::move(rPair.second);
120 // push to back of the lru list
121 mLruList.splice(mLruList.begin(), mLruList, i->second);
125 const list_const_iterator_t find(const Key& key)
127 const map_iterator_t i = mLruMap.find(key);
128 if (i == mLruMap.cend()) // can't find entry for the key
130 // return empty iterator
131 return mLruList.cend();
133 else
135 // push to back of the lru list
136 mLruList.splice(mLruList.begin(), mLruList, i->second);
137 return i->second;
141 // reverse-iterates the list removing all items matching the predicate
142 template<class UnaryPredicate>
143 void remove_if(UnaryPredicate pred)
145 auto it = mLruList.rbegin();
146 while (it != mLruList.rend())
148 if (pred(*it))
150 mLruMap.erase(it->first);
151 it = decltype(it){ mLruList.erase(std::next(it).base()) };
153 else
154 ++it;
158 const list_const_iterator_t begin() const
160 return mLruList.cbegin();
163 const list_const_iterator_t end() const
165 return mLruList.cend();
168 size_t size() const
170 assert(mLruMap.size() == mLruList.size());
171 return mLruMap.size();
174 void clear()
176 mLruMap.clear();
177 mLruList.clear();
183 #endif /* INCLUDED_O3TL_LRU_MAP_HXX */
185 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */