blob: c6bd4ffd374458425c2bcccf13540717aa5ebfab [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
Ben Wagnerf08d1d02018-06-18 15:11:00 -040016#include <utility>
17
Mike Klein22c1f372018-04-02 20:37:42 +000018template <typename T> class SkTDArray {
reed@android.com8a1c16f2008-12-17 15:59:43 +000019public:
Mike Klein22c1f372018-04-02 20:37:42 +000020 SkTDArray() : fArray(nullptr), fReserve(0), fCount(0) {}
21 SkTDArray(const T src[], int count) {
22 SkASSERT(src || count == 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +000023
Mike Klein22c1f372018-04-02 20:37:42 +000024 fReserve = fCount = 0;
25 fArray = nullptr;
26 if (count) {
27 fArray = (T*)sk_malloc_throw(count * sizeof(T));
28 memcpy(fArray, src, sizeof(T) * count);
29 fReserve = fCount = count;
reed@android.com8a1c16f2008-12-17 15:59:43 +000030 }
Mike Klein22c1f372018-04-02 20:37:42 +000031 }
32 SkTDArray(const SkTDArray<T>& src) : fArray(nullptr), fReserve(0), fCount(0) {
33 SkTDArray<T> tmp(src.fArray, src.fCount);
34 this->swap(tmp);
35 }
36 SkTDArray(SkTDArray<T>&& src) : fArray(nullptr), fReserve(0), fCount(0) {
37 this->swap(src);
38 }
39 ~SkTDArray() {
40 sk_free(fArray);
reed@android.com8a1c16f2008-12-17 15:59:43 +000041 }
42
Mike Klein22c1f372018-04-02 20:37:42 +000043 SkTDArray<T>& operator=(const SkTDArray<T>& src) {
44 if (this != &src) {
45 if (src.fCount > fReserve) {
46 SkTDArray<T> tmp(src.fArray, src.fCount);
47 this->swap(tmp);
48 } else {
49 sk_careful_memcpy(fArray, src.fArray, sizeof(T) * src.fCount);
50 fCount = src.fCount;
51 }
52 }
53 return *this;
Mike Klein80e1d562018-03-22 11:36:52 -040054 }
Mike Klein22c1f372018-04-02 20:37:42 +000055 SkTDArray<T>& operator=(SkTDArray<T>&& src) {
56 if (this != &src) {
57 this->swap(src);
58 src.reset();
59 }
60 return *this;
reed@android.com8a1c16f2008-12-17 15:59:43 +000061 }
62
Mike Klein22c1f372018-04-02 20:37:42 +000063 friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
64 return a.fCount == b.fCount &&
65 (a.fCount == 0 ||
66 !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
67 }
68 friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) {
69 return !(a == b);
70 }
71
Ben Wagnerf08d1d02018-06-18 15:11:00 -040072 void swap(SkTDArray<T>& that) {
73 using std::swap;
74 swap(fArray, that.fArray);
75 swap(fReserve, that.fReserve);
76 swap(fCount, that.fCount);
Mike Klein22c1f372018-04-02 20:37:42 +000077 }
78
79 bool isEmpty() const { return fCount == 0; }
80
81 /**
82 * Return the number of elements in the array
83 */
84 int count() const { return fCount; }
85
86 /**
87 * Return the total number of elements allocated.
88 * reserved() - count() gives you the number of elements you can add
89 * without causing an allocation.
90 */
91 int reserved() const { return fReserve; }
92
93 /**
94 * return the number of bytes in the array: count * sizeof(T)
95 */
96 size_t bytes() const { return fCount * sizeof(T); }
97
98 T* begin() { return fArray; }
99 const T* begin() const { return fArray; }
100 T* end() { return fArray ? fArray + fCount : nullptr; }
101 const T* end() const { return fArray ? fArray + fCount : nullptr; }
102
103 T& operator[](int index) {
104 SkASSERT(index < fCount);
105 return fArray[index];
106 }
107 const T& operator[](int index) const {
108 SkASSERT(index < fCount);
109 return fArray[index];
110 }
111
112 T& getAt(int index) {
113 return (*this)[index];
114 }
115 const T& getAt(int index) const {
116 return (*this)[index];
117 }
118
119 void reset() {
120 if (fArray) {
121 sk_free(fArray);
122 fArray = nullptr;
123 fReserve = fCount = 0;
124 } else {
125 SkASSERT(fReserve == 0 && fCount == 0);
126 }
127 }
128
129 void rewind() {
130 // same as setCount(0)
131 fCount = 0;
132 }
133
134 /**
135 * Sets the number of elements in the array.
136 * If the array does not have space for count elements, it will increase
137 * the storage allocated to some amount greater than that required.
138 * It will never shrink the storage.
139 */
140 void setCount(int count) {
141 SkASSERT(count >= 0);
142 if (count > fReserve) {
143 this->resizeStorageToAtLeast(count);
144 }
145 fCount = count;
146 }
147
148 void setReserve(int reserve) {
Mike Klein23e45442018-04-19 09:29:02 -0400149 SkASSERT(reserve >= 0);
Mike Klein22c1f372018-04-02 20:37:42 +0000150 if (reserve > fReserve) {
151 this->resizeStorageToAtLeast(reserve);
152 }
153 }
154
155 T* prepend() {
156 this->adjustCount(1);
157 memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
158 return fArray;
159 }
160
161 T* append() {
162 return this->append(1, nullptr);
163 }
164 T* append(int count, const T* src = nullptr) {
165 int oldCount = fCount;
166 if (count) {
167 SkASSERT(src == nullptr || fArray == nullptr ||
168 src + count <= fArray || fArray + oldCount <= src);
169
170 this->adjustCount(count);
171 if (src) {
172 memcpy(fArray + oldCount, src, sizeof(T) * count);
173 }
174 }
175 return fArray + oldCount;
176 }
177
178 T* appendClear() {
179 T* result = this->append();
180 *result = 0;
181 return result;
182 }
183
184 T* insert(int index) {
185 return this->insert(index, 1, nullptr);
186 }
187 T* insert(int index, int count, const T* src = nullptr) {
188 SkASSERT(count);
189 SkASSERT(index <= fCount);
190 size_t oldCount = fCount;
191 this->adjustCount(count);
192 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
200 void remove(int index, int count = 1) {
201 SkASSERT(index + count <= fCount);
202 fCount = fCount - count;
203 memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
204 }
205
206 void removeShuffle(int index) {
207 SkASSERT(index < fCount);
208 int newCount = fCount - 1;
209 fCount = newCount;
210 if (index != newCount) {
211 memcpy(fArray + index, fArray + newCount, sizeof(T));
212 }
213 }
214
Mike Klein22c1f372018-04-02 20:37:42 +0000215 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) {
221 return SkToInt(iter - fArray);
222 }
223 }
224 return -1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225 }
226
Mike Klein22c1f372018-04-02 20:37:42 +0000227 int rfind(const T& elem) const {
228 const T* iter = fArray + fCount;
229 const T* stop = fArray;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230
Mike Klein22c1f372018-04-02 20:37:42 +0000231 while (iter > stop) {
232 if (*--iter == elem) {
233 return SkToInt(iter - stop);
234 }
235 }
236 return -1;
237 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
Mike Klein22c1f372018-04-02 20:37:42 +0000239 /**
240 * 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 /**
247 * 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 */
250 int copyRange(T* dst, int index, int max) const {
251 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 {
262 this->copyRange(dst, 0, fCount);
263 }
264
265 // routines to treat the array like a stack
266 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; }
272
273 void deleteAll() {
274 T* iter = fArray;
275 T* stop = fArray + fCount;
276 while (iter < stop) {
277 delete *iter;
278 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 }
302
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
313 void visitAll(void visitor(T&)) {
314 T* stop = this->end();
315 for (T* curr = this->begin(); curr < stop; curr++) {
316 if (*curr) {
317 visitor(*curr);
318 }
319 }
320 }
321
322#ifdef SK_DEBUG
323 void validate() const {
324 SkASSERT((fReserve == 0 && fArray == nullptr) ||
325 (fReserve > 0 && fArray != nullptr));
326 SkASSERT(fCount <= fReserve);
327 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328#endif
329
Mike Klein22c1f372018-04-02 20:37:42 +0000330 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:
Mike Klein22c1f372018-04-02 20:37:42 +0000336 T* fArray;
337 int fReserve;
338 int fCount;
339
340 /**
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) {
Mike Klein12ee97c2018-04-19 10:34:08 -0400345 SkASSERT(delta > 0);
346
347 // We take care to avoid overflow here.
348 // The sum of fCount and delta is at most 4294967294, which fits fine in uint32_t.
349 uint32_t count = (uint32_t)fCount + (uint32_t)delta;
350 SkASSERT_RELEASE( SkTFitsIn<int>(count) );
351
352 this->setCount(SkTo<int>(count));
Mike Klein22c1f372018-04-02 20:37:42 +0000353 }
354
355 /**
356 * Increase the storage allocation such that it can hold (fCount + extra)
357 * elements.
358 * It never shrinks the allocation, and it may increase the allocation by
359 * more than is strictly required, based on a private growth heuristic.
360 *
361 * note: does NOT modify fCount
362 */
363 void resizeStorageToAtLeast(int count) {
364 SkASSERT(count > fReserve);
Mike Klein12ee97c2018-04-19 10:34:08 -0400365
366 // We take care to avoid overflow here.
367 // The maximum value we can get for reserve here is 2684354563, which fits in uint32_t.
368 uint32_t reserve = (uint32_t)count + 4;
369 reserve += reserve / 4;
370 SkASSERT_RELEASE( SkTFitsIn<int>(reserve) );
371
372 fReserve = SkTo<int>(reserve);
Mike Klein22c1f372018-04-02 20:37:42 +0000373 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
374 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375};
376
Ben Wagnerf08d1d02018-06-18 15:11:00 -0400377template <typename T> static inline void swap(SkTDArray<T>& a, SkTDArray<T>& b) {
378 a.swap(b);
379}
380
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381#endif