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 <optional>
12#include <type_traits>
13
14namespace tt {
15
26template<typename BaseType, size_t Capacity>
28public:
29 using value_type = BaseType;
30 using reference = value_type &;
31 using const_reference = value_type const &;
32 using pointer = value_type *;
33 using const_pointer = value_type const *;
34
35 static constexpr size_t capacity = Capacity;
36
40 {
41 reset();
42 }
43
44 polymorphic_optional(polymorphic_optional const &other) = delete;
46 polymorphic_optional &operator=(polymorphic_optional const &other) = delete;
47 polymorphic_optional &operator=(polymorphic_optional &&other) = delete;
48
51 [[nodiscard]] constexpr polymorphic_optional() noexcept : _state(state::empty) {}
52
57 template<typename Other>
58 requires(is_different_v<Other, value_type>) [[nodiscard]] polymorphic_optional(Other &&other) noexcept
59 {
60 static_assert(std::is_base_of_v<value_type, std::remove_cvref_t<Other>>);
61 _state = state::empty;
62 emplace<std::remove_cvref_t<Other>>(std::forward<Other>(other));
63 }
64
70 template<decayed_derived_from<value_type> Other>
71 polymorphic_optional &operator=(Other &&other) noexcept
72 {
73 emplace<std::remove_cvref_t<Other>>(std::forward<Other>(other));
74 return *this;
75 }
76
83 template<derived_from<value_type> T, typename... Args>
84 reference emplace(Args &&...args) noexcept
85 {
86 reset();
87
88 pointer r;
89 if (sizeof(T) <= capacity) {
90 r = new (_value.buffer.data()) T(std::forward<Args>(args)...);
91 _state = state::internal;
92
93 } else {
94 r = _value.pointer = new T(std::forward<Args>(args)...);
95 _state = state::external;
96 }
97 tt_axiom(r != nullptr);
98 return *r;
99 }
100
105 [[nodiscard]] bool has_value() const noexcept
106 {
107 return _state != state::empty;
108 }
109
114 [[nodiscard]] operator bool() const noexcept
115 {
116 return has_value();
117 }
118
121 void reset() noexcept
122 {
123 if (_state != state::empty) {
124 [[unlikely]] reset_deep();
125 }
126 }
127
133 [[nodiscard]] const_reference value() const &noexcept
134 {
135 if (_state == state::empty) {
137 }
138 return *_pointer();
139 }
140
146 [[nodiscard]] reference value() &noexcept
147 {
148 if (_state == state::empty) {
150 }
151 return *_pointer();
152 }
153
160 [[nodiscard]] const_reference operator*() const noexcept
161 {
162 tt_axiom(_state != state::empty);
163 return *_pointer();
164 }
165
172 [[nodiscard]] reference operator*() noexcept
173 {
174 tt_axiom(_state != state::empty);
175 return *_pointer();
176 }
177
182 [[nodiscard]] const_pointer operator->() const noexcept
183 {
184 return _pointer();
185 }
186
191 [[nodiscard]] pointer operator->() noexcept
192 {
193 return _pointer();
194 }
195
196private:
197 enum class state : uint8_t { empty, internal, external };
198
199 state _state;
200
201 union {
202 pointer pointer;
203 // The pointer will align the buffer properly.
205 } _value;
206
207 tt_no_inline void reset_deep() noexcept
208 {
209 if (_state == state::internal) {
210 std::destroy_at(internal_pointer());
211 } else if (_state == state::external) {
212 delete external_pointer();
213 }
214 _state = state::empty;
215 }
216
217 [[nodiscard]] const_pointer internal_pointer() const noexcept
218 {
219 tt_axiom(_state == state::internal);
220 return std::launder(reinterpret_cast<const_pointer>(_value.buffer.data()));
221 }
222
223 [[nodiscard]] pointer internal_pointer() noexcept
224 {
225 tt_axiom(_state == state::internal);
226 return std::launder(reinterpret_cast<pointer>(_value.buffer.data()));
227 }
228
229 [[nodiscard]] const_pointer external_pointer() const noexcept
230 {
231 tt_axiom(_state == state::external);
232 return std::launder(_value.pointer);
233 ;
234 }
235
236 [[nodiscard]] pointer external_pointer() noexcept
237 {
238 tt_axiom(_state == state::external);
239 return std::launder(_value.pointer);
240 ;
241 }
242
247 [[nodiscard]] const_pointer _pointer() const noexcept
248 {
249 if (_state == state::internal) {
250 return internal_pointer();
251 } else if (_state == state::external) {
252 return external_pointer();
253 } else {
254 return nullptr;
255 }
256 }
257
262 [[nodiscard]] pointer _pointer() noexcept
263 {
264 if (_state == state::internal) {
265 return internal_pointer();
266 } else if (_state == state::external) {
267 return external_pointer();
268 } else {
269 return nullptr;
270 }
271 }
272};
273
274} // namespace tt
Polymorphic optional.
Definition polymorphic_optional.hpp:27
polymorphic_optional(Other &&other) noexcept
Construct an object as value.
Definition polymorphic_optional.hpp:58
reference value() &noexcept
Returns the contained value.
Definition polymorphic_optional.hpp:146
void reset() noexcept
Destroys any contained value.
Definition polymorphic_optional.hpp:121
bool has_value() const noexcept
Check whether the object contains a value.
Definition polymorphic_optional.hpp:105
polymorphic_optional & operator=(Other &&other) noexcept
Assign an object.
Definition polymorphic_optional.hpp:71
pointer operator->() noexcept
Get a pointer to the contained value.
Definition polymorphic_optional.hpp:191
constexpr polymorphic_optional() noexcept
Construct an empty value.
Definition polymorphic_optional.hpp:51
reference operator*() noexcept
Dereference the contained value.
Definition polymorphic_optional.hpp:172
reference emplace(Args &&...args) noexcept
Construct the contained value in-place.
Definition polymorphic_optional.hpp:84
const_pointer operator->() const noexcept
Get a pointer to the contained value.
Definition polymorphic_optional.hpp:182
const_reference operator*() const noexcept
Dereference the contained value.
Definition polymorphic_optional.hpp:160
const_reference value() const &noexcept
Returns the contained value.
Definition polymorphic_optional.hpp:133
~polymorphic_optional()
Destroy any contained value.
Definition polymorphic_optional.hpp:39
Definition concepts.hpp:34
Definition concepts.hpp:37