Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkTemplates.h
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkTemplates_DEFINED
9#define SkTemplates_DEFINED
10
17
18#include <array>
19#include <cstddef>
20#include <cstdint>
21#include <cstring>
22#include <memory>
23#include <type_traits>
24#include <utility>
25
26
27/** \file SkTemplates.h
28
29 This file contains light-weight template classes for type-safe and exception-safe
30 resource management.
31*/
32
33/**
34 * Marks a local variable as known to be unused (to avoid warnings).
35 * Note that this does *not* prevent the local variable from being optimized away.
36 */
37template<typename T> inline void sk_ignore_unused_variable(const T&) { }
38
39/**
40 * This is a general purpose absolute-value function.
41 * See SkAbs32 in (SkSafe32.h) for a 32-bit int specific version that asserts.
42 */
43template <typename T> static inline T SkTAbs(T value) {
44 if (value < 0) {
45 value = -value;
46 }
47 return value;
48}
49
50/**
51 * Returns a pointer to a D which comes immediately after S[count].
52 */
53template <typename D, typename S> inline D* SkTAfter(S* ptr, size_t count = 1) {
54 return reinterpret_cast<D*>(ptr + count);
55}
56
57/**
58 * Returns a pointer to a D which comes byteOffset bytes after S.
59 */
60template <typename D, typename S> inline D* SkTAddOffset(S* ptr, ptrdiff_t byteOffset) {
61 // The intermediate char* has the same cv-ness as D as this produces better error messages.
62 // This relies on the fact that reinterpret_cast can add constness, but cannot remove it.
63 return reinterpret_cast<D*>(reinterpret_cast<sknonstd::same_cv_t<char, D>*>(ptr) + byteOffset);
64}
65
66template <typename T, T* P> struct SkOverloadedFunctionObject {
67 template <typename... Args>
68 auto operator()(Args&&... args) const -> decltype(P(std::forward<Args>(args)...)) {
69 return P(std::forward<Args>(args)...);
70 }
71};
72
73template <auto F> using SkFunctionObject =
74 SkOverloadedFunctionObject<std::remove_pointer_t<decltype(F)>, F>;
75
76/** \class SkAutoTCallVProc
77
78 Call a function when this goes out of scope. The template uses two
79 parameters, the object, and a function that is to be called in the destructor.
80 If release() is called, the object reference is set to null. If the object
81 reference is null when the destructor is called, we do not call the
82 function.
83*/
84template <typename T, void (*P)(T*)> class SkAutoTCallVProc
85 : public std::unique_ptr<T, SkFunctionObject<P>> {
86 using inherited = std::unique_ptr<T, SkFunctionObject<P>>;
87public:
88 using inherited::inherited;
90 SkAutoTCallVProc(SkAutoTCallVProc&& that) : inherited(std::move(that)) {}
91
92 operator T*() const { return this->get(); }
93};
94
95
96namespace skia_private {
97/** Allocate an array of T elements, and free the array in the destructor
98 */
99template <typename T> class AutoTArray {
100public:
102 // Allocate size number of T elements
103 explicit AutoTArray(size_t size) {
104 fSize = check_size_bytes_too_big<T>(size);
105 fData.reset(size > 0 ? new T[size] : nullptr);
106 }
107
108 // TODO: remove when all uses are gone.
110
111 AutoTArray(AutoTArray&& other) : fData(std::move(other.fData)) {
112 fSize = std::exchange(other.fSize, 0);
113 }
115 if (this != &other) {
116 fData = std::move(other.fData);
117 fSize = std::exchange(other.fSize, 0);
118 }
119 return *this;
120 }
121
122 // Reallocates given a new count. Reallocation occurs even if new count equals old count.
123 void reset(size_t count = 0) {
124 *this = AutoTArray(count);
125 }
126
127 T* get() const { return fData.get(); }
128
129 T& operator[](size_t index) const {
130 return fData[sk_collection_check_bounds(index, fSize)];
131 }
132
133 const T* data() const { return fData.get(); }
134 T* data() { return fData.get(); }
135
136 size_t size() const { return fSize; }
137 bool empty() const { return fSize == 0; }
138 size_t size_bytes() const { return sizeof(T) * fSize; }
139
140 T* begin() {
141 return fData;
142 }
143 const T* begin() const {
144 return fData;
145 }
146
147 // It's safe to use fItemArray + fSize because if fItemArray is nullptr then adding 0 is
148 // valid and returns nullptr. See [expr.add] in the C++ standard.
149 T* end() {
150 if (fData == nullptr) {
151 SkASSERT(fSize == 0);
152 }
153 return fData + fSize;
154 }
155 const T* end() const {
156 if (fData == nullptr) {
157 SkASSERT(fSize == 0);
158 }
159 return fData + fSize;
160 }
161
162private:
163 std::unique_ptr<T[]> fData;
164 size_t fSize = 0;
165};
166
167/** Wraps AutoTArray, with room for kCountRequested elements preallocated.
168 */
169template <int kCountRequested, typename T> class AutoSTArray {
170public:
172 AutoSTArray(const AutoSTArray&) = delete;
175
176 /** Initialize with no objects */
178 fArray = nullptr;
179 fCount = 0;
180 }
181
182 /** Allocate count number of T elements
183 */
185 fArray = nullptr;
186 fCount = 0;
187 this->reset(count);
188 }
189
191 this->reset(0);
192 }
193
194 /** Destroys previous objects in the array and default constructs count number of objects */
195 void reset(int count) {
196 T* start = fArray;
197 T* iter = start + fCount;
198 while (iter > start) {
199 (--iter)->~T();
200 }
201
202 SkASSERT(count >= 0);
203 if (fCount != count) {
204 if (fCount > kCount) {
205 // 'fArray' was allocated last time so free it now
206 SkASSERT((T*) fStorage != fArray);
207 sk_free(fArray);
208 }
209
210 if (count > kCount) {
211 fArray = (T*) sk_malloc_throw(count, sizeof(T));
212 } else if (count > 0) {
213 fArray = (T*) fStorage;
214 } else {
215 fArray = nullptr;
216 }
217
218 fCount = count;
219 }
220
221 iter = fArray;
222 T* stop = fArray + count;
223 while (iter < stop) {
224 new (iter++) T;
225 }
226 }
227
228 /** Return the number of T elements in the array
229 */
230 int count() const { return fCount; }
231
232 /** Return the array of T elements. Will be NULL if count == 0
233 */
234 T* get() const { return fArray; }
235
236 T* begin() { return fArray; }
237
238 const T* begin() const { return fArray; }
239
240 T* end() { return fArray + fCount; }
241
242 const T* end() const { return fArray + fCount; }
243
244 /** Return the nth element in the array
245 */
246 T& operator[](int index) const {
247 return fArray[sk_collection_check_bounds(index, fCount)];
248 }
249
250 /** Aliases matching other types, like std::vector. */
251 const T* data() const { return fArray; }
252 T* data() { return fArray; }
253 size_t size() const { return fCount; }
254
255private:
256#if defined(SK_BUILD_FOR_GOOGLE3)
257 // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max,
258 // but some functions have multiple large stack allocations.
259 static const int kMaxBytes = 4 * 1024;
260 static const int kCount = kCountRequested * sizeof(T) > kMaxBytes
261 ? kMaxBytes / sizeof(T)
262 : kCountRequested;
263#else
264 static const int kCount = kCountRequested;
265#endif
266
267 int fCount;
268 T* fArray;
269 alignas(T) char fStorage[kCount * sizeof(T)];
270};
271
272/** Manages an array of T elements, freeing the array in the destructor.
273 * Does NOT call any constructors/destructors on T (T must be POD).
274 */
275template <typename T,
276 typename = std::enable_if_t<std::is_trivially_default_constructible<T>::value &&
277 std::is_trivially_destructible<T>::value>>
279public:
280 /** Takes ownership of the ptr. The ptr must be a value which can be passed to sk_free. */
281 explicit AutoTMalloc(T* ptr = nullptr) : fPtr(ptr) {}
282
283 /** Allocates space for 'count' Ts. */
284 explicit AutoTMalloc(size_t count)
285 : fPtr(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr) {}
286
289
290 /** Resize the memory area pointed to by the current ptr preserving contents. */
291 void realloc(size_t count) {
292 fPtr.reset(count ? (T*)sk_realloc_throw(fPtr.release(), count * sizeof(T)) : nullptr);
293 }
294
295 /** Resize the memory area pointed to by the current ptr without preserving contents. */
296 T* reset(size_t count = 0) {
297 fPtr.reset(count ? (T*)sk_malloc_throw(count, sizeof(T)) : nullptr);
298 return this->get();
299 }
300
301 T* get() const { return fPtr.get(); }
302
303 operator T*() { return fPtr.get(); }
304
305 operator const T*() const { return fPtr.get(); }
306
307 T& operator[](int index) { return fPtr.get()[index]; }
308
309 const T& operator[](int index) const { return fPtr.get()[index]; }
310
311 /** Aliases matching other types, like std::vector. */
312 const T* data() const { return fPtr.get(); }
313 T* data() { return fPtr.get(); }
314
315 /**
316 * 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 */
320 T* release() { return fPtr.release(); }
321
322private:
323 std::unique_ptr<T, SkOverloadedFunctionObject<void(void*), sk_free>> fPtr;
324};
325
326template <size_t kCountRequested,
327 typename T,
328 typename = std::enable_if_t<std::is_trivially_default_constructible<T>::value &&
329 std::is_trivially_destructible<T>::value>>
331public:
333
335 if (count > kCount) {
336 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
337 } else if (count) {
338 fPtr = fTStorage;
339 } else {
340 fPtr = nullptr;
341 }
342 }
343
345 AutoSTMalloc(const AutoSTMalloc&) = delete;
348
350 if (fPtr != fTStorage) {
351 sk_free(fPtr);
352 }
353 }
354
355 // doesn't preserve contents
356 T* reset(size_t count) {
357 if (fPtr != fTStorage) {
358 sk_free(fPtr);
359 }
360 if (count > kCount) {
361 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
362 } else if (count) {
363 fPtr = fTStorage;
364 } else {
365 fPtr = nullptr;
366 }
367 return fPtr;
368 }
369
370 T* get() const { return fPtr; }
371
372 operator T*() {
373 return fPtr;
374 }
375
376 operator const T*() const {
377 return fPtr;
378 }
379
380 T& operator[](int index) {
381 return fPtr[index];
382 }
383
384 const T& operator[](int index) const {
385 return fPtr[index];
386 }
387
388 /** Aliases matching other types, like std::vector. */
389 const T* data() const { return fPtr; }
390 T* data() { return fPtr; }
391
392 // Reallocs the array, can be used to shrink the allocation. Makes no attempt to be intelligent
393 void realloc(size_t count) {
394 if (count > kCount) {
395 if (fPtr == fTStorage) {
396 fPtr = (T*)sk_malloc_throw(count, sizeof(T));
397 memcpy((void*)fPtr, fTStorage, kCount * sizeof(T));
398 } else {
399 fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
400 }
401 } else if (count) {
402 if (fPtr != fTStorage) {
403 fPtr = (T*)sk_realloc_throw(fPtr, count, sizeof(T));
404 }
405 } else {
406 this->reset(0);
407 }
408 }
409
410private:
411 // Since we use uint32_t storage, we might be able to get more elements for free.
412 static const size_t kCountWithPadding = SkAlign4(kCountRequested*sizeof(T)) / sizeof(T);
413#if defined(SK_BUILD_FOR_GOOGLE3)
414 // Stack frame size is limited for SK_BUILD_FOR_GOOGLE3. 4k is less than the actual max, but some functions
415 // have multiple large stack allocations.
416 static const size_t kMaxBytes = 4 * 1024;
417 static const size_t kCount = kCountRequested * sizeof(T) > kMaxBytes
418 ? kMaxBytes / sizeof(T)
419 : kCountWithPadding;
420#else
421 static const size_t kCount = kCountWithPadding;
422#endif
423
424 T* fPtr;
425 union {
426 uint32_t fStorage32[SkAlign4(kCount*sizeof(T)) >> 2];
427 T fTStorage[1]; // do NOT want to invoke T::T()
428 };
429};
430
431using UniqueVoidPtr = std::unique_ptr<void, SkOverloadedFunctionObject<void(void*), sk_free>>;
432
433} // namespace skia_private
434
435template<typename C, std::size_t... Is>
436constexpr auto SkMakeArrayFromIndexSequence(C c, std::index_sequence<Is...> is)
437-> std::array<decltype(c(std::declval<typename decltype(is)::value_type>())), sizeof...(Is)> {
438 return {{ c(Is)... }};
439}
440
441template<size_t N, typename C> constexpr auto SkMakeArray(C c)
442-> std::array<decltype(c(std::declval<typename std::index_sequence<N>::value_type>())), N> {
443 return SkMakeArrayFromIndexSequence(c, std::make_index_sequence<N>{});
444}
445
446#endif
m reset()
int count
static constexpr T SkAlign4(T x)
Definition SkAlign.h:16
SK_API T sk_collection_check_bounds(T i, T size)
Definition SkAssert.h:143
#define SkASSERT(cond)
Definition SkAssert.h:116
SK_API void sk_free(void *)
static void * sk_malloc_throw(size_t size)
Definition SkMalloc.h:67
SK_API void * sk_realloc_throw(void *buffer, size_t size)
constexpr auto SkMakeArray(C c) -> std::array< decltype(c(std::declval< typename std::index_sequence< N >::value_type >())), N >
constexpr auto SkMakeArrayFromIndexSequence(C c, std::index_sequence< Is... > is) -> std::array< decltype(c(std::declval< typename decltype(is)::value_type >())), sizeof...(Is)>
static T SkTAbs(T value)
Definition SkTemplates.h:43
void sk_ignore_unused_variable(const T &)
Definition SkTemplates.h:37
D * SkTAfter(S *ptr, size_t count=1)
Definition SkTemplates.h:53
D * SkTAddOffset(S *ptr, ptrdiff_t byteOffset)
Definition SkTemplates.h:60
constexpr size_t SkToSizeT(S x)
Definition SkTo.h:31
#define F(x)
#define N
Definition beziers.cpp:19
SkAutoTCallVProc(SkAutoTCallVProc &&that)
Definition SkTemplates.h:90
SkAutoTCallVProc(const SkAutoTCallVProc &)=delete
const T * begin() const
AutoSTArray(const AutoSTArray &)=delete
T & operator[](int index) const
AutoSTArray & operator=(const AutoSTArray &)=delete
const T * data() const
const T * end() const
AutoSTArray & operator=(AutoSTArray &&)=delete
AutoSTArray(AutoSTArray &&)=delete
T * reset(size_t count)
AutoSTMalloc(AutoSTMalloc &&)=delete
const T & operator[](int index) const
AutoSTMalloc & operator=(AutoSTMalloc &&)=delete
AutoSTMalloc & operator=(const AutoSTMalloc &)=delete
void realloc(size_t count)
const T * data() const
AutoSTMalloc(const AutoSTMalloc &)=delete
uint32_t fStorage32[SkAlign4(kCount *sizeof(T)) > > 2]
const T * begin() const
void reset(size_t count=0)
T & operator[](size_t index) const
size_t size_bytes() const
const T * end() const
AutoTArray & operator=(AutoTArray &&other)
AutoTArray(AutoTArray &&other)
const T * data() const
void realloc(size_t count)
AutoTMalloc(AutoTMalloc &&)=default
const T & operator[](int index) const
AutoTMalloc & operator=(AutoTMalloc &&)=default
const T * data() const
T * reset(size_t count=0)
T & operator[](int index)
AutoTMalloc(T *ptr=nullptr)
#define C(TEST_CATEGORY)
Definition colrv1.cpp:247
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
std::unique_ptr< void, SkOverloadedFunctionObject< void(void *), sk_free > > UniqueVoidPtr
typename same_cv< D, S >::type same_cv_t
Definition SkTLogic.h:49
Definition ref_ptr.h:256
#define T
Definition SkMD5.cpp:120
auto operator()(Args &&... args) const -> decltype(P(std::forward< Args >(args)...))
Definition SkTemplates.h:68