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