Home | History | Annotate | Download | only in core
      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