UdonLibrary 1.0.0
機械システム研究部 C++ ライブラリ
読み取り中…
検索中…
一致する文字列を見つけられません
Optional.hpp
[詳解]
1//
2// Optional
3//
4// Copyright (c) 2022-2024 udonrobo
5//
6
7#pragma once
8
10#include <Udon/Utility/Show.hpp>
11#include <type_traits>
12#include <new>
13
14#if __has_include(<new.h>)
15# include <new.h>
16#endif
17
18namespace Udon
19{
20
21#if UDON_PLATFORM_ENABLE_EXCEPTION
22 struct BadOptionalAccess : public std::exception
23 {
24 const char* what() const noexcept override
25 {
26 return "Bad Optional Access";
27 }
28 };
29 inline void ThrowBadOptionalAccess(bool throwException)
30 {
31 if (throwException)
32 {
33 throw BadOptionalAccess{};
34 }
35 }
36#else
37 inline void ThrowBadOptionalAccess(bool /* throwException */)
38 {
39 }
40#endif
41
45 struct NulloptT
46 {
47 };
48
52 constexpr NulloptT nullopt{};
53
54
60 template <typename T>
62 {
63
64 static_assert(std::is_nothrow_destructible<T>::value, "T must be nothrow destructible");
65
66 static_assert(not std::is_same<typename std::remove_cv<T>::type, NulloptT>::value, "T must not be the same as NulloptT");
67
68 static_assert(not std::is_array<T>::value, "T must not be an array");
69
70 template <typename> friend class Optional;
71
72 public:
73 using ValueType = T;
74
78 constexpr Optional() noexcept
79 : mStorage()
80 , mHasValue()
81 {
82 }
83
84
89 constexpr Optional(NulloptT)
90 : mStorage()
91 , mHasValue()
92 {
93 }
94
95
100 template <typename U, typename std::enable_if<std::is_constructible<ValueType, U>::value, std::nullptr_t>::type = nullptr>
101 Optional(U&& value) noexcept(std::is_nothrow_constructible<ValueType>::value)
102 : mStorage()
103 , mHasValue(true)
104 {
105 ConstructValue(std::forward<U>(value));
106 }
107
108
114 template <typename U, typename std::enable_if<std::is_constructible<ValueType, const U&>::value, std::nullptr_t>::type = nullptr>
115 Optional(const Optional<U>& other) noexcept(std::is_nothrow_constructible<ValueType, U>::value)
116 : mStorage()
117 , mHasValue(other.mHasValue)
118 {
119 if (mHasValue)
120 {
121 ConstructValue(other.mStorage.value);
122 }
123 }
124
125
131 template <typename U, typename std::enable_if<std::is_constructible<ValueType, U&&>::value, std::nullptr_t>::type = nullptr>
132 Optional(Optional<U>&& other) noexcept(std::is_nothrow_constructible<ValueType, U>::value)
133 : mStorage()
134 , mHasValue(other.mHasValue)
135 {
136 if (mHasValue)
137 {
138 ConstructValue(std::move(other.mStorage.value));
139 }
140 }
141
142
146 ~Optional() noexcept
147 {
148 reset();
149 }
150
151
158 {
159 reset();
160 return *this;
161 }
162
163
169 // template <typename U>
170 template <typename U, typename std::enable_if<std::is_constructible<ValueType, U>::value and std::is_assignable<ValueType, U>::value, std::nullptr_t>::type = nullptr>
171 Optional& operator=(U&& value) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
172 {
173 AssignmentValue(std::forward<U>(value));
174 return *this;
175 }
176
177
182 template <typename U, typename std::enable_if<std::is_constructible<ValueType, const U&>::value and std::is_assignable<ValueType, const U&>::value, std::nullptr_t>::type = nullptr>
183 Optional& operator=(const Optional<U>& other) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
184 {
185 if (other)
186 {
187 AssignmentValue(other.value());
188 }
189 else
190 {
191 reset();
192 }
193 return *this;
194 }
195
196
201 template <typename U, typename std::enable_if<std::is_constructible<ValueType, U&&>::value and std::is_assignable<ValueType, U&&>::value, std::nullptr_t>::type = nullptr>
202 Optional& operator=(Optional<U>&& other) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
203 {
204 if (other)
205 {
206 AssignmentValue(std::move(other.value()));
207 }
208 else
209 {
210 reset();
211 }
212 return *this;
213 }
214
215
221 friend bool operator==(const Optional& lhs, const Optional& rhs) noexcept
222 {
223 if (lhs and rhs)
224 {
225 return *lhs == *rhs;
226 }
227 if (not lhs and not rhs)
228 {
229 return true; // nullopt == nullopt
230 }
231 return false;
232 }
233
239 friend bool operator!=(const Optional& lhs, const Optional& rhs) noexcept
240 {
241 return not(lhs == rhs);
242 }
243
249 friend bool operator<(const Optional& lhs, const Optional& rhs) noexcept
250 {
251 if (lhs and rhs)
252 {
253 return *lhs < *rhs;
254 }
255 if (not rhs)
256 {
257 return false;
258 }
259 return not lhs;
260 }
261
267 friend bool operator>(const Optional& lhs, const Optional& rhs) noexcept
268 {
269 return rhs < lhs;
270 }
271
277 friend bool operator>=(const Optional& lhs, const Optional& rhs) noexcept
278 {
279 return not(lhs < rhs);
280 }
281
287 friend bool operator<=(const Optional& lhs, const Optional& rhs) noexcept
288 {
289 return not(rhs < lhs);
290 }
291
292
297 explicit constexpr operator bool() const noexcept
298 {
299 return mHasValue;
300 }
301
302
307 constexpr bool hasValue() const noexcept
308 {
309 return mHasValue;
310 }
311
312
319 {
320 ThrowBadOptionalAccess(not mHasValue);
321 return mStorage.value;
322 }
323
329 const ValueType& value() const&
330 {
331 ThrowBadOptionalAccess(not mHasValue);
332 return mStorage.value;
333 }
334
341 {
342 ThrowBadOptionalAccess(not mHasValue);
343 return std::move(mStorage.value);
344 }
345
351 const ValueType&& value() const&&
352 {
353 ThrowBadOptionalAccess(not mHasValue);
354 return std::move(mStorage.value);
355 }
356
363 {
364 return value();
365 }
366
372 const ValueType& operator*() const&
373 {
374 return value();
375 }
376
383 {
384 return std::move(*this).value();
385 }
386
392 const ValueType&& operator*() const&&
393 {
394 return std::move(*this).value();
395 }
396
398 {
399 return &value();
400 }
401
402 const ValueType* operator->() const
403 {
404 return &value();
405 }
406
412 template <typename U>
413 constexpr ValueType valueOr(U&& defaultValue) const&
414 {
415 return mHasValue ? **this : static_cast<ValueType>(std::forward<U>(defaultValue));
416 }
417
423 template <typename U>
424 constexpr ValueType valueOr(U&& defaultValue) &&
425 {
426 return mHasValue ? std::move(**this) : static_cast<ValueType>(std::forward<U>(defaultValue));
427 }
428
429
433 void swap(Optional& other) noexcept(/* std::is_nothrow_swappable<ValueType>::value and*/ std::is_nothrow_move_assignable<ValueType>::value)
434 {
435 if (*this and other)
436 {
437 std::swap(**this, *other);
438 }
439 else if (not *this and other)
440 {
441 mStorage.value = std::move(*other);
442 other.reset();
443 }
444 else if (*this and not other)
445 {
446 *other = std::move(**this);
447 reset();
448 }
449 }
450
451
456 template <typename U = ValueType, typename std::enable_if<std::is_trivially_destructible<U>::value, std::nullptr_t>::type = nullptr>
457 void reset() noexcept(std::is_nothrow_destructible<ValueType>::value)
458 {
459 if (mHasValue)
460 {
461 mHasValue = false;
462 }
463 }
464
465
470 template <typename U = ValueType, typename std::enable_if<not std::is_trivially_destructible<U>::value, std::nullptr_t>::type = nullptr>
471 void reset() noexcept(std::is_nothrow_destructible<ValueType>::value)
472 {
473 if (mHasValue)
474 {
475 mStorage.value.~ValueType();
476 mHasValue = false;
477 }
478 }
479
480
484 void show() const noexcept
485 {
486 if (mHasValue)
487 {
488 Udon::ShowRaw(mStorage.value);
489 }
490 else
491 {
492 Udon::ShowRaw("nullopt");
493 }
494 }
495
496#if UDON_PLATFORM_OUTPUT_STREAM == UDON_PLATFORM_OUTPUT_CONSOLE
497
505 template <typename CharType>
506 friend std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& os, const Optional& opt)
507 {
508 if (opt)
509 {
510 return os << *opt;
511 }
512 else
513 {
514 return os << "nullopt";
515 }
516 }
517
518#endif
519
520 private:
521 // 共用体を用いて初期化タイミングを遅延
522 union Storage
523 {
524 struct Dummy
525 {
526 constexpr Dummy() noexcept {}
527 } dummy;
528
529 ValueType value;
530
531 constexpr Storage() noexcept
532 : dummy{}
533 {
534 }
535
536 constexpr Storage(Storage&& other) noexcept(std::is_nothrow_move_constructible<ValueType>::value)
537 : value{ std::move(other.value) }
538 {
539 }
540
541 constexpr Storage(const Storage& other) noexcept(std::is_nothrow_move_constructible<ValueType>::value)
542 : value{ other.value }
543 {
544 }
545
546 ~Storage() noexcept {}
547
548 Storage& operator=(const Storage& other)
549 {
550 value = other.value;
551 return *this;
552 }
553
554 Storage& operator=(Storage&& other) noexcept(std::is_nothrow_assignable<ValueType, ValueType>::value)
555 {
556 value = std::move(other.value);
557 return *this;
558 }
559
560 } mStorage{};
561
562 bool mHasValue;
563
564 template <typename U>
565 void ConstructValue(U&& value) noexcept(std::is_nothrow_constructible<ValueType, U>::value)
566 {
567 new (&mStorage.value) ValueType(std::forward<U>(value));
568 }
569
570 template <typename U>
571 void AssignmentValue(U&& value) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
572 {
573 if (mHasValue)
574 {
575 mStorage.value = std::forward<U>(value);
576 }
577 else
578 {
579 ConstructValue(std::forward<U>(value));
580 mHasValue = true;
581 }
582 }
583 };
584
585} // namespace Udon
オプショナル型
Definition Optional.hpp:62
Optional & operator=(const Optional< U > &other) noexcept(std::is_nothrow_constructible< ValueType, U >::value and std::is_nothrow_assignable< ValueType, U >::value)
コピー代入演算子
Definition Optional.hpp:183
void show() const noexcept
値を表示
Definition Optional.hpp:484
friend bool operator<(const Optional &lhs, const Optional &rhs) noexcept
比較演算子
Definition Optional.hpp:249
friend bool operator>(const Optional &lhs, const Optional &rhs) noexcept
比較演算子
Definition Optional.hpp:267
friend bool operator==(const Optional &lhs, const Optional &rhs) noexcept
等価演算子
Definition Optional.hpp:221
Optional(U &&value) noexcept(std::is_nothrow_constructible< ValueType >::value)
値から構築
Definition Optional.hpp:101
constexpr ValueType valueOr(U &&defaultValue) &&
有効であれば自身を、無効であればデフォルト値を取得する
Definition Optional.hpp:424
ValueType && operator*() &&
値を取得
Definition Optional.hpp:382
const ValueType & operator*() const &
値を取得
Definition Optional.hpp:372
T ValueType
Definition Optional.hpp:73
Optional & operator=(NulloptT) noexcept
無効値代入演算子
Definition Optional.hpp:157
constexpr bool hasValue() const noexcept
値が有効か
Definition Optional.hpp:307
const ValueType && operator*() const &&
値を取得
Definition Optional.hpp:392
Optional & operator=(U &&value) noexcept(std::is_nothrow_constructible< ValueType, U >::value and std::is_nothrow_assignable< ValueType, U >::value)
値代入演算子
Definition Optional.hpp:171
constexpr ValueType valueOr(U &&defaultValue) const &
有効であれば自身を、無効であればデフォルト値を取得する
Definition Optional.hpp:413
constexpr Optional(NulloptT)
無効値として構築
Definition Optional.hpp:89
void swap(Optional &other) noexcept(/*std::is_nothrow_swappable< ValueType >::value and */std::is_nothrow_move_assignable< ValueType >::value)
他のOptionalと値を交換する
Definition Optional.hpp:433
ValueType & value() &
値を取得
Definition Optional.hpp:318
ValueType & operator*() &
値を取得
Definition Optional.hpp:362
Optional(Optional< U > &&other) noexcept(std::is_nothrow_constructible< ValueType, U >::value)
ムーブコンストラクタ
Definition Optional.hpp:132
friend bool operator!=(const Optional &lhs, const Optional &rhs) noexcept
非等価演算子
Definition Optional.hpp:239
constexpr Optional() noexcept
デフォルトコンストラクタ
Definition Optional.hpp:78
const ValueType & value() const &
値を取得
Definition Optional.hpp:329
friend bool operator<=(const Optional &lhs, const Optional &rhs) noexcept
比較演算子
Definition Optional.hpp:287
void reset() noexcept(std::is_nothrow_destructible< ValueType >::value)
無効状態にする (トリビアルな型)
Definition Optional.hpp:457
ValueType && value() &&
値を取得
Definition Optional.hpp:340
friend bool operator>=(const Optional &lhs, const Optional &rhs) noexcept
比較演算子
Definition Optional.hpp:277
~Optional() noexcept
デストラクタ
Definition Optional.hpp:146
const ValueType * operator->() const
Definition Optional.hpp:402
Optional(const Optional< U > &other) noexcept(std::is_nothrow_constructible< ValueType, U >::value)
コピーコンストラクタ
Definition Optional.hpp:115
ValueType * operator->()
Definition Optional.hpp:397
Optional & operator=(Optional< U > &&other) noexcept(std::is_nothrow_constructible< ValueType, U >::value and std::is_nothrow_assignable< ValueType, U >::value)
ムーブ代入演算子
Definition Optional.hpp:202
friend std::basic_ostream< CharType > & operator<<(std::basic_ostream< CharType > &os, const Optional &opt)
std::basic_ostream への出力
Definition Optional.hpp:506
const ValueType && value() const &&
値を取得
Definition Optional.hpp:351
Definition Bit.hpp:12
void ThrowBadOptionalAccess(bool)
Definition Optional.hpp:37
void ShowRaw(Args &&... args)
改行、区切り文字なしで出力する
Definition Show.hpp:362
constexpr NulloptT nullopt
無効値
Definition Optional.hpp:52
Definition Typedef.hpp:94
無効値型
Definition Optional.hpp:46
Definition Optional.hpp:525
constexpr Dummy() noexcept
Definition Optional.hpp:526