1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2023 Google LLC 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkAnySubclass_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define SkAnySubclass_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h" 12*c8dee2aaSAndroid Build Coastguard Worker 13*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 14*c8dee2aaSAndroid Build Coastguard Worker #include <new> 15*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits> // IWYU pragma: keep 16*c8dee2aaSAndroid Build Coastguard Worker #include <utility> 17*c8dee2aaSAndroid Build Coastguard Worker 18*c8dee2aaSAndroid Build Coastguard Worker /** 19*c8dee2aaSAndroid Build Coastguard Worker * Stores any subclass `T` of `Base`, where sizeof(T) <= `Size`, without using the heap. 20*c8dee2aaSAndroid Build Coastguard Worker * Doesn't need advance knowledge of T, so it's particularly suited to platform or backend 21*c8dee2aaSAndroid Build Coastguard Worker * implementations of a generic interface, where the set of possible subclasses is finite and 22*c8dee2aaSAndroid Build Coastguard Worker * known, but can't be made available at compile-time. 23*c8dee2aaSAndroid Build Coastguard Worker */ 24*c8dee2aaSAndroid Build Coastguard Worker template <typename Base, size_t Size> 25*c8dee2aaSAndroid Build Coastguard Worker class SkAnySubclass { 26*c8dee2aaSAndroid Build Coastguard Worker public: 27*c8dee2aaSAndroid Build Coastguard Worker SkAnySubclass() = default; ~SkAnySubclass()28*c8dee2aaSAndroid Build Coastguard Worker ~SkAnySubclass() { 29*c8dee2aaSAndroid Build Coastguard Worker this->reset(); 30*c8dee2aaSAndroid Build Coastguard Worker } 31*c8dee2aaSAndroid Build Coastguard Worker 32*c8dee2aaSAndroid Build Coastguard Worker SkAnySubclass(const SkAnySubclass&) = delete; 33*c8dee2aaSAndroid Build Coastguard Worker SkAnySubclass& operator=(const SkAnySubclass&) = delete; 34*c8dee2aaSAndroid Build Coastguard Worker SkAnySubclass(SkAnySubclass&&) = delete; 35*c8dee2aaSAndroid Build Coastguard Worker SkAnySubclass& operator=(SkAnySubclass&&) = delete; 36*c8dee2aaSAndroid Build Coastguard Worker 37*c8dee2aaSAndroid Build Coastguard Worker template <typename T, typename... Args> emplace(Args &&...args)38*c8dee2aaSAndroid Build Coastguard Worker void emplace(Args&&... args) { 39*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::is_base_of_v<Base, T>); 40*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(T) <= Size); 41*c8dee2aaSAndroid Build Coastguard Worker // We're going to clean up our stored object by calling ~Base: 42*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::has_virtual_destructor_v<Base> || std::is_trivially_destructible_v<T>); 43*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fValid); 44*c8dee2aaSAndroid Build Coastguard Worker new (fData) T(std::forward<Args>(args)...); 45*c8dee2aaSAndroid Build Coastguard Worker fValid = true; 46*c8dee2aaSAndroid Build Coastguard Worker } 47*c8dee2aaSAndroid Build Coastguard Worker reset()48*c8dee2aaSAndroid Build Coastguard Worker void reset() { 49*c8dee2aaSAndroid Build Coastguard Worker if (fValid) { 50*c8dee2aaSAndroid Build Coastguard Worker this->get()->~Base(); 51*c8dee2aaSAndroid Build Coastguard Worker } 52*c8dee2aaSAndroid Build Coastguard Worker fValid = false; 53*c8dee2aaSAndroid Build Coastguard Worker } 54*c8dee2aaSAndroid Build Coastguard Worker get()55*c8dee2aaSAndroid Build Coastguard Worker const Base* get() const { 56*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fValid); 57*c8dee2aaSAndroid Build Coastguard Worker return std::launder(reinterpret_cast<const Base*>(fData)); 58*c8dee2aaSAndroid Build Coastguard Worker } 59*c8dee2aaSAndroid Build Coastguard Worker get()60*c8dee2aaSAndroid Build Coastguard Worker Base* get() { 61*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fValid); 62*c8dee2aaSAndroid Build Coastguard Worker return std::launder(reinterpret_cast<Base*>(fData)); 63*c8dee2aaSAndroid Build Coastguard Worker } 64*c8dee2aaSAndroid Build Coastguard Worker 65*c8dee2aaSAndroid Build Coastguard Worker Base* operator->() { return this->get(); } 66*c8dee2aaSAndroid Build Coastguard Worker const Base* operator->() const { return this->get(); } 67*c8dee2aaSAndroid Build Coastguard Worker 68*c8dee2aaSAndroid Build Coastguard Worker private: 69*c8dee2aaSAndroid Build Coastguard Worker alignas(8) std::byte fData[Size]; 70*c8dee2aaSAndroid Build Coastguard Worker bool fValid = false; 71*c8dee2aaSAndroid Build Coastguard Worker }; 72*c8dee2aaSAndroid Build Coastguard Worker 73*c8dee2aaSAndroid Build Coastguard Worker #endif // SkAnySubclass_DEFINED 74