• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #ifndef SkTDArray_DEFINED
11 #define SkTDArray_DEFINED
12 
13 #include "SkTypes.h"
14 
15 template <typename T> class SK_API SkTDArray {
16 public:
SkTDArray()17     SkTDArray() {
18         fReserve = fCount = 0;
19         fArray = NULL;
20 #ifdef SK_DEBUG
21         fData = NULL;
22 #endif
23     }
SkTDArray(const T src[],size_t count)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     }
SkTDArray(const SkTDArray<T> & src)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     }
~SkTDArray()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 
67     friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
68         return  a.fCount == b.fCount &&
69                 (a.fCount == 0 ||
70                  !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
71     }
72 
swap(SkTDArray<T> & other)73     void swap(SkTDArray<T>& other) {
74         SkTSwap(fArray, other.fArray);
75 #ifdef SK_DEBUG
76         SkTSwap(fData, other.fData);
77 #endif
78         SkTSwap(fReserve, other.fReserve);
79         SkTSwap(fCount, other.fCount);
80     }
81 
82     /** Return a ptr to the array of data, to be freed with sk_free. This also
83         resets the SkTDArray to be empty.
84      */
detach()85     T* detach() {
86         T* array = fArray;
87         fArray = NULL;
88         fReserve = fCount = 0;
89         SkDEBUGCODE(fData = NULL;)
90         return array;
91     }
92 
isEmpty()93     bool isEmpty() const { return fCount == 0; }
94 
95     /**
96      *  Return the number of elements in the array
97      */
count()98     int count() const { return (int)fCount; }
99 
100     /**
101      *  return the number of bytes in the array: count * sizeof(T)
102      */
bytes()103     size_t bytes() const { return fCount * sizeof(T); }
104 
begin()105     T*  begin() const { return fArray; }
end()106     T*  end() const { return fArray ? fArray + fCount : NULL; }
107     T&  operator[](int index) const {
108         SkASSERT((unsigned)index < fCount);
109         return fArray[index];
110     }
111 
getAt(int index)112     T&  getAt(int index) const {
113         return (*this)[index];
114     }
115 
reset()116     void reset() {
117         if (fArray) {
118             sk_free(fArray);
119             fArray = NULL;
120 #ifdef SK_DEBUG
121             fData = NULL;
122 #endif
123             fReserve = fCount = 0;
124         } else {
125             SkASSERT(fReserve == 0 && fCount == 0);
126         }
127     }
128 
rewind()129     void rewind() {
130         // same as setCount(0)
131         fCount = 0;
132     }
133 
setCount(size_t count)134     void setCount(size_t count) {
135         if (count > fReserve) {
136             this->growBy(count - fCount);
137         } else {
138             fCount = count;
139         }
140     }
141 
setReserve(size_t reserve)142     void setReserve(size_t reserve) {
143         if (reserve > fReserve) {
144             SkASSERT(reserve > fCount);
145             size_t count = fCount;
146             this->growBy(reserve - fCount);
147             fCount = count;
148         }
149     }
150 
prepend()151     T* prepend() {
152         this->growBy(1);
153         memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
154         return fArray;
155     }
156 
append()157     T* append() {
158         return this->append(1, NULL);
159     }
160     T* append(size_t count, const T* src = NULL) {
161         size_t oldCount = fCount;
162         if (count)  {
163             SkASSERT(src == NULL || fArray == NULL ||
164                     src + count <= fArray || fArray + oldCount <= src);
165 
166             this->growBy(count);
167             if (src) {
168                 memcpy(fArray + oldCount, src, sizeof(T) * count);
169             }
170         }
171         return fArray + oldCount;
172     }
173 
appendClear()174     T* appendClear() {
175         T* result = this->append();
176         *result = 0;
177         return result;
178     }
179 
insert(size_t index)180     T* insert(size_t index) {
181         return this->insert(index, 1, NULL);
182     }
183     T* insert(size_t index, size_t count, const T* src = NULL) {
184         SkASSERT(count);
185         SkASSERT(index <= fCount);
186         size_t oldCount = fCount;
187         this->growBy(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(size_t index, size_t count = 1) {
197         SkASSERT(index + count <= fCount);
198         fCount = fCount - count;
199         memmove(fArray + index, fArray + index + count, sizeof(T) * (fCount - index));
200     }
201 
removeShuffle(size_t index)202     void removeShuffle(size_t index) {
203         SkASSERT(index < fCount);
204         size_t newCount = fCount - 1;
205         fCount = newCount;
206         if (index != newCount) {
207             memcpy(fArray + index, fArray + newCount, sizeof(T));
208         }
209     }
210 
find(const T & elem)211     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 (int) (iter - fArray);
218             }
219         }
220         return -1;
221     }
222 
rfind(const T & elem)223     int rfind(const T& elem) const {
224         const T* iter = fArray + fCount;
225         const T* stop = fArray;
226 
227         while (iter > stop) {
228             if (*--iter == elem) {
229                 return iter - stop;
230             }
231         }
232         return -1;
233     }
234 
235     /**
236      * Returns true iff the array contains this element.
237      */
contains(const T & elem)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      */
copyRange(T * dst,size_t index,int max)246     int copyRange(T* dst, size_t 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 
copy(T * dst)257     void copy(T* dst) const {
258         this->copyRange(0, fCount, dst);
259     }
260 
261     // routines to treat the array like a stack
push()262     T*          push() { return this->append(); }
push(const T & elem)263     void        push(const T& elem) { *this->append() = elem; }
top()264     const T&    top() const { return (*this)[fCount - 1]; }
top()265     T&          top() { return (*this)[fCount - 1]; }
pop(T * elem)266     void        pop(T* elem) { if (elem) *elem = (*this)[fCount - 1]; --fCount; }
pop()267     void        pop() { --fCount; }
268 
deleteAll()269     void deleteAll() {
270         T*  iter = fArray;
271         T*  stop = fArray + fCount;
272         while (iter < stop) {
273             SkDELETE (*iter);
274             iter += 1;
275         }
276         this->reset();
277     }
278 
freeAll()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 
unrefAll()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 
safeUnrefAll()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 
visitAll(void visitor (T &))309     void visitAll(void visitor(T&)) const {
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
validate()319     void validate() const {
320         SkASSERT((fReserve == 0 && fArray == NULL) ||
321                  (fReserve > 0 && fArray != NULL));
322         SkASSERT(fCount <= fReserve);
323         SkASSERT(fData == (ArrayT*)fArray);
324     }
325 #endif
326 
327 private:
328 #ifdef SK_DEBUG
329     enum {
330         kDebugArraySize = 16
331     };
332     typedef T ArrayT[kDebugArraySize];
333     ArrayT* fData;
334 #endif
335     T*      fArray;
336     size_t  fReserve, fCount;
337 
growBy(size_t extra)338     void growBy(size_t extra) {
339         SkASSERT(extra);
340 
341         if (fCount + extra > fReserve) {
342             size_t size = fCount + extra + 4;
343             size += size >> 2;
344 
345             fArray = (T*)sk_realloc_throw(fArray, size * sizeof(T));
346 #ifdef SK_DEBUG
347             fData = (ArrayT*)fArray;
348 #endif
349             fReserve = size;
350         }
351         fCount += extra;
352     }
353 };
354 
355 #endif
356