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