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 * SkTIsConst<T>::value is true if the type T is const. 24 * The type T is constrained not to be an array or reference type. 25 */ 26 template <typename T> struct SkTIsConst { 27 static T* t; 28 static uint16_t test(const volatile void*); 29 static uint32_t test(volatile void *); 30 static const bool value = (sizeof(uint16_t) == sizeof(test(t))); 31 }; 32 33 ///@{ 34 /** SkTConstType<T, CONST>::type will be 'const T' if CONST is true, 'T' otherwise. */ 35 template <typename T, bool CONST> struct SkTConstType { 36 typedef T type; 37 }; 38 template <typename T> struct SkTConstType<T, true> { 39 typedef const T type; 40 }; 41 ///@} 42 43 /** \class SkAutoTCallVProc 44 45 Call a function when this goes out of scope. The template uses two 46 parameters, the object, and a function that is to be called in the destructor. 47 If detach() is called, the object reference is set to null. If the object 48 reference is null when the destructor is called, we do not call the 49 function. 50 */ 51 template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable { 52 public: 53 SkAutoTCallVProc(T* obj): fObj(obj) {} 54 ~SkAutoTCallVProc() { if (fObj) P(fObj); } 55 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 56 private: 57 T* fObj; 58 }; 59 60 /** \class SkAutoTCallIProc 61 62 Call a function when this goes out of scope. The template uses two 63 parameters, the object, and a function that is to be called in the destructor. 64 If detach() is called, the object reference is set to null. If the object 65 reference is null when the destructor is called, we do not call the 66 function. 67 */ 68 template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable { 69 public: 70 SkAutoTCallIProc(T* obj): fObj(obj) {} 71 ~SkAutoTCallIProc() { if (fObj) P(fObj); } 72 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 73 private: 74 T* fObj; 75 }; 76 77 // See also SkTScopedPtr. 78 template <typename T> class SkAutoTDelete : SkNoncopyable { 79 public: 80 SkAutoTDelete(T* obj) : fObj(obj) {} 81 ~SkAutoTDelete() { delete fObj; } 82 83 T* get() const { return fObj; } 84 T& operator*() const { SkASSERT(fObj); return *fObj; } 85 T* operator->() const { SkASSERT(fObj); return fObj; } 86 87 /** 88 * Delete the owned object, setting the internal pointer to NULL. 89 */ 90 void free() { 91 delete fObj; 92 fObj = NULL; 93 } 94 95 /** 96 * Transfer ownership of the object to the caller, setting the internal 97 * pointer to NULL. Note that this differs from get(), which also returns 98 * the pointer, but it does not transfer ownership. 99 */ 100 T* detach() { 101 T* obj = fObj; 102 fObj = NULL; 103 return obj; 104 } 105 106 private: 107 T* fObj; 108 }; 109 110 template <typename T> class SkAutoTDeleteArray : SkNoncopyable { 111 public: 112 SkAutoTDeleteArray(T array[]) : fArray(array) {} 113 ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); } 114 115 T* get() const { return fArray; } 116 void free() { SkDELETE_ARRAY(fArray); fArray = NULL; } 117 T* detach() { T* array = fArray; fArray = NULL; return array; } 118 119 private: 120 T* fArray; 121 }; 122 123 /** Allocate an array of T elements, and free the array in the destructor 124 */ 125 template <typename T> class SkAutoTArray : SkNoncopyable { 126 public: 127 SkAutoTArray() { 128 fArray = NULL; 129 SkDEBUGCODE(fCount = 0;) 130 } 131 /** Allocate count number of T elements 132 */ 133 explicit SkAutoTArray(int count) { 134 SkASSERT(count >= 0); 135 fArray = NULL; 136 if (count) { 137 fArray = new T[count]; 138 } 139 SkDEBUGCODE(fCount = count;) 140 } 141 142 /** Reallocates given a new count. Reallocation occurs even if new count equals old count. 143 */ 144 void reset(int count) { 145 delete[] fArray; 146 SkASSERT(count >= 0); 147 fArray = NULL; 148 if (count) { 149 fArray = new T[count]; 150 } 151 SkDEBUGCODE(fCount = count;) 152 } 153 154 ~SkAutoTArray() { 155 delete[] fArray; 156 } 157 158 /** Return the array of T elements. Will be NULL if count == 0 159 */ 160 T* get() const { return fArray; } 161 162 /** Return the nth element in the array 163 */ 164 T& operator[](int index) const { 165 SkASSERT((unsigned)index < (unsigned)fCount); 166 return fArray[index]; 167 } 168 169 private: 170 T* fArray; 171 SkDEBUGCODE(int fCount;) 172 }; 173 174 /** Wraps SkAutoTArray, with room for up to N elements preallocated 175 */ 176 template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable { 177 public: 178 /** Allocate count number of T elements 179 */ 180 SkAutoSTArray(size_t count) { 181 if (count > N) { 182 fArray = new T[count]; 183 } else if (count) { 184 fArray = new (fStorage) T[count]; 185 } else { 186 fArray = NULL; 187 } 188 fCount = count; 189 } 190 191 ~SkAutoSTArray() { 192 if (fCount > N) { 193 delete[] fArray; 194 } else { 195 T* start = fArray; 196 T* iter = start + fCount; 197 while (iter > start) { 198 (--iter)->~T(); 199 } 200 } 201 } 202 203 /** Return the number of T elements in the array 204 */ 205 size_t count() const { return fCount; } 206 207 /** Return the array of T elements. Will be NULL if count == 0 208 */ 209 T* get() const { return fArray; } 210 211 /** Return the nth element in the array 212 */ 213 T& operator[](int index) const { 214 SkASSERT((unsigned)index < fCount); 215 return fArray[index]; 216 } 217 218 private: 219 size_t fCount; 220 T* fArray; 221 // since we come right after fArray, fStorage should be properly aligned 222 char fStorage[N * sizeof(T)]; 223 }; 224 225 /** Allocate a temp array on the stack/heap. 226 Does NOT call any constructors/destructors on T (i.e. T must be POD) 227 */ 228 template <typename T> class SkAutoTMalloc : SkNoncopyable { 229 public: 230 SkAutoTMalloc(size_t count) { 231 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 232 } 233 234 ~SkAutoTMalloc() { 235 sk_free(fPtr); 236 } 237 238 // doesn't preserve contents 239 void reset (size_t count) { 240 sk_free(fPtr); 241 fPtr = fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 242 } 243 244 T* get() const { return fPtr; } 245 246 operator T*() { 247 return fPtr; 248 } 249 250 operator const T*() const { 251 return fPtr; 252 } 253 254 T& operator[](int index) { 255 return fPtr[index]; 256 } 257 258 const T& operator[](int index) const { 259 return fPtr[index]; 260 } 261 262 private: 263 T* fPtr; 264 }; 265 266 template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable { 267 public: 268 SkAutoSTMalloc(size_t count) { 269 if (count <= N) { 270 fPtr = fTStorage; 271 } else { 272 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 273 } 274 } 275 276 ~SkAutoSTMalloc() { 277 if (fPtr != fTStorage) { 278 sk_free(fPtr); 279 } 280 } 281 282 // doesn't preserve contents 283 void reset(size_t count) { 284 if (fPtr != fTStorage) { 285 sk_free(fPtr); 286 } 287 if (count <= N) { 288 fPtr = fTStorage; 289 } else { 290 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 291 } 292 } 293 294 T* get() const { return fPtr; } 295 296 operator T*() { 297 return fPtr; 298 } 299 300 operator const T*() const { 301 return fPtr; 302 } 303 304 T& operator[](int index) { 305 return fPtr[index]; 306 } 307 308 const T& operator[](int index) const { 309 return fPtr[index]; 310 } 311 312 private: 313 T* fPtr; 314 union { 315 uint32_t fStorage32[(N*sizeof(T) + 3) >> 2]; 316 T fTStorage[1]; // do NOT want to invoke T::T() 317 }; 318 }; 319 320 /** 321 * Reserves memory that is aligned on double and pointer boundaries. 322 * Hopefully this is sufficient for all practical purposes. 323 */ 324 template <size_t N> class SkAlignedSStorage : SkNoncopyable { 325 public: 326 void* get() { return fData; } 327 private: 328 union { 329 void* fPtr; 330 double fDouble; 331 char fData[N]; 332 }; 333 }; 334 335 /** 336 * Reserves memory that is aligned on double and pointer boundaries. 337 * Hopefully this is sufficient for all practical purposes. Otherwise, 338 * we have to do some arcane trickery to determine alignment of non-POD 339 * types. Lifetime of the memory is the lifetime of the object. 340 */ 341 template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable { 342 public: 343 /** 344 * Returns void* because this object does not initialize the 345 * memory. Use placement new for types that require a cons. 346 */ 347 void* get() { return fStorage.get(); } 348 private: 349 SkAlignedSStorage<sizeof(T)*N> fStorage; 350 }; 351 352 #endif 353