1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 
9 #ifndef SkTDArray_DEFINED
10 #define SkTDArray_DEFINED
11 
12 #include "include/core/SkTypes.h"
13 #include "include/private/SkMalloc.h"
14 #include "include/private/SkTo.h"
15 
16 #include <initializer_list>
17 #include <utility>
18 
19 template <typename T> class SkTDArray {
20 public:
SkTDArray()21     SkTDArray() : fArray(nullptr), fReserve(0), fCount(0) {}
SkTDArray(const T src[],int count)22     SkTDArray(const T src[], int count) {
23         SkASSERT(src || count == 0);
24 
25         fReserve = fCount = 0;
26         fArray = nullptr;
27         if (count) {
28             fArray = (T*)sk_malloc_throw(count * sizeof(T));
29             memcpy(fArray, src, sizeof(T) * count);
30             fReserve = fCount = count;
31         }
32     }
SkTDArray(const std::initializer_list<T> & list)33     SkTDArray(const std::initializer_list<T>& list) : SkTDArray(list.begin(), list.size()) {}
SkTDArray(const SkTDArray<T> & src)34     SkTDArray(const SkTDArray<T>& src) : fArray(nullptr), fReserve(0), fCount(0) {
35         SkTDArray<T> tmp(src.fArray, src.fCount);
36         this->swap(tmp);
37     }
SkTDArray(SkTDArray<T> && src)38     SkTDArray(SkTDArray<T>&& src) : fArray(nullptr), fReserve(0), fCount(0) {
39         this->swap(src);
40     }
~SkTDArray()41     ~SkTDArray() {
42         sk_free(fArray);
43     }
44 
45     SkTDArray<T>& operator=(const SkTDArray<T>& src) {
46         if (this != &src) {
47             if (src.fCount > fReserve) {
48                 SkTDArray<T> tmp(src.fArray, src.fCount);
49                 this->swap(tmp);
50             } else {
51                 sk_careful_memcpy(fArray, src.fArray, sizeof(T) * src.fCount);
52                 fCount = src.fCount;
53             }
54         }
55         return *this;
56     }
57     SkTDArray<T>& operator=(SkTDArray<T>&& src) {
58         if (this != &src) {
59             this->swap(src);
60             src.reset();
61         }
62         return *this;
63     }
64 
65     friend bool operator==(const SkTDArray<T>& a, const SkTDArray<T>& b) {
66         return  a.fCount == b.fCount &&
67                 (a.fCount == 0 ||
68                  !memcmp(a.fArray, b.fArray, a.fCount * sizeof(T)));
69     }
70     friend bool operator!=(const SkTDArray<T>& a, const SkTDArray<T>& b) {
71         return !(a == b);
72     }
73 
swap(SkTDArray<T> & that)74     void swap(SkTDArray<T>& that) {
75         using std::swap;
76         swap(fArray, that.fArray);
77         swap(fReserve, that.fReserve);
78         swap(fCount, that.fCount);
79     }
80 
isEmpty()81     bool isEmpty() const { return fCount == 0; }
empty()82     bool empty() const { return this->isEmpty(); }
83 
84     /**
85      *  Return the number of elements in the array
86      */
count()87     int count() const { return fCount; }
size()88     size_t size() const { return fCount; }
89 
90     /**
91      *  Return the total number of elements allocated.
92      *  reserved() - count() gives you the number of elements you can add
93      *  without causing an allocation.
94      */
reserved()95     int reserved() const { return fReserve; }
96 
97     /**
98      *  return the number of bytes in the array: count * sizeof(T)
99      */
bytes()100     size_t bytes() const { return fCount * sizeof(T); }
101 
begin()102     T*        begin() { return fArray; }
begin()103     const T*  begin() const { return fArray; }
end()104     T*        end() { return fArray ? fArray + fCount : nullptr; }
end()105     const T*  end() const { return fArray ? fArray + fCount : nullptr; }
106 
107     T&  operator[](int index) {
108         SkASSERT(index < fCount);
109         return fArray[index];
110     }
111     const T&  operator[](int index) const {
112         SkASSERT(index < fCount);
113         return fArray[index];
114     }
115 
getAt(int index)116     T&  getAt(int index)  {
117         return (*this)[index];
118     }
119 
120 
reset()121     void reset() {
122         if (fArray) {
123             sk_free(fArray);
124             fArray = nullptr;
125             fReserve = fCount = 0;
126         } else {
127             SkASSERT(fReserve == 0 && fCount == 0);
128         }
129     }
130 
rewind()131     void rewind() {
132         // same as setCount(0)
133         fCount = 0;
134     }
135 
136     /**
137      *  Sets the number of elements in the array.
138      *  If the array does not have space for count elements, it will increase
139      *  the storage allocated to some amount greater than that required.
140      *  It will never shrink the storage.
141      */
setCount(int count)142     void setCount(int count) {
143         SkASSERT(count >= 0);
144         if (count > fReserve) {
145             this->resizeStorageToAtLeast(count);
146         }
147         fCount = count;
148     }
149 
setReserve(int reserve)150     void setReserve(int reserve) {
151         SkASSERT(reserve >= 0);
152         if (reserve > fReserve) {
153             this->resizeStorageToAtLeast(reserve);
154         }
155     }
reserve(size_t n)156     void reserve(size_t n) {
157         SkASSERT_RELEASE(SkTFitsIn<int>(n));
158         this->setReserve(SkToInt(n));
159     }
160 
prepend()161     T* prepend() {
162         this->adjustCount(1);
163         memmove(fArray + 1, fArray, (fCount - 1) * sizeof(T));
164         return fArray;
165     }
166 
append()167     T* append() {
168         return this->append(1, nullptr);
169     }
170     T* append(int count, const T* src = nullptr) {
171         int oldCount = fCount;
172         if (count)  {
173             SkASSERT(src == nullptr || fArray == nullptr ||
174                     src + count <= fArray || fArray + oldCount <= src);
175 
176             this->adjustCount(count);
177             if (src) {
178                 memcpy(fArray + oldCount, src, sizeof(T) * count);
179             }
180         }
181         return fArray + oldCount;
182     }
183 
insert(int index)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 
removeShuffle(int index)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 
find(const T & elem)215     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;
225     }
226 
rfind(const T & elem)227     int rfind(const T& elem) const {
228         const T* iter = fArray + fCount;
229         const T* stop = fArray;
230 
231         while (iter > stop) {
232             if (*--iter == elem) {
233                 return SkToInt(iter - stop);
234             }
235         }
236         return -1;
237     }
238 
239     /**
240      * Returns true iff the array contains this element.
241      */
contains(const T & elem)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      */
copyRange(T * dst,int index,int max)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 
copy(T * dst)261     void copy(T* dst) const {
262         this->copyRange(dst, 0, fCount);
263     }
264 
265     // routines to treat the array like a stack
push_back(const T & v)266     void push_back(const T& v) { *this->append() = v; }
push()267     T*      push() { return this->append(); }
top()268     const T& top() const { return (*this)[fCount - 1]; }
top()269     T&       top() { return (*this)[fCount - 1]; }
pop(T * elem)270     void     pop(T* elem) { SkASSERT(fCount > 0); if (elem) *elem = (*this)[fCount - 1]; --fCount; }
pop()271     void     pop() { SkASSERT(fCount > 0); --fCount; }
272 
deleteAll()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 
freeAll()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 
unrefAll()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 
safeUnrefAll()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 #ifdef SK_DEBUG
validate()314     void validate() const {
315         SkASSERT((fReserve == 0 && fArray == nullptr) ||
316                  (fReserve > 0 && fArray != nullptr));
317         SkASSERT(fCount <= fReserve);
318     }
319 #endif
320 
shrinkToFit()321     void shrinkToFit() {
322         fReserve = fCount;
323         fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
324     }
325 
326 private:
327     T*      fArray;
328     int     fReserve;   // size of the allocation in fArray (#elements)
329     int     fCount;     // logical number of elements (fCount <= fReserve)
330 
331     /**
332      *  Adjusts the number of elements in the array.
333      *  This is the same as calling setCount(count() + delta).
334      */
adjustCount(int delta)335     void adjustCount(int delta) {
336         SkASSERT(delta > 0);
337 
338         // We take care to avoid overflow here.
339         // The sum of fCount and delta is at most 4294967294, which fits fine in uint32_t.
340         uint32_t count = (uint32_t)fCount + (uint32_t)delta;
341         SkASSERT_RELEASE( SkTFitsIn<int>(count) );
342 
343         this->setCount(SkTo<int>(count));
344     }
345 
346     /**
347      *  Increase the storage allocation such that it can hold (fCount + extra)
348      *  elements.
349      *  It never shrinks the allocation, and it may increase the allocation by
350      *  more than is strictly required, based on a private growth heuristic.
351      *
352      *  note: does NOT modify fCount
353      */
resizeStorageToAtLeast(int count)354     void resizeStorageToAtLeast(int count) {
355         SkASSERT(count > fReserve);
356 
357         // We take care to avoid overflow here.
358         // The maximum value we can get for reserve here is 2684354563, which fits in uint32_t.
359         uint32_t reserve = (uint32_t)count + 4;
360         reserve += reserve / 4;
361         SkASSERT_RELEASE( SkTFitsIn<int>(reserve) );
362 
363         fReserve = SkTo<int>(reserve);
364         fArray = (T*)sk_realloc_throw(fArray, fReserve * sizeof(T));
365     }
366 };
367 
swap(SkTDArray<T> & a,SkTDArray<T> & b)368 template <typename T> static inline void swap(SkTDArray<T>& a, SkTDArray<T>& b) {
369     a.swap(b);
370 }
371 
372 #endif
373