blob: 526c307558c6a98db262d54ef37bc5548af69f14 [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.
mtklein18300a32016-03-16 13:53:35 -070056 If release() is called, the object reference is set to null. If the object
reed@android.com8a1c16f2008-12-17 15:59:43 +000057 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(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000066};
67
68/** \class SkAutoTCallIProc
69
70Call a function when this goes out of scope. The template uses two
71parameters, the object, and a function that is to be called in the destructor.
mtklein18300a32016-03-16 13:53:35 -070072If release() is called, the object reference is set to null. If the object
reed@android.com8a1c16f2008-12-17 15:59:43 +000073reference is null when the destructor is called, we do not call the
74function.
75*/
mtklein1138be42016-01-24 19:49:24 -080076template <typename T, int (*P)(T*)> class SkAutoTCallIProc
mtklein5f939ab2016-03-16 10:28:35 -070077 : public std::unique_ptr<T, SkFunctionWrapper<int, T, P>> {
reed@android.com8a1c16f2008-12-17 15:59:43 +000078public:
mtklein5f939ab2016-03-16 10:28:35 -070079 SkAutoTCallIProc(T* obj): std::unique_ptr<T, SkFunctionWrapper<int, T, P>>(obj) {}
bungemanc3c69432015-02-11 07:18:51 -080080
mtklein1138be42016-01-24 19:49:24 -080081 operator T*() const { return this->get(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000082};
83
commit-bot@chromium.orge0294402013-08-29 22:14:04 +000084/** \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*/
mtklein5f939ab2016-03-16 10:28:35 -070094template <typename T> class SkAutoTDelete : public std::unique_ptr<T> {
reed@android.com8a1c16f2008-12-17 15:59:43 +000095public:
mtklein5f939ab2016-03-16 10:28:35 -070096 SkAutoTDelete(T* obj = NULL) : std::unique_ptr<T>(obj) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000097
mtklein1138be42016-01-24 19:49:24 -080098 operator T*() const { return this->get(); }
99 void free() { this->reset(nullptr); }
mtklein5f939ab2016-03-16 10:28:35 -0700100
101 // See SkAutoTUnref for why we do this.
102 explicit operator bool() const { return this->get() != nullptr; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103};
104
mtklein5f939ab2016-03-16 10:28:35 -0700105template <typename T> class SkAutoTDeleteArray : public std::unique_ptr<T[]> {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000106public:
mtklein5f939ab2016-03-16 10:28:35 -0700107 SkAutoTDeleteArray(T array[]) : std::unique_ptr<T[]>(array) {}
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000108
bungemana3434d82015-09-07 12:45:52 -0700109 void free() { this->reset(nullptr); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000110};
111
112/** Allocate an array of T elements, and free the array in the destructor
113 */
114template <typename T> class SkAutoTArray : SkNoncopyable {
115public:
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000116 SkAutoTArray() {
117 fArray = NULL;
118 SkDEBUGCODE(fCount = 0;)
119 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120 /** Allocate count number of T elements
121 */
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000122 explicit SkAutoTArray(int count) {
123 SkASSERT(count >= 0);
124 fArray = NULL;
125 if (count) {
halcanary385fe4d2015-08-26 13:07:48 -0700126 fArray = new T[count];
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000127 }
128 SkDEBUGCODE(fCount = count;)
129 }
130
131 /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
132 */
133 void reset(int count) {
halcanary385fe4d2015-08-26 13:07:48 -0700134 delete[] fArray;
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000135 SkASSERT(count >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 fArray = NULL;
137 if (count) {
halcanary385fe4d2015-08-26 13:07:48 -0700138 fArray = new T[count];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139 }
140 SkDEBUGCODE(fCount = count;)
141 }
142
halcanary385fe4d2015-08-26 13:07:48 -0700143 ~SkAutoTArray() { delete[] fArray; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144
145 /** Return the array of T elements. Will be NULL if count == 0
146 */
147 T* get() const { return fArray; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000148
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 /** Return the nth element in the array
150 */
151 T& operator[](int index) const {
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000152 SkASSERT((unsigned)index < (unsigned)fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 return fArray[index];
154 }
155
mtklein979e0ea2015-02-12 13:20:08 -0800156 void swap(SkAutoTArray& other) {
157 SkTSwap(fArray, other.fArray);
158 SkDEBUGCODE(SkTSwap(fCount, other.fCount));
159 }
160
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161private:
162 T* fArray;
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000163 SkDEBUGCODE(int fCount;)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164};
165
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800166/** Wraps SkAutoTArray, with room for kCountRequested elements preallocated.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167 */
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800168template <int kCountRequested, typename T> class SkAutoSTArray : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169public:
bsalomon@google.comd5104142013-06-13 15:13:46 +0000170 /** Initialize with no objects */
171 SkAutoSTArray() {
172 fArray = NULL;
173 fCount = 0;
174 }
175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 /** Allocate count number of T elements
177 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000178 SkAutoSTArray(int count) {
bsalomon@google.comd5104142013-06-13 15:13:46 +0000179 fArray = NULL;
180 fCount = 0;
181 this->reset(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000183
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184 ~SkAutoSTArray() {
bsalomon@google.comd5104142013-06-13 15:13:46 +0000185 this->reset(0);
186 }
187
188 /** Destroys previous objects in the array and default constructs count number of objects */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000189 void reset(int count) {
scroggo@google.com1198e742013-05-29 20:10:25 +0000190 T* start = fArray;
191 T* iter = start + fCount;
192 while (iter > start) {
193 (--iter)->~T();
194 }
bsalomon@google.comd5104142013-06-13 15:13:46 +0000195
196 if (fCount != count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800197 if (fCount > kCount) {
robertphillips@google.com4d376732013-07-12 18:44:23 +0000198 // 'fArray' was allocated last time so free it now
199 SkASSERT((T*) fStorage != fArray);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000200 sk_free(fArray);
201 }
202
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800203 if (count > kCount) {
sugoi23d43202015-01-07 13:28:08 -0800204 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);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000210 } else if (count > 0) {
211 fArray = (T*) fStorage;
212 } else {
213 fArray = NULL;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000214 }
215
216 fCount = count;
217 }
218
219 iter = fArray;
220 T* stop = fArray + count;
221 while (iter < stop) {
halcanary385fe4d2015-08-26 13:07:48 -0700222 new (iter++) T;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 }
224 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000225
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 /** Return the number of T elements in the array
227 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000228 int count() const { return fCount; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000229
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230 /** Return the array of T elements. Will be NULL if count == 0
231 */
232 T* get() const { return fArray; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000233
reed@android.com8a1c16f2008-12-17 15:59:43 +0000234 /** Return the nth element in the array
235 */
236 T& operator[](int index) const {
robertphillips@google.comadacc702013-10-14 21:53:24 +0000237 SkASSERT(index < fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 return fArray[index];
239 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000240
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241private:
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800242#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
robertphillips@google.comadacc702013-10-14 21:53:24 +0000253 int fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 T* fArray;
255 // since we come right after fArray, fStorage should be properly aligned
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800256 char fStorage[kCount * sizeof(T)];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257};
258
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000259/** 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 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262template <typename T> class SkAutoTMalloc : SkNoncopyable {
263public:
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000264 /** 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. */
270 explicit SkAutoTMalloc(size_t count) {
Mike Klein93fabf42014-06-26 11:04:28 -0400271 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000273
274 ~SkAutoTMalloc() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 sk_free(fPtr);
276 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000277
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000278 /** Resize the memory area pointed to by the current ptr preserving contents. */
279 void realloc(size_t count) {
280 fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T)));
281 }
282
283 /** Resize the memory area pointed to by the current ptr without preserving contents. */
scroggo565901d2015-12-10 10:44:13 -0800284 T* reset(size_t count) {
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000285 sk_free(fPtr);
Mike Klein93fabf42014-06-26 11:04:28 -0400286 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW);
scroggo565901d2015-12-10 10:44:13 -0800287 return fPtr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000288 }
289
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 T* get() const { return fPtr; }
291
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000292 operator T*() {
293 return fPtr;
294 }
295
296 operator const T*() const {
297 return fPtr;
298 }
299
300 T& operator[](int index) {
301 return fPtr[index];
302 }
303
304 const T& operator[](int index) const {
305 return fPtr[index];
306 }
307
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000308 /**
scroggo565901d2015-12-10 10:44:13 -0800309 * Releases the block back to the heap
310 */
311 void free() {
312 this->reset(0);
313 }
314
315 /**
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000316 * Transfer ownership of the ptr to the caller, setting the internal
317 * pointer to NULL. Note that this differs from get(), which also returns
318 * the pointer, but it does not transfer ownership.
319 */
mtklein18300a32016-03-16 13:53:35 -0700320 T* release() {
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000321 T* ptr = fPtr;
322 fPtr = NULL;
323 return ptr;
324 }
325
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326private:
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000327 T* fPtr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328};
329
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800330template <size_t kCountRequested, typename T> class SkAutoSTMalloc : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331public:
joshualittf1f88952015-04-08 07:33:33 -0700332 SkAutoSTMalloc() : fPtr(fTStorage) {}
bungeman@google.com71033442013-05-01 14:21:20 +0000333
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000334 SkAutoSTMalloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800335 if (count > kCount) {
bungeman@google.com71033442013-05-01 14:21:20 +0000336 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000337 } else {
joshualittf1f88952015-04-08 07:33:33 -0700338 fPtr = fTStorage;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000339 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000341
342 ~SkAutoSTMalloc() {
343 if (fPtr != fTStorage) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 sk_free(fPtr);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000345 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000346 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000347
348 // doesn't preserve contents
reed@google.com4e05fd22013-06-10 18:58:11 +0000349 T* reset(size_t count) {
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000350 if (fPtr != fTStorage) {
351 sk_free(fPtr);
352 }
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800353 if (count > kCount) {
joshualittf1f88952015-04-08 07:33:33 -0700354 fPtr = (T*)sk_malloc_throw(count * sizeof(T));
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000355 } else {
joshualittf1f88952015-04-08 07:33:33 -0700356 fPtr = fTStorage;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000357 }
reed@google.com4e05fd22013-06-10 18:58:11 +0000358 return fPtr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000359 }
360
reed@android.com8a1c16f2008-12-17 15:59:43 +0000361 T* get() const { return fPtr; }
362
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000363 operator T*() {
364 return fPtr;
365 }
366
367 operator const T*() const {
368 return fPtr;
369 }
370
371 T& operator[](int index) {
372 return fPtr[index];
373 }
374
375 const T& operator[](int index) const {
376 return fPtr[index];
377 }
378
joshualittf1f88952015-04-08 07:33:33 -0700379 // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent
380 void realloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800381 if (count > kCount) {
joshualittf1f88952015-04-08 07:33:33 -0700382 if (fPtr == fTStorage) {
383 fPtr = (T*)sk_malloc_throw(count * sizeof(T));
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800384 memcpy(fPtr, fTStorage, kCount * sizeof(T));
joshualittf1f88952015-04-08 07:33:33 -0700385 } else {
386 fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
387 }
388 } else if (fPtr != fTStorage) {
389 fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
390 }
391 }
392
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393private:
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800394 // Since we use uint32_t storage, we might be able to get more elements for free.
395 static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
396#if defined(GOOGLE3)
397 // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions
398 // have multiple large stack allocations.
399 static const size_t kMaxBytes = 4 * 1024;
400 static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
401 ? kMaxBytes / sizeof(T)
402 : kCountWithPadding;
403#else
404 static const size_t kCount = kCountWithPadding;
405#endif
406
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407 T* fPtr;
408 union {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800409 uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000410 T fTStorage[1]; // do NOT want to invoke T::T()
411 };
412};
413
reed64045422015-06-04 06:31:31 -0700414//////////////////////////////////////////////////////////////////////////////////////////////////
415
416/**
417 * Pass the object and the storage that was offered during SkInPlaceNewCheck, and this will
418 * safely destroy (and free if it was dynamically allocated) the object.
419 */
420template <typename T> void SkInPlaceDeleteCheck(T* obj, void* storage) {
421 if (storage == obj) {
422 obj->~T();
423 } else {
halcanary385fe4d2015-08-26 13:07:48 -0700424 delete obj;
reed64045422015-06-04 06:31:31 -0700425 }
426}
427
428/**
429 * Allocates T, using storage if it is large enough, and allocating on the heap (via new) if
430 * storage is not large enough.
431 *
432 * obj = SkInPlaceNewCheck<Type>(storage, size);
433 * ...
434 * SkInPlaceDeleteCheck(obj, storage);
435 */
436template <typename T> T* SkInPlaceNewCheck(void* storage, size_t size) {
halcanary385fe4d2015-08-26 13:07:48 -0700437 return (sizeof(T) <= size) ? new (storage) T : new T;
reed64045422015-06-04 06:31:31 -0700438}
439
440template <typename T, typename A1, typename A2, typename A3>
441T* SkInPlaceNewCheck(void* storage, size_t size, const A1& a1, const A2& a2, const A3& a3) {
halcanary385fe4d2015-08-26 13:07:48 -0700442 return (sizeof(T) <= size) ? new (storage) T(a1, a2, a3) : new T(a1, a2, a3);
reed64045422015-06-04 06:31:31 -0700443}
444
bsalomon@google.com49313f62011-09-14 13:54:05 +0000445/**
446 * Reserves memory that is aligned on double and pointer boundaries.
447 * Hopefully this is sufficient for all practical purposes.
448 */
449template <size_t N> class SkAlignedSStorage : SkNoncopyable {
450public:
reed64045422015-06-04 06:31:31 -0700451 size_t size() const { return N; }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000452 void* get() { return fData; }
joshualitt9b989322014-12-15 14:16:27 -0800453 const void* get() const { return fData; }
reed64045422015-06-04 06:31:31 -0700454
bsalomon@google.com49313f62011-09-14 13:54:05 +0000455private:
456 union {
457 void* fPtr;
458 double fDouble;
459 char fData[N];
460 };
461};
462
463/**
464 * Reserves memory that is aligned on double and pointer boundaries.
465 * Hopefully this is sufficient for all practical purposes. Otherwise,
466 * we have to do some arcane trickery to determine alignment of non-POD
467 * types. Lifetime of the memory is the lifetime of the object.
468 */
469template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
470public:
471 /**
472 * Returns void* because this object does not initialize the
473 * memory. Use placement new for types that require a cons.
474 */
475 void* get() { return fStorage.get(); }
bsalomona387a112015-08-11 14:47:42 -0700476 const void* get() const { return fStorage.get(); }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000477private:
478 SkAlignedSStorage<sizeof(T)*N> fStorage;
479};
480
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481#endif