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