1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkTDArray_DEFINED
#define SkTDArray_DEFINED
#include "include/private/base/SkAPI.h"
#include "include/private/base/SkAssert.h"
#include "include/private/base/SkTo.h"
#include <algorithm>
#include <cstddef>
#include <initializer_list>
class SK_SPI SkTDStorage {
public:
explicit SkTDStorage(int sizeOfT);
SkTDStorage(const void* src, int size, int sizeOfT);
// Copy
SkTDStorage(const SkTDStorage& that);
SkTDStorage& operator= (const SkTDStorage& that);
// Move
SkTDStorage(SkTDStorage&& that);
SkTDStorage& operator= (SkTDStorage&& that);
~SkTDStorage();
void reset();
void swap(SkTDStorage& that);
// Size routines
bool empty() const { return fSize == 0; }
void clear() { fSize = 0; }
int size() const { return fSize; }
void resize(int newSize);
size_t size_bytes() const { return this->bytes(fSize); }
// Capacity routines
int capacity() const { return fCapacity; }
void reserve(int newCapacity);
void shrink_to_fit();
void* data() { return fStorage; }
const void* data() const { return fStorage; }
// Deletion routines
void erase(int index, int count);
// Removes the entry at 'index' and replaces it with the last array element
void removeShuffle(int index);
// Insertion routines
void* prepend();
void append();
void append(int count);
void* append(const void* src, int count);
void* insert(int index);
void* insert(int index, int count, const void* src);
void pop_back() {
SkASSERT(fSize > 0);
fSize--;
}
friend bool operator==(const SkTDStorage& a, const SkTDStorage& b);
friend bool operator!=(const SkTDStorage& a, const SkTDStorage& b) {
return !(a == b);
}
private:
size_t bytes(int n) const { return SkToSizeT(n * fSizeOfT); }
void* address(int n) { return fStorage + this->bytes(n); }
// Adds delta to fSize. Crash if outside [0, INT_MAX]
int calculateSizeOrDie(int delta);
// Move the tail of the array defined by the indexes tailStart and tailEnd to dstIndex. The
// elements at dstIndex are overwritten by the tail.
void moveTail(int dstIndex, int tailStart, int tailEnd);
// Copy src into the array at dstIndex.
void copySrc(int dstIndex, const void* src, int count);
const int fSizeOfT;
std::byte* fStorage{nullptr};
int fCapacity{0}; // size of the allocation in fArray (#elements)
int fSize{0}; // logical number of elements (fSize <= fCapacity)
};
static inline void swap(SkTDStorage& a, SkTDStorage& b) {
a.swap(b);
}
// SkTDArray<T> implements a std::vector-like array for raw data-only objects that do not require
// construction or destruction. The constructor and destructor for T will not be called; T objects
// will always be moved via raw memcpy. Newly created T objects will contain uninitialized memory.
template <typename T> class SkTDArray {
public:
SkTDArray() : fStorage{sizeof(T)} {}
SkTDArray(const T src[], int count) : fStorage{src, count, sizeof(T)} { }
SkTDArray(const std::initializer_list<T>& list) : SkTDArray(list.begin(), list.size()) {}
// Copy
SkTDArray(const SkTDArray<T>& src) : SkTDArray(src.data(), src.size()) {}
SkTDArray<T>& operator=(const SkTDArray<T>& src) {
fStorage = src.fStorage;
return *this;
}
// Move
SkTDArray(SkTDArray<T>&& src) : fStorage{std::move(src.fStorage)} {}
SkTDArray<T>& operator=(SkTDArray<T>&& src) {
fStorage = std::move(src.fStorage);
return *this;
}
friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
return a.fStorage == b.fStorage;
}
friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) { return !(a == b); }
void swap(SkTDArray<T>& that) {
using std::swap;
swap(fStorage, that.fStorage);
}
bool empty() const { return fStorage.empty(); }
// Return the number of elements in the array
int size() const { return fStorage.size(); }
// Return the total number of elements allocated.
// Note: capacity() - size() gives you the number of elements you can add without causing an
// allocation.
int capacity() const { return fStorage.capacity(); }
// return the number of bytes in the array: count * sizeof(T)
size_t size_bytes() const { return fStorage.size_bytes(); }
T* data() { return static_cast<T*>(fStorage.data()); }
const T* data() const { return static_cast<const T*>(fStorage.data()); }
T* begin() { return this->data(); }
const T* begin() const { return this->data(); }
T* end() { return this->data() + this->size(); }
const T* end() const { return this->data() + this->size(); }
T& operator[](int index) {
SkASSERT(index < this->size());
return this->data()[index];
}
const T& operator[](int index) const {
SkASSERT(index < this->size());
return this->data()[index];
}
const T& back() const {
SkASSERT(this->size() > 0);
return this->data()[this->size() - 1];
}
T& back() {
SkASSERT(this->size() > 0);
return this->data()[this->size() - 1];
}
void reset() {
fStorage.reset();
}
void clear() {
fStorage.clear();
}
// Sets the number of elements in the array.
// If the array does not have space for count elements, it will increase
// the storage allocated to some amount greater than that required.
// It will never shrink the storage.
void resize(int count) {
fStorage.resize(count);
}
void reserve(int n) {
fStorage.reserve(n);
}
T* append() {
fStorage.append();
return this->end() - 1;
}
T* append(int count) {
fStorage.append(count);
return this->end() - count;
}
T* append(int count, const T* src) {
return static_cast<T*>(fStorage.append(src, count));
}
T* insert(int index) {
return static_cast<T*>(fStorage.insert(index));
}
T* insert(int index, int count, const T* src = nullptr) {
return static_cast<T*>(fStorage.insert(index, count, src));
}
void remove(int index, int count = 1) {
fStorage.erase(index, count);
}
void removeShuffle(int index) {
fStorage.removeShuffle(index);
}
// routines to treat the array like a stack
void push_back(const T& v) {
this->append();
this->back() = v;
}
void pop_back() { fStorage.pop_back(); }
void shrink_to_fit() {
fStorage.shrink_to_fit();
}
private:
SkTDStorage fStorage;
};
template <typename T> static inline void swap(SkTDArray<T>& a, SkTDArray<T>& b) { a.swap(b); }
#endif
|