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