NcEngine
AnyComponentUtility.h
1#pragma once
2
4
5#include <string_view>
6
7namespace nc
8{
9namespace ui::editor
10{
11struct EditorContext;
12} // namespace ui::editor
13
14namespace detail
15{
16class AnyImplStorage;
17
19{
20 virtual ~AnyImplBase() = default;
21 virtual auto Clone(AnyImplStorage& dest) const noexcept -> AnyImplBase* = 0;
22 virtual auto MoveTo(AnyImplStorage& dest) noexcept -> AnyImplBase* = 0;
23 virtual auto Id() const noexcept -> size_t = 0;
24 virtual auto Name() const noexcept -> std::string_view = 0;
25 virtual auto HasDrawUI() const noexcept -> bool = 0;
26 virtual void DrawUI(ui::editor::EditorContext& ctx) = 0;
27
28};
29
30template<PooledComponent T>
32{
33 public:
34 explicit AnyImplConcrete(T* instance, ComponentHandler<T>* handler) noexcept
35 : m_instance{instance}, m_handler{handler} {}
36
37 auto Clone(AnyImplStorage& dest) const noexcept -> AnyImplBase* override;
38 auto MoveTo(AnyImplStorage& dest) noexcept -> AnyImplBase* override;
39 auto Id() const noexcept -> size_t override;
40 auto Name() const noexcept -> std::string_view override;
41 auto HasDrawUI() const noexcept -> bool override;
42 void DrawUI(ui::editor::EditorContext& ctx) override;
43
44 private:
45 T* m_instance;
46 ComponentHandler<T>* m_handler;
47};
48
50{
51 public:
52 constexpr AnyImplStorage() noexcept
53 : buffer{} {}
54
55 template<PooledComponent T>
56 AnyImplStorage(T* instance, ComponentHandler<T>* handler);
57
58 ~AnyImplStorage() noexcept;
59 AnyImplStorage(const AnyImplStorage& other) noexcept;
60 AnyImplStorage(AnyImplStorage&& other) noexcept;
61 auto operator=(const AnyImplStorage& other) noexcept -> AnyImplStorage&;
62 auto operator=(AnyImplStorage&& other) noexcept -> AnyImplStorage&;
63
64 auto operator==(const AnyImplStorage& other) const noexcept
65 {
66 return std::ranges::equal(buffer, other.buffer);
67 }
68
69 auto HasValue() const noexcept -> bool
70 {
71 return std::ranges::any_of(buffer, [](auto b) { return b != std::byte{}; });
72 }
73
74 auto AsImpl() noexcept -> AnyImplBase*
75 {
76 return reinterpret_cast<AnyImplBase*>(buffer);
77 }
78
79 auto AsImpl() const noexcept -> const AnyImplBase*
80 {
81 return reinterpret_cast<const AnyImplBase*>(buffer);
82 }
83
84 auto AsStorage() noexcept -> void*
85 {
86 return buffer;
87 }
88
89 private:
90 struct Any{};
92 static constexpr auto align = alignof(Placeholder);
93 static constexpr auto size = sizeof(Placeholder);
94
95 alignas(align) std::byte buffer[size];
96
97 void Clear() noexcept;
98};
99
100template<PooledComponent T>
101auto AnyImplConcrete<T>::Clone(AnyImplStorage& dest) const noexcept -> AnyImplBase*
102{
103 return new (dest.AsStorage()) AnyImplConcrete<T>{*this};
104}
105
106template<PooledComponent T>
107auto AnyImplConcrete<T>::MoveTo(AnyImplStorage& dest) noexcept -> AnyImplBase*
108{
109 return new (dest.AsStorage()) AnyImplConcrete<T>{std::move(*this)};
110}
111
112template<PooledComponent T>
113auto AnyImplConcrete<T>::Id() const noexcept -> size_t
114{
115 return m_handler->id;
116}
117
118template<PooledComponent T>
119auto AnyImplConcrete<T>::Name() const noexcept -> std::string_view
120{
121 return m_handler->name;
122}
123
124template<PooledComponent T>
125auto AnyImplConcrete<T>::HasDrawUI() const noexcept -> bool
126{
127 return m_handler->drawUI != nullptr;
128}
129
130template<PooledComponent T>
131void AnyImplConcrete<T>::DrawUI(ui::editor::EditorContext& ctx)
132{
133 m_handler->drawUI(*m_instance, ctx, m_handler->userData);
134}
135
136template<PooledComponent T>
137AnyImplStorage::AnyImplStorage(T* instance, ComponentHandler<T>* handler)
138{
139 NC_ASSERT(instance && handler, "AnyComponent params must not be null, use AnyComponent() instead.")
140 using Impl = detail::AnyImplConcrete<T>;
141
142 // Only place we know the derived Impl type - validate all of our assumptions.
143 static_assert(sizeof(Impl) == size &&
144 alignof(Impl) == align &&
145 std::has_virtual_destructor_v<Impl> &&
146 std::is_nothrow_destructible_v<Impl> &&
147 std::is_nothrow_copy_constructible_v<Impl> &&
148 std::is_nothrow_move_constructible_v<Impl> &&
149 std::is_nothrow_copy_assignable_v<Impl> &&
150 std::is_nothrow_move_assignable_v<Impl>);
151
152 new (buffer) Impl{instance, handler};
153}
154
155inline AnyImplStorage::~AnyImplStorage() noexcept
156{
157 if (HasValue())
158 {
159 AsImpl()->~AnyImplBase();
160 }
161}
162
163inline AnyImplStorage::AnyImplStorage(const AnyImplStorage& other) noexcept
164 : buffer{}
165{
166 if (other.HasValue())
167 {
168 other.AsImpl()->Clone(*this);
169 }
170}
171
172inline AnyImplStorage::AnyImplStorage(AnyImplStorage&& other) noexcept
173 : buffer{}
174{
175 if (other.HasValue())
176 {
177 other.AsImpl()->MoveTo(*this);
178 }
179}
180
181inline auto AnyImplStorage::operator=(const AnyImplStorage& other) noexcept -> AnyImplStorage&
182{
183 Clear();
184 if (other.HasValue())
185 {
186 other.AsImpl()->Clone(*this);
187 }
188
189 return *this;
190}
191
192inline auto AnyImplStorage::operator=(AnyImplStorage&& other) noexcept -> AnyImplStorage&
193{
194 Clear();
195 if (other.HasValue())
196 {
197 other.AsImpl()->MoveTo(*this);
198 }
199
200 return *this;
201}
202
203inline void AnyImplStorage::Clear() noexcept
204{
205 if (HasValue())
206 {
207 AsImpl()->~AnyImplBase();
208 std::memset(buffer, 0, size);
209 }
210}
211} // namespace detail
212} // namespace nc
Definition: AnyComponentUtility.h:32
Definition: AnyComponentUtility.h:50
Optional data and callbacks for generic component operations.
Definition: Component.h:101
Definition: AnyComponentUtility.h:19
State for the editor.
Definition: EditorContext.h:39