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