1 /*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9 #ifndef SkTDArray_DEFINED
10 #define SkTDArray_DEFINED
11
12 #include "SkMalloc.h"
13 #include "SkTo.h"
14 #include "SkTypes.h"
15
16 #include <initializer_list>
17 #include <utility>
18
19 template <typename T> class SkTDArray {
20 public:
SkTDArray()21 SkTDArray() : fArray(nullptr), fReserve(0), fCount(0) {}
SkTDArray(const T src[],int count)22 SkTDArray(const T src[], int count) {
23 SkASSERT(src || count == 0);
24
25 fReserve = fCount = 0;
26 fArray = nullptr;
27 if (count) {
28 fArray = (T*)sk_malloc_throw(count * sizeof(T));
29 memcpy(fArray, src, sizeof(T) * count);
30 fReserve = fCount = count;
31 }
32 }
SkTDArray(const std::initializer_list<T> & list)33 SkTDArray(const std::initializer_list<T>& list) : SkTDArray(list.begin(), list.size()) {}
SkTDArray(const SkTDArray<T> & src)34 SkTDArray(const SkTDArray<T>& src) : fArray(nullptr), fReserve(0), fCount(0) {
35 SkTDArray<T> tmp(src.fArray, src.fCount);
36 this->swap(tmp);
37 }
SkTDArray(SkTDArray<T> && src)38 SkTDArray(SkTDArray<T>&& src) : fArray(nullptr), fReserve(0), fCount(0) {
39 this->swap(src);
40 }
~SkTDArray()41 ~SkTDArray() {
42 sk_free(fArray);
43 }
44
45 SkTDArray<T>& operator=(const SkTDArray<T>& src) {
46 if (this != &src) {
47 if (src.fCount > fReserve) {
48 SkTDArray<T> tmp(src.fArray, src.fCount);
49 this->swap(tmp);
50 } else {
51 sk_careful_memcpy(fArray, src.fArray, sizeof(T) * src.fCount);
52 fCount = src.fCount;
53 }
54 }
55 return *this;
56 }
57 SkTDArray<T>& operator=(SkTDArray<T>&& src) {
58 if (this != &src) {
59 this->swap(src);
60 src.reset();
61 }
62 return *this;
63 }
64
65 friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
66 return a.fCount == b.fCount &&
67 (a.fCount == 0 ||
68 !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
69 }
70 friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) {
71 return !(a == b);
72 }
73
swap(SkTDArray<T> & that)74 void swap(SkTDArray<T>& that) {
75 using std::swap;
76 swap(fArray, that.fArray);
77 swap(fReserve, that.fReserve);
78 swap(fCount, that.fCount);
79 }
80
isEmpty()81 bool isEmpty() const { return fCount == 0; }
empty()82 bool empty() const { return this->isEmpty(); }
83
84 /**
85 * Return the number of elements in the array
86 */
count()87 int count() const { return fCount; }
size()88 size_t size() const { return fCount; }
89
90 /**
91 * Return the total number of elements allocated.
92 * reserved() - count() gives you the number of elements you can add
93 * without causing an allocation.
94 */
reserved()95 int reserved() const { return fReserve; }
96
97 /**
98 * return the number of bytes in the array: count * sizeof(T)
99 */
bytes()100 size_t bytes() const { return fCount * sizeof(T); }
101
begin()102 T* begin() { return fArray; }
begin()103 const T* begin() const { return fArray; }
end()104 T* end() { return fArray ? fArray + fCount : nullptr; }
end()105 const T* end() const { return fArray ? fArray + fCount : nullptr; }
106
107 T& operator[](int index) {
108 SkASSERT(index < fCount);
109 return fArray[index];
110 }
111 const T& operator[](int index) const {
112 SkASSERT(index < fCount);
113 return fArray[index];
114 }
115
getAt(int index)116 T& getAt(int index) {
117 return (*this)[index];
118 }
119
120
reset()121 void reset() {
122 if (fArray) {
123 sk_free(fArray);
124 fArray = nullptr;
125 fReserve = fCount = 0;
126 } else {
127 SkASSERT(fReserve == 0 && fCount == 0);
128 }
129 }
130
rewind()131 void rewind() {
132 // same as setCount(0)
133 fCount = 0;
134 }
135
136 /**
137 * Sets the number of elements in the array.
138 * If the array does not have space for count elements, it will increase
139 * the storage allocated to some amount greater than that required.
140 * It will never shrink the storage.
141 */
setCount(int count)142 void setCount(int count) {
143 SkASSERT(count >= 0);
144 if (count > fReserve) {
145 this->resizeStorageToAtLeast(count);
146 }
147 fCount = count;
148 }
149
setReserve(int reserve)150 void setReserve(int reserve) {
151 SkASSERT(reserve >= 0);
152 if (reserve > fReserve) {
153 this->resizeStorageToAtLeast(reserve);
154 }
155 }
reserve(size_t n)156 void reserve(size_t n) {
157 SkASSERT_RELEASE(SkTFitsIn<int>(n));
158 this->setReserve(SkToInt(n));
159 }
160
prepend()161 T* prepend() {
162 this->adjustCount(1);
163 memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
164 return fArray;
165 }
166
append()167 T* append() {
168 return this->append(1, nullptr);
169 }
170 T* append(int count, const T* src = nullptr) {
171 int oldCount = fCount;
172 if (count) {
173 SkASSERT(src == nullptr || fArray == nullptr ||
174 src + count <= fArray || fArray + oldCount <= src);
175
176 this->adjustCount(count);
177 if (src) {
178 memcpy(fArray + oldCount, src, sizeof(T) * count);
179 }
180 }
181 return fArray + oldCount;
182 }
183
insert(int index)184 T* insert(int index) {
185 return this->insert(index, 1, nullptr);
186 }
187 T* insert(int index, int count, const T* src = nullptr) {
188 SkASSERT(count);
189 SkASSERT(index <= fCount);
190 size_t oldCount = fCount;
191 this->adjustCount(count);
192 T* dst = fArray + index;
193 memmove(dst + count, dst, sizeof(T) * (oldCount - index));
194 if (src) {
195 memcpy(dst, src, sizeof(T) * count);
196 }
197 return dst;
198 }
199
200 void remove(int index, int count = 1) {
201 SkASSERT(index + count <= fCount);
202 fCount = fCount - count;
203 memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
204 }
205
removeShuffle(int index)206 void removeShuffle(int index) {
207 SkASSERT(index < fCount);
208 int newCount = fCount - 1;
209 fCount = newCount;
210 if (index != newCount) {
211 memcpy(fArray + index, fArray + newCount, sizeof(T));
212 }
213 }
214
find(const T & elem)215 int find(const T& elem) const {
216 const T* iter = fArray;
217 const T* stop = fArray + fCount;
218
219 for (; iter < stop; iter++) {
220 if (*iter == elem) {
221 return SkToInt(iter - fArray);
222 }
223 }
224 return -1;
225 }
226
rfind(const T & elem)227 int rfind(const T& elem) const {
228 const T* iter = fArray + fCount;
229 const T* stop = fArray;
230
231 while (iter > stop) {
232 if (*--iter == elem) {
233 return SkToInt(iter - stop);
234 }
235 }
236 return -1;
237 }
238
239 /**
240 * Returns true iff the array contains this element.
241 */
contains(const T & elem)242 bool contains(const T& elem) const {
243 return (this->find(elem) >= 0);
244 }
245
246 /**
247 * Copies up to max elements into dst. The number of items copied is
248 * capped by count - index. The actual number copied is returned.
249 */
copyRange(T * dst,int index,int max)250 int copyRange(T* dst, int index, int max) const {
251 SkASSERT(max >= 0);
252 SkASSERT(!max || dst);
253 if (index >= fCount) {
254 return 0;
255 }
256 int count = SkMin32(max, fCount - index);
257 memcpy(dst, fArray + index, sizeof(T) * count);
258 return count;
259 }
260
copy(T * dst)261 void copy(T* dst) const {
262 this->copyRange(dst, 0, fCount);
263 }
264
265 // routines to treat the array like a stack
push_back(const T & v)266 void push_back(const T& v) { *this->append() = v; }
push()267 T* push() { return this->append(); }
top()268 const T& top() const { return (*this)[fCount - 1]; }
top()269 T& top() { return (*this)[fCount - 1]; }
pop(T * elem)270 void pop(T* elem) { SkASSERT(fCount > 0); if (elem) *elem = (*this)[fCount - 1]; --fCount; }
pop()271 void pop() { SkASSERT(fCount > 0); --fCount; }
272
deleteAll()273 void deleteAll() {
274 T* iter = fArray;
275 T* stop = fArray + fCount;
276 while (iter < stop) {
277 delete *iter;
278 iter += 1;
279 }
280 this->reset();
281 }
282
freeAll()283 void freeAll() {
284 T* iter = fArray;
285 T* stop = fArray + fCount;
286 while (iter < stop) {
287 sk_free(*iter);
288 iter += 1;
289 }
290 this->reset();
291 }
292
unrefAll()293 void unrefAll() {
294 T* iter = fArray;
295 T* stop = fArray + fCount;
296 while (iter < stop) {
297 (*iter)->unref();
298 iter += 1;
299 }
300 this->reset();
301 }
302
safeUnrefAll()303 void safeUnrefAll() {
304 T* iter = fArray;
305 T* stop = fArray + fCount;
306 while (iter < stop) {
307 SkSafeUnref(*iter);
308 iter += 1;
309 }
310 this->reset();
311 }
312
313 #ifdef SK_DEBUG
validate()314 void validate() const {
315 SkASSERT((fReserve == 0 && fArray == nullptr) ||
316 (fReserve > 0 && fArray != nullptr));
317 SkASSERT(fCount <= fReserve);
318 }
319 #endif
320
shrinkToFit()321 void shrinkToFit() {
322 fReserve = fCount;
323 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
324 }
325
326 private:
327 T* fArray;
328 int fReserve;
329 int fCount;
330
331 /**
332 * Adjusts the number of elements in the array.
333 * This is the same as calling setCount(count() + delta).
334 */
adjustCount(int delta)335 void adjustCount(int delta) {
336 SkASSERT(delta > 0);
337
338 // We take care to avoid overflow here.
339 // The sum of fCount and delta is at most 4294967294, which fits fine in uint32_t.
340 uint32_t count = (uint32_t)fCount + (uint32_t)delta;
341 SkASSERT_RELEASE( SkTFitsIn<int>(count) );
342
343 this->setCount(SkTo<int>(count));
344 }
345
346 /**
347 * Increase the storage allocation such that it can hold (fCount + extra)
348 * elements.
349 * It never shrinks the allocation, and it may increase the allocation by
350 * more than is strictly required, based on a private growth heuristic.
351 *
352 * note: does NOT modify fCount
353 */
resizeStorageToAtLeast(int count)354 void resizeStorageToAtLeast(int count) {
355 SkASSERT(count > fReserve);
356
357 // We take care to avoid overflow here.
358 // The maximum value we can get for reserve here is 2684354563, which fits in uint32_t.
359 uint32_t reserve = (uint32_t)count + 4;
360 reserve += reserve / 4;
361 SkASSERT_RELEASE( SkTFitsIn<int>(reserve) );
362
363 fReserve = SkTo<int>(reserve);
364 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
365 }
366 };
367
swap(SkTDArray<T> & a,SkTDArray<T> & b)368 template <typename T> static inline void swap(SkTDArray<T>& a, SkTDArray<T>& b) {
369 a.swap(b);
370 }
371
372 #endif
373