blob: 919d160d0db11b8561dce790f9aab511bfd34a64 [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"
Herb Derbyb549cc32017-03-27 13:35:15 -040014#include "SkMalloc.h"
bungemana3434d82015-09-07 12:45:52 -070015#include "SkTLogic.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkTypes.h"
bungeman@google.com562b2e62014-03-12 21:41:06 +000017#include <limits.h>
mtklein5f939ab2016-03-16 10:28:35 -070018#include <memory>
bungeman@google.com7103f182012-10-31 20:53:49 +000019#include <new>
reed@android.com8a1c16f2008-12-17 15:59:43 +000020
21/** \file SkTemplates.h
22
23 This file contains light-weight template classes for type-safe and exception-safe
24 resource management.
25*/
26
bungeman@google.com91208922012-07-30 15:03:59 +000027/**
bungeman@google.com7de18e52013-02-04 15:58:08 +000028 * Marks a local variable as known to be unused (to avoid warnings).
29 * Note that this does *not* prevent the local variable from being optimized away.
30 */
31template<typename T> inline void sk_ignore_unused_variable(const T&) { }
32
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000033/**
34 * Returns a pointer to a D which comes immediately after S[count].
35 */
36template <typename D, typename S> static D* SkTAfter(S* ptr, size_t count = 1) {
37 return reinterpret_cast<D*>(ptr + count);
38}
39
40/**
41 * Returns a pointer to a D which comes byteOffset bytes after S.
42 */
43template <typename D, typename S> static D* SkTAddOffset(S* ptr, size_t byteOffset) {
bungeman761cf612015-08-28 07:09:20 -070044 // 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 +000045 // This relies on the fact that reinterpret_cast can add constness, but cannot remove it.
bungeman761cf612015-08-28 07:09:20 -070046 return reinterpret_cast<D*>(reinterpret_cast<sknonstd::same_cv_t<char, D>*>(ptr) + byteOffset);
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000047}
48
bungemana3434d82015-09-07 12:45:52 -070049template <typename R, typename T, R (*P)(T*)> struct SkFunctionWrapper {
50 R operator()(T* t) { return P(t); }
51};
52
reed@android.com8a1c16f2008-12-17 15:59:43 +000053/** \class SkAutoTCallVProc
54
55 Call a function when this goes out of scope. The template uses two
56 parameters, the object, and a function that is to be called in the destructor.
mtklein18300a32016-03-16 13:53:35 -070057 If release() is called, the object reference is set to null. If the object
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 reference is null when the destructor is called, we do not call the
59 function.
60*/
mtklein1138be42016-01-24 19:49:24 -080061template <typename T, void (*P)(T*)> class SkAutoTCallVProc
mtklein5f939ab2016-03-16 10:28:35 -070062 : public std::unique_ptr<T, SkFunctionWrapper<void, T, P>> {
reed@android.com8a1c16f2008-12-17 15:59:43 +000063public:
mtklein5f939ab2016-03-16 10:28:35 -070064 SkAutoTCallVProc(T* obj): std::unique_ptr<T, SkFunctionWrapper<void, T, P>>(obj) {}
bungemana6785cc2014-08-25 12:00:49 -070065
mtklein1138be42016-01-24 19:49:24 -080066 operator T*() const { return this->get(); }
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.
mtklein18300a32016-03-16 13:53:35 -070073If release() is called, the object reference is set to null. If the object
reed@android.com8a1c16f2008-12-17 15:59:43 +000074reference 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(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000083};
84
reed@android.com8a1c16f2008-12-17 15:59:43 +000085/** Allocate an array of T elements, and free the array in the destructor
86 */
87template <typename T> class SkAutoTArray : SkNoncopyable {
88public:
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000089 SkAutoTArray() {
90 fArray = NULL;
91 SkDEBUGCODE(fCount = 0;)
92 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 /** Allocate count number of T elements
94 */
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000095 explicit SkAutoTArray(int count) {
96 SkASSERT(count >= 0);
97 fArray = NULL;
98 if (count) {
halcanary385fe4d2015-08-26 13:07:48 -070099 fArray = new T[count];
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000100 }
101 SkDEBUGCODE(fCount = count;)
102 }
103
104 /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
105 */
106 void reset(int count) {
halcanary385fe4d2015-08-26 13:07:48 -0700107 delete[] fArray;
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000108 SkASSERT(count >= 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 fArray = NULL;
110 if (count) {
halcanary385fe4d2015-08-26 13:07:48 -0700111 fArray = new T[count];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 }
113 SkDEBUGCODE(fCount = count;)
114 }
115
halcanary385fe4d2015-08-26 13:07:48 -0700116 ~SkAutoTArray() { delete[] fArray; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117
118 /** Return the array of T elements. Will be NULL if count == 0
119 */
120 T* get() const { return fArray; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000121
reed@android.com8a1c16f2008-12-17 15:59:43 +0000122 /** Return the nth element in the array
123 */
124 T& operator[](int index) const {
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000125 SkASSERT((unsigned)index < (unsigned)fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 return fArray[index];
127 }
128
mtklein979e0ea2015-02-12 13:20:08 -0800129 void swap(SkAutoTArray& other) {
130 SkTSwap(fArray, other.fArray);
131 SkDEBUGCODE(SkTSwap(fCount, other.fCount));
132 }
133
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134private:
135 T* fArray;
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000136 SkDEBUGCODE(int fCount;)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137};
138
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800139/** Wraps SkAutoTArray, with room for kCountRequested elements preallocated.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 */
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800141template <int kCountRequested, typename T> class SkAutoSTArray : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142public:
bsalomon@google.comd5104142013-06-13 15:13:46 +0000143 /** Initialize with no objects */
144 SkAutoSTArray() {
145 fArray = NULL;
146 fCount = 0;
147 }
148
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149 /** Allocate count number of T elements
150 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000151 SkAutoSTArray(int count) {
bsalomon@google.comd5104142013-06-13 15:13:46 +0000152 fArray = NULL;
153 fCount = 0;
154 this->reset(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000155 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000156
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 ~SkAutoSTArray() {
bsalomon@google.comd5104142013-06-13 15:13:46 +0000158 this->reset(0);
159 }
160
161 /** Destroys previous objects in the array and default constructs count number of objects */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000162 void reset(int count) {
scroggo@google.com1198e742013-05-29 20:10:25 +0000163 T* start = fArray;
164 T* iter = start + fCount;
165 while (iter > start) {
166 (--iter)->~T();
167 }
bsalomon@google.comd5104142013-06-13 15:13:46 +0000168
csmartdaltond0e402f2016-06-23 12:55:14 -0700169 SkASSERT(count >= 0);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000170 if (fCount != count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800171 if (fCount > kCount) {
robertphillips@google.com4d376732013-07-12 18:44:23 +0000172 // 'fArray' was allocated last time so free it now
173 SkASSERT((T*) fStorage != fArray);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000174 sk_free(fArray);
175 }
176
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800177 if (count > kCount) {
sugoi23d43202015-01-07 13:28:08 -0800178 const uint64_t size64 = sk_64_mul(count, sizeof(T));
179 const size_t size = static_cast<size_t>(size64);
180 if (size != size64) {
181 sk_out_of_memory();
182 }
183 fArray = (T*) sk_malloc_throw(size);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000184 } else if (count > 0) {
185 fArray = (T*) fStorage;
186 } else {
187 fArray = NULL;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000188 }
189
190 fCount = count;
191 }
192
193 iter = fArray;
194 T* stop = fArray + count;
195 while (iter < stop) {
halcanary385fe4d2015-08-26 13:07:48 -0700196 new (iter++) T;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 }
198 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000199
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 /** Return the number of T elements in the array
201 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000202 int count() const { return fCount; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000203
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 /** Return the array of T elements. Will be NULL if count == 0
205 */
206 T* get() const { return fArray; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000207
Brian Salomon92ce5942017-01-18 11:01:10 -0500208 T* begin() { return fArray; }
209
210 const T* begin() const { return fArray; }
211
212 T* end() { return fArray + fCount; }
213
214 const T* end() const { return fArray + fCount; }
215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 /** Return the nth element in the array
217 */
218 T& operator[](int index) const {
robertphillips@google.comadacc702013-10-14 21:53:24 +0000219 SkASSERT(index < fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 return fArray[index];
221 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000222
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223private:
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800224#if defined(GOOGLE3)
225 // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions
226 // have multiple large stack allocations.
227 static const int kMaxBytes = 4 * 1024;
228 static const int kCount = kCountRequested * sizeof(T) > kMaxBytes
229 ? kMaxBytes / sizeof(T)
230 : kCountRequested;
231#else
232 static const int kCount = kCountRequested;
233#endif
234
robertphillips@google.comadacc702013-10-14 21:53:24 +0000235 int fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 T* fArray;
237 // since we come right after fArray, fStorage should be properly aligned
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800238 char fStorage[kCount * sizeof(T)];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000239};
240
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000241/** Manages an array of T elements, freeing the array in the destructor.
242 * Does NOT call any constructors/destructors on T (T must be POD).
243 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244template <typename T> class SkAutoTMalloc : SkNoncopyable {
245public:
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000246 /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
247 explicit SkAutoTMalloc(T* ptr = NULL) {
248 fPtr = ptr;
249 }
250
251 /** Allocates space for 'count' Ts. */
252 explicit SkAutoTMalloc(size_t count) {
csmartdaltond0e402f2016-06-23 12:55:14 -0700253 fPtr = count ? (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW) : nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000255
csmartdalton320ade42017-02-13 11:54:37 -0700256 SkAutoTMalloc(SkAutoTMalloc<T>&& that) : fPtr(that.release()) {}
257
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000258 ~SkAutoTMalloc() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000259 sk_free(fPtr);
260 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000261
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000262 /** Resize the memory area pointed to by the current ptr preserving contents. */
263 void realloc(size_t count) {
csmartdaltond0e402f2016-06-23 12:55:14 -0700264 if (count) {
265 fPtr = reinterpret_cast<T*>(sk_realloc_throw(fPtr, count * sizeof(T)));
266 } else {
267 this->reset(0);
268 }
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000269 }
270
271 /** Resize the memory area pointed to by the current ptr without preserving contents. */
mtklein852f15d2016-03-17 10:51:27 -0700272 T* reset(size_t count = 0) {
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000273 sk_free(fPtr);
mtklein852f15d2016-03-17 10:51:27 -0700274 fPtr = count ? (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW) : nullptr;
scroggo565901d2015-12-10 10:44:13 -0800275 return fPtr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000276 }
277
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278 T* get() const { return fPtr; }
279
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000280 operator T*() {
281 return fPtr;
282 }
283
284 operator const T*() const {
285 return fPtr;
286 }
287
288 T& operator[](int index) {
289 return fPtr[index];
290 }
291
292 const T& operator[](int index) const {
293 return fPtr[index];
294 }
295
csmartdalton320ade42017-02-13 11:54:37 -0700296 SkAutoTMalloc& operator=(SkAutoTMalloc<T>&& that) {
Mike Klein149e42e2017-04-07 14:18:29 -0400297 if (this != &that) {
298 sk_free(fPtr);
299 fPtr = that.release();
300 }
csmartdalton320ade42017-02-13 11:54:37 -0700301 return *this;
302 }
303
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000304 /**
305 * Transfer ownership of the ptr to the caller, setting the internal
306 * pointer to NULL. Note that this differs from get(), which also returns
307 * the pointer, but it does not transfer ownership.
308 */
mtklein18300a32016-03-16 13:53:35 -0700309 T* release() {
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000310 T* ptr = fPtr;
311 fPtr = NULL;
312 return ptr;
313 }
314
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315private:
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000316 T* fPtr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000317};
318
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800319template <size_t kCountRequested, typename T> class SkAutoSTMalloc : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320public:
joshualittf1f88952015-04-08 07:33:33 -0700321 SkAutoSTMalloc() : fPtr(fTStorage) {}
bungeman@google.com71033442013-05-01 14:21:20 +0000322
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000323 SkAutoSTMalloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800324 if (count > kCount) {
bungeman@google.com71033442013-05-01 14:21:20 +0000325 fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
csmartdaltond0e402f2016-06-23 12:55:14 -0700326 } else if (count) {
joshualittf1f88952015-04-08 07:33:33 -0700327 fPtr = fTStorage;
csmartdaltond0e402f2016-06-23 12:55:14 -0700328 } else {
329 fPtr = nullptr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000330 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000332
333 ~SkAutoSTMalloc() {
334 if (fPtr != fTStorage) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 sk_free(fPtr);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000336 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000338
339 // doesn't preserve contents
reed@google.com4e05fd22013-06-10 18:58:11 +0000340 T* reset(size_t count) {
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000341 if (fPtr != fTStorage) {
342 sk_free(fPtr);
343 }
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800344 if (count > kCount) {
joshualittf1f88952015-04-08 07:33:33 -0700345 fPtr = (T*)sk_malloc_throw(count * sizeof(T));
csmartdaltond0e402f2016-06-23 12:55:14 -0700346 } else if (count) {
joshualittf1f88952015-04-08 07:33:33 -0700347 fPtr = fTStorage;
csmartdaltond0e402f2016-06-23 12:55:14 -0700348 } else {
349 fPtr = nullptr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000350 }
reed@google.com4e05fd22013-06-10 18:58:11 +0000351 return fPtr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000352 }
353
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 T* get() const { return fPtr; }
355
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000356 operator T*() {
357 return fPtr;
358 }
359
360 operator const T*() const {
361 return fPtr;
362 }
363
364 T& operator[](int index) {
365 return fPtr[index];
366 }
367
368 const T& operator[](int index) const {
369 return fPtr[index];
370 }
371
joshualittf1f88952015-04-08 07:33:33 -0700372 // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent
373 void realloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800374 if (count > kCount) {
joshualittf1f88952015-04-08 07:33:33 -0700375 if (fPtr == fTStorage) {
376 fPtr = (T*)sk_malloc_throw(count * sizeof(T));
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800377 memcpy(fPtr, fTStorage, kCount * sizeof(T));
joshualittf1f88952015-04-08 07:33:33 -0700378 } else {
379 fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
380 }
csmartdaltond0e402f2016-06-23 12:55:14 -0700381 } else if (count) {
382 if (fPtr != fTStorage) {
383 fPtr = (T*)sk_realloc_throw(fPtr, count * sizeof(T));
384 }
385 } else {
386 this->reset(0);
joshualittf1f88952015-04-08 07:33:33 -0700387 }
388 }
389
reed@android.com8a1c16f2008-12-17 15:59:43 +0000390private:
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800391 // Since we use uint32_t storage, we might be able to get more elements for free.
392 static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
393#if defined(GOOGLE3)
394 // Stack frame size is limited for GOOGLE3. 4k is less than the actual max, but some functions
395 // have multiple large stack allocations.
396 static const size_t kMaxBytes = 4 * 1024;
397 static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
398 ? kMaxBytes / sizeof(T)
399 : kCountWithPadding;
400#else
401 static const size_t kCount = kCountWithPadding;
402#endif
403
reed@android.com8a1c16f2008-12-17 15:59:43 +0000404 T* fPtr;
405 union {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800406 uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000407 T fTStorage[1]; // do NOT want to invoke T::T()
408 };
409};
410
reed64045422015-06-04 06:31:31 -0700411//////////////////////////////////////////////////////////////////////////////////////////////////
412
413/**
414 * Pass the object and the storage that was offered during SkInPlaceNewCheck, and this will
415 * safely destroy (and free if it was dynamically allocated) the object.
416 */
417template <typename T> void SkInPlaceDeleteCheck(T* obj, void* storage) {
418 if (storage == obj) {
419 obj->~T();
420 } else {
halcanary385fe4d2015-08-26 13:07:48 -0700421 delete obj;
reed64045422015-06-04 06:31:31 -0700422 }
423}
424
425/**
426 * Allocates T, using storage if it is large enough, and allocating on the heap (via new) if
427 * storage is not large enough.
428 *
429 * obj = SkInPlaceNewCheck<Type>(storage, size);
430 * ...
431 * SkInPlaceDeleteCheck(obj, storage);
432 */
433template <typename T> T* SkInPlaceNewCheck(void* storage, size_t size) {
halcanary385fe4d2015-08-26 13:07:48 -0700434 return (sizeof(T) <= size) ? new (storage) T : new T;
reed64045422015-06-04 06:31:31 -0700435}
436
437template <typename T, typename A1, typename A2, typename A3>
438T* SkInPlaceNewCheck(void* storage, size_t size, const A1& a1, const A2& a2, const A3& a3) {
halcanary385fe4d2015-08-26 13:07:48 -0700439 return (sizeof(T) <= size) ? new (storage) T(a1, a2, a3) : new T(a1, a2, a3);
reed64045422015-06-04 06:31:31 -0700440}
441
reed6644d932016-06-10 11:41:47 -0700442template <typename T, typename A1, typename A2, typename A3, typename A4>
443T* SkInPlaceNewCheck(void* storage, size_t size,
444 const A1& a1, const A2& a2, const A3& a3, const A4& a4) {
445 return (sizeof(T) <= size) ? new (storage) T(a1, a2, a3, a4) : new T(a1, a2, a3, a4);
446}
447
bsalomon@google.com49313f62011-09-14 13:54:05 +0000448/**
449 * Reserves memory that is aligned on double and pointer boundaries.
450 * Hopefully this is sufficient for all practical purposes.
451 */
452template <size_t N> class SkAlignedSStorage : SkNoncopyable {
453public:
reed64045422015-06-04 06:31:31 -0700454 size_t size() const { return N; }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000455 void* get() { return fData; }
joshualitt9b989322014-12-15 14:16:27 -0800456 const void* get() const { return fData; }
reed64045422015-06-04 06:31:31 -0700457
bsalomon@google.com49313f62011-09-14 13:54:05 +0000458private:
459 union {
460 void* fPtr;
461 double fDouble;
462 char fData[N];
463 };
464};
465
466/**
467 * Reserves memory that is aligned on double and pointer boundaries.
468 * Hopefully this is sufficient for all practical purposes. Otherwise,
469 * we have to do some arcane trickery to determine alignment of non-POD
470 * types. Lifetime of the memory is the lifetime of the object.
471 */
472template <int N, typename T> class SkAlignedSTStorage : SkNoncopyable {
473public:
474 /**
475 * Returns void* because this object does not initialize the
476 * memory. Use placement new for types that require a cons.
477 */
478 void* get() { return fStorage.get(); }
bsalomona387a112015-08-11 14:47:42 -0700479 const void* get() const { return fStorage.get(); }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000480private:
481 SkAlignedSStorage<sizeof(T)*N> fStorage;
482};
483
Hal Canary95e3c052017-01-11 12:44:43 -0500484using SkAutoFree = std::unique_ptr<void, SkFunctionWrapper<void, void, sk_free>>;
485
reed@android.com8a1c16f2008-12-17 15:59:43 +0000486#endif