blob: 8b8bb01e3df4e12e6e3be4506b8a380f9afb7011 [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
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +000015template <typename T> class SK_API SkTDArray {
reed@android.com8a1c16f2008-12-17 15:59:43 +000016public:
17 SkTDArray() {
18 fReserve = fCount = 0;
19 fArray = NULL;
20#ifdef SK_DEBUG
21 fData = NULL;
22#endif
23 }
24 SkTDArray(const T src[], size_t count) {
25 SkASSERT(src || count == 0);
26
27 fReserve = fCount = 0;
28 fArray = NULL;
29#ifdef SK_DEBUG
30 fData = NULL;
31#endif
32 if (count) {
33 fArray = (T*)sk_malloc_throw(count * sizeof(T));
34#ifdef SK_DEBUG
35 fData = (ArrayT*)fArray;
36#endif
37 memcpy(fArray, src, sizeof(T) * count);
38 fReserve = fCount = count;
39 }
40 }
41 SkTDArray(const SkTDArray<T>& src) {
42 fReserve = fCount = 0;
43 fArray = NULL;
44#ifdef SK_DEBUG
45 fData = NULL;
46#endif
47 SkTDArray<T> tmp(src.fArray, src.fCount);
48 this->swap(tmp);
49 }
50 ~SkTDArray() {
51 sk_free(fArray);
52 }
53
54 SkTDArray<T>& operator=(const SkTDArray<T>& src) {
55 if (this != &src) {
56 if (src.fCount > fReserve) {
57 SkTDArray<T> tmp(src.fArray, src.fCount);
58 this->swap(tmp);
59 } else {
60 memcpy(fArray, src.fArray, sizeof(T) * src.fCount);
61 fCount = src.fCount;
62 }
63 }
64 return *this;
65 }
66
reed@google.comb530ef52011-07-20 19:55:42 +000067 friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000068 return a.fCount == b.fCount &&
69 (a.fCount == 0 ||
70 !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
71 }
reed@google.com3467ee02013-05-29 18:05:52 +000072 friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) {
73 return !(a == b);
74 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000075
76 void swap(SkTDArray<T>& other) {
77 SkTSwap(fArray, other.fArray);
78#ifdef SK_DEBUG
79 SkTSwap(fData, other.fData);
80#endif
81 SkTSwap(fReserve, other.fReserve);
82 SkTSwap(fCount, other.fCount);
83 }
84
reed@android.com0da41db2009-08-25 16:03:59 +000085 /** Return a ptr to the array of data, to be freed with sk_free. This also
86 resets the SkTDArray to be empty.
87 */
88 T* detach() {
89 T* array = fArray;
90 fArray = NULL;
91 fReserve = fCount = 0;
92 SkDEBUGCODE(fData = NULL;)
93 return array;
94 }
95
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 bool isEmpty() const { return fCount == 0; }
reed@google.com1271d782011-11-28 19:54:12 +000097
98 /**
99 * Return the number of elements in the array
100 */
reed@google.comb158a822012-07-09 13:13:23 +0000101 int count() const { return (int)fCount; }
reed@google.com1271d782011-11-28 19:54:12 +0000102
103 /**
104 * return the number of bytes in the array: count * sizeof(T)
105 */
106 size_t bytes() const { return fCount * sizeof(T); }
107
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000108 T* begin() { return fArray; }
109 const T* begin() const { return fArray; }
110 T* end() { return fArray ? fArray + fCount : NULL; }
111 const T* end() const { return fArray ? fArray + fCount : NULL; }
112
113 T& operator[](int index) {
114 SkASSERT((unsigned)index < fCount);
115 return fArray[index];
116 }
117 const T& operator[](int index) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 SkASSERT((unsigned)index < fCount);
119 return fArray[index];
120 }
skia.committer@gmail.com7fc0e0a2013-01-15 02:01:40 +0000121
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000122 T& getAt(int index) {
123 return (*this)[index];
124 }
125 const T& getAt(int index) const {
humper@google.com7af56be2013-01-14 18:49:19 +0000126 return (*this)[index];
127 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128
129 void reset() {
130 if (fArray) {
131 sk_free(fArray);
132 fArray = NULL;
133#ifdef SK_DEBUG
134 fData = NULL;
135#endif
136 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
147 void setCount(size_t count) {
148 if (count > fReserve) {
149 this->growBy(count - fCount);
150 } else {
151 fCount = count;
152 }
153 }
154
155 void setReserve(size_t reserve) {
156 if (reserve > fReserve) {
157 SkASSERT(reserve > fCount);
158 size_t count = fCount;
159 this->growBy(reserve - fCount);
160 fCount = count;
161 }
162 }
163
164 T* prepend() {
165 this->growBy(1);
166 memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
167 return fArray;
168 }
169
170 T* append() {
171 return this->append(1, NULL);
172 }
173 T* append(size_t count, const T* src = NULL) {
tomhudson@google.comffe39bd2012-05-17 15:38:00 +0000174 size_t oldCount = fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175 if (count) {
176 SkASSERT(src == NULL || fArray == NULL ||
177 src + count <= fArray || fArray + oldCount <= src);
178
179 this->growBy(count);
180 if (src) {
181 memcpy(fArray + oldCount, src, sizeof(T) * count);
182 }
183 }
184 return fArray + oldCount;
185 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000186
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 T* appendClear() {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000188 T* result = this->append();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 *result = 0;
190 return result;
191 }
192
193 T* insert(size_t index) {
194 return this->insert(index, 1, NULL);
195 }
196 T* insert(size_t index, size_t count, const T* src = NULL) {
197 SkASSERT(count);
198 SkASSERT(index <= fCount);
tomhudson@google.comffe39bd2012-05-17 15:38:00 +0000199 size_t oldCount = fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 this->growBy(count);
201 T* dst = fArray + index;
202 memmove(dst + count, dst, sizeof(T) * (oldCount - index));
203 if (src) {
204 memcpy(dst, src, sizeof(T) * count);
205 }
206 return dst;
207 }
208
209 void remove(size_t index, size_t count = 1) {
210 SkASSERT(index + count <= fCount);
211 fCount = fCount - count;
212 memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
213 }
214
215 void removeShuffle(size_t index) {
216 SkASSERT(index < fCount);
tomhudson@google.comffe39bd2012-05-17 15:38:00 +0000217 size_t newCount = fCount - 1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 fCount = newCount;
219 if (index != newCount) {
220 memcpy(fArray + index, fArray + newCount, sizeof(T));
221 }
222 }
223
224 int find(const T& elem) const {
225 const T* iter = fArray;
226 const T* stop = fArray + fCount;
227
228 for (; iter < stop; iter++) {
229 if (*iter == elem) {
230 return (int) (iter - fArray);
231 }
232 }
233 return -1;
234 }
235
236 int rfind(const T& elem) const {
237 const T* iter = fArray + fCount;
238 const T* stop = fArray;
239
240 while (iter > stop) {
241 if (*--iter == elem) {
242 return iter - stop;
243 }
244 }
245 return -1;
246 }
247
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000248 /**
epoger@google.comaf07d062012-07-13 14:53:18 +0000249 * Returns true iff the array contains this element.
250 */
251 bool contains(const T& elem) const {
252 return (this->find(elem) >= 0);
253 }
254
255 /**
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000256 * Copies up to max elements into dst. The number of items copied is
257 * capped by count - index. The actual number copied is returned.
258 */
259 int copyRange(T* dst, size_t index, int max) const {
260 SkASSERT(max >= 0);
261 SkASSERT(!max || dst);
262 if (index >= fCount) {
263 return 0;
264 }
265 int count = SkMin32(max, fCount - index);
266 memcpy(dst, fArray + index, sizeof(T) * count);
267 return count;
268 }
269
270 void copy(T* dst) const {
zachr@google.comc6081ab2013-07-01 17:04:32 +0000271 this->copyRange(dst, 0, fCount);
bsalomon@google.comdf9d6562012-06-07 21:43:15 +0000272 }
273
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 // routines to treat the array like a stack
275 T* push() { return this->append(); }
276 void push(const T& elem) { *this->append() = elem; }
277 const T& top() const { return (*this)[fCount - 1]; }
278 T& top() { return (*this)[fCount - 1]; }
279 void pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; }
280 void pop() { --fCount; }
281
282 void deleteAll() {
283 T* iter = fArray;
284 T* stop = fArray + fCount;
285 while (iter < stop) {
scroggoc51db022012-08-16 20:30:18 +0000286 SkDELETE (*iter);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 iter += 1;
288 }
289 this->reset();
290 }
291
292 void freeAll() {
293 T* iter = fArray;
294 T* stop = fArray + fCount;
295 while (iter < stop) {
296 sk_free(*iter);
297 iter += 1;
298 }
299 this->reset();
300 }
301
302 void unrefAll() {
303 T* iter = fArray;
304 T* stop = fArray + fCount;
305 while (iter < stop) {
306 (*iter)->unref();
307 iter += 1;
308 }
309 this->reset();
310 }
reed@android.com8433b5d2009-07-03 02:52:27 +0000311
312 void safeUnrefAll() {
313 T* iter = fArray;
314 T* stop = fArray + fCount;
315 while (iter < stop) {
316 SkSafeUnref(*iter);
317 iter += 1;
318 }
319 this->reset();
320 }
321
commit-bot@chromium.orgaa537d42013-02-28 19:03:13 +0000322 void visitAll(void visitor(T&)) {
bsalomon@google.com21cbec42013-01-07 17:23:00 +0000323 T* stop = this->end();
324 for (T* curr = this->begin(); curr < stop; curr++) {
325 if (*curr) {
326 visitor(*curr);
327 }
328 }
329 }
330
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331#ifdef SK_DEBUG
332 void validate() const {
333 SkASSERT((fReserve == 0 && fArray == NULL) ||
334 (fReserve > 0 && fArray != NULL));
335 SkASSERT(fCount <= fReserve);
336 SkASSERT(fData == (ArrayT*)fArray);
337 }
338#endif
339
340private:
341#ifdef SK_DEBUG
342 enum {
343 kDebugArraySize = 16
344 };
345 typedef T ArrayT[kDebugArraySize];
346 ArrayT* fData;
347#endif
348 T* fArray;
349 size_t fReserve, fCount;
350
351 void growBy(size_t extra) {
352 SkASSERT(extra);
353
354 if (fCount + extra > fReserve) {
355 size_t size = fCount + extra + 4;
356 size += size >> 2;
357
358 fArray = (T*)sk_realloc_throw(fArray, size * sizeof(T));
359#ifdef SK_DEBUG
360 fData = (ArrayT*)fArray;
361#endif
362 fReserve = size;
363 }
364 fCount += extra;
365 }
366};
367
368#endif