• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 Google Inc.
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 #ifndef SkTArray_DEFINED
9 #define SkTArray_DEFINED
10 
11 #include <new>
12 #include "SkTypes.h"
13 #include "SkTemplates.h"
14 
15 template <typename T, bool MEM_COPY = false> class SkTArray;
16 
17 namespace SkTArrayExt {
18 
19 template<typename T>
copy(SkTArray<T,true> * self,const T * array)20 inline void copy(SkTArray<T, true>* self, const T* array) {
21     memcpy(self->fMemArray, array, self->fCount * sizeof(T));
22 }
23 template<typename T>
copyAndDelete(SkTArray<T,true> * self,char * newMemArray)24 inline void copyAndDelete(SkTArray<T, true>* self, char* newMemArray) {
25     memcpy(newMemArray, self->fMemArray, self->fCount * sizeof(T));
26 }
27 
28 template<typename T>
copy(SkTArray<T,false> * self,const T * array)29 inline void copy(SkTArray<T, false>* self, const T* array) {
30     for (int i = 0; i < self->fCount; ++i) {
31         new (self->fItemArray + i) T(array[i]);
32     }
33 }
34 template<typename T>
copyAndDelete(SkTArray<T,false> * self,char * newMemArray)35 inline void copyAndDelete(SkTArray<T, false>* self, char* newMemArray) {
36     for (int i = 0; i < self->fCount; ++i) {
37         new (newMemArray + sizeof(T) * i) T(self->fItemArray[i]);
38         self->fItemArray[i].~T();
39     }
40 }
41 
42 }
43 
44 /** When MEM_COPY is true T will be bit copied when moved.
45     When MEM_COPY is false, T will be copy constructed / destructed.
46     In all cases T's constructor will be called on allocation,
47     and its destructor will be called from this object's destructor.
48 */
49 template <typename T, bool MEM_COPY> class SkTArray {
50 public:
51     /**
52      * Creates an empty array with no initial storage
53      */
SkTArray()54     SkTArray() {
55         fCount = 0;
56         fReserveCount = gMIN_ALLOC_COUNT;
57         fAllocCount = 0;
58         fMemArray = NULL;
59         fPreAllocMemArray = NULL;
60     }
61 
62     /**
63      * Creates an empty array that will preallocate space for reserveCount
64      * elements.
65      */
SkTArray(int reserveCount)66     explicit SkTArray(int reserveCount) {
67         this->init(NULL, 0, NULL, reserveCount);
68     }
69 
70     /**
71      * Copies one array to another. The new array will be heap allocated.
72      */
SkTArray(const SkTArray & array)73     explicit SkTArray(const SkTArray& array) {
74         this->init(array.fItemArray, array.fCount, NULL, 0);
75     }
76 
77     /**
78      * Creates a SkTArray by copying contents of a standard C array. The new
79      * array will be heap allocated. Be careful not to use this constructor
80      * when you really want the (void*, int) version.
81      */
SkTArray(const T * array,int count)82     SkTArray(const T* array, int count) {
83         this->init(array, count, NULL, 0);
84     }
85 
86     /**
87      * assign copy of array to this
88      */
89     SkTArray& operator =(const SkTArray& array) {
90         for (int i = 0; i < fCount; ++i) {
91             fItemArray[i].~T();
92         }
93         fCount = 0;
94         checkRealloc((int)array.count());
95         fCount = array.count();
96         SkTArrayExt::copy(this, static_cast<const T*>(array.fMemArray));
97         return *this;
98     }
99 
~SkTArray()100     virtual ~SkTArray() {
101         for (int i = 0; i < fCount; ++i) {
102             fItemArray[i].~T();
103         }
104         if (fMemArray != fPreAllocMemArray) {
105             sk_free(fMemArray);
106         }
107     }
108 
109     /**
110      * Resets to count() == 0
111      */
reset()112     void reset() { this->pop_back_n(fCount); }
113 
114     /**
115      * Number of elements in the array.
116      */
count()117     int count() const { return fCount; }
118 
119     /**
120      * Is the array empty.
121      */
empty()122     bool empty() const { return !fCount; }
123 
124     /**
125      * Adds 1 new default-constructed T value and returns in by reference. Note
126      * the reference only remains valid until the next call that adds or removes
127      * elements.
128      */
push_back()129     T& push_back() {
130         checkRealloc(1);
131         new ((char*)fMemArray+sizeof(T)*fCount) T;
132         ++fCount;
133         return fItemArray[fCount-1];
134     }
135 
136     /**
137      * Version of above that uses a copy constructor to initialize the new item
138      */
push_back(const T & t)139     T& push_back(const T& t) {
140         checkRealloc(1);
141         new ((char*)fMemArray+sizeof(T)*fCount) T(t);
142         ++fCount;
143         return fItemArray[fCount-1];
144     }
145 
146     /**
147      * Allocates n more default T values, and returns the address of the start
148      * of that new range. Note: this address is only valid until the next API
149      * call made on the array that might add or remove elements.
150      */
push_back_n(int n)151     T* push_back_n(int n) {
152         SkASSERT(n >= 0);
153         checkRealloc(n);
154         for (int i = 0; i < n; ++i) {
155             new (fItemArray + fCount + i) T;
156         }
157         fCount += n;
158         return fItemArray + fCount - n;
159     }
160 
161     /**
162      * Version of above that uses a copy constructor to initialize all n items
163      * to the same T.
164      */
push_back_n(int n,const T & t)165     T* push_back_n(int n, const T& t) {
166         SkASSERT(n >= 0);
167         checkRealloc(n);
168         for (int i = 0; i < n; ++i) {
169             new (fItemArray + fCount + i) T(t);
170         }
171         fCount += n;
172         return fItemArray + fCount - n;
173     }
174 
175     /**
176      * Version of above that uses a copy constructor to initialize the n items
177      * to separate T values.
178      */
push_back_n(int n,const T t[])179     T* push_back_n(int n, const T t[]) {
180         SkASSERT(n >= 0);
181         checkRealloc(n);
182         for (int i = 0; i < n; ++i) {
183             new (fItemArray + fCount + i) T(t[i]);
184         }
185         fCount += n;
186         return fItemArray + fCount - n;
187     }
188 
189     /**
190      * Removes the last element. Not safe to call when count() == 0.
191      */
pop_back()192     void pop_back() {
193         SkASSERT(fCount > 0);
194         --fCount;
195         fItemArray[fCount].~T();
196         checkRealloc(0);
197     }
198 
199     /**
200      * Removes the last n elements. Not safe to call when count() < n.
201      */
pop_back_n(int n)202     void pop_back_n(int n) {
203         SkASSERT(n >= 0);
204         SkASSERT(fCount >= n);
205         fCount -= n;
206         for (int i = 0; i < n; ++i) {
207             fItemArray[i].~T();
208         }
209         checkRealloc(0);
210     }
211 
212     /**
213      * Pushes or pops from the back to resize. Pushes will be default
214      * initialized.
215      */
resize_back(int newCount)216     void resize_back(int newCount) {
217         SkASSERT(newCount >= 0);
218 
219         if (newCount > fCount) {
220             push_back_n(newCount - fCount);
221         } else if (newCount < fCount) {
222             pop_back_n(fCount - newCount);
223         }
224     }
225 
226     /**
227      * Get the i^th element.
228      */
229     T& operator[] (int i) {
230         SkASSERT(i < fCount);
231         SkASSERT(i >= 0);
232         return fItemArray[i];
233     }
234 
235     const T& operator[] (int i) const {
236         SkASSERT(i < fCount);
237         SkASSERT(i >= 0);
238         return fItemArray[i];
239     }
240 
241     /**
242      * equivalent to operator[](0)
243      */
front()244     T& front() { SkASSERT(fCount > 0); return fItemArray[0];}
245 
front()246     const T& front() const { SkASSERT(fCount > 0); return fItemArray[0];}
247 
248     /**
249      * equivalent to operator[](count() - 1)
250      */
back()251     T& back() { SkASSERT(fCount); return fItemArray[fCount - 1];}
252 
back()253     const T& back() const { SkASSERT(fCount > 0); return fItemArray[fCount - 1];}
254 
255     /**
256      * equivalent to operator[](count()-1-i)
257      */
fromBack(int i)258     T& fromBack(int i) {
259         SkASSERT(i >= 0);
260         SkASSERT(i < fCount);
261         return fItemArray[fCount - i - 1];
262     }
263 
fromBack(int i)264     const T& fromBack(int i) const {
265         SkASSERT(i >= 0);
266         SkASSERT(i < fCount);
267         return fItemArray[fCount - i - 1];
268     }
269 
270 protected:
271     /**
272      * Creates an empty array that will use the passed storage block until it
273      * is insufficiently large to hold the entire array.
274      */
275     template <int N>
SkTArray(SkAlignedSTStorage<N,T> * storage)276     SkTArray(SkAlignedSTStorage<N,T>* storage) {
277         this->init(NULL, 0, storage->get(), N);
278     }
279 
280     /**
281      * Copy another array, using preallocated storage if preAllocCount >=
282      * array.count(). Otherwise storage will only be used when array shrinks
283      * to fit.
284      */
285     template <int N>
SkTArray(const SkTArray & array,SkAlignedSTStorage<N,T> * storage)286     SkTArray(const SkTArray& array, SkAlignedSTStorage<N,T>* storage) {
287         this->init(array.fItemArray, array.fCount, storage->get(), N);
288     }
289 
290     /**
291      * Copy a C array, using preallocated storage if preAllocCount >=
292      * count. Otherwise storage will only be used when array shrinks
293      * to fit.
294      */
295     template <int N>
SkTArray(const T * array,int count,SkAlignedSTStorage<N,T> * storage)296     SkTArray(const T* array, int count, SkAlignedSTStorage<N,T>* storage) {
297         this->init(array, count, storage->get(), N);
298     }
299 
init(const T * array,int count,void * preAllocStorage,int preAllocOrReserveCount)300     void init(const T* array, int count,
301                void* preAllocStorage, int preAllocOrReserveCount) {
302         SkASSERT(count >= 0);
303         SkASSERT(preAllocOrReserveCount >= 0);
304         fCount              = count;
305         fReserveCount       = (preAllocOrReserveCount > 0) ?
306                                     preAllocOrReserveCount :
307                                     gMIN_ALLOC_COUNT;
308         fPreAllocMemArray   = preAllocStorage;
309         if (fReserveCount >= fCount &&
310             NULL != preAllocStorage) {
311             fAllocCount = fReserveCount;
312             fMemArray = preAllocStorage;
313         } else {
314             fAllocCount = SkMax32(fCount, fReserveCount);
315             fMemArray = sk_malloc_throw(fAllocCount * sizeof(T));
316         }
317 
318         SkTArrayExt::copy(this, array);
319     }
320 
321 private:
322 
323     static const int gMIN_ALLOC_COUNT = 8;
324 
checkRealloc(int delta)325     inline void checkRealloc(int delta) {
326         SkASSERT(fCount >= 0);
327         SkASSERT(fAllocCount >= 0);
328 
329         SkASSERT(-delta <= fCount);
330 
331         int newCount = fCount + delta;
332         int newAllocCount = fAllocCount;
333 
334         if (newCount > fAllocCount || newCount < (fAllocCount / 3)) {
335             // whether we're growing or shrinking, we leave at least 50% extra space for future
336             // growth (clamped to the reserve count).
337             newAllocCount = SkMax32(newCount + ((newCount + 1) >> 1), fReserveCount);
338         }
339         if (newAllocCount != fAllocCount) {
340 
341             fAllocCount = newAllocCount;
342             char* newMemArray;
343 
344             if (fAllocCount == fReserveCount && NULL != fPreAllocMemArray) {
345                 newMemArray = (char*) fPreAllocMemArray;
346             } else {
347                 newMemArray = (char*) sk_malloc_throw(fAllocCount*sizeof(T));
348             }
349 
350             SkTArrayExt::copyAndDelete<T>(this, newMemArray);
351 
352             if (fMemArray != fPreAllocMemArray) {
353                 sk_free(fMemArray);
354             }
355             fMemArray = newMemArray;
356         }
357     }
358 
359     template<typename X> friend void SkTArrayExt::copy(SkTArray<X, true>* that, const X*);
360     template<typename X> friend void SkTArrayExt::copyAndDelete(SkTArray<X, true>* that, char*);
361 
362     template<typename X> friend void SkTArrayExt::copy(SkTArray<X, false>* that, const X*);
363     template<typename X> friend void SkTArrayExt::copyAndDelete(SkTArray<X, false>* that, char*);
364 
365     int fReserveCount;
366     int fCount;
367     int fAllocCount;
368     void*    fPreAllocMemArray;
369     union {
370         T*       fItemArray;
371         void*    fMemArray;
372     };
373 };
374 
375 /**
376  * Subclass of SkTArray that contains a preallocated memory block for the array.
377  */
378 template <int N, typename T, bool DATA_TYPE = false>
379 class SkSTArray : public SkTArray<T, DATA_TYPE> {
380 private:
381     typedef SkTArray<T, DATA_TYPE> INHERITED;
382 
383 public:
SkSTArray()384     SkSTArray() : INHERITED(&fStorage) {
385     }
386 
SkSTArray(const SkSTArray & array)387     SkSTArray(const SkSTArray& array)
388         : INHERITED(array, &fStorage) {
389     }
390 
SkSTArray(const INHERITED & array)391     explicit SkSTArray(const INHERITED& array)
392         : INHERITED(array, &fStorage) {
393     }
394 
SkSTArray(const T * array,int count)395     SkSTArray(const T* array, int count)
396         : INHERITED(array, count, &fStorage) {
397     }
398 
399     SkSTArray& operator= (const SkSTArray& array) {
400         return *this = *(const INHERITED*)&array;
401     }
402 
403     SkSTArray& operator= (const INHERITED& array) {
404         INHERITED::operator=(array);
405         return *this;
406     }
407 
408 private:
409     SkAlignedSTStorage<N,T> fStorage;
410 };
411 
412 #endif
413