2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file lrucache.hpp Size limited cache map with a least recently used eviction strategy. */
14 #include <unordered_map>
17 * Size limited cache with a least recently used eviction strategy.
18 * @tparam Tkey Type of the cache key.
19 * @tparam Tdata Type of the cache item. The cache will store a pointer of this type.
21 template <class Tkey
, class Tdata
>
24 typedef std::pair
<Tkey
, Tdata
*> Tpair
;
25 typedef typename
std::list
<Tpair
>::iterator Titer
;
27 std::list
<Tpair
> data
; ///< Ordered list of all items.
28 std::unordered_map
<Tkey
, Titer
> lookup
; ///< Map of keys to items.
30 const size_t capacity
; ///< Number of items to cache.
34 * Construct new LRU cache map.
35 * @param max_items Number of items to store at most.
37 LRUCache(size_t max_items
) : capacity(max_items
) {}
40 * Test if a key is already contained in the cache.
41 * @param key The key to search.
42 * @return True, if the key was found.
44 inline bool Contains(const Tkey key
)
46 return this->lookup
.find(key
) != this->lookup
.end();
50 * Insert a new data item with a specified key.
51 * @param key Key under which the item should be stored.
52 * @param item Item to insert.
53 * @return Evicted item or nullptr, if no item had to be evicted.
55 Tdata
*Insert(const Tkey key
, Tdata
*item
)
59 if (this->Contains(key
)) {
60 /* Replace old value. */
61 old
= this->lookup
[key
]->second
;
62 this->lookup
[key
]->second
= item
;
64 /* Delete least used item if maximum items cached. */
65 if (this->data
.size() >= this->capacity
) {
66 Tpair last
= data
.back();
67 this->lookup
.erase(last
.first
);
68 this->data
.pop_back();
73 /* Insert new item. */
74 this->data
.push_front(std::make_pair(key
, item
));
75 this->lookup
.emplace(key
, this->data
.begin());
82 * Pop the least recently used item.
83 * @return The item value or nullptr if no items cached.
87 if (this->data
.empty()) return nullptr;
89 Tdata
*value
= this->data
.back().second
;
90 this->lookup
.erase(this->data
.back().first
);
91 this->data
.pop_back();
96 * Get an item from the cache.
97 * @param key The key to look up.
98 * @return The item value.
99 * @note Throws if item not found.
101 inline Tdata
*Get(const Tkey key
)
103 if (this->lookup
.find(key
) == this->lookup
.end()) throw std::out_of_range("item not found");
104 /* Move to front if needed. */
105 this->data
.splice(this->data
.begin(), this->data
, this->lookup
[key
]);
107 return this->data
.front().second
;
111 #endif /* LRUCACHE_HPP */