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 
     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:
     31     SkAutoTCallVProc(T* obj): fObj(obj) {}
     32     ~SkAutoTCallVProc() { if (fObj) P(fObj); }
     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:
     48     SkAutoTCallIProc(T* obj): fObj(obj) {}
     49     ~SkAutoTCallIProc() { if (fObj) P(fObj); }
     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:
     58     SkAutoTDelete(T* obj, bool deleteWhenDone = true) : fObj(obj) {
     59         fDeleteWhenDone = deleteWhenDone;
     60     }
     61     ~SkAutoTDelete() { if (fDeleteWhenDone) delete fObj; }
     62 
     63     T*      get() const { return fObj; }
     64     void    free() { delete fObj; fObj = NULL; }
     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:
     74     SkAutoTDeleteArray(T array[]) : fArray(array) {}
     75     ~SkAutoTDeleteArray() { delete[] fArray; }
     76 
     77     T*      get() const { return fArray; }
     78     void    free() { delete[] fArray; fArray = NULL; }
     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      */
     91     SkAutoTArray(size_t count) {
     92         fArray = NULL;
     93         if (count) {
     94             fArray = new T[count];
     95         }
     96         SkDEBUGCODE(fCount = count;)
     97     }
     98 
     99     ~SkAutoTArray() {
    100         delete[] fArray;
    101     }
    102 
    103     /** Return the array of T elements. Will be NULL if count == 0
    104      */
    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      */
    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 
    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      */
    150     size_t count() const { return fCount; }
    151 
    152     /** Return the array of T elements. Will be NULL if count == 0
    153      */
    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:
    175     SkAutoTMalloc(size_t count) {
    176         fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
    177     }
    178 
    179     ~SkAutoTMalloc() {
    180         sk_free(fPtr);
    181     }
    182 
    183     // doesn't preserve contents
    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 
    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:
    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 
    221     ~SkAutoSTMalloc() {
    222         if (fPtr != fTStorage) {
    223             sk_free(fPtr);
    224         }
    225     }
    226 
    227     // doesn't preserve contents
    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 
    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:
    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      */
    292     void* get() { return fStorage.get(); }
    293 private:
    294     SkAlignedSStorage<sizeof(T)*N> fStorage;
    295 };
    296 
    297 #endif
    298 
    299