xref: /aosp_15_r20/external/skia/include/private/base/SkAnySubclass.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 
get()55     const Base* get() const {
56         SkASSERT(fValid);
57         return std::launder(reinterpret_cast<const Base*>(fData));
58     }
59 
get()60     Base* get() {
61         SkASSERT(fValid);
62         return std::launder(reinterpret_cast<Base*>(fData));
63     }
64 
65     Base* operator->() { return this->get(); }
66     const Base* operator->() const { return this->get(); }
67 
68 private:
69     alignas(8) std::byte fData[Size];
70     bool fValid = false;
71 };
72 
73 #endif  // SkAnySubclass_DEFINED
74