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 */ 26template <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. */ 35template <typename T, bool CONST> struct SkTConstType { 36 typedef T type; 37}; 38template <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*/ 51template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable { 52public: 53 SkAutoTCallVProc(T* obj): fObj(obj) {} 54 ~SkAutoTCallVProc() { if (fObj) P(fObj); } 55 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 56private: 57 T* fObj; 58}; 59 60/** \class SkAutoTCallIProc 61 62Call a function when this goes out of scope. The template uses two 63parameters, the object, and a function that is to be called in the destructor. 64If detach() is called, the object reference is set to null. If the object 65reference is null when the destructor is called, we do not call the 66function. 67*/ 68template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable { 69public: 70 SkAutoTCallIProc(T* obj): fObj(obj) {} 71 ~SkAutoTCallIProc() { if (fObj) P(fObj); } 72 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 73private: 74 T* fObj; 75}; 76 77// See also SkTScopedPtr. 78template <typename T> class SkAutoTDelete : SkNoncopyable { 79public: 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 106private: 107 T* fObj; 108}; 109 110template <typename T> class SkAutoTDeleteArray : SkNoncopyable { 111public: 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 119private: 120 T* fArray; 121}; 122 123/** Allocate an array of T elements, and free the array in the destructor 124 */ 125template <typename T> class SkAutoTArray : SkNoncopyable { 126public: 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 169private: 170 T* fArray; 171 SkDEBUGCODE(int fCount;) 172}; 173 174/** Wraps SkAutoTArray, with room for up to N elements preallocated 175 */ 176template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable { 177public: 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 218private: 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*/ 228template <typename T> class SkAutoTMalloc : SkNoncopyable { 229public: 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 262private: 263 T* fPtr; 264}; 265 266template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable { 267public: 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 312private: 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 */ 324template <size_t N> class SkAlignedSStorage : SkNoncopyable { 325public: 326 void* get() { return fData; } 327private: 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 */ 341template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable { 342public: 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(); } 348private: 349 SkAlignedSStorage<sizeof(T)*N> fStorage; 350}; 351 352#endif 353