blob: 811b817d2258df0c6216497d6667963419a1a52d [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#ifndef SkTemplates_DEFINED
11#define SkTemplates_DEFINED
12
sugoi23d43202015-01-07 13:28:08 -080013#include "SkMath.h"
bungemana3434d82015-09-07 12:45:52 -070014#include "SkTLogic.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015#include "SkTypes.h"
bungeman@google.com562b2e62014-03-12 21:41:06 +000016#include <limits.h>
mtklein5f939ab2016-03-16 10:28:35 -070017#include <memory>
bungeman@google.com7103f182012-10-31 20:53:49 +000018#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000019
20/** \file SkTemplates.h
21
22 This file contains light-weight template classes for type-safe and exception-safe
23 resource management.
24*/
25
bungeman@google.com91208922012-07-30 15:03:59 +000026/**
bungeman@google.com7de18e52013-02-04 15:58:08 +000027 * 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 */
30template<typename T> inline void sk_ignore_unused_variable(const T&) { }
31
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000032/**
33 * Returns a pointer to a D which comes immediately after S[count].
34 */
35template <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 */
42template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) {
bungeman761cf612015-08-28 07:09:20 -070043 // The intermediate char* has the same cv-ness as D as this produces better error messages.
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000044 // This relies on the fact that reinterpret_cast can add constness, but cannot remove it.
bungeman761cf612015-08-28 07:09:20 -070045 return reinterpret_cast<D*>(reinterpret_cast<sknonstd::same_cv_t<char, D>*>(ptr) + byteOffset);
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000046}
47
bungemana3434d82015-09-07 12:45:52 -070048template <typename R, typename T, R (*P)(T*)> struct SkFunctionWrapper {
49 R operator()(T* t) { return P(t); }
50};
51
reed@android.com8a1c16f2008-12-17 15:59:43 +000052/** \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*/
mtklein1138be42016-01-24 19:49:24 -080060template <typename T, void (*P)(T*)> class SkAutoTCallVProc
mtklein5f939ab2016-03-16 10:28:35 -070061 : public std::unique_ptr<T, SkFunctionWrapper<void, T, P>> {
reed@android.com8a1c16f2008-12-17 15:59:43 +000062public:
mtklein5f939ab2016-03-16 10:28:35 -070063 SkAutoTCallVProc(T* obj): std::unique_ptr<T, SkFunctionWrapper<void, T, P>>(obj) {}
bungemana6785cc2014-08-25 12:00:49 -070064
mtklein1138be42016-01-24 19:49:24 -080065 operator T*() const { return this->get(); }
66 T* detach() { return this->release(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000067};
68
69/** \class SkAutoTCallIProc
70
71Call a function when this goes out of scope. The template uses two
72parameters, the object, and a function that is to be called in the destructor.
73If detach() is called, the object reference is set to null. If the object
74reference is null when the destructor is called, we do not call the
75function.
76*/
mtklein1138be42016-01-24 19:49:24 -080077template <typename T, int (*P)(T*)> class SkAutoTCallIProc
mtklein5f939ab2016-03-16 10:28:35 -070078 : public std::unique_ptr<T, SkFunctionWrapper<int, T, P>> {
reed@android.com8a1c16f2008-12-17 15:59:43 +000079public:
mtklein5f939ab2016-03-16 10:28:35 -070080 SkAutoTCallIProc(T* obj): std::unique_ptr<T, SkFunctionWrapper<int, T, P>>(obj) {}
bungemanc3c69432015-02-11 07:18:51 -080081
mtklein1138be42016-01-24 19:49:24 -080082 operator T*() const { return this->get(); }
83 T* detach() { return this->release(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000084};
85
commit-bot@chromium.orge0294402013-08-29 22:14:04 +000086/** \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*/
mtklein5f939ab2016-03-16 10:28:35 -070096template <typename T> class SkAutoTDelete : public std::unique_ptr<T> {
reed@android.com8a1c16f2008-12-17 15:59:43 +000097public:
mtklein5f939ab2016-03-16 10:28:35 -070098 SkAutoTDelete(T* obj = NULL) : std::unique_ptr<T>(obj) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000099
mtklein1138be42016-01-24 19:49:24 -0800100 operator T*() const { return this->get(); }
101 void free() { this->reset(nullptr); }
102 T* detach() { return this->release(); }
mtklein5f939ab2016-03-16 10:28:35 -0700103
104 // See SkAutoTUnref for why we do this.
105 explicit operator bool() const { return this->get() != nullptr; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106};
107
mtklein5f939ab2016-03-16 10:28:35 -0700108template <typename T> class SkAutoTDeleteArray : public std::unique_ptr<T[]> {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000109public:
mtklein5f939ab2016-03-16 10:28:35 -0700110 SkAutoTDeleteArray(T array[]) : std::unique_ptr<T[]>(array) {}
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000111
bungemana3434d82015-09-07 12:45:52 -0700112 void free() { this->reset(nullptr); }
113 T* detach() { return this->release(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114};
115
116/** Allocate an array of T elements, and free the array in the destructor
117 */
118template <typename T> class SkAutoTArray : SkNoncopyable {
119public:
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000120 SkAutoTArray() {
121 fArray = NULL;
122 SkDEBUGCODE(fCount = 0;)
123 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124 /** Allocate count number of T elements
125 */
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000126 explicit SkAutoTArray(int count) {
127 SkASSERT(count >= 0);
128 fArray = NULL;
129 if (count) {
halcanary385fe4d2015-08-26 13:07:48 -0700130 fArray = new T[count];
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000131 }
132 SkDEBUGCODE(fCount = count;)
133 }
134
135 /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
136 */
137 void reset(int count) {
halcanary385fe4d2015-08-26 13:07:48 -0700138 delete[] fArray;
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000139 SkASSERT(count >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 fArray = NULL;
141 if (count) {
halcanary385fe4d2015-08-26 13:07:48 -0700142 fArray = new T[count];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 }
144 SkDEBUGCODE(fCount = count;)
145 }
146
halcanary385fe4d2015-08-26 13:07:48 -0700147 ~SkAutoTArray() { delete[] fArray; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148
149 /** Return the array of T elements. Will be NULL if count == 0
150 */
151 T* get() const { return fArray; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000152
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 /** Return the nth element in the array
154 */
155 T& operator[](int index) const {
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000156 SkASSERT((unsigned)index < (unsigned)fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 return fArray[index];
158 }
159
mtklein979e0ea2015-02-12 13:20:08 -0800160 void swap(SkAutoTArray& other) {
161 SkTSwap(fArray, other.fArray);
162 SkDEBUGCODE(SkTSwap(fCount, other.fCount));
163 }
164
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165private:
166 T* fArray;
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000167 SkDEBUGCODE(int fCount;)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168};
169
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800170/** Wraps SkAutoTArray, with room for kCountRequested elements preallocated.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 */
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800172template <int kCountRequested, typename T> class SkAutoSTArray : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173public:
bsalomon@google.comd5104142013-06-13 15:13:46 +0000174 /** Initialize with no objects */
175 SkAutoSTArray() {
176 fArray = NULL;
177 fCount = 0;
178 }
179
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 /** Allocate count number of T elements
181 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000182 SkAutoSTArray(int count) {
bsalomon@google.comd5104142013-06-13 15:13:46 +0000183 fArray = NULL;
184 fCount = 0;
185 this->reset(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000187
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 ~SkAutoSTArray() {
bsalomon@google.comd5104142013-06-13 15:13:46 +0000189 this->reset(0);
190 }
191
192 /** Destroys previous objects in the array and default constructs count number of objects */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000193 void reset(int count) {
scroggo@google.com1198e742013-05-29 20:10:25 +0000194 T* start = fArray;
195 T* iter = start + fCount;
196 while (iter > start) {
197 (--iter)->~T();
198 }
bsalomon@google.comd5104142013-06-13 15:13:46 +0000199
200 if (fCount != count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800201 if (fCount > kCount) {
robertphillips@google.com4d376732013-07-12 18:44:23 +0000202 // 'fArray' was allocated last time so free it now
203 SkASSERT((T*) fStorage != fArray);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000204 sk_free(fArray);
205 }
206
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800207 if (count > kCount) {
sugoi23d43202015-01-07 13:28:08 -0800208 const uint64_t size64 = sk_64_mul(count, sizeof(T));
209 const size_t size = static_cast<size_t>(size64);
210 if (size != size64) {
211 sk_out_of_memory();
212 }
213 fArray = (T*) sk_malloc_throw(size);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000214 } else if (count > 0) {
215 fArray = (T*) fStorage;
216 } else {
217 fArray = NULL;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000218 }
219
220 fCount = count;
221 }
222
223 iter = fArray;
224 T* stop = fArray + count;
225 while (iter < stop) {
halcanary385fe4d2015-08-26 13:07:48 -0700226 new (iter++) T;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000227 }
228 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000229
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 /** Return the number of T elements in the array
231 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000232 int count() const { return fCount; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 /** Return the array of T elements. Will be NULL if count == 0
235 */
236 T* get() const { return fArray; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000237
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 /** Return the nth element in the array
239 */
240 T& operator[](int index) const {
robertphillips@google.comadacc702013-10-14 21:53:24 +0000241 SkASSERT(index < fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 return fArray[index];
243 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245private:
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800246#if defined(GOOGLE3)
247 // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions
248 // have multiple large stack allocations.
249 static const int kMaxBytes = 4 * 1024;
250 static const int kCount = kCountRequested * sizeof(T) > kMaxBytes
251 ? kMaxBytes / sizeof(T)
252 : kCountRequested;
253#else
254 static const int kCount = kCountRequested;
255#endif
256
robertphillips@google.comadacc702013-10-14 21:53:24 +0000257 int fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258 T* fArray;
259 // since we come right after fArray, fStorage should be properly aligned
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800260 char fStorage[kCount * sizeof(T)];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261};
262
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000263/** Manages an array of T elements, freeing the array in the destructor.
264 * Does NOT call any constructors/destructors on T (T must be POD).
265 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266template <typename T> class SkAutoTMalloc : SkNoncopyable {
267public:
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000268 /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
269 explicit SkAutoTMalloc(T* ptr = NULL) {
270 fPtr = ptr;
271 }
272
273 /** Allocates space for 'count' Ts. */
274 explicit SkAutoTMalloc(size_t count) {
Mike Klein93fabf42014-06-26 11:04:28 -0400275 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000277
278 ~SkAutoTMalloc() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 sk_free(fPtr);
280 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000281
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000282 /** Resize the memory area pointed to by the current ptr preserving contents. */
283 void realloc(size_t count) {
284 fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T)));
285 }
286
287 /** Resize the memory area pointed to by the current ptr without preserving contents. */
scroggo565901d2015-12-10 10:44:13 -0800288 T* reset(size_t count) {
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000289 sk_free(fPtr);
Mike Klein93fabf42014-06-26 11:04:28 -0400290 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
scroggo565901d2015-12-10 10:44:13 -0800291 return fPtr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000292 }
293
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 T* get() const { return fPtr; }
295
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000296 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
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000312 /**
scroggo565901d2015-12-10 10:44:13 -0800313 * Releases the block back to the heap
314 */
315 void free() {
316 this->reset(0);
317 }
318
319 /**
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000320 * Transfer ownership of the ptr to the caller, setting the internal
321 * pointer to NULL. Note that this differs from get(), which also returns
322 * the pointer, but it does not transfer ownership.
323 */
324 T* detach() {
325 T* ptr = fPtr;
326 fPtr = NULL;
327 return ptr;
328 }
329
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330private:
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000331 T* fPtr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000332};
333
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800334template <size_t kCountRequested, typename T> class SkAutoSTMalloc : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335public:
joshualittf1f88952015-04-08 07:33:33 -0700336 SkAutoSTMalloc() : fPtr(fTStorage) {}
bungeman@google.com71033442013-05-01 14:21:20 +0000337
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000338 SkAutoSTMalloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800339 if (count > kCount) {
bungeman@google.com71033442013-05-01 14:21:20 +0000340 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000341 } else {
joshualittf1f88952015-04-08 07:33:33 -0700342 fPtr = fTStorage;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000343 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000345
346 ~SkAutoSTMalloc() {
347 if (fPtr != fTStorage) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000348 sk_free(fPtr);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000349 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000350 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000351
352 // doesn't preserve contents
reed@google.com4e05fd22013-06-10 18:58:11 +0000353 T* reset(size_t count) {
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000354 if (fPtr != fTStorage) {
355 sk_free(fPtr);
356 }
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800357 if (count > kCount) {
joshualittf1f88952015-04-08 07:33:33 -0700358 fPtr = (T*)sk_malloc_throw(count * sizeof(T));
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000359 } else {
joshualittf1f88952015-04-08 07:33:33 -0700360 fPtr = fTStorage;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000361 }
reed@google.com4e05fd22013-06-10 18:58:11 +0000362 return fPtr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000363 }
364
reed@android.com8a1c16f2008-12-17 15:59:43 +0000365 T* get() const { return fPtr; }
366
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000367 operator T*() {
368 return fPtr;
369 }
370
371 operator const T*() const {
372 return fPtr;
373 }
374
375 T& operator[](int index) {
376 return fPtr[index];
377 }
378
379 const T& operator[](int index) const {
380 return fPtr[index];
381 }
382
joshualittf1f88952015-04-08 07:33:33 -0700383 // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent
384 void realloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800385 if (count > kCount) {
joshualittf1f88952015-04-08 07:33:33 -0700386 if (fPtr == fTStorage) {
387 fPtr = (T*)sk_malloc_throw(count * sizeof(T));
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800388 memcpy(fPtr, fTStorage, kCount * sizeof(T));
joshualittf1f88952015-04-08 07:33:33 -0700389 } else {
390 fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
391 }
392 } else if (fPtr != fTStorage) {
393 fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
394 }
395 }
396
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397private:
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800398 // Since we use uint32_t storage, we might be able to get more elements for free.
399 static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
400#if defined(GOOGLE3)
401 // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions
402 // have multiple large stack allocations.
403 static const size_t kMaxBytes = 4 * 1024;
404 static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
405 ? kMaxBytes / sizeof(T)
406 : kCountWithPadding;
407#else
408 static const size_t kCount = kCountWithPadding;
409#endif
410
reed@android.com8a1c16f2008-12-17 15:59:43 +0000411 T* fPtr;
412 union {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800413 uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000414 T fTStorage[1]; // do NOT want to invoke T::T()
415 };
416};
417
reed64045422015-06-04 06:31:31 -0700418//////////////////////////////////////////////////////////////////////////////////////////////////
419
420/**
421 * Pass the object and the storage that was offered during SkInPlaceNewCheck, and this will
422 * safely destroy (and free if it was dynamically allocated) the object.
423 */
424template <typename T> void SkInPlaceDeleteCheck(T* obj, void* storage) {
425 if (storage == obj) {
426 obj->~T();
427 } else {
halcanary385fe4d2015-08-26 13:07:48 -0700428 delete obj;
reed64045422015-06-04 06:31:31 -0700429 }
430}
431
432/**
433 * Allocates T, using storage if it is large enough, and allocating on the heap (via new) if
434 * storage is not large enough.
435 *
436 * obj = SkInPlaceNewCheck<Type>(storage, size);
437 * ...
438 * SkInPlaceDeleteCheck(obj, storage);
439 */
440template <typename T> T* SkInPlaceNewCheck(void* storage, size_t size) {
halcanary385fe4d2015-08-26 13:07:48 -0700441 return (sizeof(T) <= size) ? new (storage) T : new T;
reed64045422015-06-04 06:31:31 -0700442}
443
444template <typename T, typename A1, typename A2, typename A3>
445T* SkInPlaceNewCheck(void* storage, size_t size, const A1& a1, const A2& a2, const A3& a3) {
halcanary385fe4d2015-08-26 13:07:48 -0700446 return (sizeof(T) <= size) ? new (storage) T(a1, a2, a3) : new T(a1, a2, a3);
reed64045422015-06-04 06:31:31 -0700447}
448
bsalomon@google.com49313f62011-09-14 13:54:05 +0000449/**
450 * Reserves memory that is aligned on double and pointer boundaries.
451 * Hopefully this is sufficient for all practical purposes.
452 */
453template <size_t N> class SkAlignedSStorage : SkNoncopyable {
454public:
reed64045422015-06-04 06:31:31 -0700455 size_t size() const { return N; }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000456 void* get() { return fData; }
joshualitt9b989322014-12-15 14:16:27 -0800457 const void* get() const { return fData; }
reed64045422015-06-04 06:31:31 -0700458
bsalomon@google.com49313f62011-09-14 13:54:05 +0000459private:
460 union {
461 void* fPtr;
462 double fDouble;
463 char fData[N];
464 };
465};
466
467/**
468 * Reserves memory that is aligned on double and pointer boundaries.
469 * Hopefully this is sufficient for all practical purposes. Otherwise,
470 * we have to do some arcane trickery to determine alignment of non-POD
471 * types. Lifetime of the memory is the lifetime of the object.
472 */
473template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
474public:
475 /**
476 * Returns void* because this object does not initialize the
477 * memory. Use placement new for types that require a cons.
478 */
479 void* get() { return fStorage.get(); }
bsalomona387a112015-08-11 14:47:42 -0700480 const void* get() const { return fStorage.get(); }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000481private:
482 SkAlignedSStorage<sizeof(T)*N> fStorage;
483};
484
reed@android.com8a1c16f2008-12-17 15:59:43 +0000485#endif