blob: 8af54bbcc5bb58382ff739201999ad1d40f93bfc [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"
14
ehsan.akhgaridb5f7bf2014-07-09 11:13:55 -070015template <typename T> class SkTDArray {
reed@android.com8a1c16f2008-12-17 15:59:43 +000016public:
17 SkTDArray() {
18 fReserve = fCount = 0;
19 fArray = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000020 }
robertphillips@google.come9cd27d2013-10-16 17:48:11 +000021 SkTDArray(const T src[], int count) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000022 SkASSERT(src || count == 0);
23
24 fReserve = fCount = 0;
25 fArray = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000026 if (count) {
27 fArray = (T*)sk_malloc_throw(count * sizeof(T));
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 memcpy(fArray, src, sizeof(T) * count);
29 fReserve = fCount = count;
30 }
31 }
32 SkTDArray(const SkTDArray<T>& src) {
33 fReserve = fCount = 0;
34 fArray = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +000035 SkTDArray<T> tmp(src.fArray, src.fCount);
36 this->swap(tmp);
37 }
38 ~SkTDArray() {
39 sk_free(fArray);
40 }
41
42 SkTDArray<T>& operator=(const SkTDArray<T>& src) {
43 if (this != &src) {
44 if (src.fCount > fReserve) {
45 SkTDArray<T> tmp(src.fArray, src.fCount);
46 this->swap(tmp);
47 } else {
mtkleincc881da2015-12-08 11:55:17 -080048 sk_careful_memcpy(fArray, src.fArray, sizeof(T) * src.fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +000049 fCount = src.fCount;
50 }
51 }
52 return *this;
53 }
54
reed@google.comb530ef52011-07-20 19:55:42 +000055 friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000056 return a.fCount == b.fCount &&
57 (a.fCount == 0 ||
58 !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
59 }
reed@google.com3467ee02013-05-29 18:05:52 +000060 friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) {
61 return !(a == b);
62 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000063
64 void swap(SkTDArray<T>& other) {
65 SkTSwap(fArray, other.fArray);
reed@android.com8a1c16f2008-12-17 15:59:43 +000066 SkTSwap(fReserve, other.fReserve);
67 SkTSwap(fCount, other.fCount);
68 }
69
reed@android.com0da41db2009-08-25 16:03:59 +000070 /** Return a ptr to the array of data, to be freed with sk_free. This also
71 resets the SkTDArray to be empty.
72 */
mtklein18300a32016-03-16 13:53:35 -070073 T* release() {
reed@android.com0da41db2009-08-25 16:03:59 +000074 T* array = fArray;
75 fArray = NULL;
76 fReserve = fCount = 0;
reed@android.com0da41db2009-08-25 16:03:59 +000077 return array;
78 }
79
reed@android.com8a1c16f2008-12-17 15:59:43 +000080 bool isEmpty() const { return fCount == 0; }
reed@google.com1271d782011-11-28 19:54:12 +000081
82 /**
83 * Return the number of elements in the array
84 */
robertphillips@google.come9cd27d2013-10-16 17:48:11 +000085 int count() const { return fCount; }
reed@google.com1271d782011-11-28 19:54:12 +000086
87 /**
commit-bot@chromium.org046f1f62014-02-11 10:17:02 +000088 * Return the total number of elements allocated.
89 * reserved() - count() gives you the number of elements you can add
90 * without causing an allocation.
91 */
92 int reserved() const { return fReserve; }
93
94 /**
reed@google.com1271d782011-11-28 19:54:12 +000095 * return the number of bytes in the array: count * sizeof(T)
96 */
97 size_t bytes() const { return fCount * sizeof(T); }
98
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +000099 T* begin() { return fArray; }
100 const T* begin() const { return fArray; }
101 T* end() { return fArray ? fArray + fCount : NULL; }
102 const T* end() const { return fArray ? fArray + fCount : NULL; }
103
104 T& operator[](int index) {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000105 SkASSERT(index < fCount);
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000106 return fArray[index];
107 }
108 const T& operator[](int index) const {
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000109 SkASSERT(index < fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110 return fArray[index];
111 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000112
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000113 T& getAt(int index) {
114 return (*this)[index];
115 }
116 const T& getAt(int index) const {
humper@google.com7af56be2013-01-14 18:49:19 +0000117 return (*this)[index];
118 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119
120 void reset() {
121 if (fArray) {
122 sk_free(fArray);
123 fArray = NULL;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 fReserve = fCount = 0;
125 } else {
126 SkASSERT(fReserve == 0 && fCount == 0);
127 }
128 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000129
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 void rewind() {
131 // same as setCount(0)
132 fCount = 0;
133 }
134
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000135 /**
136 * Sets the number of elements in the array.
137 * If the array does not have space for count elements, it will increase
138 * the storage allocated to some amount greater than that required.
robertphillips91df6c22015-04-24 11:10:51 -0700139 * It will never shrink the storage.
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000140 */
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000141 void setCount(int count) {
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000142 SkASSERT(count >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 if (count > fReserve) {
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000144 this->resizeStorageToAtLeast(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 }
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000146 fCount = count;
147 }
148
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000149 void setReserve(int reserve) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 if (reserve > fReserve) {
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000151 this->resizeStorageToAtLeast(reserve);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 }
153 }
154
155 T* prepend() {
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000156 this->adjustCount(1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
158 return fArray;
159 }
160
161 T* append() {
162 return this->append(1, NULL);
163 }
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000164 T* append(int count, const T* src = NULL) {
165 int oldCount = fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 if (count) {
167 SkASSERT(src == NULL || fArray == NULL ||
168 src + count <= fArray || fArray + oldCount <= src);
169
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000170 this->adjustCount(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 if (src) {
172 memcpy(fArray + oldCount, src, sizeof(T) * count);
173 }
174 }
175 return fArray + oldCount;
176 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000177
reed@android.com8a1c16f2008-12-17 15:59:43 +0000178 T* appendClear() {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000179 T* result = this->append();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 *result = 0;
181 return result;
182 }
183
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000184 T* insert(int index) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 return this->insert(index, 1, NULL);
186 }
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000187 T* insert(int index, int count, const T* src = NULL) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 SkASSERT(count);
189 SkASSERT(index <= fCount);
tomhudson@google.comffe39bd2012-05-17 15:38:00 +0000190 size_t oldCount = fCount;
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000191 this->adjustCount(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 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
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000200 void remove(int index, int count = 1) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 SkASSERT(index + count <= fCount);
202 fCount = fCount - count;
203 memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
204 }
205
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000206 void removeShuffle(int index) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 SkASSERT(index < fCount);
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000208 int newCount = fCount - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209 fCount = newCount;
210 if (index != newCount) {
211 memcpy(fArray + index, fArray + newCount, sizeof(T));
212 }
213 }
214
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) {
fmalitaf89f60f2015-02-13 08:55:24 -0800221 return SkToInt(iter - fArray);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000222 }
223 }
224 return -1;
225 }
226
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) {
reed@google.com6fcd28b2014-02-04 16:03:51 +0000233 return SkToInt(iter - stop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 }
235 }
236 return -1;
237 }
238
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000239 /**
epoger@google.comaf07d062012-07-13 14:53:18 +0000240 * Returns true iff the array contains this element.
241 */
242 bool contains(const T& elem) const {
243 return (this->find(elem) >= 0);
244 }
245
246 /**
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000247 * 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 */
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000250 int copyRange(T* dst, int index, int max) const {
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000251 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
261 void copy(T* dst) const {
zachr@google.comc6081ab2013-07-01 17:04:32 +0000262 this->copyRange(dst, 0, fCount);
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000263 }
264
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265 // routines to treat the array like a stack
mtkleinaa90d002014-09-11 06:36:11 -0700266 T* push() { return this->append(); }
267 void push(const T& elem) { *this->append() = elem; }
268 const T& top() const { return (*this)[fCount - 1]; }
269 T& top() { return (*this)[fCount - 1]; }
270 void pop(T* elem) { SkASSERT(fCount > 0); if (elem) *elem = (*this)[fCount - 1]; --fCount; }
271 void pop() { SkASSERT(fCount > 0); --fCount; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272
273 void deleteAll() {
274 T* iter = fArray;
275 T* stop = fArray + fCount;
276 while (iter < stop) {
halcanary385fe4d2015-08-26 13:07:48 -0700277 delete *iter;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 iter += 1;
279 }
280 this->reset();
281 }
282
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
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 }
reed@android.com8433b5d2009-07-03 02:52:27 +0000302
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
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000313 void visitAll(void visitor(T&)) {
bsalomon@google.com21cbec42013-01-07 17:23:00 +0000314 T* stop = this->end();
315 for (T* curr = this->begin(); curr < stop; curr++) {
316 if (*curr) {
317 visitor(*curr);
318 }
319 }
320 }
321
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322#ifdef SK_DEBUG
323 void validate() const {
324 SkASSERT((fReserve == 0 && fArray == NULL) ||
325 (fReserve > 0 && fArray != NULL));
326 SkASSERT(fCount <= fReserve);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327 }
328#endif
329
mtklein092dab92014-10-09 18:22:41 -0700330 void shrinkToFit() {
331 fReserve = fCount;
332 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
333 }
334
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335private:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336 T* fArray;
robertphillips@google.come9cd27d2013-10-16 17:48:11 +0000337 int fReserve;
338 int fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000339
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000340 /**
341 * Adjusts the number of elements in the array.
342 * This is the same as calling setCount(count() + delta).
343 */
344 void adjustCount(int delta) {
345 this->setCount(fCount + delta);
346 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000348 /**
commit-bot@chromium.orga87b21c2014-02-11 18:22:04 +0000349 * Increase the storage allocation such that it can hold (fCount + extra)
350 * elements.
351 * It never shrinks the allocation, and it may increase the allocation by
352 * more than is strictly required, based on a private growth heuristic.
353 *
354 * note: does NOT modify fCount
355 */
356 void resizeStorageToAtLeast(int count) {
357 SkASSERT(count > fReserve);
commit-bot@chromium.orgca21a002014-02-13 18:35:54 +0000358 fReserve = count + 4;
359 fReserve += fReserve / 4;
360 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 }
362};
363
364#endif