summaryrefslogtreecommitdiff
path: root/src/common/range_map.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/range_map.h')
-rw-r--r--src/common/range_map.h139
1 files changed, 139 insertions, 0 deletions
diff --git a/src/common/range_map.h b/src/common/range_map.h
new file mode 100644
index 000000000..79c7ef547
--- /dev/null
+++ b/src/common/range_map.h
@@ -0,0 +1,139 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <map>
7#include <type_traits>
8
9#include "common/common_types.h"
10
11namespace Common {
12
13template <typename KeyTBase, typename ValueT>
14class RangeMap {
15private:
16 using KeyT =
17 std::conditional_t<std::is_signed_v<KeyTBase>, KeyTBase, std::make_signed_t<KeyTBase>>;
18
19public:
20 explicit RangeMap(ValueT null_value_) : null_value{null_value_} {
21 container.emplace(std::numeric_limits<KeyT>::min(), null_value);
22 };
23 ~RangeMap() = default;
24
25 void Map(KeyTBase address, KeyTBase address_end, ValueT value) {
26 KeyT new_address = static_cast<KeyT>(address);
27 KeyT new_address_end = static_cast<KeyT>(address_end);
28 if (new_address < 0) {
29 new_address = 0;
30 }
31 if (new_address_end < 0) {
32 new_address_end = 0;
33 }
34 InternalMap(new_address, new_address_end, value);
35 }
36
37 void Unmap(KeyTBase address, KeyTBase address_end) {
38 Map(address, address_end, null_value);
39 }
40
41 [[nodiscard]] size_t GetContinousSizeFrom(KeyTBase address) const {
42 const KeyT new_address = static_cast<KeyT>(address);
43 if (new_address < 0) {
44 return 0;
45 }
46 return ContinousSizeInternal(new_address);
47 }
48
49 [[nodiscard]] ValueT GetValueAt(KeyT address) const {
50 const KeyT new_address = static_cast<KeyT>(address);
51 if (new_address < 0) {
52 return null_value;
53 }
54 return GetValueInternal(new_address);
55 }
56
57private:
58 using MapType = std::map<KeyT, ValueT>;
59 using IteratorType = typename MapType::iterator;
60 using ConstIteratorType = typename MapType::const_iterator;
61
62 size_t ContinousSizeInternal(KeyT address) const {
63 const auto it = GetFirstElementBeforeOrOn(address);
64 if (it == container.end() || it->second == null_value) {
65 return 0;
66 }
67 const auto it_end = std::next(it);
68 if (it_end == container.end()) {
69 return std::numeric_limits<KeyT>::max() - address;
70 }
71 return it_end->first - address;
72 }
73
74 ValueT GetValueInternal(KeyT address) const {
75 const auto it = GetFirstElementBeforeOrOn(address);
76 if (it == container.end()) {
77 return null_value;
78 }
79 return it->second;
80 }
81
82 ConstIteratorType GetFirstElementBeforeOrOn(KeyT address) const {
83 auto it = container.lower_bound(address);
84 if (it == container.begin()) {
85 return it;
86 }
87 if (it != container.end() && (it->first == address)) {
88 return it;
89 }
90 --it;
91 return it;
92 }
93
94 ValueT GetFirstValueWithin(KeyT address) {
95 auto it = container.lower_bound(address);
96 if (it == container.begin()) {
97 return it->second;
98 }
99 if (it == container.end()) [[unlikely]] { // this would be a bug
100 return null_value;
101 }
102 --it;
103 return it->second;
104 }
105
106 ValueT GetLastValueWithin(KeyT address) {
107 auto it = container.upper_bound(address);
108 if (it == container.end()) {
109 return null_value;
110 }
111 if (it == container.begin()) [[unlikely]] { // this would be a bug
112 return it->second;
113 }
114 --it;
115 return it->second;
116 }
117
118 void InternalMap(KeyT address, KeyT address_end, ValueT value) {
119 const bool must_add_start = GetFirstValueWithin(address) != value;
120 const ValueT last_value = GetLastValueWithin(address_end);
121 const bool must_add_end = last_value != value;
122 auto it = container.lower_bound(address);
123 const auto it_end = container.upper_bound(address_end);
124 while (it != it_end) {
125 it = container.erase(it);
126 }
127 if (must_add_start) {
128 container.emplace(address, value);
129 }
130 if (must_add_end) {
131 container.emplace(address_end, last_value);
132 }
133 }
134
135 ValueT null_value;
136 MapType container;
137};
138
139} // namespace Common