CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Data/Collections/TinySet.h
Views: 1401
1
#pragma once
2
3
#include <vector>
4
5
#include "Common/Log.h"
6
7
// Insert-only small-set implementation. Performs no allocation unless MaxFastSize is exceeded.
8
// Can also be used as a small vector, then use push_back (or push_in_place) instead of insert.
9
// Duplicates are thus allowed if you use that, but not if you exclusively use insert.
10
template <class T, int MaxFastSize>
11
struct TinySet {
12
~TinySet() { delete slowLookup_; }
13
inline void insert(const T &t) {
14
// Fast linear scan.
15
for (int i = 0; i < fastCount_; i++) {
16
if (fastLookup_[i] == t)
17
return; // We already have it.
18
}
19
// Fast insertion
20
if (fastCount_ < MaxFastSize) {
21
fastLookup_[fastCount_++] = t;
22
return;
23
}
24
// Fall back to slow path.
25
insertSlow(t);
26
}
27
inline void push_back(const T &t) {
28
if (fastCount_ < MaxFastSize) {
29
fastLookup_[fastCount_++] = t;
30
return;
31
}
32
if (!slowLookup_) {
33
slowLookup_ = new std::vector<T>();
34
}
35
slowLookup_->push_back(t);
36
}
37
inline T &push_uninitialized() {
38
if (fastCount_ < MaxFastSize) {
39
return fastLookup_[fastCount_++];
40
}
41
if (!slowLookup_) {
42
slowLookup_ = new std::vector<T>();
43
}
44
45
// The slow lookup is also slow at adding.
46
T t;
47
slowLookup_->push_back(t);
48
return *slowLookup_->back();
49
}
50
void append(const TinySet<T, MaxFastSize> &other) {
51
size_t otherSize = other.size();
52
if (size() + otherSize <= MaxFastSize) {
53
// Fast case
54
for (size_t i = 0; i < otherSize; i++) {
55
fastLookup_[fastCount_ + i] = other.fastLookup_[i];
56
}
57
fastCount_ += other.fastCount_;
58
} else {
59
for (size_t i = 0; i < otherSize; i++) {
60
push_back(other[i]);
61
}
62
}
63
}
64
bool contains(T t) const {
65
for (int i = 0; i < fastCount_; i++) {
66
if (fastLookup_[i] == t)
67
return true;
68
}
69
if (slowLookup_) {
70
for (auto x : *slowLookup_) {
71
if (x == t)
72
return true;
73
}
74
}
75
return false;
76
}
77
bool contains(const TinySet<T, MaxFastSize> &otherSet) {
78
// Awkward, kind of ruins the fun.
79
for (int i = 0; i < fastCount_; i++) {
80
if (otherSet.contains(fastLookup_[i]))
81
return true;
82
}
83
if (slowLookup_) {
84
for (auto x : *slowLookup_) {
85
if (otherSet.contains(x))
86
return true;
87
}
88
}
89
return false;
90
}
91
void clear() {
92
// TODO: Keep slowLookup_ around? That would be more similar to real vector behavior.
93
delete slowLookup_;
94
slowLookup_ = nullptr;
95
fastCount_ = 0;
96
}
97
bool empty() const {
98
return fastCount_ == 0;
99
}
100
size_t size() const {
101
if (!slowLookup_) {
102
return fastCount_;
103
} else {
104
return slowLookup_->size() + MaxFastSize;
105
}
106
}
107
T &operator[] (size_t index) {
108
if (index < MaxFastSize) {
109
return fastLookup_[index];
110
} else {
111
return (*slowLookup_)[index - MaxFastSize];
112
}
113
}
114
const T &operator[] (size_t index) const {
115
if (index < MaxFastSize) {
116
return fastLookup_[index];
117
} else {
118
return (*slowLookup_)[index - MaxFastSize];
119
}
120
}
121
const T &back() const {
122
return (*this)[size() - 1];
123
}
124
125
private:
126
void insertSlow(T t) {
127
if (!slowLookup_) {
128
slowLookup_ = new std::vector<T>();
129
} else {
130
for (size_t i = 0; i < slowLookup_->size(); i++) {
131
if ((*slowLookup_)[i] == t)
132
return;
133
}
134
}
135
slowLookup_->push_back(t);
136
}
137
int fastCount_ = 0; // first in the struct just so it's more visible in the VS debugger.
138
T fastLookup_[MaxFastSize];
139
std::vector<T> *slowLookup_ = nullptr;
140
};
141
142
template <class T, int MaxSize>
143
struct FixedVec {
144
~FixedVec() {}
145
// WARNING: Can fail if you exceed MaxSize!
146
inline bool push_back(const T &t) {
147
if (count_ < MaxSize) {
148
data_[count_++] = t;
149
return true;
150
} else {
151
return false;
152
}
153
}
154
155
// WARNING: Can fail if you exceed MaxSize!
156
inline T &push_uninitialized() {
157
if (count_ < MaxSize) {
158
return &data_[count_++];
159
}
160
_dbg_assert_(false);
161
return *data_[MaxSize - 1]; // BAD
162
}
163
164
// Invalid if empty().
165
void pop_back() { count_--; }
166
167
// Unlike TinySet, we can trivially support begin/end as pointers.
168
T *begin() { return data_; }
169
T *end() { return data_ + count_; }
170
const T *begin() const { return data_; }
171
const T *end() const { return data_ + count_; }
172
173
size_t capacity() const { return MaxSize; }
174
void clear() { count_ = 0; }
175
bool empty() const { return count_ == 0; }
176
size_t size() const { return count_; }
177
178
bool contains(T t) const {
179
for (int i = 0; i < count_; i++) {
180
if (data_[i] == t)
181
return true;
182
}
183
return false;
184
}
185
186
// Out of bounds (past size() - 1) is undefined behavior.
187
T &operator[] (const size_t index) { return data_[index]; }
188
const T &operator[] (const size_t index) const { return data_[index]; }
189
190
// These two are invalid if empty().
191
const T &back() const { return (*this)[size() - 1]; }
192
const T &front() const { return (*this)[0]; }
193
194
bool operator == (const FixedVec<T, MaxSize> &other) const {
195
if (count_ != other.count_)
196
return false;
197
for (int i = 0; i < count_; i++) {
198
if (!(data_[i] == other.data_[i])) {
199
return false;
200
}
201
}
202
return true;
203
}
204
205
private:
206
int count_ = 0; // first in the struct just so it's more visible in the VS debugger.
207
T data_[MaxSize];
208
};
209
210