blob: 418502b2c1df51b82cb66be2e7ccd58cbdf1a506 [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 */
Hal Canary67362362018-04-24 13:58:37 -040087template <typename T> class SkAutoTArray {
reed@android.com8a1c16f2008-12-17 15:59:43 +000088public:
Hal Canary67362362018-04-24 13:58:37 -040089 SkAutoTArray() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000090 /** Allocate count number of T elements
91 */
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000092 explicit SkAutoTArray(int count) {
93 SkASSERT(count >= 0);
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000094 if (count) {
Hal Canary67362362018-04-24 13:58:37 -040095 fArray.reset(new T[count]);
bsalomon@google.com6d552ee2012-08-14 15:10:09 +000096 }
97 SkDEBUGCODE(fCount = count;)
98 }
99
Hal Canary67362362018-04-24 13:58:37 -0400100 SkAutoTArray(SkAutoTArray&& other) : fArray(std::move(other.fArray)) {
101 SkDEBUGCODE(fCount = other.fCount; other.fCount = 0;)
102 }
103 SkAutoTArray& operator=(SkAutoTArray&& other) {
104 if (this != &other) {
105 fArray = std::move(other.fArray);
106 SkDEBUGCODE(fCount = other.fCount; other.fCount = 0;)
107 }
108 return *this;
109 }
110
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000111 /** Reallocates given a new count. Reallocation occurs even if new count equals old count.
112 */
Hal Canary67362362018-04-24 13:58:37 -0400113 void reset(int count) { *this = SkAutoTArray(count); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114
115 /** Return the array of T elements. Will be NULL if count == 0
116 */
Hal Canary67362362018-04-24 13:58:37 -0400117 T* get() const { return fArray.get(); }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000118
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119 /** Return the nth element in the array
120 */
121 T& operator[](int index) const {
bsalomon@google.com6d552ee2012-08-14 15:10:09 +0000122 SkASSERT((unsigned)index < (unsigned)fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123 return fArray[index];
124 }
125
126private:
Hal Canary67362362018-04-24 13:58:37 -0400127 std::unique_ptr<T[]> fArray;
128 SkDEBUGCODE(int fCount = 0;)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129};
130
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800131/** Wraps SkAutoTArray, with room for kCountRequested elements preallocated.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 */
Hal Canary0acb79e2018-06-14 15:12:42 -0400133template <int kCountRequested, typename T> class SkAutoSTArray {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134public:
Hal Canary0acb79e2018-06-14 15:12:42 -0400135 SkAutoSTArray(SkAutoSTArray&&) = delete;
136 SkAutoSTArray(const SkAutoSTArray&) = delete;
137 SkAutoSTArray& operator=(SkAutoSTArray&&) = delete;
138 SkAutoSTArray& operator=(const SkAutoSTArray&) = delete;
139
bsalomon@google.comd5104142013-06-13 15:13:46 +0000140 /** Initialize with no objects */
141 SkAutoSTArray() {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400142 fArray = nullptr;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000143 fCount = 0;
144 }
145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 /** Allocate count number of T elements
147 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000148 SkAutoSTArray(int count) {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400149 fArray = nullptr;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000150 fCount = 0;
151 this->reset(count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000153
reed@android.com8a1c16f2008-12-17 15:59:43 +0000154 ~SkAutoSTArray() {
bsalomon@google.comd5104142013-06-13 15:13:46 +0000155 this->reset(0);
156 }
157
158 /** Destroys previous objects in the array and default constructs count number of objects */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000159 void reset(int count) {
scroggo@google.com1198e742013-05-29 20:10:25 +0000160 T* start = fArray;
161 T* iter = start + fCount;
162 while (iter > start) {
163 (--iter)->~T();
164 }
bsalomon@google.comd5104142013-06-13 15:13:46 +0000165
csmartdaltond0e402f2016-06-23 12:55:14 -0700166 SkASSERT(count >= 0);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000167 if (fCount != count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800168 if (fCount > kCount) {
robertphillips@google.com4d376732013-07-12 18:44:23 +0000169 // 'fArray' was allocated last time so free it now
170 SkASSERT((T*) fStorage != fArray);
bsalomon@google.comd5104142013-06-13 15:13:46 +0000171 sk_free(fArray);
172 }
173
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800174 if (count > kCount) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500175 fArray = (T*) sk_malloc_throw(count, sizeof(T));
bsalomon@google.comd5104142013-06-13 15:13:46 +0000176 } else if (count > 0) {
177 fArray = (T*) fStorage;
178 } else {
Ben Wagnera93a14a2017-08-28 10:34:05 -0400179 fArray = nullptr;
bsalomon@google.comd5104142013-06-13 15:13:46 +0000180 }
181
182 fCount = count;
183 }
184
185 iter = fArray;
186 T* stop = fArray + count;
187 while (iter < stop) {
halcanary385fe4d2015-08-26 13:07:48 -0700188 new (iter++) T;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 }
190 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000191
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192 /** Return the number of T elements in the array
193 */
robertphillips@google.comadacc702013-10-14 21:53:24 +0000194 int count() const { return fCount; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000195
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 /** Return the array of T elements. Will be NULL if count == 0
197 */
198 T* get() const { return fArray; }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000199
Brian Salomon92ce5942017-01-18 11:01:10 -0500200 T* begin() { return fArray; }
201
202 const T* begin() const { return fArray; }
203
204 T* end() { return fArray + fCount; }
205
206 const T* end() const { return fArray + fCount; }
207
reed@android.com8a1c16f2008-12-17 15:59:43 +0000208 /** Return the nth element in the array
209 */
210 T& operator[](int index) const {
robertphillips@google.comadacc702013-10-14 21:53:24 +0000211 SkASSERT(index < fCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 return fArray[index];
213 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000214
reed@android.com8a1c16f2008-12-17 15:59:43 +0000215private:
Mike Klein6613cc52017-12-19 09:09:33 -0500216#if defined(SK_BUILD_FOR_GOOGLE3)
217 // 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 -0800218 // have multiple large stack allocations.
219 static const int kMaxBytes = 4 * 1024;
220 static const int kCount = kCountRequested * sizeof(T) > kMaxBytes
221 ? kMaxBytes / sizeof(T)
222 : kCountRequested;
223#else
224 static const int kCount = kCountRequested;
225#endif
226
robertphillips@google.comadacc702013-10-14 21:53:24 +0000227 int fCount;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228 T* fArray;
229 // since we come right after fArray, fStorage should be properly aligned
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800230 char fStorage[kCount * sizeof(T)];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000231};
232
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000233/** Manages an array of T elements, freeing the array in the destructor.
234 * Does NOT call any constructors/destructors on T (T must be POD).
235 */
Hal Canary67362362018-04-24 13:58:37 -0400236template <typename T> class SkAutoTMalloc {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237public:
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000238 /** 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 -0400239 explicit SkAutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {}
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000240
241 /** Allocates space for 'count' Ts. */
Hal Canary67362362018-04-24 13:58:37 -0400242 explicit SkAutoTMalloc(size_t count)
243 : fPtr(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr) {}
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000244
Hal Canary67362362018-04-24 13:58:37 -0400245 SkAutoTMalloc(SkAutoTMalloc&&) = default;
246 SkAutoTMalloc& operator=(SkAutoTMalloc&&) = default;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000247
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000248 /** Resize the memory area pointed to by the current ptr preserving contents. */
249 void realloc(size_t count) {
Hal Canary67362362018-04-24 13:58:37 -0400250 fPtr.reset(count ? (T*)sk_realloc_throw(fPtr.release(), count * sizeof(T)) : nullptr);
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000251 }
252
253 /** Resize the memory area pointed to by the current ptr without preserving contents. */
mtklein852f15d2016-03-17 10:51:27 -0700254 T* reset(size_t count = 0) {
Hal Canary67362362018-04-24 13:58:37 -0400255 fPtr.reset(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr);
256 return this->get();
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000257 }
258
Hal Canary67362362018-04-24 13:58:37 -0400259 T* get() const { return fPtr.get(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000260
Hal Canary67362362018-04-24 13:58:37 -0400261 operator T*() { return fPtr.get(); }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000262
Hal Canary67362362018-04-24 13:58:37 -0400263 operator const T*() const { return fPtr.get(); }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000264
Hal Canary67362362018-04-24 13:58:37 -0400265 T& operator[](int index) { return fPtr.get()[index]; }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000266
Hal Canary67362362018-04-24 13:58:37 -0400267 const T& operator[](int index) const { return fPtr.get()[index]; }
csmartdalton320ade42017-02-13 11:54:37 -0700268
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000269 /**
270 * Transfer ownership of the ptr to the caller, setting the internal
271 * pointer to NULL. Note that this differs from get(), which also returns
272 * the pointer, but it does not transfer ownership.
273 */
Hal Canary67362362018-04-24 13:58:37 -0400274 T* release() { return fPtr.release(); }
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000275
reed@android.com8a1c16f2008-12-17 15:59:43 +0000276private:
Hal Canary67362362018-04-24 13:58:37 -0400277 std::unique_ptr<T, SkFunctionWrapper<void, void, sk_free>> fPtr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000278};
279
Hal Canary0acb79e2018-06-14 15:12:42 -0400280template <size_t kCountRequested, typename T> class SkAutoSTMalloc {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281public:
joshualittf1f88952015-04-08 07:33:33 -0700282 SkAutoSTMalloc() : fPtr(fTStorage) {}
bungeman@google.com71033442013-05-01 14:21:20 +0000283
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000284 SkAutoSTMalloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800285 if (count > kCount) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500286 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
csmartdaltond0e402f2016-06-23 12:55:14 -0700287 } else if (count) {
joshualittf1f88952015-04-08 07:33:33 -0700288 fPtr = fTStorage;
csmartdaltond0e402f2016-06-23 12:55:14 -0700289 } else {
290 fPtr = nullptr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000291 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000292 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000293
Hal Canary0acb79e2018-06-14 15:12:42 -0400294 SkAutoSTMalloc(SkAutoSTMalloc&&) = delete;
295 SkAutoSTMalloc(const SkAutoSTMalloc&) = delete;
296 SkAutoSTMalloc& operator=(SkAutoSTMalloc&&) = delete;
297 SkAutoSTMalloc& operator=(const SkAutoSTMalloc&) = delete;
298
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000299 ~SkAutoSTMalloc() {
300 if (fPtr != fTStorage) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301 sk_free(fPtr);
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000302 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000303 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000304
305 // doesn't preserve contents
reed@google.com4e05fd22013-06-10 18:58:11 +0000306 T* reset(size_t count) {
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000307 if (fPtr != fTStorage) {
308 sk_free(fPtr);
309 }
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800310 if (count > kCount) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500311 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
csmartdaltond0e402f2016-06-23 12:55:14 -0700312 } else if (count) {
joshualittf1f88952015-04-08 07:33:33 -0700313 fPtr = fTStorage;
csmartdaltond0e402f2016-06-23 12:55:14 -0700314 } else {
315 fPtr = nullptr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000316 }
reed@google.com4e05fd22013-06-10 18:58:11 +0000317 return fPtr;
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000318 }
319
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320 T* get() const { return fPtr; }
321
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000322 operator T*() {
323 return fPtr;
324 }
325
326 operator const T*() const {
327 return fPtr;
328 }
329
330 T& operator[](int index) {
331 return fPtr[index];
332 }
333
334 const T& operator[](int index) const {
335 return fPtr[index];
336 }
337
joshualittf1f88952015-04-08 07:33:33 -0700338 // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent
339 void realloc(size_t count) {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800340 if (count > kCount) {
joshualittf1f88952015-04-08 07:33:33 -0700341 if (fPtr == fTStorage) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500342 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800343 memcpy(fPtr, fTStorage, kCount * sizeof(T));
joshualittf1f88952015-04-08 07:33:33 -0700344 } else {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500345 fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
joshualittf1f88952015-04-08 07:33:33 -0700346 }
csmartdaltond0e402f2016-06-23 12:55:14 -0700347 } else if (count) {
348 if (fPtr != fTStorage) {
Mike Reed8dc8dbc2018-01-05 11:20:10 -0500349 fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
csmartdaltond0e402f2016-06-23 12:55:14 -0700350 }
351 } else {
352 this->reset(0);
joshualittf1f88952015-04-08 07:33:33 -0700353 }
354 }
355
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356private:
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800357 // Since we use uint32_t storage, we might be able to get more elements for free.
358 static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
Mike Klein6613cc52017-12-19 09:09:33 -0500359#if defined(SK_BUILD_FOR_GOOGLE3)
360 // 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 -0800361 // have multiple large stack allocations.
362 static const size_t kMaxBytes = 4 * 1024;
363 static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
364 ? kMaxBytes / sizeof(T)
365 : kCountWithPadding;
366#else
367 static const size_t kCount = kCountWithPadding;
368#endif
369
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370 T* fPtr;
371 union {
benjaminwagnerf49c75a2016-02-05 07:02:38 -0800372 uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373 T fTStorage[1]; // do NOT want to invoke T::T()
374 };
375};
376
reed64045422015-06-04 06:31:31 -0700377//////////////////////////////////////////////////////////////////////////////////////////////////
378
379/**
380 * Pass the object and the storage that was offered during SkInPlaceNewCheck, and this will
381 * safely destroy (and free if it was dynamically allocated) the object.
382 */
383template <typename T> void SkInPlaceDeleteCheck(T* obj, void* storage) {
384 if (storage == obj) {
385 obj->~T();
386 } else {
halcanary385fe4d2015-08-26 13:07:48 -0700387 delete obj;
reed64045422015-06-04 06:31:31 -0700388 }
389}
390
391/**
392 * Allocates T, using storage if it is large enough, and allocating on the heap (via new) if
393 * storage is not large enough.
394 *
395 * obj = SkInPlaceNewCheck<Type>(storage, size);
396 * ...
397 * SkInPlaceDeleteCheck(obj, storage);
398 */
Hal Canary47728252018-04-24 14:57:09 -0400399template<typename T, typename... Args>
400T* SkInPlaceNewCheck(void* storage, size_t size, Args&&... args) {
401 return (sizeof(T) <= size) ? new (storage) T(std::forward<Args>(args)...)
402 : new T(std::forward<Args>(args)...);
reed64045422015-06-04 06:31:31 -0700403}
bsalomon@google.com49313f62011-09-14 13:54:05 +0000404/**
405 * Reserves memory that is aligned on double and pointer boundaries.
406 * Hopefully this is sufficient for all practical purposes.
407 */
Hal Canary0acb79e2018-06-14 15:12:42 -0400408template <size_t N> class SkAlignedSStorage {
bsalomon@google.com49313f62011-09-14 13:54:05 +0000409public:
Hal Canary0acb79e2018-06-14 15:12:42 -0400410 SkAlignedSStorage() {}
411 SkAlignedSStorage(SkAlignedSStorage&&) = delete;
412 SkAlignedSStorage(const SkAlignedSStorage&) = delete;
413 SkAlignedSStorage& operator=(SkAlignedSStorage&&) = delete;
414 SkAlignedSStorage& operator=(const SkAlignedSStorage&) = delete;
415
reed64045422015-06-04 06:31:31 -0700416 size_t size() const { return N; }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000417 void* get() { return fData; }
joshualitt9b989322014-12-15 14:16:27 -0800418 const void* get() const { return fData; }
reed64045422015-06-04 06:31:31 -0700419
bsalomon@google.com49313f62011-09-14 13:54:05 +0000420private:
421 union {
422 void* fPtr;
423 double fDouble;
424 char fData[N];
425 };
426};
427
428/**
429 * Reserves memory that is aligned on double and pointer boundaries.
430 * Hopefully this is sufficient for all practical purposes. Otherwise,
431 * we have to do some arcane trickery to determine alignment of non-POD
432 * types. Lifetime of the memory is the lifetime of the object.
433 */
Hal Canary0acb79e2018-06-14 15:12:42 -0400434template <int N, typename T> class SkAlignedSTStorage {
bsalomon@google.com49313f62011-09-14 13:54:05 +0000435public:
Hal Canary0acb79e2018-06-14 15:12:42 -0400436 SkAlignedSTStorage() {}
437 SkAlignedSTStorage(SkAlignedSTStorage&&) = delete;
438 SkAlignedSTStorage(const SkAlignedSTStorage&) = delete;
439 SkAlignedSTStorage& operator=(SkAlignedSTStorage&&) = delete;
440 SkAlignedSTStorage& operator=(const SkAlignedSTStorage&) = delete;
441
bsalomon@google.com49313f62011-09-14 13:54:05 +0000442 /**
443 * Returns void* because this object does not initialize the
444 * memory. Use placement new for types that require a cons.
445 */
446 void* get() { return fStorage.get(); }
bsalomona387a112015-08-11 14:47:42 -0700447 const void* get() const { return fStorage.get(); }
bsalomon@google.com49313f62011-09-14 13:54:05 +0000448private:
449 SkAlignedSStorage<sizeof(T)*N> fStorage;
450};
451
Hal Canary95e3c052017-01-11 12:44:43 -0500452using SkAutoFree = std::unique_ptr<void, SkFunctionWrapper<void, void, sk_free>>;
453
Ben Wagner7a0248f2017-10-18 11:30:56 -0400454template<typename C, std::size_t... Is>
455constexpr auto SkMakeArrayFromIndexSequence(C c, skstd::index_sequence<Is...>)
456-> std::array<skstd::result_of_t<C(std::size_t)>, sizeof...(Is)> {
457 return {{ c(Is)... }};
458}
459
460template<size_t N, typename C> constexpr auto SkMakeArray(C c)
461-> std::array<skstd::result_of_t<C(std::size_t)>, N> {
462 return SkMakeArrayFromIndexSequence(c, skstd::make_index_sequence<N>{});
463}
464
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465#endif