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