|
- /// \file
- // Range v3 library
- //
- // Copyright Casey Carter 2017
- //
- // Use, modification and distribution is subject to the
- // Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- // Project home: https://github.com/ericniebler/range-v3
- //
-
- #ifndef RANGES_V3_UTILITY_OPTIONAL_HPP
- #define RANGES_V3_UTILITY_OPTIONAL_HPP
-
- #include <exception>
- #include <initializer_list>
- #include <memory>
- #include <new>
-
- #include <concepts/concepts.hpp>
-
- #include <range/v3/detail/config.hpp>
- #include <range/v3/utility/addressof.hpp>
- #include <range/v3/utility/in_place.hpp>
- #include <range/v3/utility/static_const.hpp>
- #include <range/v3/utility/swap.hpp>
-
- namespace ranges
- {
- template<typename>
- struct optional;
-
- struct bad_optional_access : std::exception
- {
- virtual const char * what() const noexcept override
- {
- return "bad optional access";
- }
- };
-
- struct nullopt_t
- {
- struct tag
- {};
- explicit constexpr nullopt_t(tag) noexcept
- {}
- };
- #if RANGES_CXX_INLINE_VARIABLES >= RANGES_CXX_INLINE_VARIABLES_17
- inline constexpr nullopt_t nullopt{nullopt_t::tag{}};
- #else
- /// \cond
- namespace detail
- {
- template<typename>
- struct nullopt_holder
- {
- static constexpr nullopt_t nullopt{nullopt_t::tag{}};
- };
- template<typename T>
- constexpr nullopt_t nullopt_holder<T>::nullopt;
- } // namespace detail
- /// \endcond
- namespace
- {
- constexpr auto & nullopt = detail::nullopt_holder<void>::nullopt;
- }
- #endif
-
- /// \cond
- namespace detail
- {
- template<typename = void>
- [[noreturn]] bool throw_bad_optional_access()
- {
- throw bad_optional_access{};
- }
-
- namespace optional_adl
- {
- template<typename T, bool = std::is_trivially_destructible<T>::value>
- struct optional_storage
- {
- union
- {
- char dummy_;
- meta::_t<std::remove_cv<T>> data_;
- };
- bool engaged_;
-
- constexpr optional_storage() noexcept
- : optional_storage(
- tag{},
- meta::strict_and<detail::is_trivially_default_constructible<T>,
- detail::is_trivially_copyable<T>>{})
- {}
- CPP_template(typename... Args)( //
- requires constructible_from<T, Args...>) //
- constexpr explicit optional_storage(in_place_t,
- Args &&... args) //
- noexcept(std::is_nothrow_constructible<T, Args...>::value)
- : data_(static_cast<Args &&>(args)...)
- , engaged_{true}
- {}
-
- constexpr void reset() noexcept
- {
- engaged_ = false;
- }
-
- private:
- struct tag
- {};
- constexpr optional_storage(tag, std::false_type) noexcept
- : dummy_{}
- , engaged_{false}
- {}
- constexpr optional_storage(tag, std::true_type) noexcept
- : data_{}
- , engaged_{false}
- {}
- };
-
- template<typename T>
- struct optional_storage<T, false>
- {
- union
- {
- char dummy_;
- meta::_t<std::remove_cv<T>> data_;
- };
- bool engaged_;
-
- ~optional_storage()
- {
- reset();
- }
- constexpr optional_storage() noexcept
- : dummy_{}
- , engaged_{false}
- {}
- CPP_template(typename... Args)( //
- requires constructible_from<T, Args...>) //
- constexpr explicit optional_storage(in_place_t,
- Args &&... args) //
- noexcept(std::is_nothrow_constructible<T, Args...>::value)
- : data_(static_cast<Args &&>(args)...)
- , engaged_{true}
- {}
- optional_storage(optional_storage const &) = default;
- optional_storage(optional_storage &&) = default;
- optional_storage & operator=(optional_storage const &) = default;
- optional_storage & operator=(optional_storage &&) = default;
-
- void reset() noexcept
- {
- if(engaged_)
- {
- data_.~T();
- engaged_ = false;
- }
- }
- };
-
- template<typename T>
- struct optional_base : private optional_storage<T>
- {
- using optional_storage<T>::optional_storage;
- using optional_storage<T>::reset;
-
- constexpr bool has_value() const noexcept
- {
- return engaged_;
- }
- constexpr T & operator*() & noexcept
- {
- return RANGES_EXPECT(engaged_), data_;
- }
- constexpr T const & operator*() const & noexcept
- {
- return RANGES_EXPECT(engaged_), data_;
- }
- constexpr T && operator*() && noexcept
- {
- return RANGES_EXPECT(engaged_), detail::move(data_);
- }
- constexpr T const && operator*() const && noexcept
- {
- return RANGES_EXPECT(engaged_), detail::move(data_);
- }
- constexpr T * operator->() noexcept
- {
- return RANGES_EXPECT(engaged_), detail::addressof(data_);
- }
- constexpr T const * operator->() const noexcept
- {
- return RANGES_EXPECT(engaged_), detail::addressof(data_);
- }
- CPP_member
- constexpr auto swap(optional_base & that) noexcept(
- std::is_nothrow_move_constructible<T>::value &&
- is_nothrow_swappable<T>::value) -> CPP_ret(void)( //
- requires move_constructible<T> && swappable<T>)
- {
- constexpr bool can_swap_trivially =
- !::concepts::adl_swap_detail::is_adl_swappable_v<T> &&
- detail::is_trivially_move_constructible<T>::value &&
- detail::is_trivially_move_assignable<T>::value;
-
- swap_(meta::bool_<can_swap_trivially>{}, that);
- }
-
- protected:
- template<typename... Args>
- auto construct_from(Args &&... args) noexcept(
- std::is_nothrow_constructible<T, Args...>::value) -> CPP_ret(T &)( //
- requires constructible_from<T, Args...>)
- {
- RANGES_EXPECT(!engaged_);
- auto const address = static_cast<void *>(std::addressof(data_));
- ::new(address) T(static_cast<Args &&>(args)...);
- engaged_ = true;
- return data_;
- }
- template<typename U>
- constexpr void assign_from(U && that) noexcept(
- std::is_nothrow_constructible<T, decltype(*static_cast<U &&>(that))>::
- value && std::is_nothrow_assignable<
- T &, decltype(*static_cast<U &&>(that))>::value)
- {
- if(!that.has_value())
- reset();
- else if(engaged_)
- data_ = *static_cast<U &&>(that);
- else
- {
- auto const address =
- static_cast<void *>(detail::addressof(data_));
- ::new(address) T(*static_cast<U &&>(that));
- engaged_ = true;
- }
- }
-
- private:
- constexpr void swap_(std::true_type, optional_base & that) noexcept
- {
- ranges::swap(static_cast<optional_storage<T> &>(*this),
- static_cast<optional_storage<T> &>(that));
- }
- constexpr void swap_(std::false_type, optional_base & that) noexcept(
- std::is_nothrow_move_constructible<T>::value &&
- is_nothrow_swappable<T>::value)
- {
- if(that.engaged_ == engaged_)
- {
- if(engaged_)
- ranges::swap(data_, that.data_);
- }
- else
- {
- auto & src = engaged_ ? *this : that;
- auto & dst = engaged_ ? that : *this;
- dst.construct_from(detail::move(src.data_));
- src.reset();
- }
- }
-
- using optional_storage<T>::engaged_;
- using optional_storage<T>::data_;
- };
-
- template<typename T>
- struct optional_base<T &>
- {
- optional_base() = default;
- template<typename Arg>
- constexpr explicit CPP_ctor(optional_base)(in_place_t, Arg && arg)( //
- noexcept(true) //
- requires constructible_from<T &, Arg>)
- : ptr_(detail::addressof(arg))
- {}
- constexpr bool has_value() const noexcept
- {
- return ptr_;
- }
- constexpr T & operator*() const noexcept
- {
- return RANGES_EXPECT(ptr_), *ptr_;
- }
- constexpr T * operator->() const noexcept
- {
- return RANGES_EXPECT(ptr_), ptr_;
- }
- constexpr void reset() noexcept
- {
- ptr_ = nullptr;
- }
- CPP_member
- constexpr auto swap(optional_base & that) noexcept(
- is_nothrow_swappable<T>::value) -> CPP_ret(void)( //
- requires swappable<T>)
- {
- if(ptr_ && that.ptr_)
- ranges::swap(*ptr_, *that.ptr_);
- else
- ranges::swap(ptr_, that.ptr_);
- }
-
- protected:
- template<typename U>
- constexpr auto construct_from(U && ref) noexcept -> CPP_ret(T &)( //
- requires convertible_to<U &, T &>)
- {
- RANGES_EXPECT(!ptr_);
- ptr_ = detail::addressof(ref);
- return *ptr_;
- }
- template<typename U>
- constexpr void assign_from(U && that)
- {
- if(ptr_ && that.ptr_)
- *ptr_ = *that.ptr_;
- else
- ptr_ = that.ptr_;
- }
-
- private:
- T * ptr_ = nullptr;
- };
-
- template<typename T>
- struct optional_copy : optional_base<T>
- {
- optional_copy() = default;
- optional_copy(optional_copy const & that) noexcept(
- std::is_nothrow_copy_constructible<T>::value)
- {
- if(that.has_value())
- this->construct_from(*that);
- }
- optional_copy(optional_copy &&) = default;
- optional_copy & operator=(optional_copy const &) = default;
- optional_copy & operator=(optional_copy &&) = default;
-
- using optional_base<T>::optional_base;
- };
-
- template<typename T>
- using copy_construct_layer =
- meta::if_c<std::is_copy_constructible<T>::value &&
- !detail::is_trivially_copy_constructible<T>::value,
- optional_copy<T>, optional_base<T>>;
-
- template<typename T>
- struct optional_move : copy_construct_layer<T>
- {
- optional_move() = default;
- optional_move(optional_move const &) = default;
- optional_move(optional_move && that) noexcept(
- std::is_nothrow_move_constructible<T>::value)
- {
- if(that.has_value())
- this->construct_from(std::move(*that));
- }
- optional_move & operator=(optional_move const &) = default;
- optional_move & operator=(optional_move &&) = default;
-
- using copy_construct_layer<T>::copy_construct_layer;
- };
-
- template<typename T>
- using move_construct_layer =
- meta::if_c<std::is_move_constructible<T>::value &&
- !detail::is_trivially_move_constructible<T>::value,
- optional_move<T>, copy_construct_layer<T>>;
-
- template<typename T>
- struct optional_copy_assign : move_construct_layer<T>
- {
- optional_copy_assign() = default;
- optional_copy_assign(optional_copy_assign const &) = default;
- optional_copy_assign(optional_copy_assign &&) = default;
- optional_copy_assign & operator=(optional_copy_assign const & that) //
- noexcept(std::is_nothrow_copy_constructible<T>::value &&
- std::is_nothrow_copy_assignable<T>::value)
- {
- this->assign_from(that);
- return *this;
- }
- optional_copy_assign & operator=(optional_copy_assign &&) = default;
-
- using move_construct_layer<T>::move_construct_layer;
- };
-
- template<typename T>
- struct deleted_copy_assign : move_construct_layer<T>
- {
- deleted_copy_assign() = default;
- deleted_copy_assign(deleted_copy_assign const &) = default;
- deleted_copy_assign(deleted_copy_assign &&) = default;
- deleted_copy_assign & operator=(deleted_copy_assign const &) = delete;
- deleted_copy_assign & operator=(deleted_copy_assign &&) = default;
-
- using move_construct_layer<T>::move_construct_layer;
- };
-
- template<typename T>
- using copy_assign_layer = meta::if_c<
- std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
- meta::if_c<std::is_reference<T>::value ||
- !(detail::is_trivially_copy_constructible<T>::value &&
- detail::is_trivially_copy_assignable<T>::value),
- optional_copy_assign<T>, move_construct_layer<T>>,
- deleted_copy_assign<T>>;
-
- template<typename T>
- struct optional_move_assign : copy_assign_layer<T>
- {
- optional_move_assign() = default;
- optional_move_assign(optional_move_assign const &) = default;
- optional_move_assign(optional_move_assign &&) = default;
- optional_move_assign & operator=(optional_move_assign const &) = default;
- optional_move_assign & operator=(optional_move_assign && that) noexcept(
- std::is_nothrow_move_constructible<T>::value &&
- std::is_nothrow_move_assignable<T>::value)
- {
- this->assign_from(std::move(that));
- return *this;
- }
-
- using copy_assign_layer<T>::copy_assign_layer;
- };
-
- template<typename T>
- struct deleted_move_assign : copy_assign_layer<T>
- {
- deleted_move_assign() = default;
- deleted_move_assign(deleted_move_assign const &) = default;
- deleted_move_assign(deleted_move_assign &&) = default;
- deleted_move_assign & operator=(deleted_move_assign const &) = default;
- deleted_move_assign & operator=(deleted_move_assign &&) = delete;
-
- using copy_assign_layer<T>::copy_assign_layer;
- };
-
- template<typename T>
- using move_assign_layer = meta::if_c<
- std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,
- meta::if_c<std::is_reference<T>::value ||
- !(detail::is_trivially_move_constructible<T>::value &&
- detail::is_trivially_move_assignable<T>::value),
- optional_move_assign<T>, copy_assign_layer<T>>,
- deleted_move_assign<T>>;
- } // namespace optional_adl
- } // namespace detail
- /// \endcond
-
- // clang-format off
- CPP_def
- (
- template(typename U, typename T)
- concept optional_should_convert,
- requires(int)(void()) && !(
- constructible_from<T, optional<U> & > ||
- constructible_from<T, optional<U> && > ||
- constructible_from<T, optional<U> const & > ||
- constructible_from<T, optional<U> const &&> ||
- convertible_to<optional<U> &, T> ||
- convertible_to<optional<U> &&, T> ||
- convertible_to<optional<U> const &, T> ||
- convertible_to<optional<U> const &&, T>
- )
- );
-
- CPP_def
- (
- template(typename U, typename T)
- concept optional_should_convert_assign,
- optional_should_convert<U, T> &&
- !(assignable_from<T &, optional<U> &> ||
- assignable_from<T &, optional<U> &&> ||
- assignable_from<T &, optional<U> const &> ||
- assignable_from<T &, optional<U> const &&>)
- );
- // clang-format on
-
- template<typename T>
- struct optional : detail::optional_adl::move_assign_layer<T>
- {
- private:
- using base_t = detail::optional_adl::move_assign_layer<T>;
-
- public:
- CPP_assert(destructible<T>);
- static_assert(std::is_object<T>::value || std::is_lvalue_reference<T>::value, "");
- static_assert((bool)!same_as<nullopt_t, uncvref_t<T>>, "");
- static_assert((bool)!same_as<in_place_t, uncvref_t<T>>, "");
- using value_type = meta::_t<std::remove_cv<T>>;
-
- constexpr optional() noexcept
- {}
- constexpr optional(nullopt_t) noexcept
- : optional{}
- {}
- optional(optional const &) = default;
- optional(optional &&) = default;
-
- using base_t::base_t;
-
- CPP_template(typename E, typename... Args)( //
- requires constructible_from<T, std::initializer_list<E> &, Args...>) //
- constexpr explicit optional(in_place_t, std::initializer_list<E> il,
- Args &&... args) //
- noexcept(std::is_nothrow_constructible<T, std::initializer_list<E> &,
- Args...>::value)
- : base_t(in_place, il, static_cast<Args &&>(args)...)
- {}
-
- template<typename U = T>
- constexpr CPP_ctor(optional)(U && v)( //
- requires(!defer::same_as<detail::decay_t<U>, in_place_t>) &&
- (!defer::same_as<detail::decay_t<U>,
- optional>)&&defer::constructible_from<T, U> &&
- defer::convertible_to<U, T>)
- : base_t(in_place, static_cast<U &&>(v))
- {}
- template<typename U = T>
- explicit constexpr CPP_ctor(optional)(U && v)( //
- requires(!defer::same_as<detail::decay_t<U>, in_place_t>) &&
- (!defer::same_as<detail::decay_t<U>,
- optional>)&&defer::constructible_from<T, U> &&
- (!defer::convertible_to<U, T>))
- : base_t(in_place, static_cast<U &&>(v))
- {}
-
- template<typename U>
- CPP_ctor(optional)(optional<U> const & that)( //
- requires optional_should_convert<U, T> && constructible_from<T, U const &> &&
- convertible_to<U const &, T>)
- {
- if(that.has_value())
- base_t::construct_from(*that);
- }
- template<typename U>
- explicit CPP_ctor(optional)(optional<U> const & that)( //
- requires optional_should_convert<U, T> && constructible_from<T, U const &> &&
- (!convertible_to<U const &, T>))
- {
- if(that.has_value())
- base_t::construct_from(*that);
- }
-
- template<typename U>
- CPP_ctor(optional)(optional<U> && that)( //
- requires optional_should_convert<U, T> && constructible_from<T, U> &&
- convertible_to<U, T>)
- {
- if(that.has_value())
- base_t::construct_from(detail::move(*that));
- }
- template<typename U>
- explicit CPP_ctor(optional)(optional<U> && that)( //
- requires optional_should_convert<U, T> && constructible_from<T, U> &&
- (!convertible_to<U, T>))
- {
- if(that.has_value())
- base_t::construct_from(detail::move(*that));
- }
-
- constexpr optional & operator=(nullopt_t) noexcept
- {
- reset();
- return *this;
- }
-
- optional & operator=(optional const &) = default;
- optional & operator=(optional &&) = default;
-
- template<typename U = T>
- constexpr auto operator=(U && u) noexcept(
- std::is_nothrow_constructible<T, U>::value &&
- std::is_nothrow_assignable<T &, U>::value) -> CPP_ret(optional &)( //
- requires(!defer::same_as<optional, detail::decay_t<U>>) &&
- (!(defer::satisfies<T, std::is_scalar> &&
- defer::same_as<T, detail::decay_t<U>>)) &&
- defer::constructible_from<T, U> && defer::assignable_from<T &, U>)
- {
- if(has_value())
- **this = static_cast<U &&>(u);
- else
- base_t::construct_from(static_cast<U &&>(u));
- return *this;
- }
-
- template<typename U>
- constexpr auto operator=(optional<U> const & that) -> CPP_ret(optional &)( //
- requires optional_should_convert_assign<U, T> &&
- constructible_from<T, const U &> && assignable_from<T &, const U &>)
- {
- base_t::assign_from(that);
- return *this;
- }
-
- template<typename U>
- constexpr auto operator=(optional<U> && that) -> CPP_ret(optional &)( //
- requires optional_should_convert_assign<U, T> && constructible_from<T, U> &&
- assignable_from<T &, U>)
- {
- base_t::assign_from(std::move(that));
- return *this;
- }
-
- template<typename... Args>
- auto emplace(Args &&... args) noexcept(
- std::is_nothrow_constructible<T, Args...>::value) -> CPP_ret(T &)( //
- requires constructible_from<T, Args...>)
- {
- reset();
- return base_t::construct_from(static_cast<Args &&>(args)...);
- }
- template<typename E, typename... Args>
- auto emplace(std::initializer_list<E> il, Args &&... args) noexcept(
- std::is_nothrow_constructible<T, std::initializer_list<E> &, Args...>::value)
- -> CPP_ret(T &)( //
- requires constructible_from<T, std::initializer_list<E> &, Args &&...>)
- {
- reset();
- return base_t::construct_from(il, static_cast<Args &&>(args)...);
- }
-
- using base_t::swap;
- using base_t::operator->;
- using base_t::operator*;
-
- constexpr explicit operator bool() const noexcept
- {
- return has_value();
- }
- using base_t::has_value;
-
- constexpr T const & value() const &
- {
- return (has_value() || detail::throw_bad_optional_access()), **this;
- }
- constexpr T & value() &
- {
- return (has_value() || detail::throw_bad_optional_access()), **this;
- }
- constexpr T const && value() const &&
- {
- return (has_value() || detail::throw_bad_optional_access()),
- detail::move(**this);
- }
- constexpr T && value() &&
- {
- return (has_value() || detail::throw_bad_optional_access()),
- detail::move(**this);
- }
-
- CPP_template(typename U)( //
- requires copy_constructible<T> && convertible_to<U, T>) //
- constexpr T value_or(U && u) const &
- {
- return has_value() ? **this : static_cast<T>((U &&) u);
- }
- CPP_template(typename U)( //
- requires move_constructible<T> && convertible_to<U, T>) //
- constexpr T value_or(U && u) &&
- {
- return has_value() ? detail::move(**this) : static_cast<T>((U &&) u);
- }
-
- using base_t::reset;
- };
-
- /// \cond
- namespace detail
- {
- namespace optional_adl
- {
- constexpr bool convert_bool(bool b) noexcept
- {
- return b;
- }
-
- // Relational operators [optional.relops]
- template<typename T, typename U>
- constexpr auto operator==(optional<T> const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(*x == *y)))
- -> decltype(convert_bool(*x == *y))
- {
- return x.has_value() == y.has_value() && (!x || convert_bool(*x == *y));
- }
- template<typename T, typename U>
- constexpr auto operator!=(optional<T> const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(*x != *y)))
- -> decltype(convert_bool(*x != *y))
- {
- return x.has_value() != y.has_value() || (x && convert_bool(*x != *y));
- }
- template<typename T, typename U>
- constexpr auto operator<(optional<T> const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(*x < *y)))
- -> decltype(convert_bool(*x < *y))
- {
- return y && (!x || convert_bool(*x < *y));
- }
- template<typename T, typename U>
- constexpr auto operator>(optional<T> const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(*x > *y)))
- -> decltype(convert_bool(*x > *y))
- {
- return x && (!y || convert_bool(*x > *y));
- }
- template<typename T, typename U>
- constexpr auto operator<=(optional<T> const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(*x <= *y)))
- -> decltype(convert_bool(*x <= *y))
- {
- return !x || (y && convert_bool(*x <= *y));
- }
- template<typename T, typename U>
- constexpr auto operator>=(optional<T> const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(*x >= *y)))
- -> decltype(convert_bool(*x >= *y))
- {
- return !y || (x && convert_bool(*x >= *y));
- }
-
- // Comparisons with nullopt [optional.nullops]
- template<typename T>
- constexpr bool operator==(optional<T> const & x, nullopt_t) noexcept
- {
- return !x;
- }
- template<typename T>
- constexpr bool operator==(nullopt_t, optional<T> const & x) noexcept
- {
- return !x;
- }
- template<typename T>
- constexpr bool operator!=(optional<T> const & x, nullopt_t) noexcept
- {
- return !!x;
- }
- template<typename T>
- constexpr bool operator!=(nullopt_t, optional<T> const & x) noexcept
- {
- return !!x;
- }
- template<typename T>
- constexpr bool operator<(optional<T> const &, nullopt_t) noexcept
- {
- return false;
- }
- template<typename T>
- constexpr bool operator<(nullopt_t, optional<T> const & x) noexcept
- {
- return !!x;
- }
- template<typename T>
- constexpr bool operator>(optional<T> const & x, nullopt_t) noexcept
- {
- return !!x;
- }
- template<typename T>
- constexpr bool operator>(nullopt_t, optional<T> const &) noexcept
- {
- return false;
- }
- template<typename T>
- constexpr bool operator<=(optional<T> const & x, nullopt_t) noexcept
- {
- return !x;
- }
- template<typename T>
- constexpr bool operator<=(nullopt_t, optional<T> const &) noexcept
- {
- return true;
- }
- template<typename T>
- constexpr bool operator>=(optional<T> const &, nullopt_t) noexcept
- {
- return true;
- }
- template<typename T>
- constexpr bool operator>=(nullopt_t, optional<T> const & x) noexcept
- {
- return !x;
- }
-
- // Comparisons with T [optional.comp_with_t]
- template<typename T, typename U>
- constexpr auto operator==(optional<T> const & x, U const & y) //
- noexcept(noexcept(convert_bool(*x == y))) //
- -> decltype(convert_bool(*x == y))
- {
- return x && convert_bool(*x == y);
- }
- template<typename T, typename U>
- constexpr auto operator==(T const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(x == *y))) //
- -> decltype(convert_bool(x == *y))
- {
- return y && convert_bool(x == *y);
- }
- template<typename T, typename U>
- constexpr auto operator!=(optional<T> const & x, U const & y) //
- noexcept(noexcept(convert_bool(*x != y))) //
- -> decltype(convert_bool(*x != y))
- {
- return !x || convert_bool(*x != y);
- }
- template<typename T, typename U>
- constexpr auto operator!=(T const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(x != *y))) //
- -> decltype(convert_bool(x != *y))
- {
- return !y || convert_bool(x != *y);
- }
- template<typename T, typename U>
- constexpr auto operator<(optional<T> const & x, U const & y) //
- noexcept(noexcept(convert_bool(*x < y))) //
- -> decltype(convert_bool(*x < y))
- {
- return !x || convert_bool(*x < y);
- }
- template<typename T, typename U>
- constexpr auto operator<(T const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(x < *y))) //
- -> decltype(convert_bool(x < *y))
- {
- return y && convert_bool(x < *y);
- }
- template<typename T, typename U>
- constexpr auto operator>(optional<T> const & x, U const & y) //
- noexcept(noexcept(convert_bool(*x > y))) -> decltype(convert_bool(*x > y))
- {
- return x && convert_bool(*x > y);
- }
- template<typename T, typename U>
- constexpr auto operator>(T const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(x > *y))) //
- -> decltype(convert_bool(x > *y))
- {
- return !y || convert_bool(x > *y);
- }
- template<typename T, typename U>
- constexpr auto operator<=(optional<T> const & x, U const & y) //
- noexcept(noexcept(convert_bool(*x <= y))) //
- -> decltype(convert_bool(*x <= y))
- {
- return !x || convert_bool(*x <= y);
- }
- template<typename T, typename U>
- constexpr auto operator<=(T const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(x <= *y))) //
- -> decltype(convert_bool(x <= *y))
- {
- return y && convert_bool(x <= *y);
- }
- template<typename T, typename U>
- constexpr auto operator>=(optional<T> const & x, U const & y) //
- noexcept(noexcept(convert_bool(*x >= y))) //
- -> decltype(convert_bool(*x >= y))
- {
- return x && convert_bool(*x >= y);
- }
- template<typename T, typename U>
- constexpr auto operator>=(T const & x, optional<U> const & y) //
- noexcept(noexcept(convert_bool(x >= *y))) //
- -> decltype(convert_bool(x >= *y))
- {
- return !y || convert_bool(x >= *y);
- }
-
- // clang-format off
- template<typename T>
- auto CPP_auto_fun(swap)(optional<T> &x, optional<T> &y)
- (
- return x.swap(y)
- )
- // clang-format on
- } // namespace optional_adl
- } // namespace detail
- /// \endcond
-
- // clang-format off
- template<typename T>
- constexpr auto CPP_auto_fun(make_optional)(T &&t)
- (
- return optional<detail::decay_t<T>>{static_cast<T &&>(t)}
- )
- template<typename T, typename... Args>
- constexpr auto CPP_auto_fun(make_optional)(Args &&... args)
- (
- return optional<T>{in_place, static_cast<Args &&>(args)...}
- )
- template<typename T, typename U, typename... Args>
- constexpr auto CPP_auto_fun(make_optional)(std::initializer_list<U> il,
- Args &&... args)
- (
- return optional<T>{in_place, il, static_cast<Args &&>(args)...}
- )
- // clang-format on
-
- /// \cond
- namespace detail
- {
- template<typename T, typename Tag = void, bool Enable = true>
- struct non_propagating_cache : optional<T>
- {
- non_propagating_cache() = default;
- constexpr non_propagating_cache(nullopt_t) noexcept
- {}
- constexpr non_propagating_cache(non_propagating_cache const &) noexcept
- : optional<T>{}
- {}
- constexpr non_propagating_cache(non_propagating_cache && that) noexcept
- : optional<T>{}
- {
- that.optional<T>::reset();
- }
- constexpr non_propagating_cache & operator=(
- non_propagating_cache const &) noexcept
- {
- optional<T>::reset();
- return *this;
- }
- constexpr non_propagating_cache & operator=(
- non_propagating_cache && that) noexcept
- {
- that.optional<T>::reset();
- optional<T>::reset();
- return *this;
- }
- using optional<T>::operator=;
- };
-
- template<typename T, typename Tag>
- struct non_propagating_cache<T, Tag, false>
- {};
- } // namespace detail
- /// \endcond
- } // namespace ranges
-
- #endif
|