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