HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
polymorphic_optional.hpp
1// Copyright Take Vos 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "assert.hpp"
8#include "concepts.hpp"
9#include <array>
10#include <memory>
11#include <type_traits>
12
13namespace tt {
14
25template<typename BaseType, size_t Capacity>
26class alignas(16) polymorphic_optional {
27public:
28 using value_type = BaseType;
29 using reference = value_type &;
30 using const_reference = value_type const &;
31 using pointer = value_type *;
32 using const_pointer = value_type const *;
33
34 static constexpr size_t capacity = Capacity;
35
39 {
40 reset();
41 }
42
43 polymorphic_optional(polymorphic_optional const &other) = delete;
45 polymorphic_optional &operator=(polymorphic_optional const &other) = delete;
46 polymorphic_optional &operator=(polymorphic_optional &&other) = delete;
47
50 [[nodiscard]] constexpr polymorphic_optional() noexcept : _state(state::empty) {}
51
56 template<typename Other>
57 requires(is_different_v<Other, value_type>) [[nodiscard]] polymorphic_optional(Other &&other) noexcept
58 {
59 static_assert(std::is_base_of_v<value_type, std::remove_cvref_t<Other>>);
60 _state = state::empty;
61 emplace<std::remove_cvref_t<Other>>(std::forward<Other>(other));
62 }
63
69 template<decayed_derived_from<value_type> Other>
70 polymorphic_optional &operator=(Other &&other) noexcept
71 {
72 emplace<std::remove_cvref_t<Other>>(std::forward<Other>(other));
73 return *this;
74 }
75
82 template<derived_from<value_type> T, typename... Args>
83 reference emplace(Args &&...args) noexcept
84 {
85 reset();
86
87 pointer r;
88 if (sizeof(T) <= capacity) {
89 r = new (_value.buffer.data()) T(std::forward<Args>(args)...);
90 _state = state::internal;
91
92 } else {
93 r = _value.pointer = new T(std::forward<Args>(args)...);
94 _state = state::external;
95 }
96 tt_axiom(r != nullptr);
97 return *r;
98 }
99
104 [[nodiscard]] bool has_value() const noexcept
105 {
106 return _state != state::empty;
107 }
108
113 [[nodiscard]] operator bool() const noexcept
114 {
115 return has_value();
116 }
117
120 void reset() noexcept
121 {
122 if (_state != state::empty) {
123 [[unlikely]] reset_deep();
124 }
125 }
126
132 [[nodiscard]] const_reference value() const &noexcept
133 {
134 if (_state == state::empty) {
136 }
137 return *_pointer();
138 }
139
145 [[nodiscard]] reference value() &noexcept
146 {
147 if (_state == state::empty) {
149 }
150 return *_pointer();
151 }
152
159 [[nodiscard]] const_reference operator*() const noexcept
160 {
161 tt_axiom(_state != state::empty);
162 return *_pointer();
163 }
164
171 [[nodiscard]] reference operator*() noexcept
172 {
173 tt_axiom(_state != state::empty);
174 return *_pointer();
175 }
176
181 [[nodiscard]] const_pointer operator->() const noexcept
182 {
183 return _pointer();
184 }
185
190 [[nodiscard]] pointer operator->() noexcept
191 {
192 return _pointer();
193 }
194
195private:
196 enum state { empty, internal, external };
197
198 union {
200 pointer pointer;
201 } _value;
202 state _state;
203
204 tt_no_inline void reset_deep() noexcept
205 {
206 if (_state == state::internal) {
207 std::destroy_at(internal_pointer());
208 } else if (_state == state::external) {
209 delete external_pointer();
210 }
211 _state = state::empty;
212 }
213
214 [[nodiscard]] const_pointer internal_pointer() const noexcept
215 {
216 tt_axiom(_state == state::internal);
217 return std::launder(reinterpret_cast<const_pointer>(_value.buffer.data()));
218 }
219
220 [[nodiscard]] pointer internal_pointer() noexcept
221 {
222 tt_axiom(_state == state::internal);
223 return std::launder(reinterpret_cast<pointer>(_value.buffer.data()));
224 }
225
226 [[nodiscard]] const_pointer external_pointer() const noexcept
227 {
228 tt_axiom(_state == state::external);
229 return std::launder(_value.pointer);
230 ;
231 }
232
233 [[nodiscard]] pointer external_pointer() noexcept
234 {
235 tt_axiom(_state == state::external);
236 return std::launder(_value.pointer);
237 ;
238 }
239
244 [[nodiscard]] const_pointer _pointer() const noexcept
245 {
246 switch (_state) {
247 case state::internal: return internal_pointer();
248 case state::external: return external_pointer();
249 case state::empty: return nullptr;
250 default: tt_no_default();
251 }
252 }
253
258 [[nodiscard]] pointer _pointer() noexcept
259 {
260 switch (_state) {
261 case state::internal: return internal_pointer();
262 case state::external: return external_pointer();
263 case state::empty: return nullptr;
264 default: tt_no_default();
265 }
266 }
267};
268
269} // namespace tt
Polymorphic optional.
Definition polymorphic_optional.hpp:26
polymorphic_optional(Other &&other) noexcept
Construct an object as value.
Definition polymorphic_optional.hpp:57
reference value() &noexcept
Returns the contained value.
Definition polymorphic_optional.hpp:145
void reset() noexcept
Destroys any contained value.
Definition polymorphic_optional.hpp:120
bool has_value() const noexcept
Check whether the object contains a value.
Definition polymorphic_optional.hpp:104
polymorphic_optional & operator=(Other &&other) noexcept
Assign an object.
Definition polymorphic_optional.hpp:70
pointer operator->() noexcept
Get a pointer to the contained value.
Definition polymorphic_optional.hpp:190
constexpr polymorphic_optional() noexcept
Construct an empty value.
Definition polymorphic_optional.hpp:50
reference operator*() noexcept
Dereference the contained value.
Definition polymorphic_optional.hpp:171
reference emplace(Args &&...args) noexcept
Construct the contained value in-place.
Definition polymorphic_optional.hpp:83
const_pointer operator->() const noexcept
Get a pointer to the contained value.
Definition polymorphic_optional.hpp:181
const_reference operator*() const noexcept
Dereference the contained value.
Definition polymorphic_optional.hpp:159
const_reference value() const &noexcept
Returns the contained value.
Definition polymorphic_optional.hpp:132
~polymorphic_optional()
Destroy any contained value.
Definition polymorphic_optional.hpp:38
Definition concepts.hpp:18
Definition concepts.hpp:21