nss: upgrade to release 3.73
[LibreOffice.git] / include / o3tl / lru_map.hxx
blob96fb3161782d727f5bca903fa1228b01b51a33d7
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>
17 #include <cstddef>
19 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>,
35 class KeyEqual = std::equal_to<Key>>
36 class lru_map final
38 public:
39 typedef typename std::pair<Key, Value> key_value_pair_t;
41 private:
42 typedef std::list<key_value_pair_t> list_t;
43 typedef typename list_t::iterator list_iterator_t;
44 typedef typename list_t::const_iterator list_const_iterator_t;
46 typedef std::unordered_map<Key, list_iterator_t, KeyHash, KeyEqual> map_t;
47 typedef typename map_t::iterator map_iterator_t;
48 typedef typename map_t::const_iterator map_const_iterator_t;
50 list_t mLruList;
51 map_t mLruMap;
52 const size_t mMaxSize;
54 void checkLRU()
56 if (mLruMap.size() > mMaxSize)
58 // remove from map
59 mLruMap.erase(mLruList.back().first);
60 // remove from list
61 mLruList.pop_back();
65 public:
66 typedef list_iterator_t iterator;
67 typedef list_const_iterator_t const_iterator;
69 // a size of 0 effectively disables the LRU cleanup code
70 lru_map(size_t nMaxSize)
71 : mMaxSize(nMaxSize ? nMaxSize : std::min(mLruMap.max_size(), mLruList.max_size()))
74 ~lru_map()
76 // Some code .e.g. SalBitmap likes to remove itself from a cache during it's destructor, which means we
77 // get calls into lru_map while we are in destruction, so use the swap-and-clear idiom to avoid those problems.
78 mLruMap.clear();
79 list_t aLruListTemp;
80 aLruListTemp.swap(mLruList);
83 void insert(key_value_pair_t& rPair)
85 map_iterator_t i = mLruMap.find(rPair.first);
87 if (i == mLruMap.end()) // doesn't exist -> add to queue and map
89 // add to front of the list
90 mLruList.push_front(rPair);
91 // add the list position (iterator) to the map
92 auto it = mLruList.begin();
93 mLruMap[it->first] = it;
94 checkLRU();
96 else // already exists -> replace value
98 // replace value
99 i->second->second = rPair.second;
100 // bring to front of the lru list
101 mLruList.splice(mLruList.begin(), mLruList, i->second);
105 void insert(key_value_pair_t&& rPair)
107 map_iterator_t i = mLruMap.find(rPair.first);
109 if (i == mLruMap.end()) // doesn't exist -> add to list and map
111 // add to front of the list
112 mLruList.push_front(std::move(rPair));
113 // add the list position (iterator) to the map
114 auto it = mLruList.begin();
115 mLruMap[it->first] = it;
116 checkLRU();
118 else // already exists -> replace value
120 // replace value
121 i->second->second = std::move(rPair.second);
122 // push to back of the lru list
123 mLruList.splice(mLruList.begin(), mLruList, i->second);
127 list_const_iterator_t find(const Key& key)
129 const map_iterator_t i = mLruMap.find(key);
130 if (i == mLruMap.cend()) // can't find entry for the key
132 // return empty iterator
133 return mLruList.cend();
135 else
137 // push to back of the lru list
138 mLruList.splice(mLruList.begin(), mLruList, i->second);
139 return i->second;
143 // reverse-iterates the list removing all items matching the predicate
144 template <class UnaryPredicate> void remove_if(UnaryPredicate pred)
146 auto it = mLruList.rbegin();
147 while (it != mLruList.rend())
149 if (pred(*it))
151 mLruMap.erase(it->first);
152 it = decltype(it){ mLruList.erase(std::next(it).base()) };
154 else
155 ++it;
159 list_const_iterator_t begin() const { return mLruList.cbegin(); }
161 list_const_iterator_t end() const { return mLruList.cend(); }
163 size_t size() const
165 assert(mLruMap.size() == mLruList.size());
166 return mLruMap.size();
169 void clear()
171 mLruMap.clear();
172 mLruList.clear();
177 #endif /* INCLUDED_O3TL_LRU_MAP_HXX */
179 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */