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