blob: b0664aaa5b0eb767a7db7d384dd1a35d16343281 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#ifndef SkTDArray_DEFINED
11#define SkTDArray_DEFINED
12
13#include "SkTypes.h"
Herb Derbyb549cc32017-03-27 13:35:15 -040014#include "SkMalloc.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
ehsan.akhgaridb5f7bf2014-07-09 11:13:55 -070016template <typename T> class SkTDArray {
reed@android.com8a1c16f2008-12-17 15:59:43 +000017public:
halcanary9be37202016-08-08 07:21:42 -070018 SkTDArray() : fArray(nullptr), fReserve(0), fCount(0) {}
robertphillips@google.come9cd27d2013-10-16 17:48:11 +000019 SkTDArray(const T src[], int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000020 SkASSERT(src || count == 0);
21
22 fReserve = fCount = 0;
Ben Wagnera93a14a2017-08-28 10:34:05 -040023 fArray = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 if (count) {
25 fArray = (T*)sk_malloc_throw(count * sizeof(T));
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 memcpy(fArray, src, sizeof(T) * count);
27 fReserve = fCount = count;
28 }
29 }
halcanary9be37202016-08-08 07:21:42 -070030 SkTDArray(const SkTDArray<T>& src) : fArray(nullptr), fReserve(0), fCount(0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 SkTDArray<T> tmp(src.fArray, src.fCount);
32 this->swap(tmp);
33 }
halcanary9be37202016-08-08 07:21:42 -070034 SkTDArray(SkTDArray<T>&& src) : fArray(nullptr), fReserve(0), fCount(0) {
35 this->swap(src);
36 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000037 ~SkTDArray() {
38 sk_free(fArray);
39 }
40
41 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 {
mtkleincc881da2015-12-08 11:55:17 -080047 sk_careful_memcpy(fArray, src.fArray, sizeof(T) * src.fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +000048 fCount = src.fCount;
49 }
50 }
51 return *this;
52 }
halcanary9be37202016-08-08 07:21:42 -070053 SkTDArray<T>& operator=(SkTDArray<T>&& src) {
54 if (this != &src) {
55 this->swap(src);
56 src.reset();
57 }
58 return *this;
59 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000060
reed@google.comb530ef52011-07-20 19:55:42 +000061 friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 return a.fCount == b.fCount &&
63 (a.fCount == 0 ||
64 !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
65 }
reed@google.com3467ee02013-05-29 18:05:52 +000066 friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) {
67 return !(a == b);
68 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000069
70 void swap(SkTDArray<T>& other) {
71 SkTSwap(fArray, other.fArray);
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 SkTSwap(fReserve, other.fReserve);
73 SkTSwap(fCount, other.fCount);
74 }
75
Brian Salomon958fbc42017-01-30 17:01:28 -050076 // The deleter that ought to be used for a std:: smart pointer that takes ownership from
77 // release().
78 struct Deleter {
79 void operator()(const void* p) { sk_free((void*)p); }
80 };
81
reed@android.com0da41db2009-08-25 16:03:59 +000082 /** Return a ptr to the array of data, to be freed with sk_free. This also
83 resets the SkTDArray to be empty.
84 */
mtklein18300a32016-03-16 13:53:35 -070085 T* release() {
reed@android.com0da41db2009-08-25 16:03:59 +000086 T* array = fArray;
Ben Wagnera93a14a2017-08-28 10:34:05 -040087 fArray = nullptr;
reed@android.com0da41db2009-08-25 16:03:59 +000088 fReserve = fCount = 0;
reed@android.com0da41db2009-08-25 16:03:59 +000089 return array;
90 }
91
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 bool isEmpty() const { return fCount == 0; }
reed@google.com1271d782011-11-28 19:54:12 +000093
94 /**
95 * Return the number of elements in the array
96 */
robertphillips@google.come9cd27d2013-10-16 17:48:11 +000097 int count() const { return fCount; }
reed@google.com1271d782011-11-28 19:54:12 +000098
99 /**
commit-bot@chromium.org046f1f62014-02-11 10:17:02 +0000100 * Return the total number of elements allocated.
101 * reserved() - count() gives you the number of elements you can add
102 * without causing an allocation.
103 */
104 int reserved() const { return fReserve; }
105
106 /**
reed@google.com1271d782011-11-28 19:54:12 +0000107 * return the number of bytes in the array: count * sizeof(T)
108 */
109 size_t bytes() const { return fCount * sizeof(T); }
110
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000111 T* begin() { return fArray; }
112 const T* begin() const { return fArray; }
Ben Wagnera93a14a2017-08-28 10:34:05 -0400113 T* end() { return fArray ? fArray + fCount : nullptr; }
114 const T* end() const { return fArray ? fArray + fCount : nullptr; }
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000115
116 T& operator[](int index) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000117 SkASSERT(index < fCount);
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000118 return fArray[index];
119 }
120 const T& operator[](int index) const {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000121 SkASSERT(index < fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 return fArray[index];
123 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000124
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000125 T& getAt(int index) {
126 return (*this)[index];
127 }
128 const T& getAt(int index) const {
humper@google.com7af56be2013-01-14 18:49:19 +0000129 return (*this)[index];
130 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131
132 void reset() {
133 if (fArray) {
134 sk_free(fArray);
Ben Wagnera93a14a2017-08-28 10:34:05 -0400135 fArray = nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 fReserve = fCount = 0;
137 } else {
138 SkASSERT(fReserve == 0 && fCount == 0);
139 }
140 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000141
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 void rewind() {
143 // same as setCount(0)
144 fCount = 0;
145 }
146
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000147 /**
148 * Sets the number of elements in the array.
149 * If the array does not have space for count elements, it will increase
150 * the storage allocated to some amount greater than that required.
robertphillips91df6c22015-04-24 11:10:51 -0700151 * It will never shrink the storage.
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000152 */
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000153 void setCount(int count) {
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000154 SkASSERT(count >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 if (count > fReserve) {
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000156 this->resizeStorageToAtLeast(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 }
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000158 fCount = count;
159 }
160
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000161 void setReserve(int reserve) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 if (reserve > fReserve) {
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000163 this->resizeStorageToAtLeast(reserve);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164 }
165 }
166
167 T* prepend() {
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000168 this->adjustCount(1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
170 return fArray;
171 }
172
173 T* append() {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400174 return this->append(1, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 }
Ben Wagnera93a14a2017-08-28 10:34:05 -0400176 T* append(int count, const T* src = nullptr) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000177 int oldCount = fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 if (count) {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400179 SkASSERT(src == nullptr || fArray == nullptr ||
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 src + count <= fArray || fArray + oldCount <= src);
181
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000182 this->adjustCount(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000183 if (src) {
184 memcpy(fArray + oldCount, src, sizeof(T) * count);
185 }
186 }
187 return fArray + oldCount;
188 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000189
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190 T* appendClear() {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000191 T* result = this->append();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 *result = 0;
193 return result;
194 }
195
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000196 T* insert(int index) {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400197 return this->insert(index, 1, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000198 }
Ben Wagnera93a14a2017-08-28 10:34:05 -0400199 T* insert(int index, int count, const T* src = nullptr) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 SkASSERT(count);
201 SkASSERT(index <= fCount);
tomhudson@google.comffe39bd2012-05-17 15:38:00 +0000202 size_t oldCount = fCount;
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000203 this->adjustCount(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 T* dst = fArray + index;
205 memmove(dst + count, dst, sizeof(T) * (oldCount - index));
206 if (src) {
207 memcpy(dst, src, sizeof(T) * count);
208 }
209 return dst;
210 }
211
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000212 void remove(int index, int count = 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 SkASSERT(index + count <= fCount);
214 fCount = fCount - count;
215 memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
216 }
217
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000218 void removeShuffle(int index) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 SkASSERT(index < fCount);
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000220 int newCount = fCount - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 fCount = newCount;
222 if (index != newCount) {
223 memcpy(fArray + index, fArray + newCount, sizeof(T));
224 }
225 }
226
reed22b2af12016-08-29 07:52:13 -0700227 template <typename S> int select(S&& selector) const {
228 const T* iter = fArray;
229 const T* stop = fArray + fCount;
230
231 for (; iter < stop; iter++) {
232 if (selector(*iter)) {
233 return SkToInt(iter - fArray);
234 }
235 }
236 return -1;
237 }
Herb Derbyd7b34a52017-03-20 11:19:23 -0400238
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239 int find(const T& elem) const {
240 const T* iter = fArray;
241 const T* stop = fArray + fCount;
242
243 for (; iter < stop; iter++) {
244 if (*iter == elem) {
fmalitaf89f60f2015-02-13 08:55:24 -0800245 return SkToInt(iter - fArray);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246 }
247 }
248 return -1;
249 }
250
251 int rfind(const T& elem) const {
252 const T* iter = fArray + fCount;
253 const T* stop = fArray;
254
255 while (iter > stop) {
256 if (*--iter == elem) {
reed@google.com6fcd28b2014-02-04 16:03:51 +0000257 return SkToInt(iter - stop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 }
259 }
260 return -1;
261 }
262
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000263 /**
epoger@google.comaf07d062012-07-13 14:53:18 +0000264 * Returns true iff the array contains this element.
265 */
266 bool contains(const T& elem) const {
267 return (this->find(elem) >= 0);
268 }
269
270 /**
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000271 * Copies up to max elements into dst. The number of items copied is
272 * capped by count - index. The actual number copied is returned.
273 */
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000274 int copyRange(T* dst, int index, int max) const {
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000275 SkASSERT(max >= 0);
276 SkASSERT(!max || dst);
277 if (index >= fCount) {
278 return 0;
279 }
280 int count = SkMin32(max, fCount - index);
281 memcpy(dst, fArray + index, sizeof(T) * count);
282 return count;
283 }
284
285 void copy(T* dst) const {
zachr@google.comc6081ab2013-07-01 17:04:32 +0000286 this->copyRange(dst, 0, fCount);
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000287 }
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289 // routines to treat the array like a stack
mtkleinaa90d002014-09-11 06:36:11 -0700290 T* push() { return this->append(); }
291 void push(const T& elem) { *this->append() = elem; }
292 const T& top() const { return (*this)[fCount - 1]; }
293 T& top() { return (*this)[fCount - 1]; }
294 void pop(T* elem) { SkASSERT(fCount > 0); if (elem) *elem = (*this)[fCount - 1]; --fCount; }
295 void pop() { SkASSERT(fCount > 0); --fCount; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296
297 void deleteAll() {
298 T* iter = fArray;
299 T* stop = fArray + fCount;
300 while (iter < stop) {
halcanary385fe4d2015-08-26 13:07:48 -0700301 delete *iter;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000302 iter += 1;
303 }
304 this->reset();
305 }
306
307 void freeAll() {
308 T* iter = fArray;
309 T* stop = fArray + fCount;
310 while (iter < stop) {
311 sk_free(*iter);
312 iter += 1;
313 }
314 this->reset();
315 }
316
317 void unrefAll() {
318 T* iter = fArray;
319 T* stop = fArray + fCount;
320 while (iter < stop) {
321 (*iter)->unref();
322 iter += 1;
323 }
324 this->reset();
325 }
reed@android.com8433b5d2009-07-03 02:52:27 +0000326
327 void safeUnrefAll() {
328 T* iter = fArray;
329 T* stop = fArray + fCount;
330 while (iter < stop) {
331 SkSafeUnref(*iter);
332 iter += 1;
333 }
334 this->reset();
335 }
336
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000337 void visitAll(void visitor(T&)) {
bsalomon@google.com21cbec42013-01-07 17:23:00 +0000338 T* stop = this->end();
339 for (T* curr = this->begin(); curr < stop; curr++) {
340 if (*curr) {
341 visitor(*curr);
342 }
343 }
344 }
345
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346#ifdef SK_DEBUG
347 void validate() const {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400348 SkASSERT((fReserve == 0 && fArray == nullptr) ||
349 (fReserve > 0 && fArray != nullptr));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 SkASSERT(fCount <= fReserve);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 }
352#endif
353
mtklein092dab92014-10-09 18:22:41 -0700354 void shrinkToFit() {
355 fReserve = fCount;
356 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
357 }
358
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 T* fArray;
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000361 int fReserve;
362 int fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000363
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000364 /**
365 * Adjusts the number of elements in the array.
366 * This is the same as calling setCount(count() + delta).
367 */
368 void adjustCount(int delta) {
369 this->setCount(fCount + delta);
370 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000372 /**
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000373 * Increase the storage allocation such that it can hold (fCount + extra)
374 * elements.
375 * It never shrinks the allocation, and it may increase the allocation by
376 * more than is strictly required, based on a private growth heuristic.
377 *
378 * note: does NOT modify fCount
379 */
380 void resizeStorageToAtLeast(int count) {
381 SkASSERT(count > fReserve);
commit-bot@chromium.orgca21a002014-02-13 18:35:54 +0000382 fReserve = count + 4;
383 fReserve += fReserve / 4;
384 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385 }
386};
387
388#endif