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
>, class KeyEqual
= std::equal_to
<Key
>>
38 typedef typename
std::pair
<Key
, Value
> key_value_pair_t
;
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
;
51 const size_t mMaxSize
;
55 if (mLruMap
.size() > mMaxSize
)
58 mLruMap
.erase(mLruList
.back().first
);
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()))
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.
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
;
94 else // already exists -> 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
;
116 else // already exists -> 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();
135 // push to back of the lru list
136 mLruList
.splice(mLruList
.begin(), mLruList
, 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())
150 mLruMap
.erase(it
->first
);
151 it
= decltype(it
){ mLruList
.erase(std::next(it
).base()) };
158 const list_const_iterator_t
begin() const
160 return mLruList
.cbegin();
163 const list_const_iterator_t
end() const
165 return mLruList
.cend();
170 assert(mLruMap
.size() == mLruList
.size());
171 return mLruMap
.size();
183 #endif /* INCLUDED_O3TL_LRU_MAP_HXX */
185 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */