summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2024-02-04 14:44:17 +0100
committerGravatar Fernando Sahmkow2024-02-04 20:01:50 +0100
commit01ba6cf610641f1937092b469843b14ebc2a5962 (patch)
treec7efb1bc196a7b8e8da9eb0924977e9176e8174b
parentVideoCore: Move Slot Vector to Common (diff)
downloadyuzu-01ba6cf610641f1937092b469843b14ebc2a5962.tar.gz
yuzu-01ba6cf610641f1937092b469843b14ebc2a5962.tar.xz
yuzu-01ba6cf610641f1937092b469843b14ebc2a5962.zip
Common: Introduce Range Sets
Diffstat (limited to '')
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/range_sets.h73
-rw-r--r--src/common/range_sets.inc279
3 files changed, 354 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index bf3f3b781..c19af2ab8 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -107,6 +107,8 @@ add_library(common STATIC
107 quaternion.h 107 quaternion.h
108 range_map.h 108 range_map.h
109 range_mutex.h 109 range_mutex.h
110 range_sets.h
111 range_sets.inc
110 reader_writer_queue.h 112 reader_writer_queue.h
111 ring_buffer.h 113 ring_buffer.h
112 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp 114 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
diff --git a/src/common/range_sets.h b/src/common/range_sets.h
new file mode 100644
index 000000000..f4ee00fec
--- /dev/null
+++ b/src/common/range_sets.h
@@ -0,0 +1,73 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <memory>
7
8#include "common/common_types.h"
9
10namespace Common {
11
12template <typename AddressType>
13class RangeSet {
14public:
15 RangeSet();
16 ~RangeSet();
17
18 RangeSet(RangeSet const&) = delete;
19 RangeSet& operator=(RangeSet const&) = delete;
20
21 RangeSet(RangeSet&& other);
22 RangeSet& operator=(RangeSet&& other);
23
24 void Add(AddressType base_address, size_t size);
25 void Subtract(AddressType base_address, size_t size);
26 void Clear();
27 bool Empty() const;
28
29 template <typename Func>
30 void ForEach(Func&& func) const;
31
32 template <typename Func>
33 void ForEachInRange(AddressType device_addr, size_t size, Func&& func) const;
34
35private:
36 struct RangeSetImpl;
37 std::unique_ptr<RangeSetImpl> m_impl;
38};
39
40template <typename AddressType>
41class SplitRangeSet {
42public:
43 SplitRangeSet();
44 ~SplitRangeSet();
45
46 SplitRangeSet(SplitRangeSet const&) = delete;
47 SplitRangeSet& operator=(SplitRangeSet const&) = delete;
48
49 SplitRangeSet(SplitRangeSet&& other);
50 SplitRangeSet& operator=(SplitRangeSet&& other);
51
52 void Add(AddressType base_address, size_t size);
53 void Subtract(AddressType base_address, size_t size);
54
55 template <typename Func>
56 void Subtract(AddressType base_address, size_t size, Func&& on_delete);
57
58 void DeleteAll(AddressType base_address, size_t size);
59 void Clear();
60 bool Empty() const;
61
62 template <typename Func>
63 void ForEach(Func&& func) const;
64
65 template <typename Func>
66 void ForEachInRange(AddressType device_addr, size_t size, Func&& func) const;
67
68private:
69 struct SplitRangeSetImpl;
70 std::unique_ptr<SplitRangeSetImpl> m_impl;
71};
72
73} // namespace Common \ No newline at end of file
diff --git a/src/common/range_sets.inc b/src/common/range_sets.inc
new file mode 100644
index 000000000..fa55a68fb
--- /dev/null
+++ b/src/common/range_sets.inc
@@ -0,0 +1,279 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <limits>
7#include <utility>
8
9#define BOOST_NO_MT
10#include <boost/pool/detail/mutex.hpp>
11#undef BOOST_NO_MT
12#include <boost/icl/interval.hpp>
13#include <boost/icl/interval_base_set.hpp>
14#include <boost/icl/interval_map.hpp>
15#include <boost/icl/interval_set.hpp>
16#include <boost/icl/split_interval_map.hpp>
17#include <boost/pool/pool.hpp>
18#include <boost/pool/pool_alloc.hpp>
19#include <boost/pool/poolfwd.hpp>
20
21#include "common/range_sets.h"
22
23namespace boost {
24template <typename T>
25class fast_pool_allocator<T, default_user_allocator_new_delete, details::pool::null_mutex, 4096, 0>;
26}
27
28namespace Common {
29
30template <typename AddressType>
31struct RangeSet<AddressType>::RangeSetImpl {
32 using IntervalSet = boost::icl::interval_set<
33 AddressType, std::less, ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less),
34 boost::fast_pool_allocator>;
35 using IntervalType = typename IntervalSet::interval_type;
36
37 RangeSetImpl() = default;
38 ~RangeSetImpl() = default;
39
40 void Add(AddressType base_address, size_t size) {
41 AddressType end_address = base_address + static_cast<AddressType>(size);
42 IntervalType interval{base_address, end_address};
43 m_ranges_set.add(interval);
44 }
45
46 void Subtract(AddressType base_address, size_t size) {
47 AddressType end_address = base_address + static_cast<AddressType>(size);
48 IntervalType interval{base_address, end_address};
49 m_ranges_set.subtract(interval);
50 }
51
52 IntervalSet m_ranges_set;
53};
54
55template <typename AddressType>
56struct SplitRangeSet<AddressType>::SplitRangeSetImpl {
57
58 using IntervalSet =
59 boost::icl::split_interval_map<AddressType, s32, boost::icl::partial_enricher, std::less,
60 boost::icl::inplace_plus, boost::icl::inter_section,
61 ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType,
62 std::less),
63 boost::fast_pool_allocator>;
64 using IntervalType = typename IntervalSet::interval_type;
65
66 SplitRangeSetImpl() = default;
67 ~SplitRangeSetImpl() = default;
68
69 void Add(AddressType base_address, size_t size) {
70 AddressType end_address = base_address + static_cast<AddressType>(size);
71 IntervalType interval{base_address, end_address};
72 m_split_ranges_set += std::make_pair(interval, 1);
73 }
74
75 template <bool has_on_delete, typename Func>
76 void Subtract(AddressType base_address, size_t size, s32 amount,
77 [[maybe_unused]] Func&& on_delete) {
78 AddressType end_address = base_address + static_cast<AddressType>(size);
79 IntervalType interval{base_address, end_address};
80 bool any_removals = false;
81 m_split_ranges_set += std::make_pair(interval, -amount);
82 do {
83 any_removals = false;
84 auto it = m_split_ranges_set.lower_bound(interval);
85 if (it == m_split_ranges_set.end()) {
86 return;
87 }
88 auto end_it = m_split_ranges_set.upper_bound(interval);
89 for (; it != end_it; it++) {
90 if (it->second <= 0) {
91 if constexpr (has_on_delete) {
92 if (it->second == 0) {
93 on_delete(it->first.lower(), it->first.upper());
94 }
95 }
96 any_removals = true;
97 m_split_ranges_set.erase(it);
98 break;
99 }
100 }
101 } while (any_removals);
102 }
103
104 IntervalSet m_split_ranges_set;
105};
106
107template <typename AddressType>
108RangeSet<AddressType>::RangeSet() {
109 m_impl = std::make_unique<RangeSet<AddressType>::RangeSetImpl>();
110}
111
112template <typename AddressType>
113RangeSet<AddressType>::~RangeSet() = default;
114
115template <typename AddressType>
116RangeSet<AddressType>::RangeSet(RangeSet&& other) {
117 m_impl = std::make_unique<RangeSet<AddressType>::RangeSetImpl>();
118 m_impl->m_ranges_set = std::move(other.m_impl->m_ranges_set);
119}
120
121template <typename AddressType>
122RangeSet<AddressType>& RangeSet<AddressType>::operator=(RangeSet&& other) {
123 m_impl->m_ranges_set = std::move(other.m_impl->m_ranges_set);
124}
125
126template <typename AddressType>
127void RangeSet<AddressType>::Add(AddressType base_address, size_t size) {
128 m_impl->Add(base_address, size);
129}
130
131template <typename AddressType>
132void RangeSet<AddressType>::Subtract(AddressType base_address, size_t size) {
133 m_impl->Subtract(base_address, size);
134}
135
136template <typename AddressType>
137void RangeSet<AddressType>::Clear() {
138 m_impl->m_ranges_set.clear();
139}
140
141template <typename AddressType>
142bool RangeSet<AddressType>::Empty() const {
143 return m_impl->m_ranges_set.empty();
144}
145
146template <typename AddressType>
147template <typename Func>
148void RangeSet<AddressType>::ForEach(Func&& func) const {
149 if (m_impl->m_ranges_set.empty()) {
150 return;
151 }
152 auto it = m_impl->m_ranges_set.begin();
153 auto end_it = m_impl->m_ranges_set.end();
154 for (; it != end_it; it++) {
155 const AddressType inter_addr_end = it->upper();
156 const AddressType inter_addr = it->lower();
157 func(inter_addr, inter_addr_end);
158 }
159}
160
161template <typename AddressType>
162template <typename Func>
163void RangeSet<AddressType>::ForEachInRange(AddressType base_addr, size_t size, Func&& func) const {
164 auto& range_set = m_impl->m_ranges_set;
165 const AddressType start_address = base_addr;
166 const AddressType end_address = start_address + size;
167 const RangeSetImpl::IntervalType search_interval{start_address, end_address};
168 auto it = range_set.lower_bound(search_interval);
169 if (it == range_set.end()) {
170 return;
171 }
172 auto end_it = range_set.upper_bound(search_interval);
173 for (; it != end_it; it++) {
174 AddressType inter_addr_end = it->upper();
175 AddressType inter_addr = it->lower();
176 if (inter_addr_end > end_address) {
177 inter_addr_end = end_address;
178 }
179 if (inter_addr < start_address) {
180 inter_addr = start_address;
181 }
182 func(inter_addr, inter_addr_end);
183 }
184}
185
186template <typename AddressType>
187SplitRangeSet<AddressType>::SplitRangeSet() {
188 m_impl = std::make_unique<SplitRangeSet<AddressType>::SplitRangeSetImpl>();
189}
190
191template <typename AddressType>
192SplitRangeSet<AddressType>::~SplitRangeSet() = default;
193
194template <typename AddressType>
195SplitRangeSet<AddressType>::SplitRangeSet(SplitRangeSet&& other) {
196 m_impl = std::make_unique<SplitRangeSet<AddressType>::SplitRangeSetImpl>();
197 m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set);
198}
199
200template <typename AddressType>
201SplitRangeSet<AddressType>& SplitRangeSet<AddressType>::operator=(SplitRangeSet&& other) {
202 m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set);
203}
204
205template <typename AddressType>
206void SplitRangeSet<AddressType>::Add(AddressType base_address, size_t size) {
207 m_impl->Add(base_address, size);
208}
209
210template <typename AddressType>
211void SplitRangeSet<AddressType>::Subtract(AddressType base_address, size_t size) {
212 m_impl->Subtract<false>(base_address, size, 1, [](AddressType, AddressType) {});
213}
214
215template <typename AddressType>
216template <typename Func>
217void SplitRangeSet<AddressType>::Subtract(AddressType base_address, size_t size, Func&& on_delete) {
218 m_impl->Subtract<true>(base_address, size, 1, on_delete);
219}
220
221template <typename AddressType>
222void SplitRangeSet<AddressType>::DeleteAll(AddressType base_address, size_t size) {
223 m_impl->Subtract<false>(base_address, size, std::numeric_limits<s32>::max(),
224 [](AddressType, AddressType) {});
225}
226
227template <typename AddressType>
228void SplitRangeSet<AddressType>::Clear() {
229 m_impl->m_split_ranges_set.clear();
230}
231
232template <typename AddressType>
233bool SplitRangeSet<AddressType>::Empty() const {
234 return m_impl->m_split_ranges_set.empty();
235}
236
237template <typename AddressType>
238template <typename Func>
239void SplitRangeSet<AddressType>::ForEach(Func&& func) const {
240 if (m_impl->m_split_ranges_set.empty()) {
241 return;
242 }
243 auto it = m_impl->m_split_ranges_set.begin();
244 auto end_it = m_impl->m_split_ranges_set.end();
245 for (; it != end_it; it++) {
246 const AddressType inter_addr_end = it->first.upper();
247 const AddressType inter_addr = it->first.lower();
248 func(inter_addr, inter_addr_end, it->second);
249 }
250}
251
252template <typename AddressType>
253template <typename Func>
254void SplitRangeSet<AddressType>::ForEachInRange(AddressType base_address, size_t size,
255 Func&& func) const {
256 auto& range_set = m_impl->m_split_ranges_set;
257 const AddressType start_address = base_address;
258 const AddressType end_address = start_address + size;
259 const SplitRangeSetImpl::IntervalType search_interval{start_address, end_address};
260 auto it = range_set.lower_bound(search_interval);
261 if (it == range_set.end()) {
262 return;
263 }
264 auto end_it = range_set.upper_bound(search_interval);
265 for (; it != end_it; it++) {
266 auto& inter = it->first;
267 AddressType inter_addr_end = inter.upper();
268 AddressType inter_addr = inter.lower();
269 if (inter_addr_end > end_address) {
270 inter_addr_end = end_address;
271 }
272 if (inter_addr < start_address) {
273 inter_addr = start_address;
274 }
275 func(inter_addr, inter_addr_end, it->second);
276 }
277}
278
279} // namespace Common \ No newline at end of file