ASW Lib
A.D.S. Games SDL Wrapper Library. A library targeted at Allegro4 users who want to switch to SDL3 and use modern c++.
Loading...
Searching...
No Matches
lru_cache.h
Go to the documentation of this file.
1
4
5#ifndef ASW_SRC_LRU_CACHE_H
6#define ASW_SRC_LRU_CACHE_H
7
8#include <algorithm>
9#include <cstddef>
10#include <cstdint>
11#include <unordered_map>
12#include <utility>
13#include <vector>
14
15namespace asw::detail {
16
23template <typename Key, typename Value, typename Hash, typename Equal> class LruCache {
24public:
25 explicit LruCache(std::size_t limit)
26 : _limit(limit)
27 {
28 }
29
32 template <typename K> Value* find(const K& key)
33 {
34 auto it = _map.find(key);
35 if (it == _map.end()) {
36 return nullptr;
37 }
38 it->second.last_used = ++_clock;
39 return &it->second.value;
40 }
41
44 Value& insert(Key key, Value value)
45 {
46 if (_map.size() >= _limit) {
47 evict();
48 }
49 auto& entry
50 = _map.insert_or_assign(std::move(key), Entry { std::move(value), 0 }).first->second;
51 entry.last_used = ++_clock;
52 return entry.value;
53 }
54
55 void clear()
56 {
57 _map.clear();
58 }
59
60 std::size_t size() const
61 {
62 return _map.size();
63 }
64
65private:
66 struct Entry {
67 Value value;
68 uint64_t last_used;
69 };
70
71 // Drop the least recently used half. Runs once per limit / 2 inserts, so
72 // the cost per insert stays constant.
73 void evict()
74 {
75 // Keep the newest half, rounded down, so at least one entry goes
76 const std::size_t keep = _map.size() / 2;
77 if (keep == 0) {
78 _map.clear();
79 return;
80 }
81
82 _stamps.clear();
83 _stamps.reserve(_map.size());
84 for (const auto& [key, entry] : _map) {
85 _stamps.push_back(entry.last_used);
86 }
87
88 // Stamps are unique, so the ones below the cutoff are exactly the
89 // size - keep oldest
90 const auto cutoff_it = _stamps.begin() + static_cast<std::ptrdiff_t>(_stamps.size() - keep);
91 std::nth_element(_stamps.begin(), cutoff_it, _stamps.end());
92 const uint64_t cutoff = *cutoff_it;
93 std::erase_if(_map, [cutoff](const auto& item) { return item.second.last_used < cutoff; });
94 }
95
96 std::unordered_map<Key, Entry, Hash, Equal> _map;
97 std::vector<uint64_t> _stamps;
98 std::size_t _limit;
99 uint64_t _clock { 0 };
100};
101
103inline void hash_combine(std::size_t& seed, std::size_t hash)
104{
105 seed ^= hash + 0x9e3779b9 + ((seed << 6) + (seed >> 2));
106}
107
108} // namespace asw::detail
109
110#endif // ASW_SRC_LRU_CACHE_H
A hash map with a size limit. When full, the least recently used half is dropped, so entries in use e...
Definition lru_cache.h:23
std::unordered_map< Key, Entry, Hash, Equal > _map
Definition lru_cache.h:96
Value * find(const K &key)
Find an entry and mark it used.
Definition lru_cache.h:32
std::vector< uint64_t > _stamps
Definition lru_cache.h:97
std::size_t _limit
Definition lru_cache.h:98
Value & insert(Key key, Value value)
Add or replace an entry, dropping old entries first when full.
Definition lru_cache.h:44
LruCache(std::size_t limit)
Definition lru_cache.h:25
std::size_t size() const
Definition lru_cache.h:60
void hash_combine(std::size_t &seed, std::size_t hash)
Combine a hash into a seed, as boost::hash_combine does.
Definition lru_cache.h:103