[libcxx-commits] [libcxx] b5a84ae - [libc++][spaceship] Implement `operator<=>` for `list`

Adrian Vogelsgesang via libcxx-commits libcxx-commits at lists.llvm.org
Tue Feb 28 06:11:47 PST 2023


Author: Adrian Vogelsgesang
Date: 2023-02-28T06:11:31-08:00
New Revision: b5a84ae09ab0bb59e43c5b4388fc1fe61cffec23

URL: https://github.com/llvm/llvm-project/commit/b5a84ae09ab0bb59e43c5b4388fc1fe61cffec23
DIFF: https://github.com/llvm/llvm-project/commit/b5a84ae09ab0bb59e43c5b4388fc1fe61cffec23.diff

LOG: [libc++][spaceship] Implement `operator<=>` for `list`

Implements part of P1614R2 "The Mothership has Landed"

Differential Revision: https://reviews.llvm.org/D132312

Added: 
    libcxx/test/std/containers/sequences/list/compare.three_way.pass.cpp
    libcxx/test/support/test_container_comparisons.h

Modified: 
    libcxx/docs/Status/SpaceshipProjects.csv
    libcxx/include/list

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index e09ef9ed82655..8baba5ebc9eae 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -38,7 +38,7 @@ Section,Description,Dependencies,Assignee,Complete
 | `[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
index 0f02c99240d6b..c0fe2f93830f3 100644
--- a/libcxx/include/list
+++ b/libcxx/include/list
@@ -155,15 +155,18 @@ template <class InputIterator, class Allocator = allocator<typename iterator_tra
 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 Alloc>
 
 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 @@ template <class T, class Allocator, class Predicate>
 #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 @@ operator==(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y)
     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 @@ operator<=(const list<_Tp, _Alloc>& __x, const list<_Tp, _Alloc>& __y)
     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
index 0000000000000..592067b602cc0
--- /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
index 0000000000000..d4659bd1aa5d1
--- /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 
diff erent 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


        


More information about the libcxx-commits mailing list