| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SkAnySubclass_DEFINED | |
| #define SkAnySubclass_DEFINED | |
| #include "include/private/base/SkAssert.h" | |
| #include <cstddef> | |
| #include <new> | |
| #include <type_traits> // IWYU pragma: keep | |
| #include <utility> | |
| /** | |
| * Stores any subclass `T` of `Base`, where sizeof(T) <= `Size`, without using the heap. | |
| * Doesn't need advance knowledge of T, so it's particularly suited to platform or backend | |
| * implementations of a generic interface, where the set of possible subclasses is finite and | |
| * known, but can't be made available at compile-time. | |
| */ | |
| template <typename Base, size_t Size> | |
| class SkAnySubclass { | |
| public: | |
| SkAnySubclass() = default; | |
| ~SkAnySubclass() { | |
| this->reset(); | |
| } | |
| SkAnySubclass(const SkAnySubclass&) = delete; | |
| SkAnySubclass& operator=(const SkAnySubclass&) = delete; | |
| SkAnySubclass(SkAnySubclass&&) = delete; | |
| SkAnySubclass& operator=(SkAnySubclass&&) = delete; | |
| template <typename T, typename... Args> | |
| void emplace(Args&&... args) { | |
| static_assert(std::is_base_of_v<Base, T>); | |
| static_assert(sizeof(T) <= Size); | |
| // We're going to clean up our stored object by calling ~Base: | |
| static_assert(std::has_virtual_destructor_v<Base> || std::is_trivially_destructible_v<T>); | |
| SkASSERT(!fValid); | |
| new (fData) T(std::forward<Args>(args)...); | |
| fValid = true; | |
| } | |
| void reset() { | |
| if (fValid) { | |
| this->get()->~Base(); | |
| } | |
| fValid = false; | |
| } | |
| bool has_value() const { return fValid; } | |
| explicit operator bool() const { return this->has_value(); } | |
| const Base* get() const { | |
| SkASSERT(fValid); | |
| return std::launder(reinterpret_cast<const Base*>(fData)); | |
| } | |
| Base* get() { | |
| SkASSERT(fValid); | |
| return std::launder(reinterpret_cast<Base*>(fData)); | |
| } | |
| Base* operator->() { return this->get(); } | |
| const Base* operator->() const { return this->get(); } | |
| Base& operator*() { return *this->get(); } | |
| const Base& operator*() const { return *this->get(); } | |
| private: | |
| alignas(8) std::byte fData[Size]; | |
| bool fValid = false; | |
| }; | |
| #endif // SkAnySubclass_DEFINED |