diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv --- a/libcxx/docs/Status/SpaceshipProjects.csv +++ b/libcxx/docs/Status/SpaceshipProjects.csv @@ -39,7 +39,8 @@ | `[deque.syn] `_ (`general `_),| `deque `_,[expos.only.func],Hristo Hristov,|Complete| | `[forward.list.syn] `_ (`general `_),| `forward_list `_,[expos.only.func],Hristo Hristov,|Complete| | `[list.syn] `_ (`general `_),| `list `_,[expos.only.func],Adrian Vogelsgesang,|Complete| -| `[vector.syn] `_ (`general `_),| `vector `_,[expos.only.func],Adrian Vogelsgesang,|In Progress| +| `[vector.syn] `_ (`general `_),| `vector `_,[expos.only.func],"| Adrian Vogelsgesang +| Hristo Hristov",|Complete| | `[associative.map.syn] `_ (`general `_),"| `map `_ | `multimap `_",[expos.only.func],Hristo Hristov,|Complete| | `[associative.set.syn] `_ (`general `_),"| multiset diff --git a/libcxx/include/__algorithm/lexicographical_compare_three_way.h b/libcxx/include/__algorithm/lexicographical_compare_three_way.h --- a/libcxx/include/__algorithm/lexicographical_compare_three_way.h +++ b/libcxx/include/__algorithm/lexicographical_compare_three_way.h @@ -18,6 +18,7 @@ #include <__iterator/iterator_traits.h> #include <__type_traits/common_type.h> #include <__type_traits/is_copy_constructible.h> +#include <__utility/forward.h> #include <__utility/move.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -35,7 +36,7 @@ // then skips the iterator comparisons inside the loop. template _LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_fast_path( - _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Cmp& __comp) + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Cmp&& __comp) -> decltype(__comp(*__first1, *__first2)) { static_assert( signed_integral<__iter_diff_t<_InputIterator1>>, "Using a non-integral difference_type is undefined behavior."); @@ -65,7 +66,7 @@ // Unoptimized implementation which compares the iterators against the end in every loop iteration template _LIBCPP_HIDE_FROM_ABI constexpr auto __lexicographical_compare_three_way_slow_path( - _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Cmp& __comp) + _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _Cmp&& __comp) -> decltype(__comp(*__first1, *__first2)) { while (true) { bool __exhausted1 = __first1 == __last1; @@ -101,11 +102,19 @@ if constexpr (__is_cpp17_random_access_iterator<_InputIterator1>::value && __is_cpp17_random_access_iterator<_InputIterator2>::value) { return std::__lexicographical_compare_three_way_fast_path( - std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __wrapped_comp_ref); + std::forward<_InputIterator1>(__first1), + std::forward<_InputIterator1>(__last1), + std::forward<_InputIterator2>(__first2), + std::forward<_InputIterator2>(__last2), + std::move(__wrapped_comp_ref)); } else { // Unoptimized implementation which compares the iterators against the end in every loop iteration return std::__lexicographical_compare_three_way_slow_path( - std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), __wrapped_comp_ref); + std::forward<_InputIterator1>(__first1), + std::forward<_InputIterator1>(__last1), + std::forward<_InputIterator2>(__first2), + std::forward<_InputIterator2>(__last2), + std::move(__wrapped_comp_ref)); } } @@ -113,7 +122,11 @@ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto lexicographical_compare_three_way( _InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { return std::lexicographical_compare_three_way( - std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), std::compare_three_way()); + std::forward<_InputIterator1>(__first1), + std::forward<_InputIterator1>(__last1), + std::forward<_InputIterator2>(__first2), + std::forward<_InputIterator2>(__last2), + std::compare_three_way()); } #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__algorithm/three_way_comp_ref_type.h b/libcxx/include/__algorithm/three_way_comp_ref_type.h --- a/libcxx/include/__algorithm/three_way_comp_ref_type.h +++ b/libcxx/include/__algorithm/three_way_comp_ref_type.h @@ -28,7 +28,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr __debug_three_way_comp(_Comp& __c) : __comp_(__c) {} template - _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp& __x, _Up& __y) { + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __x, _Up&& __y) { auto __r = __comp_(__x, __y); __do_compare_assert(0, __y, __x, __r); return __r; diff --git a/libcxx/include/vector b/libcxx/include/vector --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -249,12 +249,15 @@ template struct hash>; -template bool operator==(const vector& x, const vector& y); -template bool operator< (const vector& x, const vector& y); -template bool operator!=(const vector& x, const vector& y); -template bool operator> (const vector& x, const vector& y); -template bool operator>=(const vector& x, const vector& y); -template bool operator<=(const vector& x, const vector& y); +template bool operator==(const vector& x, const vector& y); // constexpr since C++20 +template bool operator!=(const vector& x, const vector& y); // removed in C++20 +template bool operator< (const vector& x, const vector& y); // removed in C++20 +template bool operator> (const vector& x, const vector& y); // removed in C++20 +template bool operator>=(const vector& x, const vector& y); // removed in C++20 +template bool operator<=(const vector& x, const vector& y); // removed in C++20 +template constexpr + constexpr synth-three-way-result operator<=>(const vector& x, + const vector& y); // since C++20 template void swap(vector& x, vector& y) @@ -262,10 +265,10 @@ template typename vector::size_type -erase(vector& c, const U& value); // C++20 +erase(vector& c, const U& value); // since C++20 template typename vector::size_type -erase_if(vector& c, Predicate pred); // C++20 +erase_if(vector& c, Predicate pred); // since C++20 template @@ -282,6 +285,7 @@ #include <__algorithm/equal.h> #include <__algorithm/fill_n.h> #include <__algorithm/lexicographical_compare.h> +#include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/remove.h> #include <__algorithm/remove_if.h> #include <__algorithm/rotate.h> @@ -3242,8 +3246,9 @@ return __sz == __y.size() && std::equal(__x.begin(), __x.end(), __y.begin()); } +#if _LIBCPP_STD_VER <= 17 + template -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI bool operator!=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) @@ -3252,7 +3257,6 @@ } template -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI bool operator< (const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) @@ -3261,7 +3265,6 @@ } template -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI bool operator> (const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) @@ -3270,7 +3273,6 @@ } template -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI bool operator>=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) @@ -3279,7 +3281,6 @@ } template -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) @@ -3287,6 +3288,17 @@ return !(__y < __x); } +#else // _LIBCPP_STD_VER <= 17 + +template +_LIBCPP_HIDE_FROM_ABI constexpr __synth_three_way_result<_Tp> +operator<=>(const vector<_Tp, _Allocator>& __x, const vector<_Tp, _Allocator>& __y) { + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way<_Tp, _Tp>); +} + +#endif // _LIBCPP_STD_VER <= 17 + template _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI diff --git a/libcxx/test/std/containers/sequences/vector.bool/compare.three_way.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/compare.three_way.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector.bool/compare.three_way.pass.cpp @@ -0,0 +1,94 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template +// constexpr synth-three-way-result operator<=>(const vector& x, +// const vector& y); + +#include +#include + +#include "test_comparisons.h" + +constexpr bool test_sequence_container_spaceship_vectorbool() { + // Empty containers + { + std::vector l1; + std::vector l2; + assert(testOrder(l1, l2, std::strong_ordering::equivalent)); + } + // Identical contents + { + std::vector t1{true, true}; + std::vector t2{true, true}; + assert(testOrder(t1, t2, std::strong_ordering::equivalent)); + + std::vector f1{false, false}; + std::vector f2{false, false}; + assert(testOrder(f1, f2, std::strong_ordering::equivalent)); + } + // Less, due to contained values + { + std::vector l1{true, false}; + std::vector l2{true, true}; + assert(testOrder(l1, l2, std::strong_ordering::less)); + } + // Greater, due to contained values + { + std::vector l1{true, true}; + std::vector l2{true, false}; + assert(testOrder(l1, l2, std::strong_ordering::greater)); + } + // Shorter list + { + std::vector l1{true}; + std::vector l2{true, false}; + assert(testOrder(l1, l2, std::strong_ordering::less)); + + std::vector t1{true}; + std::vector t2{true, true}; + assert(testOrder(t1, t2, std::strong_ordering::less)); + + std::vector f1{false}; + std::vector f2{false, false}; + assert(testOrder(f1, f2, std::strong_ordering::less)); + + std::vector e; + assert(testOrder(e, t1, std::strong_ordering::less)); + assert(testOrder(e, f1, std::strong_ordering::less)); + } + // Longer list + { + std::vector l1{true, false}; + std::vector l2{true}; + assert(testOrder(l1, l2, std::strong_ordering::greater)); + + std::vector t1{true, true}; + std::vector t2{true}; + assert(testOrder(t1, t2, std::strong_ordering::greater)); + + std::vector f1{false, false}; + std::vector f2{false}; + assert(testOrder(f1, f2, std::strong_ordering::greater)); + + std::vector e; + assert(testOrder(t2, e, std::strong_ordering::greater)); + assert(testOrder(f2, e, std::strong_ordering::greater)); + } + + return true; +} + +int main(int, char**) { + assert(test_sequence_container_spaceship_vectorbool()); + static_assert(test_sequence_container_spaceship_vectorbool()); + return 0; +} diff --git a/libcxx/test/std/containers/sequences/vector/compare.three_way.pass.cpp b/libcxx/test/std/containers/sequences/vector/compare.three_way.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/vector/compare.three_way.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// + +// template +// constexpr synth-three-way-result operator<=>(const vector& x, +// const vector& y); + +#include +#include + +#include "test_container_comparisons.h" + +int main(int, char**) { + assert(test_sequence_container_spaceship()); + static_assert(test_sequence_container_spaceship()); + return 0; +} diff --git a/libcxx/test/support/test_container_comparisons.h b/libcxx/test/support/test_container_comparisons.h --- a/libcxx/test/support/test_container_comparisons.h +++ b/libcxx/test/support/test_container_comparisons.h @@ -62,6 +62,10 @@ // Tests the `operator<=>` on sequence containers template