[libcxx-commits] [libcxx] 3df094d - [libc++] [P1614] Implement std::compare_three_way.
Arthur O'Dwyer via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Oct 10 18:58:03 PDT 2021
Author: Arthur O'Dwyer
Date: 2021-10-10T21:57:10-04:00
New Revision: 3df094d31eac753687c7963738bb847e6d3794e9
URL: https://github.com/llvm/llvm-project/commit/3df094d31eac753687c7963738bb847e6d3794e9
DIFF: https://github.com/llvm/llvm-project/commit/3df094d31eac753687c7963738bb847e6d3794e9.diff
LOG: [libc++] [P1614] Implement std::compare_three_way.
Differential Revision: https://reviews.llvm.org/D110735
Added:
libcxx/include/__compare/compare_three_way.h
libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp
libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp
libcxx/test/std/utilities/function.objects/comparisons/compare_three_way_functional.pass.cpp
libcxx/test/std/utilities/function.objects/comparisons/transparent_three_way.compile.pass.cpp
Modified:
libcxx/docs/Status/SpaceshipProjects.csv
libcxx/include/CMakeLists.txt
libcxx/include/compare
libcxx/include/functional
libcxx/include/module.modulemap
Removed:
################################################################################
diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index f517e2bee6dad..e68f525996eec 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -4,7 +4,7 @@ Section,Description,Dependencies,Assignee,Complete
| `[cmp.result] <https://wg21.link/cmp.result>`_,| `compare_three_way_result <https://reviews.llvm.org/D103581>`_,None,Arthur O'Dwyer,|Complete|
| `[expos.only.func] <https://wg21.link/expos.only.func>`_,"| `synth-three-way <https://reviews.llvm.org/D107721>`_
| `synth-three-way-result <https://reviews.llvm.org/D107721>`_",[cmp.concept],Kent Ross,|Complete|
-| `[comparisons.three.way] <https://wg21.link/comparisons.three.way>`_,| `compare_three_way <https://reviews.llvm.org/D80899>`_,[cmp.concept],Christopher Di Bella,|In Progress|
+| `[comparisons.three.way] <https://wg21.link/comparisons.three.way>`_,| `compare_three_way <https://reviews.llvm.org/D80899>`_,[cmp.concept],Arthur O'Dwyer,|Complete|
| `[cmp.alg] <https://wg21.link/cmp.alg>`_,"| `strong_order <https://reviews.llvm.org/D107036>`_
| `weak_order <https://reviews.llvm.org/D107036>`_
| `partial_order <https://reviews.llvm.org/D107036>`_",None,Arthur O'Dwyer,|In Progress|
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 3460f72f80000..55834abde8b8a 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -102,6 +102,7 @@ set(files
__charconv/from_chars_result.h
__charconv/to_chars_result.h
__compare/common_comparison_category.h
+ __compare/compare_three_way.h
__compare/compare_three_way_result.h
__compare/is_eq.h
__compare/ordering.h
diff --git a/libcxx/include/__compare/compare_three_way.h b/libcxx/include/__compare/compare_three_way.h
new file mode 100644
index 0000000000000..492908a3a0dfc
--- /dev/null
+++ b/libcxx/include/__compare/compare_three_way.h
@@ -0,0 +1,41 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___COMPARE_COMPARE_THREE_WAY_H
+#define _LIBCPP___COMPARE_COMPARE_THREE_WAY_H
+
+#include <__config>
+#include <__compare/three_way_comparable.h>
+#include <__utility/forward.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) && !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+struct _LIBCPP_TEMPLATE_VIS compare_three_way
+{
+ template<class _T1, class _T2>
+ requires three_way_comparable_with<_T1, _T2>
+ constexpr _LIBCPP_HIDE_FROM_ABI
+ auto operator()(_T1&& __t, _T2&& __u) const
+ noexcept(noexcept(_VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u)))
+ { return _VSTD::forward<_T1>(__t) <=> _VSTD::forward<_T2>(__u); }
+
+ using is_transparent = void;
+};
+
+#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) && !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___COMPARE_COMPARE_THREE_WAY_H
diff --git a/libcxx/include/compare b/libcxx/include/compare
index ca1f57439b6b2..ddb8313547512 100644
--- a/libcxx/include/compare
+++ b/libcxx/include/compare
@@ -47,6 +47,9 @@ namespace std {
template<class T, class U = T>
using compare_three_way_result_t = typename compare_three_way_result<T, U>::type;
+ // [comparisons.three.way], class compare_three_way
+ struct compare_three_way; // C++20
+
// [cmp.alg], comparison algorithms
template<class T> constexpr strong_ordering strong_order(const T& a, const T& b);
template<class T> constexpr weak_ordering weak_order(const T& a, const T& b);
@@ -133,6 +136,7 @@ namespace std {
*/
#include <__compare/common_comparison_category.h>
+#include <__compare/compare_three_way.h>
#include <__compare/compare_three_way_result.h>
#include <__compare/is_eq.h>
#include <__compare/ordering.h>
diff --git a/libcxx/include/functional b/libcxx/include/functional
index 3cff8661faecb..53a5f2bc37705 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -135,6 +135,9 @@ struct less_equal {
bool operator()(const T& x, const T& y) const;
};
+// [comparisons.three.way], class compare_three_way
+struct compare_three_way;
+
template <class T> // <class T=void> in C++14
struct logical_and {
bool operator()(const T& x, const T& y) const;
@@ -488,6 +491,7 @@ POLICY: For non-variadic implementations, the number of arguments is limited
*/
#include <__algorithm/search.h>
+#include <__compare/compare_three_way.h>
#include <__config>
#include <__debug>
#include <__functional/binary_function.h> // TODO: deprecate
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 5abe2431300a7..d8049cb3854fc 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -372,6 +372,7 @@ module std [system] {
module __compare {
module common_comparison_category { private header "__compare/common_comparison_category.h" }
+ module compare_three_way { private header "__compare/compare_three_way.h" }
module compare_three_way_result { private header "__compare/compare_three_way_result.h" }
module is_eq { private header "__compare/is_eq.h" }
module ordering { private header "__compare/ordering.h" }
diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp
new file mode 100644
index 0000000000000..e6428cec2c430
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/compare/compare_three_way.module.verify.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__compare/compare_three_way.h'}}
+#include <__compare/compare_three_way.h>
diff --git a/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp
new file mode 100644
index 0000000000000..63e0eb3240a52
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way.pass.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+
+// <compare>
+// <functional>
+
+// compare_three_way
+
+#include <compare>
+#include <cassert>
+#include <limits>
+#include <type_traits>
+
+#include "pointer_comparison_test_helper.h"
+
+template<class T, class U>
+constexpr auto test_sfinae(T t, U u)
+ -> decltype(std::compare_three_way()(t, u), std::true_type{})
+ { return std::true_type{}; }
+
+constexpr auto test_sfinae(...)
+ { return std::false_type{}; }
+
+struct NotThreeWayComparable {
+ std::strong_ordering operator<=>(const NotThreeWayComparable&) const;
+};
+ASSERT_SAME_TYPE(std::compare_three_way_result_t<NotThreeWayComparable>, std::strong_ordering);
+static_assert(!std::three_way_comparable<NotThreeWayComparable>); // it lacks operator==
+
+struct WeaklyOrdered {
+ int i;
+ friend constexpr std::weak_ordering operator<=>(const WeaklyOrdered&, const WeaklyOrdered&) = default;
+};
+
+constexpr bool test()
+{
+ ASSERT_SAME_TYPE(decltype(std::compare_three_way()(1, 1)), std::strong_ordering);
+ assert(std::compare_three_way()(1, 2) == std::strong_ordering::less);
+ assert(std::compare_three_way()(1, 1) == std::strong_ordering::equal);
+ assert(std::compare_three_way()(2, 1) == std::strong_ordering::greater);
+
+ ASSERT_SAME_TYPE(decltype(std::compare_three_way()(WeaklyOrdered{1}, WeaklyOrdered{2})), std::weak_ordering);
+ assert(std::compare_three_way()(WeaklyOrdered{1}, WeaklyOrdered{2}) == std::weak_ordering::less);
+ assert(std::compare_three_way()(WeaklyOrdered{1}, WeaklyOrdered{1}) == std::weak_ordering::equivalent);
+ assert(std::compare_three_way()(WeaklyOrdered{2}, WeaklyOrdered{1}) == std::weak_ordering::greater);
+
+ ASSERT_SAME_TYPE(decltype(std::compare_three_way()(1.0, 1.0)), std::partial_ordering);
+ double nan = std::numeric_limits<double>::quiet_NaN();
+ assert(std::compare_three_way()(1.0, 2.0) == std::partial_ordering::less);
+ assert(std::compare_three_way()(1.0, 1.0) == std::partial_ordering::equivalent);
+ assert(std::compare_three_way()(2.0, 1.0) == std::partial_ordering::greater);
+ assert(std::compare_three_way()(nan, nan) == std::partial_ordering::unordered);
+
+ // Try heterogeneous comparison.
+ ASSERT_SAME_TYPE(decltype(std::compare_three_way()(42.0, 42)), std::partial_ordering);
+ assert(std::compare_three_way()(42.0, 42) == std::partial_ordering::equivalent);
+ ASSERT_SAME_TYPE(decltype(std::compare_three_way()(42, 42.0)), std::partial_ordering);
+ assert(std::compare_three_way()(42, 42.0) == std::partial_ordering::equivalent);
+
+ return true;
+}
+
+int main(int, char**)
+{
+ test();
+ static_assert(test());
+
+ do_pointer_comparison_test(std::compare_three_way());
+
+ static_assert(test_sfinae(1, 2));
+ static_assert(!test_sfinae(1, nullptr));
+ static_assert(!test_sfinae(NotThreeWayComparable(), NotThreeWayComparable()));
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way_functional.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way_functional.pass.cpp
new file mode 100644
index 0000000000000..bb23244c47597
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/comparisons/compare_three_way_functional.pass.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+
+// <functional>
+
+// Test that std::compare_three_way is defined in <functional>,
+// not only in <compare>.
+
+#include <functional>
+#include <cassert>
+
+int main(int, char**)
+{
+ assert(std::compare_three_way()(1, 2) < 0);
+ assert(std::compare_three_way()(1, 1) == 0);
+ assert(std::compare_three_way()(2, 1) > 0);
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/function.objects/comparisons/transparent_three_way.compile.pass.cpp b/libcxx/test/std/utilities/function.objects/comparisons/transparent_three_way.compile.pass.cpp
new file mode 100644
index 0000000000000..c48d35b23ac75
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/comparisons/transparent_three_way.compile.pass.cpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+
+#include <functional>
+
+template<class T>
+concept Transparent = requires {
+ typename T::is_transparent;
+};
+
+static_assert(Transparent<std::compare_three_way>);
More information about the libcxx-commits
mailing list