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 has_value()55 bool has_value() const { return fValid; } 56 explicit operator bool() const { return this->has_value(); } 57 get()58 const Base* get() const { 59 SkASSERT(fValid); 60 return std::launder(reinterpret_cast<const Base*>(fData)); 61 } 62 get()63 Base* get() { 64 SkASSERT(fValid); 65 return std::launder(reinterpret_cast<Base*>(fData)); 66 } 67 68 Base* operator->() { return this->get(); } 69 const Base* operator->() const { return this->get(); } 70 71 Base& operator*() { return *this->get(); } 72 const Base& operator*() const { return *this->get(); } 73 74 private: 75 alignas(8) std::byte fData[Size]; 76 bool fValid = false; 77 }; 78 79 #endif // SkAnySubclass_DEFINED 80