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