neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
optional.hpp
Go to the documentation of this file.
1// optional.hpp
2/*
3 * Copyright (c) 2007, 2021 Leigh Johnston.
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * * Neither the name of Leigh Johnston nor the names of any
19 * other contributors to this software may be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*/
35
36#pragma once
37
38#include <neolib/neolib.hpp>
39#include <optional>
40#include <istream>
41#include <ostream>
44
45namespace neolib
46{
47 template<typename T>
48 class optional;
49
50 template <typename T>
51 struct is_optional<optional<T>> { static constexpr bool value = true; };
52
53 template<typename T>
54 class optional : public reference_counted<i_optional<abstract_t<T>>>
55 {
56 typedef optional<T> self_type;
57 // types
58 public:
60 typedef std::optional<T> std_type;
61 typedef T value_type;
63 typedef const value_type* const_pointer;
68 // construction
69 public:
71 iData{}
72 {
73 }
74 optional(std::nullopt_t) :
75 iData{ std::nullopt }
76 {
77 }
78 optional(value_type const& other) :
79 iData{ other }
80 {
81 }
82 optional(abstract_type const& other) :
83 iData{}
84 {
85 *this = other;
86 }
87 template <typename U, typename = std::enable_if_t<std::is_constructible_v<T, U>, sfinae>>
88 optional(U const& value) :
89 iData{ value }
90 {
91 }
92 // state
93 public:
94 bool has_value() const noexcept final
95 {
96 return iData.has_value();
97 }
98 explicit operator bool() const noexcept final
99 {
100 return has_value();
101 }
102 // std
103 public:
105 {
106 return iData;
107 }
109 {
110 return iData;
111 }
113 {
114 return iData;
115 }
116 // element access
117 public:
119 {
120 return iData.value();
121 }
122 const_reference value() const final
123 {
124 return iData.value();
125 }
127 {
128 if (iData.has_value())
129 return iData.value();
130 else
131 return aDefaultValue;
132 }
134 {
135 if (iData.has_value())
136 return iData.value();
137 else
138 return aDefaultValue;
139 }
141 {
142 if (iData.has_value())
143 return iData.value();
144 else
145 return aDefaultValue;
146 }
148 {
149 return iData.operator*();
150 }
152 {
153 return iData.operator*();
154 }
156 {
157 return iData.operator->();
158 }
160 {
161 return iData.operator->();
162 }
163 // modifiers
164 public:
165 template <typename... Args>
166 reference& emplace(Args&&... args)
167 {
168 iData.emplace(std::forward<Args>(args)...);
169 return value();
170 }
171 void reset() final
172 {
173 iData.reset();
174 }
175 self_type& operator=(std::nullopt_t) noexcept final
176 {
177 iData = std::nullopt;
178 return *this;
179 }
181 {
182 if (rhs.has_value())
183 iData = rhs.value();
184 else
185 iData = std::nullopt;
186 return *this;
187 }
189 {
190 if (rhs.has_value())
191 iData = T{ rhs.value() };
192 else
193 iData = std::nullopt;
194 return *this;
195 }
197 {
198 iData = T{ value };
199 return *this;
200 }
201 public:
202 bool operator==(std::nullopt_t) const
203 {
204 return !has_value();
205 }
206 bool operator!=(std::nullopt_t) const
207 {
208 return has_value();
209 }
210 bool operator==(const optional<T>& that) const
211 {
212 if (has_value() != that.has_value())
213 return false;
214 if (!has_value())
215 return true;
216 return value() == that.value();
217 }
218 std::partial_ordering operator<=>(const optional<T>& that) const
219 {
220 if (has_value() < that.has_value())
221 return std::partial_ordering::less;
222 else if (has_value() > that.has_value())
223 return std::partial_ordering::greater;
224 else if (!has_value())
225 return std::partial_ordering::equivalent;
226 return value() <=> that.value();
227 }
228 private:
229 std::optional<T> iData;
230 };
231
232 template <typename T>
233 inline bool operator==(const optional<T>& lhs, const abstract_t<optional<T>>& rhs)
234 {
235 if (lhs.has_value() != rhs.has_value())
236 return false;
237 if (!lhs.has_value())
238 return true;
239 return lhs.value() == rhs.value();
240 }
241
242 template <typename T>
243 inline bool operator==(const abstract_t<optional<T>>& lhs, const optional<T>& rhs)
244 {
245 if (lhs.has_value() != rhs.has_value())
246 return false;
247 if (!lhs.has_value())
248 return true;
249 return lhs.value() == rhs.value();
250 }
251
252 template <typename T>
253 inline std::partial_ordering operator<=>(const optional<T>& lhs, const abstract_t<optional<T>>& rhs)
254 {
255 if (lhs.has_value() < rhs.has_value())
256 return std::partial_ordering::less;
257 else if (lhs.has_value() > rhs.has_value())
258 return std::partial_ordering::greater;
259 else if (!lhs.has_value())
260 return std::partial_ordering::equivalent;
261 return lhs.value() <=> rhs.value();
262 }
263
264 template <typename T>
265 inline std::partial_ordering operator<=>(const abstract_t<optional<T>>& lhs, const optional<T>& rhs)
266 {
267 if (lhs.has_value() < rhs.has_value())
268 return std::partial_ordering::less;
269 else if (lhs.has_value() > rhs.has_value())
270 return std::partial_ordering::greater;
271 else if (!lhs.has_value())
272 return std::partial_ordering::equivalent;
273 return lhs.value() <=> rhs.value();
274 }
275
276 template <typename T, typename U, typename = std::enable_if_t<!is_optional_v<U>, sfinae>>
277 inline bool operator==(const optional<T>& lhs, const U& rhs)
278 {
279 if (!lhs.has_value())
280 return false;
281 return lhs.value() == rhs;
282 }
283
284 template <typename T, typename U, typename = std::enable_if_t<!is_optional_v<U>, sfinae>>
285 inline bool operator==(const U& lhs, const optional<T>& rhs)
286 {
287 if (!rhs.has_value())
288 return false;
289 return lhs == rhs.value();
290 }
291
292 template <typename T, typename U, typename = std::enable_if_t<!is_optional_v<U>, sfinae>>
293 inline std::partial_ordering operator<=>(const optional<T>& lhs, const U& rhs)
294 {
295 if (!lhs.has_value())
296 return std::partial_ordering::less;
297 else
298 return lhs.value() <=> rhs;
299 }
300
301 template <typename T, typename U, typename = std::enable_if_t<!is_optional_v<U>, sfinae>>
302 inline std::partial_ordering operator<=>(const U& lhs, const optional<T>& rhs)
303 {
304 if (!rhs.has_value())
305 return std::partial_ordering::greater;
306 else
307 return lhs <=> rhs.value();
308 }
309
310 template <typename T, std::enable_if_t<!std::is_same_v<T, abstract_t<T>>, int> = 0>
311 inline std::partial_ordering operator<=>(const optional<T>& lhs, const abstract_t<T>& rhs)
312 {
313 if (!lhs.has_value())
314 return std::partial_ordering::less;
315 else
316 return lhs.value() <=> rhs;
317 }
318
319 template <typename T, std::enable_if_t<!std::is_same_v<T, abstract_t<T>>, int> = 0>
320 inline std::partial_ordering operator<=>(const abstract_t<T>& lhs, const optional<T>& rhs)
321 {
322 if (!rhs.has_value())
323 return std::partial_ordering::greater;
324 else
325 return lhs <=> rhs.value();
326 }
327
328 template <typename T>
329 struct optional_type { typedef T type; };
330 template <typename T>
331 struct optional_type<std::optional<T>> { typedef T type; };
332 template <typename T>
333 struct optional_type<optional<T>> { typedef T type; };
334
335 template <typename T>
337
338 template <typename Elem, typename Traits, typename T>
339 inline std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& aStream, optional<T> const& aOptional)
340 {
341 if (aOptional.has_value())
342 aStream << aOptional.value();
343 else
344 aStream << '?';
345 return aStream;
346 }
347
348 template <typename Elem, typename Traits, typename T>
349 inline std::basic_istream<Elem, Traits>& operator>>(std::basic_istream<Elem, Traits>& aStream, optional<T>& aOptional)
350 {
351 char temp;
352 aStream >> temp;
353 if (temp != '?')
354 {
355 aStream.unget();
356 aOptional.emplace();
357 aStream >> aOptional.value();
358 }
359 return aStream;
360 }
361}
std::optional< T > std_type
Definition optional.hpp:60
optional(U const &value)
Definition optional.hpp:88
reference value() final
Definition optional.hpp:118
bool has_value() const noexcept final
Definition optional.hpp:94
self_type & operator=(std::nullopt_t) noexcept final
Definition optional.hpp:175
reference & emplace(Args &&... args)
Definition optional.hpp:166
const value_type * const_pointer
Definition optional.hpp:63
bool operator==(std::nullopt_t) const
Definition optional.hpp:202
const std_type & as_std_optional() const
Definition optional.hpp:104
abstract_type::const_reference abstract_const_reference
Definition optional.hpp:67
optional(abstract_type const &other)
Definition optional.hpp:82
optional(std::nullopt_t)
Definition optional.hpp:74
i_optional< abstract_t< T > > abstract_type
Definition optional.hpp:59
const_pointer operator->() const final
Definition optional.hpp:159
self_type & operator=(const abstract_type &rhs) final
Definition optional.hpp:188
bool operator!=(std::nullopt_t) const
Definition optional.hpp:206
void reset() final
Definition optional.hpp:171
pointer operator->() final
Definition optional.hpp:155
const_reference operator*() const final
Definition optional.hpp:151
abstract_const_reference value_or(abstract_reference aDefaultValue) const final
Definition optional.hpp:133
self_type & operator=(const abstract_t< T > &value) final
Definition optional.hpp:196
std_type & as_std_optional()
Definition optional.hpp:108
value_type & reference
Definition optional.hpp:64
const value_type & const_reference
Definition optional.hpp:65
reference operator*() final
Definition optional.hpp:147
abstract_type::reference abstract_reference
Definition optional.hpp:66
abstract_reference value_or(abstract_reference aDefaultValue) final
Definition optional.hpp:140
bool operator==(const optional< T > &that) const
Definition optional.hpp:210
const_reference value() const final
Definition optional.hpp:122
value_type * pointer
Definition optional.hpp:62
self_type & operator=(const self_type &rhs)
Definition optional.hpp:180
std::partial_ordering operator<=>(const optional< T > &that) const
Definition optional.hpp:218
abstract_const_reference value_or(abstract_const_reference aDefaultValue) const final
Definition optional.hpp:126
optional(value_type const &other)
Definition optional.hpp:78
std_type to_std_optional() const
Definition optional.hpp:112
typename detail::abstract_type< T >::type abstract_t
Definition neolib.hpp:178
typename optional_type< T >::type optional_t
Definition optional.hpp:336
std::partial_ordering operator<=>(const i_container< T, ConstIteratorType, IteratorType > &lhs, const i_container< T, ConstIteratorType, IteratorType > &rhs)
Definition plf_hive.h:79
static constexpr bool value