Certain headers require `optional<T&>`, so it may be beneficial to split out `optional<T>` and `optional<T&>`. This can allow consumers to only bring in the `optional` flavour it needs.. - Parcel out the respective pieces into their own header. - Certain sources rely on transitive includes brought in by `<optional>`, so they're kept there for now, and only tests have been fixed. --------- Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
349 lines
11 KiB
C++
349 lines
11 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP___OPTIONAL_COMPARISON_H
|
|
#define _LIBCPP___OPTIONAL_COMPARISON_H
|
|
|
|
#include <__compare/compare_three_way_result.h>
|
|
#include <__compare/ordering.h>
|
|
#include <__compare/three_way_comparable.h>
|
|
#include <__config>
|
|
#include <__optional/nullopt_t.h>
|
|
#include <__type_traits/enable_if.h>
|
|
#include <__type_traits/is_constructible.h>
|
|
#include <__type_traits/is_core_convertible.h>
|
|
#include <__type_traits/is_swappable.h>
|
|
#include <__utility/declval.h>
|
|
|
|
#include <__fwd/optional.h>
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
#endif
|
|
|
|
_LIBCPP_PUSH_MACROS
|
|
#include <__undef_macros>
|
|
|
|
#if _LIBCPP_STD_VER >= 17
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
// [optional.relops] Relational operators
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const optional<_Up>& __y) {
|
|
if (static_cast<bool>(__x) != static_cast<bool>(__y))
|
|
return false;
|
|
if (!static_cast<bool>(__x))
|
|
return true;
|
|
return *__x == *__y;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const optional<_Up>& __y) {
|
|
if (static_cast<bool>(__x) != static_cast<bool>(__y))
|
|
return true;
|
|
if (!static_cast<bool>(__x))
|
|
return false;
|
|
return *__x != *__y;
|
|
}
|
|
|
|
template < class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const optional<_Up>& __y) {
|
|
if (!static_cast<bool>(__y))
|
|
return false;
|
|
if (!static_cast<bool>(__x))
|
|
return true;
|
|
return *__x < *__y;
|
|
}
|
|
|
|
template < class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const optional<_Up>& __y) {
|
|
if (!static_cast<bool>(__x))
|
|
return false;
|
|
if (!static_cast<bool>(__y))
|
|
return true;
|
|
return *__x > *__y;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const optional<_Up>& __y) {
|
|
if (!static_cast<bool>(__x))
|
|
return true;
|
|
if (!static_cast<bool>(__y))
|
|
return false;
|
|
return *__x <= *__y;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const optional<_Up>& __y) {
|
|
if (!static_cast<bool>(__y))
|
|
return true;
|
|
if (!static_cast<bool>(__x))
|
|
return false;
|
|
return *__x >= *__y;
|
|
}
|
|
|
|
# if _LIBCPP_STD_VER >= 20
|
|
|
|
template <class _Tp, three_way_comparable_with<_Tp> _Up>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up>
|
|
operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) {
|
|
if (__x && __y)
|
|
return *__x <=> *__y;
|
|
return __x.has_value() <=> __y.has_value();
|
|
}
|
|
|
|
# endif // _LIBCPP_STD_VER >= 20
|
|
|
|
// [optional.nullops] Comparison with nullopt
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, nullopt_t) noexcept {
|
|
return !static_cast<bool>(__x);
|
|
}
|
|
|
|
# if _LIBCPP_STD_VER <= 17
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(nullopt_t, const optional<_Tp>& __x) noexcept {
|
|
return !static_cast<bool>(__x);
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, nullopt_t) noexcept {
|
|
return static_cast<bool>(__x);
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(nullopt_t, const optional<_Tp>& __x) noexcept {
|
|
return static_cast<bool>(__x);
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>&, nullopt_t) noexcept {
|
|
return false;
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(nullopt_t, const optional<_Tp>& __x) noexcept {
|
|
return static_cast<bool>(__x);
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, nullopt_t) noexcept {
|
|
return !static_cast<bool>(__x);
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(nullopt_t, const optional<_Tp>&) noexcept {
|
|
return true;
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, nullopt_t) noexcept {
|
|
return static_cast<bool>(__x);
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(nullopt_t, const optional<_Tp>&) noexcept {
|
|
return false;
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>&, nullopt_t) noexcept {
|
|
return true;
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(nullopt_t, const optional<_Tp>& __x) noexcept {
|
|
return !static_cast<bool>(__x);
|
|
}
|
|
|
|
# else // _LIBCPP_STD_VER <= 17
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept {
|
|
return __x.has_value() <=> false;
|
|
}
|
|
|
|
# endif // _LIBCPP_STD_VER <= 17
|
|
|
|
// [optional.comp.with.t] Comparison with T
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const optional<_Tp>& __x, const _Up& __v) {
|
|
if (__x.has_value())
|
|
return *__x == __v;
|
|
return false;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() == std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator==(const _Tp& __v, const optional<_Up>& __x) {
|
|
if (__x.has_value())
|
|
return __v == *__x;
|
|
return false;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const optional<_Tp>& __x, const _Up& __v) {
|
|
if (__x.has_value())
|
|
return *__x != __v;
|
|
return true;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() != std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator!=(const _Tp& __v, const optional<_Up>& __x) {
|
|
if (__x.has_value())
|
|
return __v != *__x;
|
|
return true;
|
|
}
|
|
|
|
template < class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const optional<_Tp>& __x, const _Up& __v) {
|
|
if (__x.has_value())
|
|
return *__x < __v;
|
|
return true;
|
|
}
|
|
|
|
template < class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() < std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<(const _Tp& __v, const optional<_Up>& __x) {
|
|
if (__x.has_value())
|
|
return __v < *__x;
|
|
return false;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const optional<_Tp>& __x, const _Up& __v) {
|
|
if (__x.has_value())
|
|
return *__x <= __v;
|
|
return true;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() <= std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator<=(const _Tp& __v, const optional<_Up>& __x) {
|
|
if (__x.has_value())
|
|
return __v <= *__x;
|
|
return false;
|
|
}
|
|
|
|
template < class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const optional<_Tp>& __x, const _Up& __v) {
|
|
if (__x.has_value())
|
|
return *__x > __v;
|
|
return false;
|
|
}
|
|
|
|
template < class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() > std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>(const _Tp& __v, const optional<_Up>& __x) {
|
|
if (__x.has_value())
|
|
return __v > *__x;
|
|
return true;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const optional<_Tp>& __x, const _Up& __v) {
|
|
if (__x.has_value())
|
|
return *__x >= __v;
|
|
return false;
|
|
}
|
|
|
|
template <
|
|
class _Tp,
|
|
class _Up,
|
|
enable_if_t<__is_core_convertible_v<decltype(std::declval<const _Tp&>() >= std::declval<const _Up&>()), bool>,
|
|
int> = 0>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr bool operator>=(const _Tp& __v, const optional<_Up>& __x) {
|
|
if (__x.has_value())
|
|
return __v >= *__x;
|
|
return true;
|
|
}
|
|
|
|
# if _LIBCPP_STD_VER >= 20
|
|
|
|
template <class _Tp>
|
|
concept __is_derived_from_optional = requires(const _Tp& __t) { []<class _Up>(const optional<_Up>&) {}(__t); };
|
|
|
|
template <class _Tp, class _Up>
|
|
requires(!__is_derived_from_optional<_Up>) && three_way_comparable_with<_Tp, _Up>
|
|
_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up>
|
|
operator<=>(const optional<_Tp>& __x, const _Up& __v) {
|
|
return __x.has_value() ? *__x <=> __v : strong_ordering::less;
|
|
}
|
|
|
|
# endif // _LIBCPP_STD_VER >= 20
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
#endif // _LIBCPP_STD_VER >= 17
|
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
#endif // _LIBCPP___OPTIONAL_COMPARISON_H
|