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