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