axmol/thirdparty/range-v3/include/range/v3/utility/optional.hpp

997 lines
37 KiB
C++

/// \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>
#include <range/v3/detail/prologue.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
{};
constexpr explicit 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::bool_<detail::is_trivially_default_constructible_v<T> &&
detail::is_trivially_copyable_v<T>>{})
{}
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}
{}
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_v<T> &&
detail::is_trivially_move_assignable_v<T>;
swap_(meta::bool_<can_swap_trivially>{}, that);
}
protected:
template(typename... Args)(
requires constructible_from<T, Args...>)
T & construct_from(Args &&... args)
noexcept(std::is_nothrow_constructible<T, Args...>::value)
{
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 I)(
requires constructible_from<T, decltype(*std::declval<const I &>())>)
T & construct_from_deref(const I & it)
{
RANGES_EXPECT(!engaged_);
auto const address = static_cast<void *>(std::addressof(data_));
::new(address) T(*it);
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)(
requires constructible_from<T &, Arg>)
constexpr explicit optional_base(in_place_t, Arg && arg) noexcept //
: 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)(
requires convertible_to<U &, T &>)
constexpr T & construct_from(U && ref) noexcept
{
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_v<T>,
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_v<T>,
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_v<T> &&
detail::is_trivially_copy_assignable_v<T>),
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_v<T> &&
detail::is_trivially_move_assignable_v<T>),
optional_move_assign<T>, copy_assign_layer<T>>,
deleted_move_assign<T>>;
} // namespace optional_adl
} // namespace detail
/// \endcond
// clang-format off
/// \concept optional_should_convert
/// \brief The \c optional_should_convert concept
template<typename U, typename T>
CPP_concept optional_should_convert =
!(
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>
);
/// \concept optional_should_convert_assign
/// \brief The \c optional_should_convert_assign concept
template<typename U, typename T>
CPP_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;
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)...)
{}
#if defined(__cpp_conditional_explicit) && __cpp_conditional_explicit > 0
template(typename U = T)(
requires (!same_as<detail::decay_t<U>, in_place_t>) AND
(!same_as<detail::decay_t<U>, optional>) AND
constructible_from<T, U>)
constexpr explicit(!convertible_to<U, T>) optional(U && v)
: base_t(in_place, static_cast<U &&>(v))
{}
template(typename U)(
requires optional_should_convert<U, T> AND
constructible_from<T, U const &>)
explicit(!convertible_to<U const &, T>) optional(optional<U> const & that)
{
if(that.has_value())
base_t::construct_from(*that);
}
#else
template(typename U = T)(
requires (!same_as<detail::decay_t<U>, in_place_t>) AND
(!same_as<detail::decay_t<U>, optional>) AND
constructible_from<T, U> AND
convertible_to<U, T>)
constexpr optional(U && v)
: base_t(in_place, static_cast<U &&>(v))
{}
template(typename U = T)(
requires (!same_as<detail::decay_t<U>, in_place_t>) AND
(!same_as<detail::decay_t<U>, optional>) AND
constructible_from<T, U> AND
(!convertible_to<U, T>))
constexpr explicit optional(U && v)
: base_t(in_place, static_cast<U &&>(v))
{}
template(typename U)(
requires optional_should_convert<U, T> AND
constructible_from<T, U const &> AND
convertible_to<U const &, T>)
optional(optional<U> const & that)
{
if(that.has_value())
base_t::construct_from(*that);
}
template(typename U)(
requires optional_should_convert<U, T> AND
constructible_from<T, U const &> AND
(!convertible_to<U const &, T>))
explicit optional(optional<U> const & that)
{
if(that.has_value())
base_t::construct_from(*that);
}
#endif
template(typename U)(
requires optional_should_convert<U, T> AND constructible_from<T, U> AND
convertible_to<U, T>)
optional(optional<U> && that)
{
if(that.has_value())
base_t::construct_from(detail::move(*that));
}
template(typename U)(
requires optional_should_convert<U, T> AND constructible_from<T, U> AND
(!convertible_to<U, T>)) //
explicit optional(optional<U> && that)
{
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)(
requires (!same_as<optional, detail::decay_t<U>>) AND
(!(satisfies<T, std::is_scalar> && same_as<T, detail::decay_t<U>>)) AND
constructible_from<T, U> AND
assignable_from<T &, U>)
constexpr optional & operator=(U && u) noexcept(
std::is_nothrow_constructible<T, U>::value &&
std::is_nothrow_assignable<T &, U>::value)
{
if(has_value())
**this = static_cast<U &&>(u);
else
base_t::construct_from(static_cast<U &&>(u));
return *this;
}
template(typename U)(
requires optional_should_convert_assign<U, T> AND
constructible_from<T, const U &> AND
assignable_from<T &, const U &>)
constexpr optional & operator=(optional<U> const & that)
{
base_t::assign_from(that);
return *this;
}
template(typename U)(
requires optional_should_convert_assign<U, T> AND
constructible_from<T, U> AND
assignable_from<T &, U>)
constexpr optional & operator=(optional<U> && that)
{
base_t::assign_from(std::move(that));
return *this;
}
template(typename I)(
requires constructible_from<T, decltype(*std::declval<const I &>())>)
T & emplace_deref(const I & it)
{
reset();
return base_t::construct_from_deref(it);
}
template(typename... Args)(
requires constructible_from<T, Args...>)
T & emplace(Args &&... args) noexcept(
std::is_nothrow_constructible<T, Args...>::value)
{
reset();
return base_t::construct_from(static_cast<Args &&>(args)...);
}
template(typename E, typename... Args)(
requires constructible_from<T, std::initializer_list<E> &, Args...>)
T & emplace(std::initializer_list<E> il, Args &&... args) noexcept(
std::is_nothrow_constructible<T, std::initializer_list<E> &, Args...>::value)
{
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);
}
template(typename U)(
requires copy_constructible<T> AND convertible_to<U, T>)
constexpr T value_or(U && u) const &
{
return has_value() ? **this : static_cast<T>((U &&) u);
}
template(typename U)(
requires move_constructible<T> AND 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<class I>
constexpr T & emplace_deref(const I & i)
{
return optional<T>::emplace(*i);
}
};
template<typename T, typename Tag>
struct non_propagating_cache<T, Tag, false>
{};
} // namespace detail
/// \endcond
} // namespace ranges
#include <range/v3/detail/epilogue.hpp>
#endif