Commit 9e589880 by Jonathan Wakely

libstdc++: Define <=> for tuple, optional and variant

Another piece of P1614R2.

	* include/std/optional (operator<=>(optional<T>, optional<U>))
	(operator<=>(optional<T>, nullopt), operator<=>(optional<T>, U)):
	Define for C++20.
	* include/std/tuple (__tuple_cmp): New helper function for <=>.
	(operator<=>(tuple<T...>, tuple<U>...)): Define for C++20.
	* include/std/variant (operator<=>(variant<T...>, variant<T...>))
	(operator<=>(monostate, monostate)): Define for C++20.
	* testsuite/20_util/optional/relops/three_way.cc: New test.
	* testsuite/20_util/tuple/comparison_operators/three_way.cc: New test.
	* testsuite/20_util/variant/89851.cc: Move to ...
	* testsuite/20_util/variant/relops/89851.cc: ... here.
	* testsuite/20_util/variant/90008.cc: Move to ...
	* testsuite/20_util/variant/relops/90008.cc: ... here.
	* testsuite/20_util/variant/relops/three_way.cc: New test.
parent 131fbdd7
2020-02-21 Jonathan Wakely <jwakely@redhat.com>
* include/std/optional (operator<=>(optional<T>, optional<U>))
(operator<=>(optional<T>, nullopt), operator<=>(optional<T>, U)):
Define for C++20.
* include/std/tuple (__tuple_cmp): New helper function for <=>.
(operator<=>(tuple<T...>, tuple<U>...)): Define for C++20.
* include/std/variant (operator<=>(variant<T...>, variant<T...>))
(operator<=>(monostate, monostate)): Define for C++20.
* testsuite/20_util/optional/relops/three_way.cc: New test.
* testsuite/20_util/tuple/comparison_operators/three_way.cc: New test.
* testsuite/20_util/variant/89851.cc: Move to ...
* testsuite/20_util/variant/relops/89851.cc: ... here.
* testsuite/20_util/variant/90008.cc: Move to ...
* testsuite/20_util/variant/relops/90008.cc: ... here.
* testsuite/20_util/variant/relops/three_way.cc: New test.
2020-02-20 Patrick Palka <ppalka@redhat.com> 2020-02-20 Patrick Palka <ppalka@redhat.com>
* include/std/ranges (views::__adaptor::__maybe_refwrap): New utility * include/std/ranges (views::__adaptor::__maybe_refwrap): New utility
......
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
#include <bits/exception_defines.h> #include <bits/exception_defines.h>
#include <bits/functional_hash.h> #include <bits/functional_hash.h>
#include <bits/enable_special_members.h> #include <bits/enable_special_members.h>
#if __cplusplus > 201703L
# include <compare>
#endif
namespace std _GLIBCXX_VISIBILITY(default) namespace std _GLIBCXX_VISIBILITY(default)
{ {
...@@ -1027,12 +1030,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1027,12 +1030,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs); return !__rhs || (static_cast<bool>(__lhs) && *__lhs >= *__rhs);
} }
#ifdef __cpp_lib_three_way_comparison
template<typename _Tp, three_way_comparable_with<_Tp> _Up>
constexpr compare_three_way_result_t<_Tp, _Up>
operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y)
{
return __x && __y ? *__x <=> *__y : bool(__x) <=> bool(__y);
}
#endif
// Comparisons with nullopt. // Comparisons with nullopt.
template<typename _Tp> template<typename _Tp>
constexpr bool constexpr bool
operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept
{ return !__lhs; } { return !__lhs; }
#ifdef __cpp_lib_three_way_comparison
template<typename _Tp>
constexpr strong_ordering
operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept
{ return bool(__x) <=> false; }
#else
template<typename _Tp> template<typename _Tp>
constexpr bool constexpr bool
operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept
...@@ -1087,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1087,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr bool constexpr bool
operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept
{ return !__rhs; } { return !__rhs; }
#endif // three-way-comparison
// Comparisons with value type. // Comparisons with value type.
template<typename _Tp, typename _Up> template<typename _Tp, typename _Up>
...@@ -1161,6 +1180,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1161,6 +1180,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
-> __optional_relop_t<decltype(declval<_Up>() >= declval<_Tp>())> -> __optional_relop_t<decltype(declval<_Up>() >= declval<_Tp>())>
{ return !__rhs || __lhs >= *__rhs; } { return !__rhs || __lhs >= *__rhs; }
#ifdef __cpp_lib_three_way_comparison
template<typename _Tp, typename _Up>
constexpr compare_three_way_result_t<_Tp, _Up>
operator<=>(const optional<_Tp>& __x, const _Up& __v)
{ return bool(__x) ? *__x <=> __v : strong_ordering::less; }
#endif
// Swap and creation functions. // Swap and creation functions.
// _GLIBCXX_RESOLVE_LIB_DEFECTS // _GLIBCXX_RESOLVE_LIB_DEFECTS
......
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
#include <array> #include <array>
#include <bits/uses_allocator.h> #include <bits/uses_allocator.h>
#include <bits/invoke.h> #include <bits/invoke.h>
#if __cplusplus > 201703L
# include <compare>
#endif
namespace std _GLIBCXX_VISIBILITY(default) namespace std _GLIBCXX_VISIBILITY(default)
{ {
...@@ -1397,6 +1400,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1397,6 +1400,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __compare::__eq(__t, __u); return __compare::__eq(__t, __u);
} }
#if __cpp_lib_three_way_comparison
template<typename _Cat, typename _Tp, typename _Up>
constexpr _Cat
__tuple_cmp(const _Tp&, const _Up&, index_sequence<>)
{ return _Cat::equivalent; }
template<typename _Cat, typename _Tp, typename _Up,
size_t _Idx0, size_t... _Idxs>
constexpr _Cat
__tuple_cmp(const _Tp& __t, const _Up& __u,
index_sequence<_Idx0, _Idxs...>)
{
auto __c
= __detail::__synth3way(std::get<_Idx0>(__t), std::get<_Idx0>(__u));
if (__c != 0)
return __c;
return std::__tuple_cmp<_Cat>(__t, __u, index_sequence<_Idxs...>());
}
template<typename... _Tps, typename... _Ups>
constexpr
common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>
operator<=>(const tuple<_Tps...>& __t, const tuple<_Ups...>& __u)
{
using _Cat
= common_comparison_category_t<__detail::__synth3way_t<_Tps, _Ups>...>;
return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Tps...>());
}
#else
template<typename... _TElements, typename... _UElements> template<typename... _TElements, typename... _UElements>
constexpr bool constexpr bool
operator<(const tuple<_TElements...>& __t, operator<(const tuple<_TElements...>& __t,
...@@ -1433,6 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1433,6 +1465,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
operator>=(const tuple<_TElements...>& __t, operator>=(const tuple<_TElements...>& __t,
const tuple<_UElements...>& __u) const tuple<_UElements...>& __u)
{ return !(__t < __u); } { return !(__t < __u); }
#endif // three_way_comparison
// NB: DR 705. // NB: DR 705.
template<typename... _Elements> template<typename... _Elements>
......
...@@ -45,6 +45,9 @@ ...@@ -45,6 +45,9 @@
#include <bits/stl_iterator_base_types.h> #include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h> #include <bits/stl_iterator_base_funcs.h>
#include <bits/stl_construct.h> #include <bits/stl_construct.h>
#if __cplusplus > 201703L
# include <compare>
#endif
namespace std _GLIBCXX_VISIBILITY(default) namespace std _GLIBCXX_VISIBILITY(default)
{ {
...@@ -1181,10 +1184,7 @@ namespace __variant ...@@ -1181,10 +1184,7 @@ namespace __variant
__ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \ __ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \
}, __rhs); \ }, __rhs); \
return __ret; \ return __ret; \
} \ }
\
constexpr bool operator __OP(monostate, monostate) noexcept \
{ return 0 __OP 0; }
_VARIANT_RELATION_FUNCTION_TEMPLATE(<, less) _VARIANT_RELATION_FUNCTION_TEMPLATE(<, less)
_VARIANT_RELATION_FUNCTION_TEMPLATE(<=, less_equal) _VARIANT_RELATION_FUNCTION_TEMPLATE(<=, less_equal)
...@@ -1195,6 +1195,45 @@ namespace __variant ...@@ -1195,6 +1195,45 @@ namespace __variant
#undef _VARIANT_RELATION_FUNCTION_TEMPLATE #undef _VARIANT_RELATION_FUNCTION_TEMPLATE
constexpr bool operator==(monostate, monostate) noexcept { return true; }
#ifdef __cpp_lib_three_way_comparison
template<typename... _Types>
requires (three_way_comparable<_Types> && ...)
constexpr
common_comparison_category_t<compare_three_way_result_t<_Types>...>
operator<=>(const variant<_Types...>& __v, const variant<_Types...>& __w)
{
common_comparison_category_t<compare_three_way_result_t<_Types>...> __ret
= strong_ordering::equal;
__detail::__variant::__raw_idx_visit(
[&__ret, &__v] (auto&& __w_mem, auto __w_index) mutable
{
if constexpr (__w_index != variant_npos)
{
if (__v.index() == __w_index)
{
auto& __this_mem = std::get<__w_index>(__v);
__ret = __this_mem <=> __w_mem;
return;
}
}
__ret = (__v.index() + 1) <=> (__w_index + 1);
}, __w);
return __ret;
}
constexpr strong_ordering
operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; }
#else
constexpr bool operator!=(monostate, monostate) noexcept { return false; }
constexpr bool operator<(monostate, monostate) noexcept { return false; }
constexpr bool operator>(monostate, monostate) noexcept { return false; }
constexpr bool operator<=(monostate, monostate) noexcept { return true; }
constexpr bool operator>=(monostate, monostate) noexcept { return true; }
#endif
template<typename _Visitor, typename... _Variants> template<typename _Visitor, typename... _Variants>
constexpr decltype(auto) visit(_Visitor&&, _Variants&&...); constexpr decltype(auto) visit(_Visitor&&, _Variants&&...);
......
// Copyright (C) 2020 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <optional>
void
test01()
{
using O = std::optional<int>;
static_assert( std::is_eq(O{} <=> O{}) );
static_assert( std::is_lt(O{} <=> O{1}) );
static_assert( std::is_gt(O{1} <=> O{}) );
static_assert( std::is_eq(O{1} <=> O{1}) );
static_assert( std::is_lt(O{1} <=> O{2}) );
static_assert( O{} == O{} );
static_assert( O{} < O{1} );
static_assert( O{1} > O{} );
static_assert( O{1} == O{1} );
static_assert( O{1} != O{2} );
static_assert( O{1} < O{2} );
using Os = std::optional<short>;
static_assert( std::is_eq(O{} <=> Os{}) );
static_assert( std::is_lt(O{} <=> Os{1}) );
static_assert( std::is_gt(O{1} <=> Os{}) );
static_assert( std::is_eq(O{1} <=> Os{1}) );
static_assert( std::is_lt(O{1} <=> Os{2}) );
static_assert( O{} == Os{} );
static_assert( O{} < Os{1} );
static_assert( O{1} > Os{} );
static_assert( O{1} == Os{1} );
static_assert( O{1} != Os{2} );
static_assert( O{1} < Os{2} );
// Would requires narrowing conversion to make operands the same type:
static_assert( !std::three_way_comparable_with<O, std::optional<unsigned>> );
}
void
test02()
{
using O = std::optional<int>;
using std::nullopt;
static_assert( std::is_eq(O{} <=> nullopt) );
static_assert( std::is_gt(O{1} <=> nullopt) );
static_assert( std::is_lt(nullopt <=> O{1}) );
static_assert( O{} == nullopt );
static_assert( O{1} != nullopt );
static_assert( nullopt != O{1} );
static_assert( O{1} > nullopt );
static_assert( nullopt < O{1} );
static_assert( nullopt <= O{} );
static_assert( nullopt <= O{1} );
}
// { dg-options "-std=gnu++2a" }
// { dg-do run { target c++2a } }
// Copyright (C) 2020 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// Tuple
#include <tuple>
#include <testsuite_hooks.h>
using namespace std;
template<typename T>
bool self_consistent(const T& x)
{
return std::is_eq(x <=> x) && x == x && !(x != x) && x <= x && !(x < x);
}
void
test01()
{
int i=0;
int j=0;
int k=2;
tuple<int, int, int> a(0, 0, 0);
tuple<int, int, int> b(0, 0, 1);
tuple<int& , int& , int&> c(i,j,k);
tuple<const int&, const int&, const int&> d(c);
VERIFY( self_consistent(a) );
VERIFY( self_consistent(b) );
VERIFY( self_consistent(c) );
VERIFY( self_consistent(d) );
VERIFY( !(a > a) && !(b > b) );
VERIFY( a >= a && b >= b );
VERIFY( a < b && !(b < a) && a <= b && !(b <= a) );
VERIFY( b > a && !(a > b) && b >= a && !(a >= b) );
VERIFY( std::is_lt(a <=> b) );
VERIFY( std::is_gt(b <=> a) );
VERIFY( std::is_gt(c <=> a) );
VERIFY( std::is_eq(c <=> d) );
static_assert( std::is_same_v<decltype(a <=> d), std::strong_ordering> );
}
template<typename T, typename U, typename C>
constexpr bool
check_compare(T&& t, U&& u, C c)
{
using R = std::compare_three_way_result_t<T, U>;
static_assert( std::same_as<C, R> );
return (t <=> u) == c;
}
void
test02()
{
using std::strong_ordering;
using std::weak_ordering;
using std::partial_ordering;
using T0 = std::tuple<>;
static_assert( check_compare(T0(), T0(), strong_ordering::equal) );
using Ti = std::tuple<int>;
using Tu = std::tuple<unsigned>;
static_assert( check_compare(Ti(1), Tu(1u), weak_ordering::equivalent) );
static_assert( check_compare(Ti(1), Tu(2u), weak_ordering::less) );
static_assert( check_compare(Ti(-1), Tu(1u), weak_ordering::greater) );
using Tii = std::tuple<int, int>;
using Tlu = std::tuple<long, unsigned>;
static_assert( check_compare(Tii(1, 2), Tlu(2l, 1u), weak_ordering::less) );
using Tid = std::tuple<int, double>;
static_assert( check_compare(Tii(3, 4), Tid(2, 0.9), partial_ordering::greater) );
static_assert( !std::three_way_comparable_with<T0, Ti> );
static_assert( !std::three_way_comparable_with<Ti, Tii> );
static_assert( !std::three_way_comparable_with<Ti, Tid> );
}
int main()
{
test01();
test02();
}
// Copyright (C) 2020 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// { dg-options "-std=gnu++2a" }
// { dg-do compile { target c++2a } }
#include <variant>
void
test01()
{
using V = std::variant<int, int>;
constexpr auto I0 = std::in_place_index<0>;
constexpr auto I1 = std::in_place_index<1>;
static_assert( std::is_eq(V{I0, 0} <=> V{I0, 0}) );
static_assert( std::is_eq(V{I0, 1} <=> V{I0, 1}) );
static_assert( std::is_lt(V{I0, 0} <=> V{I1, 0}) );
static_assert( std::is_lt(V{I0, 1} <=> V{I1, 0}) );
static_assert( std::is_gt(V{I0, 1} <=> V{I0, 0}) );
static_assert( std::is_gt(V{I1, 0} <=> V{I0, 1}) );
static_assert( V{I0, 0} == V{I0, 0} );
static_assert( V{I0, 0} != V{I1, 0} );
static_assert( V{I1, 0} != V{I1, 1} );
}
void
test02()
{
static_assert( std::is_eq(std::monostate{} <=> std::monostate{}) );
static_assert( std::monostate{} == std::monostate{} );
static_assert( std::monostate{} <= std::monostate{} );
static_assert( std::monostate{} >= std::monostate{} );
static_assert( !(std::monostate{} != std::monostate{}) );
static_assert( !(std::monostate{} < std::monostate{}) );
static_assert( !(std::monostate{} > std::monostate{}) );
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment