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