SkTemplates.h revision d42aca31b9ddc1cb9a81522b4c73a9fe550450bc
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 */
26template<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 */
32template <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. */
41template <typename T, bool CONST> struct SkTConstType {
42    typedef T type;
43};
44template <typename T> struct SkTConstType<T, true> {
45    typedef const T type;
46};
47///@}
48
49/** \class SkAutoTCallVProc
50
51    Call a function when this goes out of scope. The template uses two
52    parameters, the object, and a function that is to be called in the destructor.
53    If detach() is called, the object reference is set to null. If the object
54    reference is null when the destructor is called, we do not call the
55    function.
56*/
57template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable {
58public:
59    SkAutoTCallVProc(T* obj): fObj(obj) {}
60    ~SkAutoTCallVProc() { if (fObj) P(fObj); }
61    T* detach() { T* obj = fObj; fObj = NULL; return obj; }
62private:
63    T* fObj;
64};
65
66/** \class SkAutoTCallIProc
67
68Call a function when this goes out of scope. The template uses two
69parameters, the object, and a function that is to be called in the destructor.
70If detach() is called, the object reference is set to null. If the object
71reference is null when the destructor is called, we do not call the
72function.
73*/
74template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable {
75public:
76    SkAutoTCallIProc(T* obj): fObj(obj) {}
77    ~SkAutoTCallIProc() { if (fObj) P(fObj); }
78    T* detach() { T* obj = fObj; fObj = NULL; return obj; }
79private:
80    T* fObj;
81};
82
83template <typename T> class SkAutoTDelete : SkNoncopyable {
84public:
85    SkAutoTDelete(T* obj = NULL) : fObj(obj) {}
86    ~SkAutoTDelete() { delete fObj; }
87
88    T* get() const { return fObj; }
89    T& operator*() const { SkASSERT(fObj); return *fObj; }
90    T* operator->() const { SkASSERT(fObj); return fObj; }
91
92    void reset(T* obj) {
93        if (fObj != obj) {
94            delete fObj;
95            fObj = obj;
96        }
97    }
98
99    /**
100     *  Delete the owned object, setting the internal pointer to NULL.
101     */
102    void free() {
103        delete fObj;
104        fObj = NULL;
105    }
106
107    /**
108     *  Transfer ownership of the object to the caller, setting the internal
109     *  pointer to NULL. Note that this differs from get(), which also returns
110     *  the pointer, but it does not transfer ownership.
111     */
112    T* detach() {
113        T* obj = fObj;
114        fObj = NULL;
115        return obj;
116    }
117
118private:
119    T*  fObj;
120};
121
122// Calls ~T() in the destructor.
123template <typename T> class SkAutoTDestroy : SkNoncopyable {
124public:
125    SkAutoTDestroy(T* obj = NULL) : fObj(obj) {}
126    ~SkAutoTDestroy() {
127        if (NULL != fObj) {
128            fObj->~T();
129        }
130    }
131
132    T* get() const { return fObj; }
133    T& operator*() const { SkASSERT(fObj); return *fObj; }
134    T* operator->() const { SkASSERT(fObj); return fObj; }
135
136private:
137    T*  fObj;
138};
139
140template <typename T> class SkAutoTDeleteArray : SkNoncopyable {
141public:
142    SkAutoTDeleteArray(T array[]) : fArray(array) {}
143    ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); }
144
145    T*      get() const { return fArray; }
146    void    free() { SkDELETE_ARRAY(fArray); fArray = NULL; }
147    T*      detach() { T* array = fArray; fArray = NULL; return array; }
148
149private:
150    T*  fArray;
151};
152
153/** Allocate an array of T elements, and free the array in the destructor
154 */
155template <typename T> class SkAutoTArray : SkNoncopyable {
156public:
157    SkAutoTArray() {
158        fArray = NULL;
159        SkDEBUGCODE(fCount = 0;)
160    }
161    /** Allocate count number of T elements
162     */
163    explicit SkAutoTArray(int count) {
164        SkASSERT(count >= 0);
165        fArray = NULL;
166        if (count) {
167            fArray = new T[count];
168        }
169        SkDEBUGCODE(fCount = count;)
170    }
171
172    /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
173     */
174    void reset(int count) {
175        delete[] fArray;
176        SkASSERT(count >= 0);
177        fArray = NULL;
178        if (count) {
179            fArray = new T[count];
180        }
181        SkDEBUGCODE(fCount = count;)
182    }
183
184    ~SkAutoTArray() {
185        delete[] fArray;
186    }
187
188    /** Return the array of T elements. Will be NULL if count == 0
189     */
190    T* get() const { return fArray; }
191
192    /** Return the nth element in the array
193     */
194    T&  operator[](int index) const {
195        SkASSERT((unsigned)index < (unsigned)fCount);
196        return fArray[index];
197    }
198
199private:
200    T*  fArray;
201    SkDEBUGCODE(int fCount;)
202};
203
204/** Wraps SkAutoTArray, with room for up to N elements preallocated
205 */
206template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable {
207public:
208    /** Allocate count number of T elements
209     */
210    SkAutoSTArray(size_t count) {
211        if (count > N) {
212            fArray = new T[count];
213        } else if (count) {
214            fArray = new (fStorage) T[count];
215        } else {
216            fArray = NULL;
217        }
218        fCount = count;
219    }
220
221    ~SkAutoSTArray() {
222        if (fCount > N) {
223            delete[] fArray;
224        } else {
225            T* start = fArray;
226            T* iter = start + fCount;
227            while (iter > start) {
228                (--iter)->~T();
229            }
230        }
231    }
232
233    /** Return the number of T elements in the array
234     */
235    size_t count() const { return fCount; }
236
237    /** Return the array of T elements. Will be NULL if count == 0
238     */
239    T* get() const { return fArray; }
240
241    /** Return the nth element in the array
242     */
243    T&  operator[](int index) const {
244        SkASSERT((unsigned)index < fCount);
245        return fArray[index];
246    }
247
248private:
249    size_t  fCount;
250    T*      fArray;
251    // since we come right after fArray, fStorage should be properly aligned
252    char    fStorage[N * sizeof(T)];
253};
254
255/** Allocate a temp array on the stack/heap.
256    Does NOT call any constructors/destructors on T (i.e. T must be POD)
257*/
258template <typename T> class SkAutoTMalloc : SkNoncopyable {
259public:
260    SkAutoTMalloc(size_t count) {
261        fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
262    }
263
264    ~SkAutoTMalloc() {
265        sk_free(fPtr);
266    }
267
268    // doesn't preserve contents
269    void reset (size_t count) {
270        sk_free(fPtr);
271        fPtr = fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
272    }
273
274    T* get() const { return fPtr; }
275
276    operator T*() {
277        return fPtr;
278    }
279
280    operator const T*() const {
281        return fPtr;
282    }
283
284    T& operator[](int index) {
285        return fPtr[index];
286    }
287
288    const T& operator[](int index) const {
289        return fPtr[index];
290    }
291
292private:
293    T*  fPtr;
294};
295
296template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable {
297public:
298    SkAutoSTMalloc(size_t count) {
299        if (count <= N) {
300            fPtr = fTStorage;
301        } else {
302            fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
303        }
304    }
305
306    ~SkAutoSTMalloc() {
307        if (fPtr != fTStorage) {
308            sk_free(fPtr);
309        }
310    }
311
312    // doesn't preserve contents
313    void reset(size_t count) {
314        if (fPtr != fTStorage) {
315            sk_free(fPtr);
316        }
317        if (count <= N) {
318            fPtr = fTStorage;
319        } else {
320            fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
321        }
322    }
323
324    T* get() const { return fPtr; }
325
326    operator T*() {
327        return fPtr;
328    }
329
330    operator const T*() const {
331        return fPtr;
332    }
333
334    T& operator[](int index) {
335        return fPtr[index];
336    }
337
338    const T& operator[](int index) const {
339        return fPtr[index];
340    }
341
342private:
343    T*          fPtr;
344    union {
345        uint32_t    fStorage32[(N*sizeof(T) + 3) >> 2];
346        T           fTStorage[1];   // do NOT want to invoke T::T()
347    };
348};
349
350/**
351 * Reserves memory that is aligned on double and pointer boundaries.
352 * Hopefully this is sufficient for all practical purposes.
353 */
354template <size_t N> class SkAlignedSStorage : SkNoncopyable {
355public:
356    void* get() { return fData; }
357private:
358    union {
359        void*   fPtr;
360        double  fDouble;
361        char    fData[N];
362    };
363};
364
365/**
366 * Reserves memory that is aligned on double and pointer boundaries.
367 * Hopefully this is sufficient for all practical purposes. Otherwise,
368 * we have to do some arcane trickery to determine alignment of non-POD
369 * types. Lifetime of the memory is the lifetime of the object.
370 */
371template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
372public:
373    /**
374     * Returns void* because this object does not initialize the
375     * memory. Use placement new for types that require a cons.
376     */
377    void* get() { return fStorage.get(); }
378private:
379    SkAlignedSStorage<sizeof(T)*N> fStorage;
380};
381
382#endif
383