summaryrefslogtreecommitdiff
path: root/src/common/lru_cache.h
diff options
context:
space:
mode:
authorGravatar bunnei2021-08-31 09:11:21 -0700
committerGravatar GitHub2021-08-31 09:11:21 -0700
commit956171f02452c7f1df3778abd9827aaebb536dd0 (patch)
tree908265b873c0f2529160454b5dc467104d5e8ac8 /src/common/lru_cache.h
parentMerge pull request #6928 from ameerj/spirv-get-frontface (diff)
parentGarbage Collection: Make it more agressive on high priority mode. (diff)
downloadyuzu-956171f02452c7f1df3778abd9827aaebb536dd0.tar.gz
yuzu-956171f02452c7f1df3778abd9827aaebb536dd0.tar.xz
yuzu-956171f02452c7f1df3778abd9827aaebb536dd0.zip
Merge pull request #6897 from FernandoS27/pineapple-does-not-belong-in-pizza
Project <tentative title>: Rework Garbage Collection.
Diffstat (limited to 'src/common/lru_cache.h')
-rw-r--r--src/common/lru_cache.h140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/common/lru_cache.h b/src/common/lru_cache.h
new file mode 100644
index 000000000..365488ba5
--- /dev/null
+++ b/src/common/lru_cache.h
@@ -0,0 +1,140 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2+ or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <deque>
8#include <memory>
9#include <type_traits>
10
11#include "common/common_types.h"
12
13namespace Common {
14
15template <class Traits>
16class LeastRecentlyUsedCache {
17 using ObjectType = typename Traits::ObjectType;
18 using TickType = typename Traits::TickType;
19
20 struct Item {
21 ObjectType obj;
22 TickType tick;
23 Item* next{};
24 Item* prev{};
25 };
26
27public:
28 LeastRecentlyUsedCache() : first_item{}, last_item{} {}
29 ~LeastRecentlyUsedCache() = default;
30
31 size_t Insert(ObjectType obj, TickType tick) {
32 const auto new_id = Build();
33 auto& item = item_pool[new_id];
34 item.obj = obj;
35 item.tick = tick;
36 Attach(item);
37 return new_id;
38 }
39
40 void Touch(size_t id, TickType tick) {
41 auto& item = item_pool[id];
42 if (item.tick >= tick) {
43 return;
44 }
45 item.tick = tick;
46 if (&item == last_item) {
47 return;
48 }
49 Detach(item);
50 Attach(item);
51 }
52
53 void Free(size_t id) {
54 auto& item = item_pool[id];
55 Detach(item);
56 item.prev = nullptr;
57 item.next = nullptr;
58 free_items.push_back(id);
59 }
60
61 template <typename Func>
62 void ForEachItemBelow(TickType tick, Func&& func) {
63 static constexpr bool RETURNS_BOOL =
64 std::is_same_v<std::invoke_result<Func, ObjectType>, bool>;
65 Item* iterator = first_item;
66 while (iterator) {
67 if (static_cast<s64>(tick) - static_cast<s64>(iterator->tick) < 0) {
68 return;
69 }
70 Item* next = iterator->next;
71 if constexpr (RETURNS_BOOL) {
72 if (func(iterator->obj)) {
73 return;
74 }
75 } else {
76 func(iterator->obj);
77 }
78 iterator = next;
79 }
80 }
81
82private:
83 size_t Build() {
84 if (free_items.empty()) {
85 const size_t item_id = item_pool.size();
86 auto& item = item_pool.emplace_back();
87 item.next = nullptr;
88 item.prev = nullptr;
89 return item_id;
90 }
91 const size_t item_id = free_items.front();
92 free_items.pop_front();
93 auto& item = item_pool[item_id];
94 item.next = nullptr;
95 item.prev = nullptr;
96 return item_id;
97 }
98
99 void Attach(Item& item) {
100 if (!first_item) {
101 first_item = &item;
102 }
103 if (!last_item) {
104 last_item = &item;
105 } else {
106 item.prev = last_item;
107 last_item->next = &item;
108 item.next = nullptr;
109 last_item = &item;
110 }
111 }
112
113 void Detach(Item& item) {
114 if (item.prev) {
115 item.prev->next = item.next;
116 }
117 if (item.next) {
118 item.next->prev = item.prev;
119 }
120 if (&item == first_item) {
121 first_item = item.next;
122 if (first_item) {
123 first_item->prev = nullptr;
124 }
125 }
126 if (&item == last_item) {
127 last_item = item.prev;
128 if (last_item) {
129 last_item->next = nullptr;
130 }
131 }
132 }
133
134 std::deque<Item> item_pool;
135 std::deque<size_t> free_items;
136 Item* first_item{};
137 Item* last_item{};
138};
139
140} // namespace Common