1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/include/core/SkTemplates.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,489 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2006 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#ifndef SkTemplates_DEFINED 1.14 +#define SkTemplates_DEFINED 1.15 + 1.16 +#include "SkTypes.h" 1.17 +#include <limits> 1.18 +#include <limits.h> 1.19 +#include <new> 1.20 + 1.21 +/** \file SkTemplates.h 1.22 + 1.23 + This file contains light-weight template classes for type-safe and exception-safe 1.24 + resource management. 1.25 +*/ 1.26 + 1.27 +/** 1.28 + * Marks a local variable as known to be unused (to avoid warnings). 1.29 + * Note that this does *not* prevent the local variable from being optimized away. 1.30 + */ 1.31 +template<typename T> inline void sk_ignore_unused_variable(const T&) { } 1.32 + 1.33 +/** 1.34 + * SkTIsConst<T>::value is true if the type T is const. 1.35 + * The type T is constrained not to be an array or reference type. 1.36 + */ 1.37 +template <typename T> struct SkTIsConst { 1.38 + static T* t; 1.39 + static uint16_t test(const volatile void*); 1.40 + static uint32_t test(volatile void *); 1.41 + static const bool value = (sizeof(uint16_t) == sizeof(test(t))); 1.42 +}; 1.43 + 1.44 +///@{ 1.45 +/** SkTConstType<T, CONST>::type will be 'const T' if CONST is true, 'T' otherwise. */ 1.46 +template <typename T, bool CONST> struct SkTConstType { 1.47 + typedef T type; 1.48 +}; 1.49 +template <typename T> struct SkTConstType<T, true> { 1.50 + typedef const T type; 1.51 +}; 1.52 +///@} 1.53 + 1.54 +/** 1.55 + * Returns a pointer to a D which comes immediately after S[count]. 1.56 + */ 1.57 +template <typename D, typename S> static D* SkTAfter(S* ptr, size_t count = 1) { 1.58 + return reinterpret_cast<D*>(ptr + count); 1.59 +} 1.60 + 1.61 +/** 1.62 + * Returns a pointer to a D which comes byteOffset bytes after S. 1.63 + */ 1.64 +template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) { 1.65 + // The intermediate char* has the same const-ness as D as this produces better error messages. 1.66 + // This relies on the fact that reinterpret_cast can add constness, but cannot remove it. 1.67 + return reinterpret_cast<D*>( 1.68 + reinterpret_cast<typename SkTConstType<char, SkTIsConst<D>::value>::type*>(ptr) + byteOffset 1.69 + ); 1.70 +} 1.71 + 1.72 +/** SkTSetBit<N, T>::value is a T with the Nth bit set. */ 1.73 +template<unsigned N, typename T = uintmax_t> struct SkTSetBit { 1.74 + static const T value = static_cast<T>(1) << N; 1.75 + SK_COMPILE_ASSERT(sizeof(T)*CHAR_BIT > N, SkTSetBit_N_too_large); 1.76 + SK_COMPILE_ASSERT(std::numeric_limits<T>::is_integer, SkTSetBit_T_must_be_integer); 1.77 + SK_COMPILE_ASSERT(!std::numeric_limits<T>::is_signed, SkTSetBit_T_must_be_unsigned); 1.78 + SK_COMPILE_ASSERT(std::numeric_limits<T>::radix == 2, SkTSetBit_T_radix_must_be_2); 1.79 +}; 1.80 + 1.81 +/** \class SkAutoTCallVProc 1.82 + 1.83 + Call a function when this goes out of scope. The template uses two 1.84 + parameters, the object, and a function that is to be called in the destructor. 1.85 + If detach() is called, the object reference is set to null. If the object 1.86 + reference is null when the destructor is called, we do not call the 1.87 + function. 1.88 +*/ 1.89 +template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable { 1.90 +public: 1.91 + SkAutoTCallVProc(T* obj): fObj(obj) {} 1.92 + ~SkAutoTCallVProc() { if (fObj) P(fObj); } 1.93 + T* detach() { T* obj = fObj; fObj = NULL; return obj; } 1.94 +private: 1.95 + T* fObj; 1.96 +}; 1.97 + 1.98 +/** \class SkAutoTCallIProc 1.99 + 1.100 +Call a function when this goes out of scope. The template uses two 1.101 +parameters, the object, and a function that is to be called in the destructor. 1.102 +If detach() is called, the object reference is set to null. If the object 1.103 +reference is null when the destructor is called, we do not call the 1.104 +function. 1.105 +*/ 1.106 +template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable { 1.107 +public: 1.108 + SkAutoTCallIProc(T* obj): fObj(obj) {} 1.109 + ~SkAutoTCallIProc() { if (fObj) P(fObj); } 1.110 + T* detach() { T* obj = fObj; fObj = NULL; return obj; } 1.111 +private: 1.112 + T* fObj; 1.113 +}; 1.114 + 1.115 +/** \class SkAutoTDelete 1.116 + An SkAutoTDelete<T> is like a T*, except that the destructor of SkAutoTDelete<T> 1.117 + automatically deletes the pointer it holds (if any). That is, SkAutoTDelete<T> 1.118 + owns the T object that it points to. Like a T*, an SkAutoTDelete<T> may hold 1.119 + either NULL or a pointer to a T object. Also like T*, SkAutoTDelete<T> is 1.120 + thread-compatible, and once you dereference it, you get the threadsafety 1.121 + guarantees of T. 1.122 + 1.123 + The size of a SkAutoTDelete is small: sizeof(SkAutoTDelete<T>) == sizeof(T*) 1.124 +*/ 1.125 +template <typename T> class SkAutoTDelete : SkNoncopyable { 1.126 +public: 1.127 + SkAutoTDelete(T* obj = NULL) : fObj(obj) {} 1.128 + ~SkAutoTDelete() { SkDELETE(fObj); } 1.129 + 1.130 + T* get() const { return fObj; } 1.131 + T& operator*() const { SkASSERT(fObj); return *fObj; } 1.132 + T* operator->() const { SkASSERT(fObj); return fObj; } 1.133 + 1.134 + void reset(T* obj) { 1.135 + if (fObj != obj) { 1.136 + SkDELETE(fObj); 1.137 + fObj = obj; 1.138 + } 1.139 + } 1.140 + 1.141 + /** 1.142 + * Delete the owned object, setting the internal pointer to NULL. 1.143 + */ 1.144 + void free() { 1.145 + SkDELETE(fObj); 1.146 + fObj = NULL; 1.147 + } 1.148 + 1.149 + /** 1.150 + * Transfer ownership of the object to the caller, setting the internal 1.151 + * pointer to NULL. Note that this differs from get(), which also returns 1.152 + * the pointer, but it does not transfer ownership. 1.153 + */ 1.154 + T* detach() { 1.155 + T* obj = fObj; 1.156 + fObj = NULL; 1.157 + return obj; 1.158 + } 1.159 + 1.160 + void swap(SkAutoTDelete* that) { 1.161 + SkTSwap(fObj, that->fObj); 1.162 + } 1.163 + 1.164 +private: 1.165 + T* fObj; 1.166 +}; 1.167 + 1.168 +// Calls ~T() in the destructor. 1.169 +template <typename T> class SkAutoTDestroy : SkNoncopyable { 1.170 +public: 1.171 + SkAutoTDestroy(T* obj = NULL) : fObj(obj) {} 1.172 + ~SkAutoTDestroy() { 1.173 + if (NULL != fObj) { 1.174 + fObj->~T(); 1.175 + } 1.176 + } 1.177 + 1.178 + T* get() const { return fObj; } 1.179 + T& operator*() const { SkASSERT(fObj); return *fObj; } 1.180 + T* operator->() const { SkASSERT(fObj); return fObj; } 1.181 + 1.182 +private: 1.183 + T* fObj; 1.184 +}; 1.185 + 1.186 +template <typename T> class SkAutoTDeleteArray : SkNoncopyable { 1.187 +public: 1.188 + SkAutoTDeleteArray(T array[]) : fArray(array) {} 1.189 + ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); } 1.190 + 1.191 + T* get() const { return fArray; } 1.192 + void free() { SkDELETE_ARRAY(fArray); fArray = NULL; } 1.193 + T* detach() { T* array = fArray; fArray = NULL; return array; } 1.194 + 1.195 + void reset(T array[]) { 1.196 + if (fArray != array) { 1.197 + SkDELETE_ARRAY(fArray); 1.198 + fArray = array; 1.199 + } 1.200 + } 1.201 + 1.202 +private: 1.203 + T* fArray; 1.204 +}; 1.205 + 1.206 +/** Allocate an array of T elements, and free the array in the destructor 1.207 + */ 1.208 +template <typename T> class SkAutoTArray : SkNoncopyable { 1.209 +public: 1.210 + SkAutoTArray() { 1.211 + fArray = NULL; 1.212 + SkDEBUGCODE(fCount = 0;) 1.213 + } 1.214 + /** Allocate count number of T elements 1.215 + */ 1.216 + explicit SkAutoTArray(int count) { 1.217 + SkASSERT(count >= 0); 1.218 + fArray = NULL; 1.219 + if (count) { 1.220 + fArray = SkNEW_ARRAY(T, count); 1.221 + } 1.222 + SkDEBUGCODE(fCount = count;) 1.223 + } 1.224 + 1.225 + /** Reallocates given a new count. Reallocation occurs even if new count equals old count. 1.226 + */ 1.227 + void reset(int count) { 1.228 + SkDELETE_ARRAY(fArray); 1.229 + SkASSERT(count >= 0); 1.230 + fArray = NULL; 1.231 + if (count) { 1.232 + fArray = SkNEW_ARRAY(T, count); 1.233 + } 1.234 + SkDEBUGCODE(fCount = count;) 1.235 + } 1.236 + 1.237 + ~SkAutoTArray() { 1.238 + SkDELETE_ARRAY(fArray); 1.239 + } 1.240 + 1.241 + /** Return the array of T elements. Will be NULL if count == 0 1.242 + */ 1.243 + T* get() const { return fArray; } 1.244 + 1.245 + /** Return the nth element in the array 1.246 + */ 1.247 + T& operator[](int index) const { 1.248 + SkASSERT((unsigned)index < (unsigned)fCount); 1.249 + return fArray[index]; 1.250 + } 1.251 + 1.252 +private: 1.253 + T* fArray; 1.254 + SkDEBUGCODE(int fCount;) 1.255 +}; 1.256 + 1.257 +/** Wraps SkAutoTArray, with room for up to N elements preallocated 1.258 + */ 1.259 +template <int N, typename T> class SkAutoSTArray : SkNoncopyable { 1.260 +public: 1.261 + /** Initialize with no objects */ 1.262 + SkAutoSTArray() { 1.263 + fArray = NULL; 1.264 + fCount = 0; 1.265 + } 1.266 + 1.267 + /** Allocate count number of T elements 1.268 + */ 1.269 + SkAutoSTArray(int count) { 1.270 + fArray = NULL; 1.271 + fCount = 0; 1.272 + this->reset(count); 1.273 + } 1.274 + 1.275 + ~SkAutoSTArray() { 1.276 + this->reset(0); 1.277 + } 1.278 + 1.279 + /** Destroys previous objects in the array and default constructs count number of objects */ 1.280 + void reset(int count) { 1.281 + T* start = fArray; 1.282 + T* iter = start + fCount; 1.283 + while (iter > start) { 1.284 + (--iter)->~T(); 1.285 + } 1.286 + 1.287 + if (fCount != count) { 1.288 + if (fCount > N) { 1.289 + // 'fArray' was allocated last time so free it now 1.290 + SkASSERT((T*) fStorage != fArray); 1.291 + sk_free(fArray); 1.292 + } 1.293 + 1.294 + if (count > N) { 1.295 + fArray = (T*) sk_malloc_throw(count * sizeof(T)); 1.296 + } else if (count > 0) { 1.297 + fArray = (T*) fStorage; 1.298 + } else { 1.299 + fArray = NULL; 1.300 + } 1.301 + 1.302 + fCount = count; 1.303 + } 1.304 + 1.305 + iter = fArray; 1.306 + T* stop = fArray + count; 1.307 + while (iter < stop) { 1.308 + SkNEW_PLACEMENT(iter++, T); 1.309 + } 1.310 + } 1.311 + 1.312 + /** Return the number of T elements in the array 1.313 + */ 1.314 + int count() const { return fCount; } 1.315 + 1.316 + /** Return the array of T elements. Will be NULL if count == 0 1.317 + */ 1.318 + T* get() const { return fArray; } 1.319 + 1.320 + /** Return the nth element in the array 1.321 + */ 1.322 + T& operator[](int index) const { 1.323 + SkASSERT(index < fCount); 1.324 + return fArray[index]; 1.325 + } 1.326 + 1.327 +private: 1.328 + int fCount; 1.329 + T* fArray; 1.330 + // since we come right after fArray, fStorage should be properly aligned 1.331 + char fStorage[N * sizeof(T)]; 1.332 +}; 1.333 + 1.334 +/** Manages an array of T elements, freeing the array in the destructor. 1.335 + * Does NOT call any constructors/destructors on T (T must be POD). 1.336 + */ 1.337 +template <typename T> class SkAutoTMalloc : SkNoncopyable { 1.338 +public: 1.339 + /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */ 1.340 + explicit SkAutoTMalloc(T* ptr = NULL) { 1.341 + fPtr = ptr; 1.342 + } 1.343 + 1.344 + /** Allocates space for 'count' Ts. */ 1.345 + explicit SkAutoTMalloc(size_t count) { 1.346 + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 1.347 + } 1.348 + 1.349 + ~SkAutoTMalloc() { 1.350 + sk_free(fPtr); 1.351 + } 1.352 + 1.353 + /** Resize the memory area pointed to by the current ptr preserving contents. */ 1.354 + void realloc(size_t count) { 1.355 + fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T))); 1.356 + } 1.357 + 1.358 + /** Resize the memory area pointed to by the current ptr without preserving contents. */ 1.359 + void reset(size_t count) { 1.360 + sk_free(fPtr); 1.361 + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 1.362 + } 1.363 + 1.364 + T* get() const { return fPtr; } 1.365 + 1.366 + operator T*() { 1.367 + return fPtr; 1.368 + } 1.369 + 1.370 + operator const T*() const { 1.371 + return fPtr; 1.372 + } 1.373 + 1.374 + T& operator[](int index) { 1.375 + return fPtr[index]; 1.376 + } 1.377 + 1.378 + const T& operator[](int index) const { 1.379 + return fPtr[index]; 1.380 + } 1.381 + 1.382 + /** 1.383 + * Transfer ownership of the ptr to the caller, setting the internal 1.384 + * pointer to NULL. Note that this differs from get(), which also returns 1.385 + * the pointer, but it does not transfer ownership. 1.386 + */ 1.387 + T* detach() { 1.388 + T* ptr = fPtr; 1.389 + fPtr = NULL; 1.390 + return ptr; 1.391 + } 1.392 + 1.393 +private: 1.394 + T* fPtr; 1.395 +}; 1.396 + 1.397 +template <size_t N, typename T> class SkAutoSTMalloc : SkNoncopyable { 1.398 +public: 1.399 + SkAutoSTMalloc() { 1.400 + fPtr = NULL; 1.401 + } 1.402 + 1.403 + SkAutoSTMalloc(size_t count) { 1.404 + if (count > N) { 1.405 + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 1.406 + } else if (count) { 1.407 + fPtr = fTStorage; 1.408 + } else { 1.409 + fPtr = NULL; 1.410 + } 1.411 + } 1.412 + 1.413 + ~SkAutoSTMalloc() { 1.414 + if (fPtr != fTStorage) { 1.415 + sk_free(fPtr); 1.416 + } 1.417 + } 1.418 + 1.419 + // doesn't preserve contents 1.420 + T* reset(size_t count) { 1.421 + if (fPtr != fTStorage) { 1.422 + sk_free(fPtr); 1.423 + } 1.424 + if (count > N) { 1.425 + fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 1.426 + } else if (count) { 1.427 + fPtr = fTStorage; 1.428 + } else { 1.429 + fPtr = NULL; 1.430 + } 1.431 + return fPtr; 1.432 + } 1.433 + 1.434 + T* get() const { return fPtr; } 1.435 + 1.436 + operator T*() { 1.437 + return fPtr; 1.438 + } 1.439 + 1.440 + operator const T*() const { 1.441 + return fPtr; 1.442 + } 1.443 + 1.444 + T& operator[](int index) { 1.445 + return fPtr[index]; 1.446 + } 1.447 + 1.448 + const T& operator[](int index) const { 1.449 + return fPtr[index]; 1.450 + } 1.451 + 1.452 +private: 1.453 + T* fPtr; 1.454 + union { 1.455 + uint32_t fStorage32[(N*sizeof(T) + 3) >> 2]; 1.456 + T fTStorage[1]; // do NOT want to invoke T::T() 1.457 + }; 1.458 +}; 1.459 + 1.460 +/** 1.461 + * Reserves memory that is aligned on double and pointer boundaries. 1.462 + * Hopefully this is sufficient for all practical purposes. 1.463 + */ 1.464 +template <size_t N> class SkAlignedSStorage : SkNoncopyable { 1.465 +public: 1.466 + void* get() { return fData; } 1.467 +private: 1.468 + union { 1.469 + void* fPtr; 1.470 + double fDouble; 1.471 + char fData[N]; 1.472 + }; 1.473 +}; 1.474 + 1.475 +/** 1.476 + * Reserves memory that is aligned on double and pointer boundaries. 1.477 + * Hopefully this is sufficient for all practical purposes. Otherwise, 1.478 + * we have to do some arcane trickery to determine alignment of non-POD 1.479 + * types. Lifetime of the memory is the lifetime of the object. 1.480 + */ 1.481 +template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable { 1.482 +public: 1.483 + /** 1.484 + * Returns void* because this object does not initialize the 1.485 + * memory. Use placement new for types that require a cons. 1.486 + */ 1.487 + void* get() { return fStorage.get(); } 1.488 +private: 1.489 + SkAlignedSStorage<sizeof(T)*N> fStorage; 1.490 +}; 1.491 + 1.492 +#endif