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