/* * 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 #include #include // IWYU pragma: keep #include /** * 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 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 void emplace(Args&&... args) { static_assert(std::is_base_of_v); static_assert(sizeof(T) <= Size); // We're going to clean up our stored object by calling ~Base: static_assert(std::has_virtual_destructor_v || std::is_trivially_destructible_v); SkASSERT(!fValid); new (fData) T(std::forward(args)...); fValid = true; } void reset() { if (fValid) { this->get()->~Base(); } fValid = false; } const Base* get() const { SkASSERT(fValid); return std::launder(reinterpret_cast(fData)); } Base* get() { SkASSERT(fValid); return std::launder(reinterpret_cast(fData)); } 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