blob: 567753a9ec1a0649966860ea66b2c1c53814585c [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
reed@android.com8a1c16f2008-12-17 15:59:43 +000069/** Allocate an array of T elements, and free the array in the destructor
70 */
Hal Canary67362362018-04-24 13:58:37 -040071template <typename T> class SkAutoTArray {
reed@android.com8a1c16f2008-12-17 15:59:43 +000072public:
Hal Canary67362362018-04-24 13:58:37 -040073 SkAutoTArray() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000074 /** Allocate count number of T elements
75 */
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000076 explicit SkAutoTArray(int count) {
77 SkASSERT(count >= 0);
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000078 if (count) {
Hal Canary67362362018-04-24 13:58:37 -040079 fArray.reset(new T[count]);
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000080 }
81 SkDEBUGCODE(fCount = count;)
82 }
83
Hal Canary67362362018-04-24 13:58:37 -040084 SkAutoTArray(SkAutoTArray&& other) : fArray(std::move(other.fArray)) {
85 SkDEBUGCODE(fCount = other.fCount; other.fCount = 0;)
86 }
87 SkAutoTArray& operator=(SkAutoTArray&& other) {
88 if (this != &other) {
89 fArray = std::move(other.fArray);
90 SkDEBUGCODE(fCount = other.fCount; other.fCount = 0;)
91 }
92 return *this;
93 }
94
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000095 /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
96 */
Hal Canary67362362018-04-24 13:58:37 -040097 void reset(int count) { *this = SkAutoTArray(count); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000098
99 /** Return the array of T elements. Will be NULL if count == 0
100 */
Hal Canary67362362018-04-24 13:58:37 -0400101 T* get() const { return fArray.get(); }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000102
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 /** Return the nth element in the array
104 */
105 T& operator[](int index) const {
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000106 SkASSERT((unsigned)index < (unsigned)fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 return fArray[index];
108 }
109
110private:
Hal Canary67362362018-04-24 13:58:37 -0400111 std::unique_ptr<T[]> fArray;
112 SkDEBUGCODE(int fCount = 0;)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113};
114
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800115/** Wraps SkAutoTArray, with room for kCountRequested elements preallocated.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116 */
Hal Canary0acb79e2018-06-14 15:12:42 -0400117template <int kCountRequested, typename T> class SkAutoSTArray {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118public:
Hal Canary0acb79e2018-06-14 15:12:42 -0400119 SkAutoSTArray(SkAutoSTArray&&) = delete;
120 SkAutoSTArray(const SkAutoSTArray&) = delete;
121 SkAutoSTArray& operator=(SkAutoSTArray&&) = delete;
122 SkAutoSTArray& operator=(const SkAutoSTArray&) = delete;
123
bsalomon@google.comd5104142013-06-13 15:13:46 +0000124 /** Initialize with no objects */
125 SkAutoSTArray() {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400126 fArray = nullptr;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000127 fCount = 0;
128 }
129
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 /** Allocate count number of T elements
131 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000132 SkAutoSTArray(int count) {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400133 fArray = nullptr;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000134 fCount = 0;
135 this->reset(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000137
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 ~SkAutoSTArray() {
bsalomon@google.comd5104142013-06-13 15:13:46 +0000139 this->reset(0);
140 }
141
142 /** Destroys previous objects in the array and default constructs count number of objects */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000143 void reset(int count) {
scroggo@google.com1198e742013-05-29 20:10:25 +0000144 T* start = fArray;
145 T* iter = start + fCount;
146 while (iter > start) {
147 (--iter)->~T();
148 }
bsalomon@google.comd5104142013-06-13 15:13:46 +0000149
csmartdaltond0e402f2016-06-23 12:55:14 -0700150 SkASSERT(count >= 0);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000151 if (fCount != count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800152 if (fCount > kCount) {
robertphillips@google.com4d376732013-07-12 18:44:23 +0000153 // 'fArray' was allocated last time so free it now
154 SkASSERT((T*) fStorage != fArray);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000155 sk_free(fArray);
156 }
157
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800158 if (count > kCount) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500159 fArray = (T*) sk_malloc_throw(count, sizeof(T));
bsalomon@google.comd5104142013-06-13 15:13:46 +0000160 } else if (count > 0) {
161 fArray = (T*) fStorage;
162 } else {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400163 fArray = nullptr;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000164 }
165
166 fCount = count;
167 }
168
169 iter = fArray;
170 T* stop = fArray + count;
171 while (iter < stop) {
halcanary385fe4d2015-08-26 13:07:48 -0700172 new (iter++) T;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000173 }
174 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 /** Return the number of T elements in the array
177 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000178 int count() const { return fCount; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000179
reed@android.com8a1c16f2008-12-17 15:59:43 +0000180 /** Return the array of T elements. Will be NULL if count == 0
181 */
182 T* get() const { return fArray; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000183
Brian Salomon92ce5942017-01-18 11:01:10 -0500184 T* begin() { return fArray; }
185
186 const T* begin() const { return fArray; }
187
188 T* end() { return fArray + fCount; }
189
190 const T* end() const { return fArray + fCount; }
191
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 /** Return the nth element in the array
193 */
194 T& operator[](int index) const {
robertphillips@google.comadacc702013-10-14 21:53:24 +0000195 SkASSERT(index < fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 return fArray[index];
197 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000198
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199private:
Mike Klein6613cc52017-12-19 09:09:33 -0500200#if defined(SK_BUILD_FOR_GOOGLE3)
201 // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800202 // have multiple large stack allocations.
203 static const int kMaxBytes = 4 * 1024;
204 static const int kCount = kCountRequested * sizeof(T) > kMaxBytes
205 ? kMaxBytes / sizeof(T)
206 : kCountRequested;
207#else
208 static const int kCount = kCountRequested;
209#endif
210
robertphillips@google.comadacc702013-10-14 21:53:24 +0000211 int fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 T* fArray;
213 // since we come right after fArray, fStorage should be properly aligned
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800214 char fStorage[kCount * sizeof(T)];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215};
216
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000217/** Manages an array of T elements, freeing the array in the destructor.
218 * Does NOT call any constructors/destructors on T (T must be POD).
219 */
Hal Canary67362362018-04-24 13:58:37 -0400220template <typename T> class SkAutoTMalloc {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221public:
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000222 /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
Hal Canary67362362018-04-24 13:58:37 -0400223 explicit SkAutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {}
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000224
225 /** Allocates space for 'count' Ts. */
Hal Canary67362362018-04-24 13:58:37 -0400226 explicit SkAutoTMalloc(size_t count)
227 : fPtr(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr) {}
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000228
Hal Canary67362362018-04-24 13:58:37 -0400229 SkAutoTMalloc(SkAutoTMalloc&&) = default;
230 SkAutoTMalloc& operator=(SkAutoTMalloc&&) = default;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000231
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000232 /** Resize the memory area pointed to by the current ptr preserving contents. */
233 void realloc(size_t count) {
Hal Canary67362362018-04-24 13:58:37 -0400234 fPtr.reset(count ? (T*)sk_realloc_throw(fPtr.release(), count * sizeof(T)) : nullptr);
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000235 }
236
237 /** Resize the memory area pointed to by the current ptr without preserving contents. */
mtklein852f15d2016-03-17 10:51:27 -0700238 T* reset(size_t count = 0) {
Hal Canary67362362018-04-24 13:58:37 -0400239 fPtr.reset(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr);
240 return this->get();
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000241 }
242
Hal Canary67362362018-04-24 13:58:37 -0400243 T* get() const { return fPtr.get(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000244
Hal Canary67362362018-04-24 13:58:37 -0400245 operator T*() { return fPtr.get(); }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000246
Hal Canary67362362018-04-24 13:58:37 -0400247 operator const T*() const { return fPtr.get(); }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000248
Hal Canary67362362018-04-24 13:58:37 -0400249 T& operator[](int index) { return fPtr.get()[index]; }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000250
Hal Canary67362362018-04-24 13:58:37 -0400251 const T& operator[](int index) const { return fPtr.get()[index]; }
csmartdalton320ade42017-02-13 11:54:37 -0700252
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000253 /**
254 * Transfer ownership of the ptr to the caller, setting the internal
255 * pointer to NULL. Note that this differs from get(), which also returns
256 * the pointer, but it does not transfer ownership.
257 */
Hal Canary67362362018-04-24 13:58:37 -0400258 T* release() { return fPtr.release(); }
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000259
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260private:
Hal Canary67362362018-04-24 13:58:37 -0400261 std::unique_ptr<T, SkFunctionWrapper<void, void, sk_free>> fPtr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262};
263
Hal Canary0acb79e2018-06-14 15:12:42 -0400264template <size_t kCountRequested, typename T> class SkAutoSTMalloc {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265public:
joshualittf1f88952015-04-08 07:33:33 -0700266 SkAutoSTMalloc() : fPtr(fTStorage) {}
bungeman@google.com71033442013-05-01 14:21:20 +0000267
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000268 SkAutoSTMalloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800269 if (count > kCount) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500270 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
csmartdaltond0e402f2016-06-23 12:55:14 -0700271 } else if (count) {
joshualittf1f88952015-04-08 07:33:33 -0700272 fPtr = fTStorage;
csmartdaltond0e402f2016-06-23 12:55:14 -0700273 } else {
274 fPtr = nullptr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000275 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000277
Hal Canary0acb79e2018-06-14 15:12:42 -0400278 SkAutoSTMalloc(SkAutoSTMalloc&&) = delete;
279 SkAutoSTMalloc(const SkAutoSTMalloc&) = delete;
280 SkAutoSTMalloc& operator=(SkAutoSTMalloc&&) = delete;
281 SkAutoSTMalloc& operator=(const SkAutoSTMalloc&) = delete;
282
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000283 ~SkAutoSTMalloc() {
284 if (fPtr != fTStorage) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 sk_free(fPtr);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000286 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000288
289 // doesn't preserve contents
reed@google.com4e05fd22013-06-10 18:58:11 +0000290 T* reset(size_t count) {
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000291 if (fPtr != fTStorage) {
292 sk_free(fPtr);
293 }
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800294 if (count > kCount) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500295 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
csmartdaltond0e402f2016-06-23 12:55:14 -0700296 } else if (count) {
joshualittf1f88952015-04-08 07:33:33 -0700297 fPtr = fTStorage;
csmartdaltond0e402f2016-06-23 12:55:14 -0700298 } else {
299 fPtr = nullptr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000300 }
reed@google.com4e05fd22013-06-10 18:58:11 +0000301 return fPtr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000302 }
303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 T* get() const { return fPtr; }
305
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000306 operator T*() {
307 return fPtr;
308 }
309
310 operator const T*() const {
311 return fPtr;
312 }
313
314 T& operator[](int index) {
315 return fPtr[index];
316 }
317
318 const T& operator[](int index) const {
319 return fPtr[index];
320 }
321
joshualittf1f88952015-04-08 07:33:33 -0700322 // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent
323 void realloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800324 if (count > kCount) {
joshualittf1f88952015-04-08 07:33:33 -0700325 if (fPtr == fTStorage) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500326 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800327 memcpy(fPtr, fTStorage, kCount * sizeof(T));
joshualittf1f88952015-04-08 07:33:33 -0700328 } else {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500329 fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
joshualittf1f88952015-04-08 07:33:33 -0700330 }
csmartdaltond0e402f2016-06-23 12:55:14 -0700331 } else if (count) {
332 if (fPtr != fTStorage) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500333 fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
csmartdaltond0e402f2016-06-23 12:55:14 -0700334 }
335 } else {
336 this->reset(0);
joshualittf1f88952015-04-08 07:33:33 -0700337 }
338 }
339
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340private:
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800341 // Since we use uint32_t storage, we might be able to get more elements for free.
342 static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
Mike Klein6613cc52017-12-19 09:09:33 -0500343#if defined(SK_BUILD_FOR_GOOGLE3)
344 // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800345 // have multiple large stack allocations.
346 static const size_t kMaxBytes = 4 * 1024;
347 static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
348 ? kMaxBytes / sizeof(T)
349 : kCountWithPadding;
350#else
351 static const size_t kCount = kCountWithPadding;
352#endif
353
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 T* fPtr;
355 union {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800356 uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000357 T fTStorage[1]; // do NOT want to invoke T::T()
358 };
359};
360
reed64045422015-06-04 06:31:31 -0700361//////////////////////////////////////////////////////////////////////////////////////////////////
362
363/**
364 * Pass the object and the storage that was offered during SkInPlaceNewCheck, and this will
365 * safely destroy (and free if it was dynamically allocated) the object.
366 */
367template <typename T> void SkInPlaceDeleteCheck(T* obj, void* storage) {
368 if (storage == obj) {
369 obj->~T();
370 } else {
halcanary385fe4d2015-08-26 13:07:48 -0700371 delete obj;
reed64045422015-06-04 06:31:31 -0700372 }
373}
374
375/**
376 * Allocates T, using storage if it is large enough, and allocating on the heap (via new) if
377 * storage is not large enough.
378 *
379 * obj = SkInPlaceNewCheck<Type>(storage, size);
380 * ...
381 * SkInPlaceDeleteCheck(obj, storage);
382 */
Hal Canary47728252018-04-24 14:57:09 -0400383template<typename T, typename... Args>
384T* SkInPlaceNewCheck(void* storage, size_t size, Args&&... args) {
385 return (sizeof(T) <= size) ? new (storage) T(std::forward<Args>(args)...)
386 : new T(std::forward<Args>(args)...);
reed64045422015-06-04 06:31:31 -0700387}
bsalomon@google.com49313f62011-09-14 13:54:05 +0000388/**
389 * Reserves memory that is aligned on double and pointer boundaries.
390 * Hopefully this is sufficient for all practical purposes.
391 */
Hal Canary0acb79e2018-06-14 15:12:42 -0400392template <size_t N> class SkAlignedSStorage {
bsalomon@google.com49313f62011-09-14 13:54:05 +0000393public:
Hal Canary0acb79e2018-06-14 15:12:42 -0400394 SkAlignedSStorage() {}
395 SkAlignedSStorage(SkAlignedSStorage&&) = delete;
396 SkAlignedSStorage(const SkAlignedSStorage&) = delete;
397 SkAlignedSStorage& operator=(SkAlignedSStorage&&) = delete;
398 SkAlignedSStorage& operator=(const SkAlignedSStorage&) = delete;
399
reed64045422015-06-04 06:31:31 -0700400 size_t size() const { return N; }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000401 void* get() { return fData; }
joshualitt9b989322014-12-15 14:16:27 -0800402 const void* get() const { return fData; }
reed64045422015-06-04 06:31:31 -0700403
bsalomon@google.com49313f62011-09-14 13:54:05 +0000404private:
405 union {
406 void* fPtr;
407 double fDouble;
408 char fData[N];
409 };
410};
411
412/**
413 * Reserves memory that is aligned on double and pointer boundaries.
414 * Hopefully this is sufficient for all practical purposes. Otherwise,
415 * we have to do some arcane trickery to determine alignment of non-POD
416 * types. Lifetime of the memory is the lifetime of the object.
417 */
Hal Canary0acb79e2018-06-14 15:12:42 -0400418template <int N, typename T> class SkAlignedSTStorage {
bsalomon@google.com49313f62011-09-14 13:54:05 +0000419public:
Hal Canary0acb79e2018-06-14 15:12:42 -0400420 SkAlignedSTStorage() {}
421 SkAlignedSTStorage(SkAlignedSTStorage&&) = delete;
422 SkAlignedSTStorage(const SkAlignedSTStorage&) = delete;
423 SkAlignedSTStorage& operator=(SkAlignedSTStorage&&) = delete;
424 SkAlignedSTStorage& operator=(const SkAlignedSTStorage&) = delete;
425
bsalomon@google.com49313f62011-09-14 13:54:05 +0000426 /**
427 * Returns void* because this object does not initialize the
428 * memory. Use placement new for types that require a cons.
429 */
430 void* get() { return fStorage.get(); }
bsalomona387a112015-08-11 14:47:42 -0700431 const void* get() const { return fStorage.get(); }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000432private:
433 SkAlignedSStorage<sizeof(T)*N> fStorage;
434};
435
Hal Canary95e3c052017-01-11 12:44:43 -0500436using SkAutoFree = std::unique_ptr<void, SkFunctionWrapper<void, void, sk_free>>;
437
Ben Wagner7a0248f2017-10-18 11:30:56 -0400438template<typename C, std::size_t... Is>
439constexpr auto SkMakeArrayFromIndexSequence(C c, skstd::index_sequence<Is...>)
440-> std::array<skstd::result_of_t<C(std::size_t)>, sizeof...(Is)> {
441 return {{ c(Is)... }};
442}
443
444template<size_t N, typename C> constexpr auto SkMakeArray(C c)
445-> std::array<skstd::result_of_t<C(std::size_t)>, N> {
446 return SkMakeArrayFromIndexSequence(c, skstd::make_index_sequence<N>{});
447}
448
reed@android.com8a1c16f2008-12-17 15:59:43 +0000449#endif