fennec
Loading...
Searching...
No Matches
optional.h
Go to the documentation of this file.
1// =====================================================================================================================
2// fennec, a free and open source game engine
3// Copyright © 2025 Medusa Slockbower
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17// =====================================================================================================================
18
30
31#ifndef FENNEC_CONTAINERS_OPTIONAL_H
32#define FENNEC_CONTAINERS_OPTIONAL_H
33
34#include <fennec/lang/utility.h>
35#include <fennec/memory/new.h>
36
37#include <fennec/lang/assert.h>
38
39namespace fennec
40{
41
42struct nullopt_t {};
43constexpr nullopt_t nullopt_v = {};
44
45#define nullopt nullopt_v
46
50template<typename T>
51struct optional {
52
53// Definitions =========================================================================================================
54public:
55 using reference_t = T&;
56 using pointer_t = T*;
57 using const_reference_t = T&;
58 using const_pointer_t = const T*;
59
60
61// Constructors ========================================================================================================
62
65
68 constexpr optional()
69 : _root(0)
70 , _set(false) {
71 }
72
75 constexpr optional(nullopt_t)
76 : _root(0)
77 , _set(false) {
78 }
79
83 constexpr optional(const T& val)
84 : _val(val)
85 , _set(true) {
86 }
87
91 constexpr optional(T&& val)
92 : _val(fennec::forward<T>(val))
93 , _set(true) {
94 }
95
99 constexpr optional(const optional& opt) requires is_copy_assignable_v<T>
100 : optional() {
101 _set = opt._set;
102 if (_set) {
103 _val = opt._val;
104 }
105 }
106
110 constexpr optional(optional&& opt) noexcept requires is_move_assignable_v<T>
111 : optional() {
112 _set = opt._set;
113 if (_set) {
114 _val = fennec::move(opt._val);
115 }
116 opt = nullopt;
117 }
118
119 template<typename...ArgsT>
120 constexpr optional(ArgsT&&...args)
121 : _val(fennec::forward<ArgsT>(args)...)
122 , _set(true) {
123 }
124
125 constexpr ~optional() {
126 if constexpr(is_fundamental_v<T>) {
127 return;
128 }
129 if (_set) {
130 fennec::destruct(&_val);
131 }
132 }
133
135
136
137// Properties ==========================================================================================================
138
141
144 constexpr operator bool() const {
145 return _set;
146 }
147
150 constexpr bool empty() const {
151 return not _set;
152 }
153
155
156
157// Assignment Operators ================================================================================================
158
161
165 constexpr optional& operator=(nullopt_t) {
166 if constexpr(not is_fundamental_v<T>) {
167 if (_set) {
168 fennec::destruct(&_val);
169 }
170 }
171 _root = '\0';
172 _set = false;
173 return *this;
174 }
175
179 constexpr optional& operator=(const T& val) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
180 if (_set) {
181 _val = val;
182 } else {
183 fennec::construct(&_val, val);
184 _set = true;
185 }
186 return *this;
187 }
188
192 constexpr optional& operator=(T&& val) requires is_move_constructible_v<T> and is_move_assignable_v<T> {
193 if (_set) {
194 _val = fennec::forward<T>(val);
195 } else {
196 fennec::construct(&_val, fennec::forward<T>(val));
197 _set = true;
198 }
199 return *this;
200 }
201
205 constexpr optional& operator=(const optional& opt) requires is_copy_constructible_v<T> and is_copy_assignable_v<T> {
206 if (_set != opt._set) {
207 _set = opt._set;
208 if (_set) { // Construct
209 fennec::construct(&_val, opt._val);
210 } else { // Destruct
211 fennec::destruct(&_val);
212 _root = 0;
213 }
214 } else if (_set) { // Copy Assignment
215 _val = opt._val;
216 }
217 return *this;
218 }
219
223 constexpr optional& operator=(optional&& opt) noexcept requires is_move_constructible_v<T> and is_move_assignable_v<T> {
224 if (_set != opt._set) {
225 _set = opt._set;
226 if (_set) { // Construct
227 fennec::construct(&_val, fennec::move(opt._val));
228 } else { // Destruct
229 fennec::destruct(&_val);
230 _root = 0;
231 }
232 } else if (_set) { // Copy Assignment
233 _val = fennec::move(opt._val);
234 }
235 return *this;
236 }
237
239
240
241// Access ==============================================================================================================
242
245
248 constexpr pointer_t operator->() noexcept {
249 return _set ? &_val : nullptr;
250 }
251
254 constexpr const_pointer_t operator->() const noexcept {
255 return _set ? &_val : nullptr;
256 }
257
261 constexpr T& operator*() & noexcept {
262 assertd(_set, "Attempted to reference the value of an unset optional");
263 return _val;
264 }
265
269 constexpr const T& operator*() const& noexcept {
270 assertd(_set, "Attempted to reference the value of an unset optional");
271 return _val;
272 }
273
277 constexpr T&& operator*() && noexcept {
278 assertd(_set, "Attempted to reference the value of an unset optional");
279 return _val;
280 }
281
285 constexpr const T&& operator*() const&& noexcept {
286 assertd(_set, "Attempted to reference the value of an unset optional");
287 return _val;
288 }
289
291
292// Modifiers ===========================================================================================================
293
296
300 constexpr T& emplace(T&& val) {
301 if (_set) {
302 _val = fennec::forward<T>(val);
303 } else {
304 fennec::construct(&_val, fennec::forward<T>(val));
305 _set = true;
306 }
307 return _val;
308 }
309
313 constexpr T& emplace(const T& val) {
314 if (_set) {
315 _val = val;
316 } else {
317 fennec::construct(&_val, val);
318 _set = true;
319 }
320 return _val;
321 }
322
326 template<typename...ArgsT>
327 constexpr T& emplace(ArgsT&&...args) {
328 if (_set) {
329 _val = T(fennec::forward<ArgsT>(args)...);
330 } else {
331 fennec::construct(&_val, fennec::forward<ArgsT>(args)...);
332 _set = true;
333 }
334 return _val;
335 }
336
339 void reset() {
340 this->operator=(nullopt);
341 }
342
344
345
346
347
348private:
349 union {
350 char _root;
351 T _val;
352 };
353 bool _set;
354};
355
356}
357
358#endif // FENNEC_CONTAINERS_OPTIONAL_H
Assertions
This header contains functions related to analyzing, modifying or copying buffers interpreted as byte...
Structure to hold an optional value.
Definition optional.h:51
constexpr const_pointer_t operator->() const noexcept
Definition optional.h:254
constexpr pointer_t operator->() noexcept
Definition optional.h:248
constexpr optional & operator=(nullopt_t)
Fundamental Type Assignment.
Definition optional.h:165
constexpr T & emplace(T &&val)
Emplace Assignment, Move overload.
Definition optional.h:300
constexpr optional(T &&val)
Type Move Constructor.
Definition optional.h:91
constexpr T & operator*() &noexcept
Dereference Operator.
Definition optional.h:261
constexpr optional(const optional &opt)
Copy Constructor.
Definition optional.h:99
constexpr T && operator*() &&noexcept
Dereference Operator.
Definition optional.h:277
constexpr optional(const T &val)
Type Copy Constructor.
Definition optional.h:83
constexpr T & emplace(const T &val)
Emplace Assignment, Copy overload.
Definition optional.h:313
void reset()
Reset the Optional.
Definition optional.h:339
constexpr optional()
Default Constructor.
Definition optional.h:68
constexpr const T && operator*() const &&noexcept
Const Dereference Operator.
Definition optional.h:285
constexpr T & emplace(ArgsT &&...args)
Emplace Assignment.
Definition optional.h:327
constexpr bool empty() const
Definition optional.h:150
constexpr optional & operator=(optional &&opt) noexcept and is_move_assignable_v< T >
Move Assignment.
Definition optional.h:223
constexpr optional(optional &&opt) noexcept
Move Constructor.
Definition optional.h:110
constexpr const T & operator*() const &noexcept
Const Dereference Operator.
Definition optional.h:269
constexpr optional & operator=(const T &val) and is_copy_assignable_v< T >
Type Copy Assignment.
Definition optional.h:179
constexpr optional(nullopt_t)
Default Constructor.
Definition optional.h:75
constexpr optional & operator=(T &&val) and is_move_assignable_v< T >
Type Move Assignment.
Definition optional.h:192
constexpr optional & operator=(const optional &opt) and is_copy_assignable_v< T >
Copy Assignment.
Definition optional.h:205
Utility
constexpr T && forward(remove_reference_t< T > &x) noexcept
forwards reference types to extend their lifetime
Definition utility.h:75
constexpr remove_reference_t< T > && move(T &&x) noexcept
produces an x-value type to indicate x may be "moved"
Definition utility.h:92