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