• 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 <limits.h>
15 #include <new>
16 
17 /** \file SkTemplates.h
18 
19     This file contains light-weight template classes for type-safe and exception-safe
20     resource management.
21 */
22 
23 /**
24  *  Marks a local variable as known to be unused (to avoid warnings).
25  *  Note that this does *not* prevent the local variable from being optimized away.
26  */
sk_ignore_unused_variable(const T &)27 template<typename T> inline void sk_ignore_unused_variable(const T&) { }
28 
29 /**
30  *  SkTIsConst<T>::value is true if the type T is const.
31  *  The type T is constrained not to be an array or reference type.
32  */
33 template <typename T> struct SkTIsConst {
34     static T* t;
35     static uint16_t test(const volatile void*);
36     static uint32_t test(volatile void *);
37     static const bool value = (sizeof(uint16_t) == sizeof(test(t)));
38 };
39 
40 ///@{
41 /** SkTConstType<T, CONST>::type will be 'const T' if CONST is true, 'T' otherwise. */
42 template <typename T, bool CONST> struct SkTConstType {
43     typedef T type;
44 };
45 template <typename T> struct SkTConstType<T, true> {
46     typedef const T type;
47 };
48 ///@}
49 
50 /**
51  *  Returns a pointer to a D which comes immediately after S[count].
52  */
53 template <typename D, typename S> static D* SkTAfter(S* ptr, size_t count = 1) {
54     return reinterpret_cast<D*>(ptr + count);
55 }
56 
57 /**
58  *  Returns a pointer to a D which comes byteOffset bytes after S.
59  */
60 template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) {
61     // The intermediate char* has the same const-ness as D as this produces better error messages.
62     // This relies on the fact that reinterpret_cast can add constness, but cannot remove it.
63     return reinterpret_cast<D*>(
64         reinterpret_cast<typename SkTConstType<char, SkTIsConst<D>::value>::type*>(ptr) + byteOffset
65     );
66 }
67 
68 /** \class SkAutoTCallVProc
69 
70     Call a function when this goes out of scope. The template uses two
71     parameters, the object, and a function that is to be called in the destructor.
72     If detach() is called, the object reference is set to null. If the object
73     reference is null when the destructor is called, we do not call the
74     function.
75 */
76 template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable {
77 public:
78     SkAutoTCallVProc(T* obj): fObj(obj) {}
79     ~SkAutoTCallVProc() { if (fObj) P(fObj); }
80 
81     operator T*() const { return fObj; }
82     T* operator->() const { SkASSERT(fObj); return fObj; }
83 
84     T* detach() { T* obj = fObj; fObj = NULL; return obj; }
85     void reset(T* obj = NULL) {
86         if (fObj != obj) {
87             if (fObj) {
88                 P(fObj);
89             }
90             fObj = obj;
91         }
92     }
93 private:
94     T* fObj;
95 };
96 
97 /** \class SkAutoTCallIProc
98 
99 Call a function when this goes out of scope. The template uses two
100 parameters, the object, and a function that is to be called in the destructor.
101 If detach() is called, the object reference is set to null. If the object
102 reference is null when the destructor is called, we do not call the
103 function.
104 */
105 template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable {
106 public:
107     SkAutoTCallIProc(T* obj): fObj(obj) {}
108     ~SkAutoTCallIProc() { if (fObj) P(fObj); }
109     T* detach() { T* obj = fObj; fObj = NULL; return obj; }
110 private:
111     T* fObj;
112 };
113 
114 /** \class SkAutoTDelete
115   An SkAutoTDelete<T> is like a T*, except that the destructor of SkAutoTDelete<T>
116   automatically deletes the pointer it holds (if any).  That is, SkAutoTDelete<T>
117   owns the T object that it points to.  Like a T*, an SkAutoTDelete<T> may hold
118   either NULL or a pointer to a T object.  Also like T*, SkAutoTDelete<T> is
119   thread-compatible, and once you dereference it, you get the threadsafety
120   guarantees of T.
121 
122   The size of a SkAutoTDelete is small: sizeof(SkAutoTDelete<T>) == sizeof(T*)
123 */
124 template <typename T> class SkAutoTDelete : SkNoncopyable {
125 public:
126     SkAutoTDelete(T* obj = NULL) : fObj(obj) {}
127     ~SkAutoTDelete() { SkDELETE(fObj); }
128 
129     T* get() const { return fObj; }
130     operator T*() { return fObj; }
131     T& operator*() const { SkASSERT(fObj); return *fObj; }
132     T* operator->() const { SkASSERT(fObj); return fObj; }
133 
134     void reset(T* obj) {
135         if (fObj != obj) {
136             SkDELETE(fObj);
137             fObj = obj;
138         }
139     }
140 
141     /**
142      *  Delete the owned object, setting the internal pointer to NULL.
143      */
144     void free() {
145         SkDELETE(fObj);
146         fObj = NULL;
147     }
148 
149     /**
150      *  Transfer ownership of the object to the caller, setting the internal
151      *  pointer to NULL. Note that this differs from get(), which also returns
152      *  the pointer, but it does not transfer ownership.
153      */
154     T* detach() {
155         T* obj = fObj;
156         fObj = NULL;
157         return obj;
158     }
159 
160     void swap(SkAutoTDelete* that) {
161         SkTSwap(fObj, that->fObj);
162     }
163 
164 private:
165     T*  fObj;
166 };
167 
168 // Calls ~T() in the destructor.
169 template <typename T> class SkAutoTDestroy : SkNoncopyable {
170 public:
171     SkAutoTDestroy(T* obj = NULL) : fObj(obj) {}
172     ~SkAutoTDestroy() {
173         if (fObj) {
174             fObj->~T();
175         }
176     }
177 
178     T* get() const { return fObj; }
179     T& operator*() const { SkASSERT(fObj); return *fObj; }
180     T* operator->() const { SkASSERT(fObj); return fObj; }
181 
182 private:
183     T*  fObj;
184 };
185 
186 template <typename T> class SkAutoTDeleteArray : SkNoncopyable {
187 public:
188     SkAutoTDeleteArray(T array[]) : fArray(array) {}
189     ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); }
190 
191     T*      get() const { return fArray; }
192     void    free() { SkDELETE_ARRAY(fArray); fArray = NULL; }
193     T*      detach() { T* array = fArray; fArray = NULL; return array; }
194 
195     void reset(T array[]) {
196         if (fArray != array) {
197             SkDELETE_ARRAY(fArray);
198             fArray = array;
199         }
200     }
201 
202 private:
203     T*  fArray;
204 };
205 
206 /** Allocate an array of T elements, and free the array in the destructor
207  */
208 template <typename T> class SkAutoTArray : SkNoncopyable {
209 public:
210     SkAutoTArray() {
211         fArray = NULL;
212         SkDEBUGCODE(fCount = 0;)
213     }
214     /** Allocate count number of T elements
215      */
216     explicit SkAutoTArray(int count) {
217         SkASSERT(count >= 0);
218         fArray = NULL;
219         if (count) {
220             fArray = SkNEW_ARRAY(T, count);
221         }
222         SkDEBUGCODE(fCount = count;)
223     }
224 
225     /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
226      */
227     void reset(int count) {
228         SkDELETE_ARRAY(fArray);
229         SkASSERT(count >= 0);
230         fArray = NULL;
231         if (count) {
232             fArray = SkNEW_ARRAY(T, count);
233         }
234         SkDEBUGCODE(fCount = count;)
235     }
236 
237     ~SkAutoTArray() {
238         SkDELETE_ARRAY(fArray);
239     }
240 
241     /** Return the array of T elements. Will be NULL if count == 0
242      */
243     T* get() const { return fArray; }
244 
245     /** Return the nth element in the array
246      */
247     T&  operator[](int index) const {
248         SkASSERT((unsigned)index < (unsigned)fCount);
249         return fArray[index];
250     }
251 
252 private:
253     T*  fArray;
254     SkDEBUGCODE(int fCount;)
255 };
256 
257 /** Wraps SkAutoTArray, with room for up to N elements preallocated
258  */
259 template <int N, typename T> class SkAutoSTArray : SkNoncopyable {
260 public:
261     /** Initialize with no objects */
262     SkAutoSTArray() {
263         fArray = NULL;
264         fCount = 0;
265     }
266 
267     /** Allocate count number of T elements
268      */
269     SkAutoSTArray(int count) {
270         fArray = NULL;
271         fCount = 0;
272         this->reset(count);
273     }
274 
275     ~SkAutoSTArray() {
276         this->reset(0);
277     }
278 
279     /** Destroys previous objects in the array and default constructs count number of objects */
280     void reset(int count) {
281         T* start = fArray;
282         T* iter = start + fCount;
283         while (iter > start) {
284             (--iter)->~T();
285         }
286 
287         if (fCount != count) {
288             if (fCount > N) {
289                 // 'fArray' was allocated last time so free it now
290                 SkASSERT((T*) fStorage != fArray);
291                 sk_free(fArray);
292             }
293 
294             if (count > N) {
295                 fArray = (T*) sk_malloc_throw(count * sizeof(T));
296             } else if (count > 0) {
297                 fArray = (T*) fStorage;
298             } else {
299                 fArray = NULL;
300             }
301 
302             fCount = count;
303         }
304 
305         iter = fArray;
306         T* stop = fArray + count;
307         while (iter < stop) {
308             SkNEW_PLACEMENT(iter++, T);
309         }
310     }
311 
312     /** Return the number of T elements in the array
313      */
314     int count() const { return fCount; }
315 
316     /** Return the array of T elements. Will be NULL if count == 0
317      */
318     T* get() const { return fArray; }
319 
320     /** Return the nth element in the array
321      */
322     T&  operator[](int index) const {
323         SkASSERT(index < fCount);
324         return fArray[index];
325     }
326 
327 private:
328     int     fCount;
329     T*      fArray;
330     // since we come right after fArray, fStorage should be properly aligned
331     char    fStorage[N * sizeof(T)];
332 };
333 
334 /** Manages an array of T elements, freeing the array in the destructor.
335  *  Does NOT call any constructors/destructors on T (T must be POD).
336  */
337 template <typename T> class SkAutoTMalloc : SkNoncopyable {
338 public:
339     /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
340     explicit SkAutoTMalloc(T* ptr = NULL) {
341         fPtr = ptr;
342     }
343 
344     /** Allocates space for 'count' Ts. */
345     explicit SkAutoTMalloc(size_t count) {
346         fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
347     }
348 
349     ~SkAutoTMalloc() {
350         sk_free(fPtr);
351     }
352 
353     /** Resize the memory area pointed to by the current ptr preserving contents. */
354     void realloc(size_t count) {
355         fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T)));
356     }
357 
358     /** Resize the memory area pointed to by the current ptr without preserving contents. */
359     void reset(size_t count) {
360         sk_free(fPtr);
361         fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
362     }
363 
364     T* get() const { return fPtr; }
365 
366     operator T*() {
367         return fPtr;
368     }
369 
370     operator const T*() const {
371         return fPtr;
372     }
373 
374     T& operator[](int index) {
375         return fPtr[index];
376     }
377 
378     const T& operator[](int index) const {
379         return fPtr[index];
380     }
381 
382     /**
383      *  Transfer ownership of the ptr to the caller, setting the internal
384      *  pointer to NULL. Note that this differs from get(), which also returns
385      *  the pointer, but it does not transfer ownership.
386      */
387     T* detach() {
388         T* ptr = fPtr;
389         fPtr = NULL;
390         return ptr;
391     }
392 
393 private:
394     T* fPtr;
395 };
396 
397 template <size_t N, typename T> class SkAutoSTMalloc : SkNoncopyable {
398 public:
399     SkAutoSTMalloc() {
400         fPtr = NULL;
401     }
402 
403     SkAutoSTMalloc(size_t count) {
404         if (count > N) {
405             fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
406         } else if (count) {
407             fPtr = fTStorage;
408         } else {
409             fPtr = NULL;
410         }
411     }
412 
413     ~SkAutoSTMalloc() {
414         if (fPtr != fTStorage) {
415             sk_free(fPtr);
416         }
417     }
418 
419     // doesn't preserve contents
420     T* reset(size_t count) {
421         if (fPtr != fTStorage) {
422             sk_free(fPtr);
423         }
424         if (count > N) {
425             fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
426         } else if (count) {
427             fPtr = fTStorage;
428         } else {
429             fPtr = NULL;
430         }
431         return fPtr;
432     }
433 
434     T* get() const { return fPtr; }
435 
436     operator T*() {
437         return fPtr;
438     }
439 
440     operator const T*() const {
441         return fPtr;
442     }
443 
444     T& operator[](int index) {
445         return fPtr[index];
446     }
447 
448     const T& operator[](int index) const {
449         return fPtr[index];
450     }
451 
452 private:
453     T*          fPtr;
454     union {
455         uint32_t    fStorage32[(N*sizeof(T) + 3) >> 2];
456         T           fTStorage[1];   // do NOT want to invoke T::T()
457     };
458 };
459 
460 /**
461  * Reserves memory that is aligned on double and pointer boundaries.
462  * Hopefully this is sufficient for all practical purposes.
463  */
464 template <size_t N> class SkAlignedSStorage : SkNoncopyable {
465 public:
466     void* get() { return fData; }
467 private:
468     union {
469         void*   fPtr;
470         double  fDouble;
471         char    fData[N];
472     };
473 };
474 
475 /**
476  * Reserves memory that is aligned on double and pointer boundaries.
477  * Hopefully this is sufficient for all practical purposes. Otherwise,
478  * we have to do some arcane trickery to determine alignment of non-POD
479  * types. Lifetime of the memory is the lifetime of the object.
480  */
481 template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
482 public:
483     /**
484      * Returns void* because this object does not initialize the
485      * memory. Use placement new for types that require a cons.
486      */
487     void* get() { return fStorage.get(); }
488 private:
489     SkAlignedSStorage<sizeof(T)*N> fStorage;
490 };
491 
492 #endif
493