• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
has_value()55     bool has_value() const { return fValid; }
56     explicit operator bool() const { return this->has_value(); }
57 
get()58     const Base* get() const {
59         SkASSERT(fValid);
60         return std::launder(reinterpret_cast<const Base*>(fData));
61     }
62 
get()63     Base* get() {
64         SkASSERT(fValid);
65         return std::launder(reinterpret_cast<Base*>(fData));
66     }
67 
68     Base* operator->() { return this->get(); }
69     const Base* operator->() const { return this->get(); }
70 
71     Base& operator*() { return *this->get(); }
72     const Base& operator*() const { return *this->get(); }
73 
74 private:
75     alignas(8) std::byte fData[Size];
76     bool fValid = false;
77 };
78 
79 #endif  // SkAnySubclass_DEFINED
80