80 lines
2.2 KiB
C++
80 lines
2.2 KiB
C++
/*
|
|
* 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
|