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