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