22 #ifndef GEARS_UTILITY_MAYBE_HPP
23 #define GEARS_UTILITY_MAYBE_HPP
25 #include "maybe/traits.hpp"
26 #include "maybe/base.hpp"
32 struct bad_maybe_access : std::exception {
33 virtual const char* what() const noexcept {
34 return "bad maybe access";
40 using MaybeBase = meta::If<std::is_trivially_destructible<T>, detail::cmaybe_base<T>, detail::maybe_base<T>>;
98 class maybe :
private MaybeBase<T> {
100 static_assert(!std::is_same<meta::Decay<T>, nothing_t>(),
"Invalid type. Must not be nothing");
101 static_assert(!std::is_same<meta::Decay<T>, in_place_t>(),
"Invalid type. Must not be in_place tag");
102 static_assert(!std::is_reference<T>(),
"Invalid type. Must not be a reference type");
103 static_assert(!is_maybe<T>(),
"Invalid type. Must not be a maybe type");
105 constexpr
bool is_valid() const noexcept {
106 return MaybeBase<T>::valid;
110 return std::addressof(MaybeBase<T>::storage.
value);
113 constexpr
const T* data()
const {
114 return detail::address_of(MaybeBase<T>::storage.
value);
117 constexpr
const T&
internal()
const {
118 return MaybeBase<T>::storage.value;
122 return MaybeBase<T>::storage.value;
125 void clear() noexcept {
129 MaybeBase<T>::valid =
false;
132 template<
typename... Args>
133 void initialise(Args&&... args) noexcept(noexcept(T(std::forward<Args>(args)...))) {
134 new(data()) T(std::forward<Args>(args)...);
135 MaybeBase<T>::valid =
true;
139 using value_type = T;
144 constexpr
maybe() noexcept: MaybeBase<T>() {}
149 constexpr
maybe(nothing_t) noexcept : MaybeBase<T>() {}
202 template<
typename... Args>
203 constexpr
explicit maybe(in_place_t, Args&&... args): MaybeBase<T>(in_place, meta::
cforward<Args>(args)...) {}
213 maybe(
const maybe& rhs): MaybeBase<T>(detail::regular_init, rhs.is_valid()) {
215 new(data()) T(rhs.internal());
228 maybe(
maybe&& rhs) noexcept(std::is_nothrow_move_constructible<T>()): MaybeBase<T>(detail::regular_init, rhs.is_valid()) {
230 new(data()) T(std::move(rhs.internal()));
255 if(is_valid() && !rhs.is_valid()) {
258 else if(!is_valid() && rhs.is_valid()) {
259 initialise(rhs.internal());
261 else if(is_valid() && rhs.is_valid()) {
262 internal() = rhs.internal();
271 maybe&
operator=(
maybe&& rhs) noexcept(std::is_nothrow_move_assignable<T>() && std::is_nothrow_move_constructible<T>()) {
272 if(is_valid() && !rhs.is_valid()) {
275 else if(!is_valid() && rhs.is_valid()) {
276 initialise(std::move(rhs.internal()));
278 else if(is_valid() && rhs.is_valid()) {
279 internal() = std::move(rhs.internal());
294 template<
typename U, meta::EnableIf<std::is_constructible<T, meta::Decay<U>>, std::is_assignable<T, meta::Decay<U>>> = meta::_>
297 internal() = std::forward<U>(
value);
300 initialise(std::forward<U>(
value));
315 template<
typename... Args>
318 initialise(std::forward<Args>(args)...);
374 return is_valid() ?
internal() : (
throw detail::bad_maybe_access(),
internal());
378 return is_valid() ?
internal() : (
throw detail::bad_maybe_access(),
internal());
387 constexpr
explicit operator bool() const noexcept {
402 return is_valid() ?
internal() : static_cast<T>(meta::cforward<U>(
value));
418 return { meta::cforward<T>(t) };
440 return static_cast<bool>(lhs) != static_cast<bool>(rhs) ?
false :
static_cast<bool>(lhs) ==
false ?
true : *lhs == *rhs;
448 return !(lhs == rhs);
455 constexpr
bool operator<(const maybe<T>& lhs,
const maybe<T>& rhs) {
456 return !rhs ?
false : !lhs ?
true : *lhs < *rhs;
471 constexpr
bool operator<=(const maybe<T>& lhs,
const maybe<T>& rhs) {
521 constexpr
bool operator!=(
const maybe<T>& lhs, nothing_t) noexcept {
522 return static_cast<bool>(lhs);
526 constexpr
bool operator!=(nothing_t,
const maybe<T>& rhs) noexcept {
527 return static_cast<bool>(rhs);
531 constexpr
bool operator<(const maybe<T>& lhs, nothing_t) noexcept {
536 constexpr
bool operator<(nothing_t, const maybe<T>& rhs) noexcept {
537 return static_cast<bool>(rhs);
541 constexpr
bool operator>(
const maybe<T>& lhs, nothing_t) noexcept {
542 return static_cast<bool>(lhs);
546 constexpr
bool operator>(nothing_t,
const maybe<T>&) noexcept {
551 constexpr
bool operator<=(const maybe<T>& lhs, nothing_t) noexcept {
556 constexpr
bool operator<=(nothing_t, const maybe<T>&) noexcept {
561 constexpr
bool operator>=(
const maybe<T>&, nothing_t) noexcept {
566 constexpr
bool operator>=(nothing_t,
const maybe<T>& rhs) noexcept {
586 return static_cast<bool>(lhs) ? *lhs == value :
false;
591 return static_cast<bool>(rhs) ? value == *rhs :
false;
599 return static_cast<bool>(lhs) ? *lhs != value :
true;
604 return static_cast<bool>(rhs) ? value != *rhs :
true;
611 constexpr
bool operator<(const maybe<T>& lhs,
const T& value) {
612 return static_cast<bool>(lhs) ? *lhs < value :
true;
616 constexpr
bool operator>(
const T& value,
const maybe<T>& rhs) {
617 return static_cast<bool>(rhs) ? value > *rhs :
true;
625 return static_cast<bool>(lhs) ? *lhs > value :
false;
629 constexpr
bool operator<(const T& value, const maybe<T>& rhs) {
630 return static_cast<bool>(rhs) ? value < *rhs :
false;
638 return static_cast<bool>(lhs) ? *lhs >= value :
false;
642 constexpr
bool operator<=(const T& value, const maybe<T>& rhs) {
643 return static_cast<bool>(rhs) ? value <= *rhs :
false;
650 constexpr
bool operator<=(const maybe<T>& lhs,
const T& value) {
651 return static_cast<bool>(lhs) ? *lhs <= value :
true;
655 constexpr
bool operator>=(
const T& value,
const maybe<T>& rhs) {
656 return static_cast<bool>(rhs) ? value >= *rhs :
true;
662 #endif // GEARS_UTILITY_MAYBE_HPP