[libc++][spaceship] Implement operator<=> for queue

Implements parts of P1614R2 `operator<=>` for `queue`

Reviewed By: #libc, Mordante

Differential Revision: https://reviews.llvm.org/D146066
This commit is contained in:
Hristo Hristov 2023-03-14 18:32:15 +02:00
parent a395892820
commit 172d990c03
5 changed files with 151 additions and 1 deletions

View File

@ -45,7 +45,7 @@ Section,Description,Dependencies,Assignee,Complete
| `multimap <https://reviews.llvm.org/D145976>`_",[expos.only.func],Hristo Hristov,|Complete|
| `[associative.set.syn] <https://wg21.link/associative.set.syn>`_ (`general <https://wg21.link/container.opt.reqmts>`_),"| multiset
| set",[expos.only.func],Hristo Hristov,|In Progress|
| `[queue.ops] <https://wg21.link/queue.ops>`_,| `queue <https://reviews.llvm.org/D146066>`_,None,Hristo Hristov,|In Progress|
| `[queue.ops] <https://wg21.link/queue.ops>`_,| `queue <https://reviews.llvm.org/D146066>`_,None,Hristo Hristov,|Complete|
| `[stack.ops] <https://wg21.link/stack.ops>`_,| `stack <https://reviews.llvm.org/D146094>`_,None,Hristo Hristov,|In Progress|
| `[reverse.iter.cmp] <https://wg21.link/reverse.iter.cmp>`_,| `reverse_iterator <https://reviews.llvm.org/D113695>`_,None,Mikhail Maltsev,|Complete|
| `[move.iter.op.comp] <https://wg21.link/move.iter.op.comp>`_,| `move_iterator <https://reviews.llvm.org/D117656>`_,None,Arthur O'Dwyer,|Complete|

1 Section Description Dependencies Assignee Complete
45 | `[fs.path.nonmember] <https://wg21.link/fs.path.nonmember>`_ | `filesystem::path <https://reviews.llvm.org/D130859>`_ None Adrian Vogelsgesang |Complete|
46 | `[fs.dir.entry.obs] <https://wg21.link/fs.dir.entry.obs>`_ | `filesystem::directory_entry <https://reviews.llvm.org/D130860>`_ None Adrian Vogelsgesang |Complete|
47 | `[re.submatch.op] <https://wg21.link/re.submatch.op>`_ | `sub_match <https://reviews.llvm.org/D132310>`_ None Mark de Wever |Complete|
48 | `[thread.thread.id] <https://wg21.link/thread.thread.id>`_ | `thread::id <https://reviews.llvm.org/D131362>`_ None Adrian Vogelsgesang |Complete|
49
50
51

View File

@ -116,6 +116,10 @@ template <class T, class Container>
template <class T, class Container>
bool operator<=(const queue<T, Container>& x,const queue<T, Container>& y);
template<class T, three_way_comparable Container>
compare_three_way_result_t<Container>
operator<=>(const queue<T, Container>& x, const queue<T, Container>& y); // since C++20
template <class T, class Container>
void swap(queue<T, Container>& x, queue<T, Container>& y)
noexcept(noexcept(x.swap(y)));
@ -550,6 +554,17 @@ operator<=(const queue<_Tp, _Container>& __x,const queue<_Tp, _Container>& __y)
return !(__y < __x);
}
#if _LIBCPP_STD_VER >= 20
template <class _Tp, three_way_comparable _Container>
_LIBCPP_HIDE_FROM_ABI compare_three_way_result_t<_Container>
operator<=>(const queue<_Tp, _Container>& __x, const queue<_Tp, _Container>& __y) {
// clang 16 bug: declaring `friend operator<=>` causes "use of overloaded operator '*' is ambiguous" errors
return __x.__get_container() <=> __y.__get_container();
}
#endif
template <class _Tp, class _Container>
inline _LIBCPP_INLINE_VISIBILITY
__enable_if_t<__is_swappable<_Container>::value, void>

View File

@ -0,0 +1,30 @@
//===----------------------------------------------------------------------===//
//
// 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
// <queue>
// template<class T, three_way_comparable Container>
// compare_three_way_result_t<Container>
// operator<=>(const queue<T, Container>& x, const queue<T, Container>& y);
#include <cassert>
#include <deque>
#include <queue>
#include <list>
#include "nasty_containers.h"
#include "test_container_comparisons.h"
int main(int, char**) {
assert((test_sequence_container_adaptor_spaceship<std::queue, std::deque>()));
assert((test_sequence_container_adaptor_spaceship<std::queue, std::list>()));
assert((test_sequence_container_adaptor_spaceship<std::queue, nasty_list>()));
// `std::queue` is not constexpr, so no `static_assert` test here.
return 0;
}

View File

@ -138,6 +138,14 @@ public:
template <class T>
bool operator==(const nasty_vector<T>& x, const nasty_vector<T>& y) { return x.v_ == y.v_; }
#if TEST_STD_VER >= 20
template <class T>
auto operator<=>(const nasty_vector<T>& x, const nasty_vector<T>& y) { return x.v_ <=> y.v_; }
#endif
template <class T>
class nasty_list
{
@ -285,6 +293,13 @@ public:
template <class T>
bool operator==(const nasty_list<T>& x, const nasty_list<T>& y) { return x.l_ == y.l_; }
#if TEST_STD_VER >= 20
template <class T>
auto operator<=>(const nasty_list<T>& x, const nasty_list<T>& y) { return x.l_ <=> y.l_; }
#endif
// Not really a mutex, but can play one in tests
class nasty_mutex
{

View File

@ -84,6 +84,96 @@ constexpr bool test_sequence_container_spaceship() {
return true;
}
// Implementation detail of `test_sequence_container_adaptor_spaceship`
template <template <typename...> typename ContainerAdaptor,
template <typename...>
typename Container,
typename Elem,
typename Order>
constexpr void test_sequence_container_adaptor_spaceship_with_type() {
// Empty containers
{
Container<Elem> l1;
ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
Container<Elem> l2;
ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
assert(testOrder(ca1, ca2, Order::equivalent));
}
// Identical contents
{
Container<Elem> l1{1, 1};
ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
Container<Elem> l2{1, 1};
ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
assert(testOrder(ca1, ca2, Order::equivalent));
}
// Less, due to contained values
{
Container<Elem> l1{1, 1};
ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
Container<Elem> l2{1, 2};
ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
assert(testOrder(ca1, ca2, Order::less));
}
// Greater, due to contained values
{
Container<Elem> l1{1, 3};
ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
Container<Elem> l2{1, 2};
ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
assert(testOrder(ca1, ca2, Order::greater));
}
// Shorter list
{
Container<Elem> l1{1};
ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
Container<Elem> l2{1, 2};
ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
assert(testOrder(ca1, ca2, Order::less));
}
// Longer list
{
Container<Elem> l1{1, 2};
ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
Container<Elem> l2{1};
ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
assert(testOrder(ca1, ca2, Order::greater));
}
// Unordered
if constexpr (std::is_same_v<Elem, PartialOrder>) {
Container<Elem> l1{1, std::numeric_limits<int>::min()};
ContainerAdaptor<Elem, Container<Elem>> ca1{l1};
Container<Elem> l2{1, 2};
ContainerAdaptor<Elem, Container<Elem>> ca2{l2};
assert(testOrder(ca1, ca2, Order::unordered));
}
}
// Tests the `operator<=>` on sequence container adaptors
template <template <typename...> typename ContainerAdaptor, template <typename...> typename Container>
constexpr bool test_sequence_container_adaptor_spaceship() {
// Thanks to SFINAE, the following is not a compiler error but returns `false`
struct NonComparable {};
static_assert(!std::three_way_comparable<ContainerAdaptor<NonComparable>>);
// The container should fulfill `std::three_way_comparable`
static_assert(std::three_way_comparable<ContainerAdaptor<int, Container<int>>>);
// Test different comparison categories
test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, int, std::strong_ordering>();
test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, StrongOrder, std::strong_ordering>();
test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, WeakOrder, std::weak_ordering>();
test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor,
Container,
PartialOrder,
std::partial_ordering>();
// `LessAndEqComp` does not have `operator<=>`. Ordering is synthesized based on `operator<`
test_sequence_container_adaptor_spaceship_with_type<ContainerAdaptor, Container, LessAndEqComp, std::weak_ordering>();
return true;
}
// Implementation detail of `test_ordered_map_container_spaceship`
template <template <typename...> typename Container, typename Key, typename Val, typename Order, typename Compare>
constexpr void test_ordered_map_container_spaceship_with_type(Compare comp) {