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 15/** \file SkTemplates.h 16 17 This file contains light-weight template classes for type-safe and exception-safe 18 resource management. 19*/ 20 21/** \class SkAutoTCallVProc 22 23 Call a function when this goes out of scope. The template uses two 24 parameters, the object, and a function that is to be called in the destructor. 25 If detach() is called, the object reference is set to null. If the object 26 reference is null when the destructor is called, we do not call the 27 function. 28*/ 29template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable { 30public: 31 SkAutoTCallVProc(T* obj): fObj(obj) {} 32 ~SkAutoTCallVProc() { if (fObj) P(fObj); } 33 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 34private: 35 T* fObj; 36}; 37 38/** \class SkAutoTCallIProc 39 40Call a function when this goes out of scope. The template uses two 41parameters, the object, and a function that is to be called in the destructor. 42If detach() is called, the object reference is set to null. If the object 43reference is null when the destructor is called, we do not call the 44function. 45*/ 46template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable { 47public: 48 SkAutoTCallIProc(T* obj): fObj(obj) {} 49 ~SkAutoTCallIProc() { if (fObj) P(fObj); } 50 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 51private: 52 T* fObj; 53}; 54 55// See also SkTScopedPtr. 56template <typename T> class SkAutoTDelete : SkNoncopyable { 57public: 58 SkAutoTDelete(T* obj, bool deleteWhenDone = true) : fObj(obj) { 59 fDeleteWhenDone = deleteWhenDone; 60 } 61 ~SkAutoTDelete() { if (fDeleteWhenDone) delete fObj; } 62 63 T* get() const { return fObj; } 64 void free() { delete fObj; fObj = NULL; } 65 T* detach() { T* obj = fObj; fObj = NULL; return obj; } 66 67private: 68 T* fObj; 69 bool fDeleteWhenDone; 70}; 71 72template <typename T> class SkAutoTDeleteArray : SkNoncopyable { 73public: 74 SkAutoTDeleteArray(T array[]) : fArray(array) {} 75 ~SkAutoTDeleteArray() { delete[] fArray; } 76 77 T* get() const { return fArray; } 78 void free() { delete[] fArray; fArray = NULL; } 79 T* detach() { T* array = fArray; fArray = NULL; return array; } 80 81private: 82 T* fArray; 83}; 84 85/** Allocate an array of T elements, and free the array in the destructor 86 */ 87template <typename T> class SkAutoTArray : SkNoncopyable { 88public: 89 /** Allocate count number of T elements 90 */ 91 SkAutoTArray(size_t count) { 92 fArray = NULL; 93 if (count) { 94 fArray = new T[count]; 95 } 96 SkDEBUGCODE(fCount = count;) 97 } 98 99 ~SkAutoTArray() { 100 delete[] fArray; 101 } 102 103 /** Return the array of T elements. Will be NULL if count == 0 104 */ 105 T* get() const { return fArray; } 106 107 /** Return the nth element in the array 108 */ 109 T& operator[](int index) const { 110 SkASSERT((unsigned)index < fCount); 111 return fArray[index]; 112 } 113 114private: 115 T* fArray; 116 SkDEBUGCODE(size_t fCount;) 117}; 118 119/** Wraps SkAutoTArray, with room for up to N elements preallocated 120 */ 121template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable { 122public: 123 /** Allocate count number of T elements 124 */ 125 SkAutoSTArray(size_t count) { 126 if (count > N) { 127 fArray = new T[count]; 128 } else if (count) { 129 fArray = new (fStorage) T[count]; 130 } else { 131 fArray = NULL; 132 } 133 fCount = count; 134 } 135 136 ~SkAutoSTArray() { 137 if (fCount > N) { 138 delete[] fArray; 139 } else { 140 T* start = fArray; 141 T* iter = start + fCount; 142 while (iter > start) { 143 (--iter)->~T(); 144 } 145 } 146 } 147 148 /** Return the number of T elements in the array 149 */ 150 size_t count() const { return fCount; } 151 152 /** Return the array of T elements. Will be NULL if count == 0 153 */ 154 T* get() const { return fArray; } 155 156 /** Return the nth element in the array 157 */ 158 T& operator[](int index) const { 159 SkASSERT((unsigned)index < fCount); 160 return fArray[index]; 161 } 162 163private: 164 size_t fCount; 165 T* fArray; 166 // since we come right after fArray, fStorage should be properly aligned 167 char fStorage[N * sizeof(T)]; 168}; 169 170/** Allocate a temp array on the stack/heap. 171 Does NOT call any constructors/destructors on T (i.e. T must be POD) 172*/ 173template <typename T> class SkAutoTMalloc : SkNoncopyable { 174public: 175 SkAutoTMalloc(size_t count) { 176 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 177 } 178 179 ~SkAutoTMalloc() { 180 sk_free(fPtr); 181 } 182 183 // doesn't preserve contents 184 void reset (size_t count) { 185 sk_free(fPtr); 186 fPtr = fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 187 } 188 189 T* get() const { return fPtr; } 190 191 operator T*() { 192 return fPtr; 193 } 194 195 operator const T*() const { 196 return fPtr; 197 } 198 199 T& operator[](int index) { 200 return fPtr[index]; 201 } 202 203 const T& operator[](int index) const { 204 return fPtr[index]; 205 } 206 207private: 208 T* fPtr; 209}; 210 211template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable { 212public: 213 SkAutoSTMalloc(size_t count) { 214 if (count <= N) { 215 fPtr = fTStorage; 216 } else { 217 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 218 } 219 } 220 221 ~SkAutoSTMalloc() { 222 if (fPtr != fTStorage) { 223 sk_free(fPtr); 224 } 225 } 226 227 // doesn't preserve contents 228 void reset(size_t count) { 229 if (fPtr != fTStorage) { 230 sk_free(fPtr); 231 } 232 if (count <= N) { 233 fPtr = fTStorage; 234 } else { 235 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP); 236 } 237 } 238 239 T* get() const { return fPtr; } 240 241 operator T*() { 242 return fPtr; 243 } 244 245 operator const T*() const { 246 return fPtr; 247 } 248 249 T& operator[](int index) { 250 return fPtr[index]; 251 } 252 253 const T& operator[](int index) const { 254 return fPtr[index]; 255 } 256 257private: 258 T* fPtr; 259 union { 260 uint32_t fStorage32[(N*sizeof(T) + 3) >> 2]; 261 T fTStorage[1]; // do NOT want to invoke T::T() 262 }; 263}; 264 265/** 266 * Reserves memory that is aligned on double and pointer boundaries. 267 * Hopefully this is sufficient for all practical purposes. 268 */ 269template <size_t N> class SkAlignedSStorage : SkNoncopyable { 270public: 271 void* get() { return fData; } 272private: 273 union { 274 void* fPtr; 275 double fDouble; 276 char fData[N]; 277 }; 278}; 279 280/** 281 * Reserves memory that is aligned on double and pointer boundaries. 282 * Hopefully this is sufficient for all practical purposes. Otherwise, 283 * we have to do some arcane trickery to determine alignment of non-POD 284 * types. Lifetime of the memory is the lifetime of the object. 285 */ 286template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable { 287public: 288 /** 289 * Returns void* because this object does not initialize the 290 * memory. Use placement new for types that require a cons. 291 */ 292 void* get() { return fStorage.get(); } 293private: 294 SkAlignedSStorage<sizeof(T)*N> fStorage; 295}; 296 297#endif 298 299