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