UdonLibrary 1.0.0
機械システム研究部 C++ ライブラリ
読み取り中…
検索中…
一致する文字列を見つけられません
Optional.hpp
[詳解]
1//
2// Optional
3//
4// Copyright (c) 2022 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>
71 friend class Optional;
72
73 public:
74 using ValueType = T;
75
79 constexpr Optional() noexcept
80 : mStorage()
81 , mHasValue()
82 {
83 }
84
85
90 constexpr Optional(NulloptT)
91 : mStorage()
92 , mHasValue()
93 {
94 }
95
96
101 template <typename U, typename std::enable_if<std::is_constructible<ValueType, U>::value, std::nullptr_t>::type = nullptr>
102 Optional(U&& value) noexcept(std::is_nothrow_constructible<ValueType>::value)
103 : mStorage()
104 , mHasValue(true)
105 {
106 ConstructValue(std::forward<U>(value));
107 }
108
109
115 template <typename U, typename std::enable_if<std::is_constructible<ValueType, const U&>::value, std::nullptr_t>::type = nullptr>
116 Optional(const Optional<U>& other) noexcept(std::is_nothrow_constructible<ValueType, U>::value)
117 : mStorage()
118 , mHasValue(other.mHasValue)
119 {
120 if (mHasValue)
121 {
122 ConstructValue(other.mStorage.value);
123 }
124 }
125
126
132 template <typename U, typename std::enable_if<std::is_constructible<ValueType, U&&>::value, std::nullptr_t>::type = nullptr>
133 Optional(Optional<U>&& other) noexcept(std::is_nothrow_constructible<ValueType, U>::value)
134 : mStorage()
135 , mHasValue(other.mHasValue)
136 {
137 if (mHasValue)
138 {
139 ConstructValue(std::move(other.mStorage.value));
140 }
141 }
142
143
147 ~Optional() noexcept
148 {
149 reset();
150 }
151
152
159 {
160 reset();
161 return *this;
162 }
163
164
170 // template <typename U>
171 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>
172 Optional& operator=(U&& value) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
173 {
174 AssignmentValue(std::forward<U>(value));
175 return *this;
176 }
177
178
183 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>
184 Optional& operator=(const Optional<U>& other) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
185 {
186 if (other)
187 {
188 AssignmentValue(other.value());
189 }
190 else
191 {
192 reset();
193 }
194 return *this;
195 }
196
197
202 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>
203 Optional& operator=(Optional<U>&& other) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
204 {
205 if (other)
206 {
207 AssignmentValue(std::move(other.value()));
208 }
209 else
210 {
211 reset();
212 }
213 return *this;
214 }
215
216
222 friend bool operator==(const Optional& lhs, const Optional& rhs) noexcept
223 {
224 if (lhs and rhs)
225 {
226 return *lhs == *rhs;
227 }
228 if (not lhs and not rhs)
229 {
230 return true; // nullopt == nullopt
231 }
232 return false;
233 }
234
240 friend bool operator!=(const Optional& lhs, const Optional& rhs) noexcept
241 {
242 return not(lhs == rhs);
243 }
244
250 friend bool operator<(const Optional& lhs, const Optional& rhs) noexcept
251 {
252 if (lhs and rhs)
253 {
254 return *lhs < *rhs;
255 }
256 if (not rhs)
257 {
258 return false;
259 }
260 return not lhs;
261 }
262
268 friend bool operator>(const Optional& lhs, const Optional& rhs) noexcept
269 {
270 return rhs < lhs;
271 }
272
278 friend bool operator>=(const Optional& lhs, const Optional& rhs) noexcept
279 {
280 return not(lhs < rhs);
281 }
282
288 friend bool operator<=(const Optional& lhs, const Optional& rhs) noexcept
289 {
290 return not(rhs < lhs);
291 }
292
293
298 explicit constexpr operator bool() const noexcept
299 {
300 return mHasValue;
301 }
302
303
308 constexpr bool hasValue() const noexcept
309 {
310 return mHasValue;
311 }
312
313
320 {
321 ThrowBadOptionalAccess(not mHasValue);
322 return mStorage.value;
323 }
324
330 const ValueType& value() const&
331 {
332 ThrowBadOptionalAccess(not mHasValue);
333 return mStorage.value;
334 }
335
342 {
343 ThrowBadOptionalAccess(not mHasValue);
344 return std::move(mStorage.value);
345 }
346
352 const ValueType&& value() const&&
353 {
354 ThrowBadOptionalAccess(not mHasValue);
355 return std::move(mStorage.value);
356 }
357
364 {
365 return value();
366 }
367
373 const ValueType& operator*() const&
374 {
375 return value();
376 }
377
384 {
385 return std::move(*this).value();
386 }
387
393 const ValueType&& operator*() const&&
394 {
395 return std::move(*this).value();
396 }
397
399 {
400 return &value();
401 }
402
403 const ValueType* operator->() const
404 {
405 return &value();
406 }
407
413 template <typename U>
414 constexpr ValueType valueOr(U&& defaultValue) const&
415 {
416 return mHasValue ? **this : static_cast<ValueType>(std::forward<U>(defaultValue));
417 }
418
424 template <typename U>
425 constexpr ValueType valueOr(U&& defaultValue) &&
426 {
427 return mHasValue ? std::move(**this) : static_cast<ValueType>(std::forward<U>(defaultValue));
428 }
429
430
434 template <typename Visitor>
435 constexpr auto transform(Visitor&& visitor) & -> Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(ValueType&)>::type>>
436 {
437 return *this ? Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(ValueType&)>::type>>{ visitor(**this) }
438 : nullopt;
439 }
440
441
445 template <typename Visitor>
446 constexpr auto transform(Visitor&& visitor) const& -> Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(const ValueType&)>::type>>
447 {
448 return *this ? Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(const ValueType&)>::type>>{ visitor(**this) }
449 : nullopt;
450 }
451
452
456 template <typename Visitor>
457 constexpr auto transform(Visitor&& visitor) && -> Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(ValueType)>::type>>
458 {
459 return *this ? Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(ValueType)>::type>>{ visitor(std::move(**this)) }
460 : nullopt;
461 }
462
463
467 void swap(Optional& other) noexcept(/* std::is_nothrow_swappable<ValueType>::value and*/ std::is_nothrow_move_assignable<ValueType>::value)
468 {
469 if (*this and other)
470 {
471 std::swap(**this, *other);
472 }
473 else if (not *this and other)
474 {
475 mStorage.value = std::move(*other);
476 other.reset();
477 }
478 else if (*this and not other)
479 {
480 *other = std::move(**this);
481 reset();
482 }
483 }
484
485
490 template <typename U = ValueType, typename std::enable_if<std::is_trivially_destructible<U>::value, std::nullptr_t>::type = nullptr>
491 void reset() noexcept(std::is_nothrow_destructible<ValueType>::value)
492 {
493 if (mHasValue)
494 {
495 mHasValue = false;
496 }
497 }
498
499
504 template <typename U = ValueType, typename std::enable_if<not std::is_trivially_destructible<U>::value, std::nullptr_t>::type = nullptr>
505 void reset() noexcept(std::is_nothrow_destructible<ValueType>::value)
506 {
507 if (mHasValue)
508 {
509 mStorage.value.~ValueType();
510 mHasValue = false;
511 }
512 }
513
514
518 void show() const noexcept
519 {
520 if (mHasValue)
521 {
522 Udon::ShowRaw(mStorage.value);
523 }
524 else
525 {
526 Udon::ShowRaw("nullopt");
527 }
528 }
529
530#if UDON_PLATFORM_OUTPUT_STREAM == UDON_PLATFORM_OUTPUT_CONSOLE
531
539 template <typename CharType>
540 friend std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& os, const Optional& opt)
541 {
542 if (opt)
543 {
544 return os << *opt;
545 }
546 else
547 {
548 return os << "nullopt";
549 }
550 }
551
552#endif
553
554 private:
555 // 共用体を用いて初期化タイミングを遅延
556 union Storage
557 {
558 struct Dummy
559 {
560 constexpr Dummy() noexcept {}
561 } dummy;
562
564
565 constexpr Storage() noexcept
566 : dummy{}
567 {
568 }
569
570 constexpr Storage(Storage&& other) noexcept(std::is_nothrow_move_constructible<ValueType>::value)
571 : value{ std::move(other.value) }
572 {
573 }
574
575 constexpr Storage(const Storage& other) noexcept(std::is_nothrow_move_constructible<ValueType>::value)
576 : value{ other.value }
577 {
578 }
579
580 ~Storage() noexcept {}
581
582 Storage& operator=(const Storage& other)
583 {
584 value = other.value;
585 return *this;
586 }
587
588 Storage& operator=(Storage&& other) noexcept(std::is_nothrow_assignable<ValueType, ValueType>::value)
589 {
590 value = std::move(other.value);
591 return *this;
592 }
593
594 } mStorage{};
595
596 bool mHasValue;
597
598 template <typename U>
599 void ConstructValue(U&& value) noexcept(std::is_nothrow_constructible<ValueType, U>::value)
600 {
601 new (&mStorage.value) ValueType(std::forward<U>(value));
602 }
603
604 template <typename U>
605 void AssignmentValue(U&& value) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
606 {
607 if (mHasValue)
608 {
609 mStorage.value = std::forward<U>(value);
610 }
611 else
612 {
613 ConstructValue(std::forward<U>(value));
614 mHasValue = true;
615 }
616 }
617 };
618
619} // namespace Udon
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:184
void show() const noexcept
値を表示
Definition Optional.hpp:518
friend bool operator<(const Optional &lhs, const Optional &rhs) noexcept
比較演算子
Definition Optional.hpp:250
friend class Optional
Definition Optional.hpp:71
friend bool operator>(const Optional &lhs, const Optional &rhs) noexcept
比較演算子
Definition Optional.hpp:268
friend bool operator==(const Optional &lhs, const Optional &rhs) noexcept
等価演算子
Definition Optional.hpp:222
Optional(U &&value) noexcept(std::is_nothrow_constructible< ValueType >::value)
値から構築
Definition Optional.hpp:102
constexpr ValueType valueOr(U &&defaultValue) &&
有効であれば自身を、無効であればデフォルト値を取得する
Definition Optional.hpp:425
ValueType && operator*() &&
値を取得
Definition Optional.hpp:383
const ValueType & operator*() const &
値を取得
Definition Optional.hpp:373
constexpr auto transform(Visitor &&visitor) &&-> Optional< Traits::RemoveCVRefT< typename std::result_of< Visitor(ValueType)>::type > >
値を変換
Definition Optional.hpp:457
constexpr auto transform(Visitor &&visitor) &-> Optional< Traits::RemoveCVRefT< typename std::result_of< Visitor(ValueType &)>::type > >
値を変換
Definition Optional.hpp:435
T ValueType
Definition Optional.hpp:74
Optional & operator=(NulloptT) noexcept
無効値代入演算子
Definition Optional.hpp:158
constexpr bool hasValue() const noexcept
値が有効か
Definition Optional.hpp:308
const ValueType && operator*() const &&
値を取得
Definition Optional.hpp:393
Optional & operator=(U &&value) noexcept(std::is_nothrow_constructible< ValueType, U >::value and std::is_nothrow_assignable< ValueType, U >::value)
値代入演算子
Definition Optional.hpp:172
constexpr ValueType valueOr(U &&defaultValue) const &
有効であれば自身を、無効であればデフォルト値を取得する
Definition Optional.hpp:414
constexpr Optional(NulloptT)
無効値として構築
Definition Optional.hpp:90
void swap(Optional &other) noexcept(/*std::is_nothrow_swappable< ValueType >::value and */std::is_nothrow_move_assignable< ValueType >::value)
他のOptionalと値を交換する
Definition Optional.hpp:467
constexpr auto transform(Visitor &&visitor) const &-> Optional< Traits::RemoveCVRefT< typename std::result_of< Visitor(const ValueType &)>::type > >
値を変換
Definition Optional.hpp:446
ValueType & value() &
値を取得
Definition Optional.hpp:319
ValueType & operator*() &
値を取得
Definition Optional.hpp:363
Optional(Optional< U > &&other) noexcept(std::is_nothrow_constructible< ValueType, U >::value)
ムーブコンストラクタ
Definition Optional.hpp:133
friend bool operator!=(const Optional &lhs, const Optional &rhs) noexcept
非等価演算子
Definition Optional.hpp:240
constexpr Optional() noexcept
デフォルトコンストラクタ
Definition Optional.hpp:79
const ValueType & value() const &
値を取得
Definition Optional.hpp:330
friend bool operator<=(const Optional &lhs, const Optional &rhs) noexcept
比較演算子
Definition Optional.hpp:288
void reset() noexcept(std::is_nothrow_destructible< ValueType >::value)
無効状態にする (トリビアルな型)
Definition Optional.hpp:491
ValueType && value() &&
値を取得
Definition Optional.hpp:341
friend bool operator>=(const Optional &lhs, const Optional &rhs) noexcept
比較演算子
Definition Optional.hpp:278
~Optional() noexcept
デストラクタ
Definition Optional.hpp:147
const ValueType * operator->() const
Definition Optional.hpp:403
Optional(const Optional< U > &other) noexcept(std::is_nothrow_constructible< ValueType, U >::value)
コピーコンストラクタ
Definition Optional.hpp:116
ValueType * operator->()
Definition Optional.hpp:398
Optional & operator=(Optional< U > &&other) noexcept(std::is_nothrow_constructible< ValueType, U >::value and std::is_nothrow_assignable< ValueType, U >::value)
ムーブ代入演算子
Definition Optional.hpp:203
friend std::basic_ostream< CharType > & operator<<(std::basic_ostream< CharType > &os, const Optional &opt)
std::basic_ostream への出力
Definition Optional.hpp:540
const ValueType && value() const &&
値を取得
Definition Optional.hpp:352
RemoveConstT< RemoveVolatileT< RemoveReferenceT< T > > > RemoveCVRefT
Definition Typedef.hpp:28
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
constexpr Dummy() noexcept
Definition Optional.hpp:560