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