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 */ 26 template<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 */ 32 template <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. */ 41 template <typename T, bool CONST> struct SkTConstType { 42 typedef T type; 43 }; 44 template <typename T> struct SkTConstType<T, true> { 45 typedef const T type; 46 }; 47 ///@} 48 49 /** 50 * Returns a pointer to a D which comes immediately after S[count]. 51 */ 52 template <typename D, typename S> static D* SkTAfter(S* ptr, size_t count = 1) { 53 return reinterpret_cast<D*>(ptr + count); 54 } 55 56 /** 57 * Returns a pointer to a D which comes byteOffset bytes after S. 58 */ 59 template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) { 60 // The intermediate char* has the same const-ness as D as this produces better error messages. 61 // This relies on the fact that reinterpret_cast can add constness, but cannot remove it. 62 return reinterpret_cast<D*>( 63 reinterpret_cast<typename SkTConstType<char, SkTIsConst<D>::value>::type*>(ptr) + byteOffset 64 ); 65 } 66 67 /** \class SkAutoTCallVProc 68 69 Call a function when this goes out of scope. The template uses two 70 parameters, the object, and a function that is to be called in the destructor. 71 If detach() is called, the object reference is set to null. If the object 72 reference is null when the destructor is called, we do not call the 73 function. 74 */ 75 template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable { 76 public: 77 SkAutoTCallVProc(T* obj): fObj(obj) {} 78 ~SkAutoTCallVProc() { if (fObj) P(fObj); } 79 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 80 private: 81 T* fObj; 82 }; 83 84 /** \class SkAutoTCallIProc 85 86 Call a function when this goes out of scope. The template uses two 87 parameters, the object, and a function that is to be called in the destructor. 88 If detach() is called, the object reference is set to null. If the object 89 reference is null when the destructor is called, we do not call the 90 function. 91 */ 92 template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable { 93 public: 94 SkAutoTCallIProc(T* obj): fObj(obj) {} 95 ~SkAutoTCallIProc() { if (fObj) P(fObj); } 96 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 97 private: 98 T* fObj; 99 }; 100 101 template <typename T> class SkAutoTDelete : SkNoncopyable { 102 public: 103 SkAutoTDelete(T* obj = NULL) : fObj(obj) {} 104 ~SkAutoTDelete() { SkDELETE(fObj); } 105 106 T* get() const { return fObj; } 107 T& operator*() const { SkASSERT(fObj); return *fObj; } 108 T* operator->() const { SkASSERT(fObj); return fObj; } 109 110 void reset(T* obj) { 111 if (fObj != obj) { 112 SkDELETE(fObj); 113 fObj = obj; 114 } 115 } 116 117 /** 118 * Delete the owned object, setting the internal pointer to NULL. 119 */ 120 void free() { 121 SkDELETE(fObj); 122 fObj = NULL; 123 } 124 125 /** 126 * Transfer ownership of the object to the caller, setting the internal 127 * pointer to NULL. Note that this differs from get(), which also returns 128 * the pointer, but it does not transfer ownership. 129 */ 130 T* detach() { 131 T* obj = fObj; 132 fObj = NULL; 133 return obj; 134 } 135 136 private: 137 T* fObj; 138 }; 139 140 // Calls ~T() in the destructor. 141 template <typename T> class SkAutoTDestroy : SkNoncopyable { 142 public: 143 SkAutoTDestroy(T* obj = NULL) : fObj(obj) {} 144 ~SkAutoTDestroy() { 145 if (NULL != fObj) { 146 fObj->~T(); 147 } 148 } 149 150 T* get() const { return fObj; } 151 T& operator*() const { SkASSERT(fObj); return *fObj; } 152 T* operator->() const { SkASSERT(fObj); return fObj; } 153 154 private: 155 T* fObj; 156 }; 157 158 template <typename T> class SkAutoTDeleteArray : SkNoncopyable { 159 public: 160 SkAutoTDeleteArray(T array[]) : fArray(array) {} 161 ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); } 162 163 T* get() const { return fArray; } 164 void free() { SkDELETE_ARRAY(fArray); fArray = NULL; } 165 T* detach() { T* array = fArray; fArray = NULL; return array; } 166 167 private: 168 T* fArray; 169 }; 170 171 /** Allocate an array of T elements, and free the array in the destructor 172 */ 173 template <typename T> class SkAutoTArray : SkNoncopyable { 174 public: 175 SkAutoTArray() { 176 fArray = NULL; 177 SkDEBUGCODE(fCount = 0;) 178 } 179 /** Allocate count number of T elements 180 */ 181 explicit SkAutoTArray(int count) { 182 SkASSERT(count >= 0); 183 fArray = NULL; 184 if (count) { 185 fArray = SkNEW_ARRAY(T, count); 186 } 187 SkDEBUGCODE(fCount = count;) 188 } 189 190 /** Reallocates given a new count. Reallocation occurs even if new count equals old count. 191 */ 192 void reset(int count) { 193 SkDELETE_ARRAY(fArray); 194 SkASSERT(count >= 0); 195 fArray = NULL; 196 if (count) { 197 fArray = SkNEW_ARRAY(T, count); 198 } 199 SkDEBUGCODE(fCount = count;) 200 } 201 202 ~SkAutoTArray() { 203 SkDELETE_ARRAY(fArray); 204 } 205 206 /** Return the array of T elements. Will be NULL if count == 0 207 */ 208 T* get() const { return fArray; } 209 210 /** Return the nth element in the array 211 */ 212 T& operator[](int index) const { 213 SkASSERT((unsigned)index < (unsigned)fCount); 214 return fArray[index]; 215 } 216 217 private: 218 T* fArray; 219 SkDEBUGCODE(int fCount;) 220 }; 221 222 /** Wraps SkAutoTArray, with room for up to N elements preallocated 223 */ 224 template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable { 225 public: 226 /** Initialize with no objects */ 227 SkAutoSTArray() { 228 fArray = NULL; 229 fCount = 0; 230 } 231 232 /** Allocate count number of T elements 233 */ 234 SkAutoSTArray(size_t count) { 235 fArray = NULL; 236 fCount = 0; 237 this->reset(count); 238 } 239 240 ~SkAutoSTArray() { 241 this->reset(0); 242 } 243 244 /** Destroys previous objects in the array and default constructs count number of objects */ 245 void reset(size_t count) { 246 T* start = fArray; 247 T* iter = start + fCount; 248 while (iter > start) { 249 (--iter)->~T(); 250 } 251 252 if (fCount != count) { 253 if (fCount > N) { 254 // 'fArray' was allocated last time so free it now 255 SkASSERT((T*) fStorage != fArray); 256 sk_free(fArray); 257 } 258 259 if (count > N) { 260 fArray = (T*) sk_malloc_throw(count * sizeof(T)); 261 } else if (count > 0) { 262 fArray = (T*) fStorage; 263 } else { 264 fArray = NULL; 265 } 266 267 fCount = count; 268 } 269 270 iter = fArray; 271 T* stop = fArray + count; 272 while (iter < stop) { 273 SkNEW_PLACEMENT(iter++, T); 274 } 275 } 276 277 /** Return the number of T elements in the array 278 */ 279 size_t count() const { return fCount; } 280 281 /** Return the array of T elements. Will be NULL if count == 0 282 */ 283 T* get() const { return fArray; } 284 285 /** Return the nth element in the array 286 */ 287 T& operator[](int index) const { 288 SkASSERT((unsigned)index < fCount); 289 return fArray[index]; 290 } 291 292 private: 293 size_t fCount; 294 T* fArray; 295 // since we come right after fArray, fStorage should be properly aligned 296 char fStorage[N * sizeof(T)]; 297 }; 298 299 /** Manages an array of T elements, freeing the array in the destructor. 300 * Does NOT call any constructors/destructors on T (T must be POD). 301 */ 302 template <typename T> class SkAutoTMalloc : SkNoncopyable { 303 public: 304 /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */ 305 explicit SkAutoTMalloc(T* ptr = NULL) { 306 fPtr = ptr; 307 } 308 309 /** Allocates space for 'count' Ts. */ 310 explicit SkAutoTMalloc(size_t count) { 311 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 312 } 313 314 ~SkAutoTMalloc() { 315 sk_free(fPtr); 316 } 317 318 /** Resize the memory area pointed to by the current ptr preserving contents. */ 319 void realloc(size_t count) { 320 fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T))); 321 } 322 323 /** Resize the memory area pointed to by the current ptr without preserving contents. */ 324 void reset(size_t count) { 325 sk_free(fPtr); 326 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 327 } 328 329 T* get() const { return fPtr; } 330 331 operator T*() { 332 return fPtr; 333 } 334 335 operator const T*() const { 336 return fPtr; 337 } 338 339 T& operator[](int index) { 340 return fPtr[index]; 341 } 342 343 const T& operator[](int index) const { 344 return fPtr[index]; 345 } 346 347 /** 348 * Transfer ownership of the ptr to the caller, setting the internal 349 * pointer to NULL. Note that this differs from get(), which also returns 350 * the pointer, but it does not transfer ownership. 351 */ 352 T* detach() { 353 T* ptr = fPtr; 354 fPtr = NULL; 355 return ptr; 356 } 357 358 private: 359 T* fPtr; 360 }; 361 362 template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable { 363 public: 364 SkAutoSTMalloc() { 365 fPtr = NULL; 366 } 367 368 SkAutoSTMalloc(size_t count) { 369 if (count > N) { 370 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 371 } else if (count) { 372 fPtr = fTStorage; 373 } else { 374 fPtr = NULL; 375 } 376 } 377 378 ~SkAutoSTMalloc() { 379 if (fPtr != fTStorage) { 380 sk_free(fPtr); 381 } 382 } 383 384 // doesn't preserve contents 385 T* reset(size_t count) { 386 if (fPtr != fTStorage) { 387 sk_free(fPtr); 388 } 389 if (count > N) { 390 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 391 } else if (count) { 392 fPtr = fTStorage; 393 } else { 394 fPtr = NULL; 395 } 396 return fPtr; 397 } 398 399 T* get() const { return fPtr; } 400 401 operator T*() { 402 return fPtr; 403 } 404 405 operator const T*() const { 406 return fPtr; 407 } 408 409 T& operator[](int index) { 410 return fPtr[index]; 411 } 412 413 const T& operator[](int index) const { 414 return fPtr[index]; 415 } 416 417 private: 418 T* fPtr; 419 union { 420 uint32_t fStorage32[(N*sizeof(T) + 3) >> 2]; 421 T fTStorage[1]; // do NOT want to invoke T::T() 422 }; 423 }; 424 425 /** 426 * Reserves memory that is aligned on double and pointer boundaries. 427 * Hopefully this is sufficient for all practical purposes. 428 */ 429 template <size_t N> class SkAlignedSStorage : SkNoncopyable { 430 public: 431 void* get() { return fData; } 432 private: 433 union { 434 void* fPtr; 435 double fDouble; 436 char fData[N]; 437 }; 438 }; 439 440 /** 441 * Reserves memory that is aligned on double and pointer boundaries. 442 * Hopefully this is sufficient for all practical purposes. Otherwise, 443 * we have to do some arcane trickery to determine alignment of non-POD 444 * types. Lifetime of the memory is the lifetime of the object. 445 */ 446 template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable { 447 public: 448 /** 449 * Returns void* because this object does not initialize the 450 * memory. Use placement new for types that require a cons. 451 */ 452 void* get() { return fStorage.get(); } 453 private: 454 SkAlignedSStorage<sizeof(T)*N> fStorage; 455 }; 456 457 #endif 458