blob: 658d371917edb4bca0f38c74d380ecc81aae5004 [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
Mike Klein22c1f372018-04-02 20:37:42 +0000211 int find(const T& elem) const {
212 const T* iter = fArray;
213 const T* stop = fArray + fCount;
214
215 for (; iter < stop; iter++) {
216 if (*iter == elem) {
217 return SkToInt(iter - fArray);
218 }
219 }
220 return -1;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221 }
222
Mike Klein22c1f372018-04-02 20:37:42 +0000223 int rfind(const T& elem) const {
224 const T* iter = fArray + fCount;
225 const T* stop = fArray;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226
Mike Klein22c1f372018-04-02 20:37:42 +0000227 while (iter > stop) {
228 if (*--iter == elem) {
229 return SkToInt(iter - stop);
230 }
231 }
232 return -1;
233 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234
Mike Klein22c1f372018-04-02 20:37:42 +0000235 /**
236 * Returns true iff the array contains this element.
237 */
238 bool contains(const T& elem) const {
239 return (this->find(elem) >= 0);
240 }
241
242 /**
243 * Copies up to max elements into dst. The number of items copied is
244 * capped by count - index. The actual number copied is returned.
245 */
246 int copyRange(T* dst, int index, int max) const {
247 SkASSERT(max >= 0);
248 SkASSERT(!max || dst);
249 if (index >= fCount) {
250 return 0;
251 }
252 int count = SkMin32(max, fCount - index);
253 memcpy(dst, fArray + index, sizeof(T) * count);
254 return count;
255 }
256
257 void copy(T* dst) const {
258 this->copyRange(dst, 0, fCount);
259 }
260
261 // routines to treat the array like a stack
262 T* push() { return this->append(); }
263 void push(const T& elem) { *this->append() = elem; }
264 const T& top() const { return (*this)[fCount - 1]; }
265 T& top() { return (*this)[fCount - 1]; }
266 void pop(T* elem) { SkASSERT(fCount > 0); if (elem) *elem = (*this)[fCount - 1]; --fCount; }
267 void pop() { SkASSERT(fCount > 0); --fCount; }
268
269 void deleteAll() {
270 T* iter = fArray;
271 T* stop = fArray + fCount;
272 while (iter < stop) {
273 delete *iter;
274 iter += 1;
275 }
276 this->reset();
277 }
278
279 void freeAll() {
280 T* iter = fArray;
281 T* stop = fArray + fCount;
282 while (iter < stop) {
283 sk_free(*iter);
284 iter += 1;
285 }
286 this->reset();
287 }
288
289 void unrefAll() {
290 T* iter = fArray;
291 T* stop = fArray + fCount;
292 while (iter < stop) {
293 (*iter)->unref();
294 iter += 1;
295 }
296 this->reset();
297 }
298
299 void safeUnrefAll() {
300 T* iter = fArray;
301 T* stop = fArray + fCount;
302 while (iter < stop) {
303 SkSafeUnref(*iter);
304 iter += 1;
305 }
306 this->reset();
307 }
308
309 void visitAll(void visitor(T&)) {
310 T* stop = this->end();
311 for (T* curr = this->begin(); curr < stop; curr++) {
312 if (*curr) {
313 visitor(*curr);
314 }
315 }
316 }
317
318#ifdef SK_DEBUG
319 void validate() const {
320 SkASSERT((fReserve == 0 && fArray == nullptr) ||
321 (fReserve > 0 && fArray != nullptr));
322 SkASSERT(fCount <= fReserve);
323 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324#endif
325
Mike Klein22c1f372018-04-02 20:37:42 +0000326 void shrinkToFit() {
327 fReserve = fCount;
328 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
329 }
330
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331private:
Mike Klein22c1f372018-04-02 20:37:42 +0000332 T* fArray;
333 int fReserve;
334 int fCount;
335
336 /**
337 * Adjusts the number of elements in the array.
338 * This is the same as calling setCount(count() + delta).
339 */
340 void adjustCount(int delta) {
341 this->setCount(fCount + delta);
342 }
343
344 /**
345 * Increase the storage allocation such that it can hold (fCount + extra)
346 * elements.
347 * It never shrinks the allocation, and it may increase the allocation by
348 * more than is strictly required, based on a private growth heuristic.
349 *
350 * note: does NOT modify fCount
351 */
352 void resizeStorageToAtLeast(int count) {
353 SkASSERT(count > fReserve);
354 fReserve = count + 4;
355 fReserve += fReserve / 4;
356 fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
357 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000358};
359
360#endif