• 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 SkTemplates_DEFINED
11 #define SkTemplates_DEFINED
12 
13 #include "SkTypes.h"
14 
15 /** \file SkTemplates.h
16 
17     This file contains light-weight template classes for type-safe and exception-safe
18     resource management.
19 */
20 
21 /** \class SkAutoTCallVProc
22 
23     Call a function when this goes out of scope. The template uses two
24     parameters, the object, and a function that is to be called in the destructor.
25     If detach() is called, the object reference is set to null. If the object
26     reference is null when the destructor is called, we do not call the
27     function.
28 */
29 template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable {
30 public:
SkAutoTCallVProc(T * obj)31     SkAutoTCallVProc(T* obj): fObj(obj) {}
~SkAutoTCallVProc()32     ~SkAutoTCallVProc() { if (fObj) P(fObj); }
detach()33     T* detach() { T* obj = fObj; fObj = NULL; return obj; }
34 private:
35     T* fObj;
36 };
37 
38 /** \class SkAutoTCallIProc
39 
40 Call a function when this goes out of scope. The template uses two
41 parameters, the object, and a function that is to be called in the destructor.
42 If detach() is called, the object reference is set to null. If the object
43 reference is null when the destructor is called, we do not call the
44 function.
45 */
46 template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable {
47 public:
SkAutoTCallIProc(T * obj)48     SkAutoTCallIProc(T* obj): fObj(obj) {}
~SkAutoTCallIProc()49     ~SkAutoTCallIProc() { if (fObj) P(fObj); }
detach()50     T* detach() { T* obj = fObj; fObj = NULL; return obj; }
51 private:
52     T* fObj;
53 };
54 
55 // See also SkTScopedPtr.
56 template <typename T> class SkAutoTDelete : SkNoncopyable {
57 public:
fObj(obj)58     SkAutoTDelete(T* obj, bool deleteWhenDone = true) : fObj(obj) {
59         fDeleteWhenDone = deleteWhenDone;
60     }
~SkAutoTDelete()61     ~SkAutoTDelete() { if (fDeleteWhenDone) delete fObj; }
62 
get()63     T*      get() const { return fObj; }
free()64     void    free() { delete fObj; fObj = NULL; }
detach()65     T*      detach() { T* obj = fObj; fObj = NULL; return obj; }
66 
67 private:
68     T*  fObj;
69     bool fDeleteWhenDone;
70 };
71 
72 template <typename T> class SkAutoTDeleteArray : SkNoncopyable {
73 public:
SkAutoTDeleteArray(T array[])74     SkAutoTDeleteArray(T array[]) : fArray(array) {}
~SkAutoTDeleteArray()75     ~SkAutoTDeleteArray() { delete[] fArray; }
76 
get()77     T*      get() const { return fArray; }
free()78     void    free() { delete[] fArray; fArray = NULL; }
detach()79     T*      detach() { T* array = fArray; fArray = NULL; return array; }
80 
81 private:
82     T*  fArray;
83 };
84 
85 /** Allocate an array of T elements, and free the array in the destructor
86  */
87 template <typename T> class SkAutoTArray : SkNoncopyable {
88 public:
89     /** Allocate count number of T elements
90      */
SkAutoTArray(size_t count)91     SkAutoTArray(size_t count) {
92         fArray = NULL;
93         if (count) {
94             fArray = new T[count];
95         }
96         SkDEBUGCODE(fCount = count;)
97     }
98 
~SkAutoTArray()99     ~SkAutoTArray() {
100         delete[] fArray;
101     }
102 
103     /** Return the array of T elements. Will be NULL if count == 0
104      */
get()105     T* get() const { return fArray; }
106 
107     /** Return the nth element in the array
108      */
109     T&  operator[](int index) const {
110         SkASSERT((unsigned)index < fCount);
111         return fArray[index];
112     }
113 
114 private:
115     T*  fArray;
116     SkDEBUGCODE(size_t fCount;)
117 };
118 
119 /** Wraps SkAutoTArray, with room for up to N elements preallocated
120  */
121 template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable {
122 public:
123     /** Allocate count number of T elements
124      */
SkAutoSTArray(size_t count)125     SkAutoSTArray(size_t count) {
126         if (count > N) {
127             fArray = new T[count];
128         } else if (count) {
129             fArray = new (fStorage) T[count];
130         } else {
131             fArray = NULL;
132         }
133         fCount = count;
134     }
135 
~SkAutoSTArray()136     ~SkAutoSTArray() {
137         if (fCount > N) {
138             delete[] fArray;
139         } else {
140             T* start = fArray;
141             T* iter = start + fCount;
142             while (iter > start) {
143                 (--iter)->~T();
144             }
145         }
146     }
147 
148     /** Return the number of T elements in the array
149      */
count()150     size_t count() const { return fCount; }
151 
152     /** Return the array of T elements. Will be NULL if count == 0
153      */
get()154     T* get() const { return fArray; }
155 
156     /** Return the nth element in the array
157      */
158     T&  operator[](int index) const {
159         SkASSERT((unsigned)index < fCount);
160         return fArray[index];
161     }
162 
163 private:
164     size_t  fCount;
165     T*      fArray;
166     // since we come right after fArray, fStorage should be properly aligned
167     char    fStorage[N * sizeof(T)];
168 };
169 
170 /** Allocate a temp array on the stack/heap.
171     Does NOT call any constructors/destructors on T (i.e. T must be POD)
172 */
173 template <typename T> class SkAutoTMalloc : SkNoncopyable {
174 public:
SkAutoTMalloc(size_t count)175     SkAutoTMalloc(size_t count) {
176         fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
177     }
178 
~SkAutoTMalloc()179     ~SkAutoTMalloc() {
180         sk_free(fPtr);
181     }
182 
183     // doesn't preserve contents
reset(size_t count)184     void reset (size_t count) {
185         sk_free(fPtr);
186         fPtr = fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
187     }
188 
get()189     T* get() const { return fPtr; }
190 
191     operator T*() {
192         return fPtr;
193     }
194 
195     operator const T*() const {
196         return fPtr;
197     }
198 
199     T& operator[](int index) {
200         return fPtr[index];
201     }
202 
203     const T& operator[](int index) const {
204         return fPtr[index];
205     }
206 
207 private:
208     T*  fPtr;
209 };
210 
211 template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable {
212 public:
SkAutoSTMalloc(size_t count)213     SkAutoSTMalloc(size_t count) {
214         if (count <= N) {
215             fPtr = fTStorage;
216         } else {
217             fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
218         }
219     }
220 
~SkAutoSTMalloc()221     ~SkAutoSTMalloc() {
222         if (fPtr != fTStorage) {
223             sk_free(fPtr);
224         }
225     }
226 
227     // doesn't preserve contents
reset(size_t count)228     void reset(size_t count) {
229         if (fPtr != fTStorage) {
230             sk_free(fPtr);
231         }
232         if (count <= N) {
233             fPtr = fTStorage;
234         } else {
235             fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
236         }
237     }
238 
get()239     T* get() const { return fPtr; }
240 
241     operator T*() {
242         return fPtr;
243     }
244 
245     operator const T*() const {
246         return fPtr;
247     }
248 
249     T& operator[](int index) {
250         return fPtr[index];
251     }
252 
253     const T& operator[](int index) const {
254         return fPtr[index];
255     }
256 
257 private:
258     T*          fPtr;
259     union {
260         uint32_t    fStorage32[(N*sizeof(T) + 3) >> 2];
261         T           fTStorage[1];   // do NOT want to invoke T::T()
262     };
263 };
264 
265 /**
266  * Reserves memory that is aligned on double and pointer boundaries.
267  * Hopefully this is sufficient for all practical purposes.
268  */
269 template <size_t N> class SkAlignedSStorage : SkNoncopyable {
270 public:
get()271     void* get() { return fData; }
272 private:
273     union {
274         void*   fPtr;
275         double  fDouble;
276         char    fData[N];
277     };
278 };
279 
280 /**
281  * Reserves memory that is aligned on double and pointer boundaries.
282  * Hopefully this is sufficient for all practical purposes. Otherwise,
283  * we have to do some arcane trickery to determine alignment of non-POD
284  * types. Lifetime of the memory is the lifetime of the object.
285  */
286 template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
287 public:
288     /**
289      * Returns void* because this object does not initialize the
290      * memory. Use placement new for types that require a cons.
291      */
get()292     void* get() { return fStorage.get(); }
293 private:
294     SkAlignedSStorage<sizeof(T)*N> fStorage;
295 };
296 
297 #endif
298 
299