LCOV - code coverage report
Current view: top level - gfx/skia/skia/include/private - SkTemplates.h (source / functions) Hit Total Coverage
Test: output.info Lines: 47 157 29.9 %
Date: 2017-07-14 16:53:18 Functions: 31 636 4.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13