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