1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
11 #ifndef INCLUDED_O3TL_LRU_MAP_HXX
12 #define INCLUDED_O3TL_LRU_MAP_HXX
16 #include <unordered_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
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.
34 template <typename Key
, typename Value
, class KeyHash
= std::hash
<Key
>,
35 class KeyEqual
= std::equal_to
<Key
>>
39 typedef typename
std::pair
<Key
, Value
> key_value_pair_t
;
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
;
52 const size_t mMaxSize
;
56 if (mLruMap
.size() > mMaxSize
)
59 mLruMap
.erase(mLruList
.back().first
);
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()))
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.
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
;
96 else // already exists -> 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
;
118 else // already exists -> 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();
137 // push to back of the lru list
138 mLruList
.splice(mLruList
.begin(), mLruList
, 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())
151 mLruMap
.erase(it
->first
);
152 it
= decltype(it
){ mLruList
.erase(std::next(it
).base()) };
159 list_const_iterator_t
begin() const { return mLruList
.cbegin(); }
161 list_const_iterator_t
end() const { return mLruList
.cend(); }
165 assert(mLruMap
.size() == mLruList
.size());
166 return mLruMap
.size();
177 #endif /* INCLUDED_O3TL_LRU_MAP_HXX */
179 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */