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
431// C++17以降 result_of -> invoke_result
432#if __cplusplus >= 201703L
433
437 template <typename Visitor>
439 {
441 : nullopt;
442 }
443
444
448 template <typename Visitor>
450 {
452 : nullopt;
453 }
454
455
459 template <typename Visitor>
461 {
462 return *this ? Optional<Traits::RemoveCVRefT<std::invoke_result_t<Visitor, ValueType>>>{ visitor(std::move(**this)) }
463 : nullopt;
464 }
465
466#else
467
471 template <typename Visitor>
472 constexpr auto transform(Visitor&& visitor) & -> Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(ValueType&)>::type>>
473 {
474 return *this ? Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(ValueType&)>::type>>{ visitor(**this) }
475 : nullopt;
476 }
477
478
482 template <typename Visitor>
483 constexpr auto transform(Visitor&& visitor) const& -> Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(const ValueType&)>::type>>
484 {
485 return *this ? Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(const ValueType&)>::type>>{ visitor(**this) }
486 : nullopt;
487 }
488
489
493 template <typename Visitor>
494 constexpr auto transform(Visitor&& visitor) && -> Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(ValueType)>::type>>
495 {
496 return *this ? Optional<Traits::RemoveCVRefT<typename std::result_of<Visitor(ValueType)>::type>>{ visitor(std::move(**this)) }
497 : nullopt;
498 }
499
500
501#endif
502
503
507 void swap(Optional& other) noexcept(/* std::is_nothrow_swappable<ValueType>::value and*/ std::is_nothrow_move_assignable<ValueType>::value)
508 {
509 if (*this and other)
510 {
511 std::swap(**this, *other);
512 }
513 else if (not *this and other)
514 {
515 mStorage.value = std::move(*other);
516 other.reset();
517 }
518 else if (*this and not other)
519 {
520 *other = std::move(**this);
521 reset();
522 }
523 }
524
525
530 template <typename U = ValueType, typename std::enable_if<std::is_trivially_destructible<U>::value, std::nullptr_t>::type = nullptr>
531 void reset() noexcept(std::is_nothrow_destructible<ValueType>::value)
532 {
533 if (mHasValue)
534 {
535 mHasValue = false;
536 }
537 }
538
539
544 template <typename U = ValueType, typename std::enable_if<not std::is_trivially_destructible<U>::value, std::nullptr_t>::type = nullptr>
545 void reset() noexcept(std::is_nothrow_destructible<ValueType>::value)
546 {
547 if (mHasValue)
548 {
549 mStorage.value.~ValueType();
550 mHasValue = false;
551 }
552 }
553
554
558 void show() const noexcept
559 {
560 if (mHasValue)
561 {
562 Udon::ShowRaw(mStorage.value);
563 }
564 else
565 {
566 Udon::ShowRaw("nullopt");
567 }
568 }
569
570#if UDON_PLATFORM_OUTPUT_STREAM == UDON_PLATFORM_OUTPUT_CONSOLE
571
579 template <typename CharType>
580 friend std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& os, const Optional& opt)
581 {
582 if (opt)
583 {
584 return os << *opt;
585 }
586 else
587 {
588 return os << "nullopt";
589 }
590 }
591
592#endif
593
594 private:
595 // 共用体を用いて初期化タイミングを遅延
596 union Storage
597 {
598 struct Dummy
599 {
600 constexpr Dummy() noexcept {}
601 } dummy;
602
604
605 constexpr Storage() noexcept
606 : dummy{}
607 {
608 }
609
610 constexpr Storage(Storage&& other) noexcept(std::is_nothrow_move_constructible<ValueType>::value)
611 : value{ std::move(other.value) }
612 {
613 }
614
615 constexpr Storage(const Storage& other) noexcept(std::is_nothrow_move_constructible<ValueType>::value)
616 : value{ other.value }
617 {
618 }
619
620 ~Storage() noexcept {}
621
622 Storage& operator=(const Storage& other)
623 {
624 value = other.value;
625 return *this;
626 }
627
628 Storage& operator=(Storage&& other) noexcept(std::is_nothrow_assignable<ValueType, ValueType>::value)
629 {
630 value = std::move(other.value);
631 return *this;
632 }
633
634 } mStorage{};
635
636 bool mHasValue;
637
638 template <typename U>
639 void ConstructValue(U&& value) noexcept(std::is_nothrow_constructible<ValueType, U>::value)
640 {
641 new (&mStorage.value) ValueType(std::forward<U>(value));
642 }
643
644 template <typename U>
645 void AssignmentValue(U&& value) noexcept(std::is_nothrow_constructible<ValueType, U>::value and std::is_nothrow_assignable<ValueType, U>::value)
646 {
647 if (mHasValue)
648 {
649 mStorage.value = std::forward<U>(value);
650 }
651 else
652 {
653 ConstructValue(std::forward<U>(value));
654 mHasValue = true;
655 }
656 }
657 };
658
659} // 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:184
void show() const noexcept
値を表示
Definition Optional.hpp:558
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:494
constexpr auto transform(Visitor &&visitor) &-> Optional< Traits::RemoveCVRefT< typename std::result_of< Visitor(ValueType &)>::type > >
値を変換
Definition Optional.hpp:472
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:507
constexpr auto transform(Visitor &&visitor) const &-> Optional< Traits::RemoveCVRefT< typename std::result_of< Visitor(const ValueType &)>::type > >
値を変換
Definition Optional.hpp:483
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:531
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:580
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:600