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 : */
29 : template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable {
30 : public:
31 0 : SkAutoTCallVProc(T* obj): fObj(obj) {}
32 0 : ~SkAutoTCallVProc() { if (fObj) P(fObj); }
33 0 : T* detach() { T* obj = fObj; fObj = NULL; return obj; }
34 : private:
35 : T* fObj;
36 : };
37 :
38 : /** \class SkAutoTCallIProc
39 :
40 : Call a function when this goes out of scope. The template uses two
41 : parameters, the object, and a function that is to be called in the destructor.
42 : If detach() is called, the object reference is set to null. If the object
43 : reference is null when the destructor is called, we do not call the
44 : function.
45 : */
46 : template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable {
47 : public:
48 0 : SkAutoTCallIProc(T* obj): fObj(obj) {}
49 0 : ~SkAutoTCallIProc() { if (fObj) P(fObj); }
50 : T* detach() { T* obj = fObj; fObj = NULL; return obj; }
51 : private:
52 : T* fObj;
53 : };
54 :
55 : // See also SkTScopedPtr.
56 : template <typename T> class SkAutoTDelete : SkNoncopyable {
57 : public:
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 :
67 : private:
68 : T* fObj;
69 : bool fDeleteWhenDone;
70 : };
71 :
72 : template <typename T> class SkAutoTDeleteArray : SkNoncopyable {
73 : public:
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 :
81 : private:
82 : T* fArray;
83 : };
84 :
85 : /** Allocate an array of T elements, and free the array in the destructor
86 : */
87 : template <typename T> class SkAutoTArray : SkNoncopyable {
88 : public:
89 : /** Allocate count number of T elements
90 : */
91 0 : SkAutoTArray(size_t count) {
92 0 : fArray = NULL;
93 0 : if (count) {
94 0 : fArray = new T[count];
95 : }
96 0 : SkDEBUGCODE(fCount = count;)
97 0 : }
98 :
99 0 : ~SkAutoTArray() {
100 0 : delete[] fArray;
101 0 : }
102 :
103 : /** Return the array of T elements. Will be NULL if count == 0
104 : */
105 0 : 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 :
114 : private:
115 : T* fArray;
116 : SkDEBUGCODE(size_t fCount;)
117 : };
118 :
119 : /** Wraps SkAutoTArray, with room for up to N elements preallocated
120 : */
121 : template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable {
122 : public:
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 :
163 : private:
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 : */
173 : template <typename T> class SkAutoTMalloc : SkNoncopyable {
174 : public:
175 0 : SkAutoTMalloc(size_t count) {
176 0 : fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
177 0 : }
178 :
179 0 : ~SkAutoTMalloc() {
180 0 : sk_free(fPtr);
181 0 : }
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 0 : 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 :
207 : private:
208 : T* fPtr;
209 : };
210 :
211 : template <size_t N, typename T> class SK_API SkAutoSTMalloc : SkNoncopyable {
212 : public:
213 0 : SkAutoSTMalloc(size_t count) {
214 0 : if (count <= N) {
215 0 : fPtr = fTStorage;
216 : } else {
217 0 : fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
218 : }
219 0 : }
220 :
221 0 : ~SkAutoSTMalloc() {
222 0 : if (fPtr != fTStorage) {
223 0 : sk_free(fPtr);
224 : }
225 0 : }
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 0 : 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 :
257 : private:
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 : */
269 : template <size_t N> class SkAlignedSStorage : SkNoncopyable {
270 : public:
271 : void* get() { return fData; }
272 : private:
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 : */
286 : template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
287 : public:
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(); }
293 : private:
294 : SkAlignedSStorage<sizeof(T)*N> fStorage;
295 : };
296 :
297 : #endif
298 :
|