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/FastVec.h
Views: 1401
1
#pragma once
2
3
// Yet another replacement for std::vector, this time for use in graphics queues.
4
// Its major difference is that you can append uninitialized structures and initialize them after.
5
// This is not allows by std::vector but is very useful for our sometimes oversized unions.
6
// Also, copies during resize are done by memcpy, not by any move constructor or similar.
7
8
#include <cstdlib>
9
#include <cstring>
10
#include <cstdint>
11
12
#include "Common/Log.h"
13
14
template<class T>
15
class FastVec {
16
public:
17
FastVec() {}
18
FastVec(size_t initialCapacity) {
19
capacity_ = initialCapacity;
20
data_ = (T *)malloc(initialCapacity * sizeof(T));
21
_assert_(data_ != nullptr);
22
}
23
~FastVec() { free(data_); }
24
25
T &push_uninitialized() {
26
if (size_ < capacity_) {
27
size_++;
28
return data_[size_ - 1];
29
} else {
30
ExtendByOne();
31
return data_[size_ - 1];
32
}
33
}
34
35
void push_back(const T &t) {
36
T &dest = push_uninitialized();
37
dest = t;
38
}
39
40
// Move constructor
41
FastVec(FastVec &&other) {
42
data_ = other.data_;
43
size_ = other.size_;
44
capacity_ = other.capacity_;
45
other.data_ = nullptr;
46
other.size_ = 0;
47
other.capacity_ = 0;
48
}
49
50
FastVec &operator=(FastVec &&other) {
51
if (this != &other) {
52
free(data_);
53
data_ = other.data_;
54
size_ = other.size_;
55
capacity_ = other.capacity_;
56
other.data_ = nullptr;
57
other.size_ = 0;
58
other.capacity_ = 0;
59
}
60
return *this;
61
}
62
63
// No copy constructor.
64
FastVec(const FastVec &other) = delete;
65
FastVec &operator=(const FastVec &other) = delete;
66
67
size_t size() const { return size_; }
68
size_t capacity() const { return capacity_; }
69
void clear() { size_ = 0; }
70
bool empty() const { return size_ == 0; }
71
72
const T *data() const { return data_; }
73
74
T *begin() { return data_; }
75
T *end() { return data_ + size_; }
76
const T *begin() const { return data_; }
77
const T *end() const { return data_ + size_; }
78
79
// Out of bounds (past size() - 1) is undefined behavior.
80
T &operator[] (const size_t index) { return data_[index]; }
81
const T &operator[] (const size_t index) const { return data_[index]; }
82
T &at(const size_t index) { return data_[index]; }
83
const T &at(const size_t index) const { return data_[index]; }
84
85
// These two are invalid if empty().
86
const T &back() const { return (*this)[size() - 1]; }
87
const T &front() const { return (*this)[0]; }
88
89
// Limited functionality for inserts and similar, add as needed.
90
T &insert(T *iter) {
91
int pos = iter - data_;
92
ExtendByOne();
93
if (pos + 1 < (int)size_) {
94
memmove(data_ + pos + 1, data_ + pos, (size_ - pos) * sizeof(T));
95
}
96
return data_[pos];
97
}
98
99
void insert(T *destIter, const T *beginIter, const T *endIter) {
100
int pos = destIter - data_;
101
if (beginIter == endIter)
102
return;
103
size_t newItems = endIter - beginIter;
104
IncreaseCapacityTo(size_ + newItems);
105
memmove(data_ + pos + newItems, data_ + pos, (size_ - pos) * sizeof(T));
106
memcpy(data_ + pos, beginIter, newItems * sizeof(T));
107
size_ += newItems;
108
}
109
110
void resize(size_t size) {
111
if (size < size_) {
112
size_ = size;
113
} else {
114
// TODO
115
}
116
}
117
118
void reserve(size_t newCapacity) {
119
IncreaseCapacityTo(newCapacity);
120
}
121
122
void extend(const T *newData, size_t count) {
123
IncreaseCapacityTo(size_ + count);
124
memcpy(data_ + size_, newData, count * sizeof(T));
125
size_ += count;
126
}
127
128
T *extend_uninitialized(size_t count) {
129
size_t sz = size_;
130
if (size_ + count <= capacity_) {
131
size_ += count;
132
return &data_[sz];
133
} else {
134
size_t newCapacity = size_ + count * 2; // Leave some extra room when growing in all cases
135
if (newCapacity < capacity_ * 2) {
136
// Standard amortized O(1).
137
newCapacity = capacity_ * 2;
138
}
139
IncreaseCapacityTo(newCapacity);
140
size_ += count;
141
return &data_[sz];
142
}
143
}
144
145
void LockCapacity() {
146
#ifdef _DEBUG
147
capacityLocked_ = true;
148
#endif
149
}
150
151
private:
152
void IncreaseCapacityTo(size_t newCapacity) {
153
#ifdef _DEBUG
154
_dbg_assert_(!capacityLocked_);
155
#endif
156
if (newCapacity <= capacity_)
157
return;
158
T *oldData = data_;
159
data_ = (T *)malloc(sizeof(T) * newCapacity);
160
_assert_msg_(data_ != nullptr, "%d", (int)newCapacity);
161
if (capacity_ != 0) {
162
memcpy(data_, oldData, sizeof(T) * size_);
163
free(oldData);
164
}
165
capacity_ = newCapacity;
166
}
167
168
void ExtendByOne() {
169
// We don't really extend capacity by one though - instead we use
170
// the usual doubling amortization.
171
size_t newCapacity = capacity_ * 2;
172
if (newCapacity < 16) {
173
newCapacity = 16;
174
}
175
IncreaseCapacityTo(newCapacity);
176
size_++;
177
}
178
179
size_t size_ = 0;
180
size_t capacity_ = 0;
181
T *data_ = nullptr;
182
#ifdef _DEBUG
183
bool capacityLocked_ = false;
184
#endif
185
};
186
187
// Simple cyclical vector.
188
template <class T, size_t size>
189
class HistoryBuffer {
190
public:
191
T &Add(size_t index) {
192
#ifdef _DEBUG
193
_dbg_assert_((int64_t)index >= 0);
194
#endif
195
if (index > maxIndex_)
196
maxIndex_ = index;
197
T &entry = data_[index % size];
198
entry = T{};
199
return entry;
200
}
201
202
const T &Back(size_t index) const {
203
#ifdef _DEBUG
204
_dbg_assert_(index < maxIndex_ && index < size);
205
#endif
206
return data_[(maxIndex_ - index) % size];
207
}
208
209
// Out of bounds (past size() - 1) is undefined behavior.
210
T &operator[] (const size_t index) {
211
#ifdef _DEBUG
212
_dbg_assert_(index <= maxIndex_);
213
#endif
214
return data_[index % size];
215
}
216
const T &operator[] (const size_t index) const {
217
#ifdef _DEBUG
218
_dbg_assert_(index <= maxIndex_);
219
#endif
220
return data_[index % size];
221
}
222
size_t MaxIndex() const {
223
return maxIndex_;
224
}
225
226
private:
227
T data_[size]{};
228
size_t maxIndex_ = 0;
229
};
230
231