gfx/skia/trunk/include/core/SkTemplates.h

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

mercurial