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 @@ -38,7 +38,7 @@ | `[array.syn] <https://wg21.link/array.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `array <https://reviews.llvm.org/D132265>`_,[expos.only.func],Adrian Vogelsgesang,|In Progress| | `[deque.syn] <https://wg21.link/deque.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| deque,[expos.only.func],Unassigned,|Not Started| | `[forward.list.syn] <https://wg21.link/forward.list.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| forward_list,[expos.only.func],Unassigned,|Not Started| -| `[list.syn] <https://wg21.link/list.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| list,[expos.only.func],Unassigned,|Not Started| +| `[list.syn] <https://wg21.link/list.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `list <https://reviews.llvm.org/D132312>`_,[expos.only.func],Adrian Vogelsgesang,|Complete| | `[vector.syn] <https://wg21.link/vector.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),| `vector <https://reviews.llvm.org/D132268>`_,[expos.only.func],Adrian Vogelsgesang,|In Progress| | `[associative.map.syn] <https://wg21.link/associative.map.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),"| map | multimap",[expos.only.func],Unassigned,|Not Started| diff --git a/libcxx/include/list b/libcxx/include/list --- a/libcxx/include/list +++ b/libcxx/include/list @@ -155,15 +155,18 @@ template <class T, class Alloc> bool operator==(const list<T,Alloc>& x, const list<T,Alloc>& y); template <class T, class Alloc> - bool operator< (const list<T,Alloc>& x, const list<T,Alloc>& y); + bool operator< (const list<T,Alloc>& x, const list<T,Alloc>& y); // removed in C++20 template <class T, class Alloc> - bool operator!=(const list<T,Alloc>& x, const list<T,Alloc>& y); + bool operator!=(const list<T,Alloc>& x, const list<T,Alloc>& y); // removed in C++20 template <class T, class Alloc> - bool operator> (const list<T,Alloc>& x, const list<T,Alloc>& y); + bool operator> (const list<T,Alloc>& x, const list<T,Alloc>& y); // removed in C++20 template <class T, class Alloc> - bool operator>=(const list<T,Alloc>& x, const list<T,Alloc>& y); + bool operator>=(const list<T,Alloc>& x, const list<T,Alloc>& y); // removed in C++20 template <class T, class Alloc> - bool operator<=(const list<T,Alloc>& x, const list<T,Alloc>& y); + bool operator<=(const list<T,Alloc>& x, const list<T,Alloc>& y); // removed in C++20 +template<class T, class Allocator> + synth-three-way-result<T> operator<=>(const list<T, Allocator>& x, + const list<T, Allocator>& y); // since C++20 template <class T, class Alloc> void swap(list<T,Alloc>& x, list<T,Alloc>& y) @@ -171,10 +174,10 @@ template <class T, class Allocator, class U> typename list<T, Allocator>::size_type - erase(list<T, Allocator>& c, const U& value); // C++20 + erase(list<T, Allocator>& c, const U& value); // since C++20 template <class T, class Allocator, class Predicate> typename list<T, Allocator>::size_type - erase_if(list<T, Allocator>& c, Predicate pred); // C++20 + erase_if(list<T, Allocator>& c, Predicate pred); // since C++20 } // std @@ -183,6 +186,7 @@ #include <__algorithm/comp.h> #include <__algorithm/equal.h> #include <__algorithm/lexicographical_compare.h> +#include <__algorithm/lexicographical_compare_three_way.h> #include <__algorithm/min.h> #include <__assert> // all public C++ headers provide the assertion handler #include <__config> @@ -2289,6 +2293,8 @@ return __x.size() == __y.size() && _VSTD::equal(__x.begin(), __x.end(), __y.begin()); } +#if _LIBCPP_STD_VER <= 17 + template <class _Tp, class _Alloc> inline _LIBCPP_INLINE_VISIBILITY bool @@ -2329,6 +2335,19 @@ return !(__y < __x); } +#else // _LIBCPP_STD_VER <= 17 + +template<class _Tp, class _Allocator> +inline _LIBCPP_HIDE_FROM_ABI +__synth_three_way_result<_Tp> +operator<=>(const list<_Tp, _Allocator>& __x, const list<_Tp, _Allocator>& __y) +{ + return std::lexicographical_compare_three_way( + __x.begin(), __x.end(), __y.begin(), __y.end(), __synth_three_way); +} + +#endif // _LIBCPP_STD_VER <= 17 + template <class _Tp, class _Alloc> inline _LIBCPP_INLINE_VISIBILITY void diff --git a/libcxx/test/std/containers/sequences/list/compare.three_way.pass.cpp b/libcxx/test/std/containers/sequences/list/compare.three_way.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/sequences/list/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 + +// <list> + +// template <class T, class Allocator> constexpr +// synth-three-way-result<T> +// operator<=>(const list<T, Allocator>& x, const list<T, Allocator>& y); + +#include <list> +#include <cassert> + +#include "test_container_comparisons.h" + +int main(int, char**) { + assert(test_ordered_container_spaceship<std::list>()); + // `std::list` is not constexpr, so no `static_assert` test here. + return 0; +} diff --git a/libcxx/test/support/test_container_comparisons.h b/libcxx/test/support/test_container_comparisons.h new file mode 100644 --- /dev/null +++ b/libcxx/test/support/test_container_comparisons.h @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// Utility functions to test comparisons on containers. + +#ifndef TEST_CONTAINER_COMPARISONS +#define TEST_CONTAINER_COMPARISONS + +#include "test_comparisons.h" + +// Implementation detail of `test_ordered_container_spaceship` +template <template <typename...> typename Container, typename Elem, typename Order> +constexpr void test_ordered_container_spaceship_with_type() { + // Empty containers + { + Container<Elem> l1; + Container<Elem> l2; + assert(testOrder(l1, l2, Order::equivalent)); + } + // Identical contents + { + Container<Elem> l1{1, 1}; + Container<Elem> l2{1, 1}; + assert(testOrder(l1, l2, Order::equivalent)); + } + // Less, due to contained values + { + Container<Elem> l1{1, 1}; + Container<Elem> l2{1, 2}; + assert(testOrder(l1, l2, Order::less)); + } + // Greater, due to contained values + { + Container<Elem> l1{1, 3}; + Container<Elem> l2{1, 2}; + assert(testOrder(l1, l2, Order::greater)); + } + // Shorter list + { + Container<Elem> l1{1}; + Container<Elem> l2{1, 2}; + assert(testOrder(l1, l2, Order::less)); + } + // Longer list + { + Container<Elem> l1{1, 2}; + Container<Elem> l2{1}; + assert(testOrder(l1, l2, Order::greater)); + } + // Unordered + if constexpr (std::is_same_v<Elem, PartialOrder>) { + Container<Elem> l1{1, std::numeric_limits<int>::min()}; + Container<Elem> l2{1, 2}; + assert(testOrder(l1, l2, Order::unordered)); + } +} + +// Tests the `operator<=>` on ordered containers +template <template <typename...> typename Container> +constexpr bool test_ordered_container_spaceship() { + // The container should fulfil `std::three_way_comparable` + static_assert(std::three_way_comparable<Container<int>>); + + // Test different comparison categories + test_ordered_container_spaceship_with_type<Container, int, std::strong_ordering>(); + test_ordered_container_spaceship_with_type<Container, StrongOrder, std::strong_ordering>(); + test_ordered_container_spaceship_with_type<Container, WeakOrder, std::weak_ordering>(); + test_ordered_container_spaceship_with_type<Container, PartialOrder, std::partial_ordering>(); + + // `LessAndEqComp` does not have `operator<=>`. ordering is sythesized based on `operator<` + test_ordered_container_spaceship_with_type<Container, LessAndEqComp, std::weak_ordering>(); + + // Thanks to SFINAE, the following is not a compiler error but returns `false` + struct NonComparable {}; + static_assert(!std::three_way_comparable<Container<NonComparable>>); + + return true; +} + +#endif