blob: 2ba33542cade643577df1099b9d7b23ef717c6db [file] [log] [blame]
Mike Klein22c1f372018-04-02 20:37:42 +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"
Mike Klein22c1f372018-04-02 20:37:42 +000014#include "SkMalloc.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) {
146 if (reserve > fReserve) {
147 this->resizeStorageToAtLeast(reserve);
148 }
149 }
150
151 T* prepend() {
152 this->adjustCount(1);
153 memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
154 return fArray;
155 }
156
157 T* append() {
158 return this->append(1, nullptr);
159 }
160 T* append(int count, const T* src = nullptr) {
161 int oldCount = fCount;
162 if (count) {
163 SkASSERT(src == nullptr || fArray == nullptr ||
164 src + count <= fArray || fArray + oldCount <= src);
165
166 this->adjustCount(count);
167 if (src) {
168 memcpy(fArray + oldCount, src, sizeof(T) * count);
169 }
170 }
171 return fArray + oldCount;
172 }
173
174 T* appendClear() {
175 T* result = this->append();
176 *result = 0;
177 return result;
178 }
179
180 T* insert(int index) {
181 return this->insert(index, 1, nullptr);
182 }
183 T* insert(int index, int count, const T* src = nullptr) {
184 SkASSERT(count);
185 SkASSERT(index <= fCount);
186 size_t oldCount = fCount;
187 this->adjustCount(count);
188 T* dst = fArray + index;
189 memmove(dst + count, dst, sizeof(T) * (oldCount - index));
190 if (src) {
191 memcpy(dst, src, sizeof(T) * count);
192 }
193 return dst;
194 }
195
196 void remove(int index, int count = 1) {
197 SkASSERT(index + count <= fCount);
198 fCount = fCount - count;
199 memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
200 }
201
202 void removeShuffle(int index) {
203 SkASSERT(index < fCount);
204 int newCount = fCount - 1;
205 fCount = newCount;
206 if (index != newCount) {
207 memcpy(fArray + index, fArray + newCount, sizeof(T));
208 }
209 }
210
211 template <typename S> int select(S&& selector) const {
212 const T* iter = fArray;
213 const T* stop = fArray + fCount;
214
215 for (; iter < stop; iter++) {
216 if (selector(*iter)) {
217 return SkToInt(iter - fArray);
reed22b2af12016-08-29 07:52:13 -0700218 }
219 }
220 return -1;
221 }
Mike Klein22c1f372018-04-02 20:37:42 +0000222
223 int find(const T& elem) const {
224 const T* iter = fArray;
225 const T* stop = fArray + fCount;
226
227 for (; iter < stop; iter++) {
228 if (*iter == elem) {
229 return SkToInt(iter - fArray);
230 }
231 }
232 return -1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 }
234
Mike Klein22c1f372018-04-02 20:37:42 +0000235 int rfind(const T& elem) const {
236 const T* iter = fArray + fCount;
237 const T* stop = fArray;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
Mike Klein22c1f372018-04-02 20:37:42 +0000239 while (iter > stop) {
240 if (*--iter == elem) {
241 return SkToInt(iter - stop);
242 }
243 }
244 return -1;
245 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000246
Mike Klein22c1f372018-04-02 20:37:42 +0000247 /**
248 * Returns true iff the array contains this element.
249 */
250 bool contains(const T& elem) const {
251 return (this->find(elem) >= 0);
252 }
253
254 /**
255 * Copies up to max elements into dst. The number of items copied is
256 * capped by count - index. The actual number copied is returned.
257 */
258 int copyRange(T* dst, int index, int max) const {
259 SkASSERT(max >= 0);
260 SkASSERT(!max || dst);
261 if (index >= fCount) {
262 return 0;
263 }
264 int count = SkMin32(max, fCount - index);
265 memcpy(dst, fArray + index, sizeof(T) * count);
266 return count;
267 }
268
269 void copy(T* dst) const {
270 this->copyRange(dst, 0, fCount);
271 }
272
273 // routines to treat the array like a stack
274 T* push() { return this->append(); }
275 void push(const T& elem) { *this->append() = elem; }
276 const T& top() const { return (*this)[fCount - 1]; }
277 T& top() { return (*this)[fCount - 1]; }
278 void pop(T* elem) { SkASSERT(fCount > 0); if (elem) *elem = (*this)[fCount - 1]; --fCount; }
279 void pop() { SkASSERT(fCount > 0); --fCount; }
280
281 void deleteAll() {
282 T* iter = fArray;
283 T* stop = fArray + fCount;
284 while (iter < stop) {
285 delete *iter;
286 iter += 1;
287 }
288 this->reset();
289 }
290
291 void freeAll() {
292 T* iter = fArray;
293 T* stop = fArray + fCount;
294 while (iter < stop) {
295 sk_free(*iter);
296 iter += 1;
297 }
298 this->reset();
299 }
300
301 void unrefAll() {
302 T* iter = fArray;
303 T* stop = fArray + fCount;
304 while (iter < stop) {
305 (*iter)->unref();
306 iter += 1;
307 }
308 this->reset();
309 }
310
311 void safeUnrefAll() {
312 T* iter = fArray;
313 T* stop = fArray + fCount;
314 while (iter < stop) {
315 SkSafeUnref(*iter);
316 iter += 1;
317 }
318 this->reset();
319 }
320
321 void visitAll(void visitor(T&)) {
322 T* stop = this->end();
323 for (T* curr = this->begin(); curr < stop; curr++) {
324 if (*curr) {
325 visitor(*curr);
326 }
327 }
328 }
329
330#ifdef SK_DEBUG
331 void validate() const {
332 SkASSERT((fReserve == 0 && fArray == nullptr) ||
333 (fReserve > 0 && fArray != nullptr));
334 SkASSERT(fCount <= fReserve);
335 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000336#endif
337
Mike Klein22c1f372018-04-02 20:37:42 +0000338 void shrinkToFit() {
339 fReserve = fCount;
340 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
341 }
342
reed@android.com8a1c16f2008-12-17 15:59:43 +0000343private:
Mike Klein22c1f372018-04-02 20:37:42 +0000344 T* fArray;
345 int fReserve;
346 int fCount;
347
348 /**
349 * Adjusts the number of elements in the array.
350 * This is the same as calling setCount(count() + delta).
351 */
352 void adjustCount(int delta) {
353 this->setCount(fCount + delta);
354 }
355
356 /**
357 * Increase the storage allocation such that it can hold (fCount + extra)
358 * elements.
359 * It never shrinks the allocation, and it may increase the allocation by
360 * more than is strictly required, based on a private growth heuristic.
361 *
362 * note: does NOT modify fCount
363 */
364 void resizeStorageToAtLeast(int count) {
365 SkASSERT(count > fReserve);
366 fReserve = count + 4;
367 fReserve += fReserve / 4;
368 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
369 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370};
371
372#endif