[libcxx-commits] [libcxx] 03cda77 - [libc++][spaceship] Implement `operator<=>` for `optional`
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Thu May 4 23:59:29 PDT 2023
Author: Hristo Hristov
Date: 2023-05-05T09:59:22+03:00
New Revision: 03cda77409023e64d6338dcb4e36bf1e40b33ea3
URL: https://github.com/llvm/llvm-project/commit/03cda77409023e64d6338dcb4e36bf1e40b33ea3
DIFF: https://github.com/llvm/llvm-project/commit/03cda77409023e64d6338dcb4e36bf1e40b33ea3.diff
LOG: [libc++][spaceship] Implement `operator<=>` for `optional`
Implements parts of **P1614R2**: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1614r2.html
- Implemented `operator<=>` for `optional`
- Updated "optional synopsis" to match the current draft https://eel.is/c++draft/optional closer
- Implemented https://cplusplus.github.io/LWG/issue3566
- Implemented https://cplusplus.github.io/LWG/issue3746
Reviewed By: #libc, philnik, ldionne
Differential Revision: https://reviews.llvm.org/D146392
Added:
libcxx/test/std/utilities/optional/optional.comp_with_t/compare.three_way.pass.cpp
libcxx/test/std/utilities/optional/optional.nullops/compare.three_way.pass.cpp
libcxx/test/std/utilities/optional/optional.relops/compare.three_way.pass.cpp
Modified:
libcxx/docs/Status/Cxx2bIssues.csv
libcxx/docs/Status/SpaceshipProjects.csv
libcxx/include/optional
Removed:
################################################################################
diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv
index 8fa96fe2cb658..5ed62484f0407 100644
--- a/libcxx/docs/Status/Cxx2bIssues.csv
+++ b/libcxx/docs/Status/Cxx2bIssues.csv
@@ -119,7 +119,7 @@
`3560 <https://wg21.link/LWG3560>`__,"``ranges::equal`` and ``ranges::is_permutation`` should short-circuit for ``sized_ranges``","October 2021","","","|ranges|"
`3561 <https://wg21.link/LWG3561>`__,"Issue with internal counter in ``discard_block_engine``","October 2021","",""
`3563 <https://wg21.link/LWG3563>`__,"``keys_view`` example is broken","October 2021","","","|ranges|"
-`3566 <https://wg21.link/LWG3566>`__,"Constraint recursion for ``operator<=>(optional<T>, U)``","October 2021","","","|spaceship|"
+`3566 <https://wg21.link/LWG3566>`__,"Constraint recursion for ``operator<=>(optional<T>, U)``","October 2021","Complete","17.0","|spaceship|"
`3567 <https://wg21.link/LWG3567>`__,"Formatting move-only iterators take two","October 2021","|Complete|","16.0","|format| |ranges|"
`3568 <https://wg21.link/LWG3568>`__,"``basic_istream_view`` needs to initialize ``value_``","October 2021","|Complete|","16.0","|ranges|"
`3570 <https://wg21.link/LWG3570>`__,"``basic_osyncstream::emit`` should be an unformatted output function","October 2021","",""
@@ -206,7 +206,7 @@
"`3738 <https://wg21.link/LWG3738>`__","Missing preconditions for ``take_view`` constructor", "November 2022","|Complete|","16.0","|ranges|"
"`3743 <https://wg21.link/LWG3743>`__","``ranges::to``'s reserve may be ill-formed", "November 2022","","","|ranges|"
"`3745 <https://wg21.link/LWG3745>`__","``std::atomic_wait`` and its friends lack ``noexcept``", "November 2022","|Complete|","16.0",""
-"`3746 <https://wg21.link/LWG3746>`__","``optional``'s spaceship with ``U`` with a type derived from optional causes infinite constraint meta-recursion", "November 2022","","","|spaceship|"
+"`3746 <https://wg21.link/LWG3746>`__","``optional``'s spaceship with ``U`` with a type derived from optional causes infinite constraint meta-recursion", "November 2022","Complete","17.0","|spaceship|"
"`3747 <https://wg21.link/LWG3747>`__","``ranges::uninitialized_copy_n``, ``ranges::uninitialized_move_n``, and ``ranges::destroy_n`` should use ``std::move``", "November 2022","","","|ranges|"
"`3750 <https://wg21.link/LWG3750>`__","Too many papers bump ``__cpp_lib_format``", "November 2022","|Partial| [#note-LWG3750]_","","|format|"
"`3751 <https://wg21.link/LWG3751>`__","Missing feature macro for ``flat_set``", "November 2022","","","|flat_containers|"
diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
index e8624cb6a6724..3eecc354b8113 100644
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -22,7 +22,7 @@ Section,Description,Dependencies,Assignee,Complete
"| `[optional.relops] <https://wg21.link/optional.relops>`_
| `[optional.nullops] <https://wg21.link/optional.nullops>`_
| `[optional.comp.with.t] <https://wg21.link/optional.comp.with.t>`_","| `optional <https://reviews.llvm.org/D146392>`_
-| `nullopt <https://reviews.llvm.org/D146392>`_",None,Hristo Hristov,|In Progress|
+| `nullopt <https://reviews.llvm.org/D146392>`_",None,Hristo Hristov,|Complete|
"| `[variant.relops] <https://wg21.link/variant.relops>`_
| `[variant.monostate.relops] <https://wg21.link/variant.monostate.relops>`_","| `monostate <https://reviews.llvm.org/D131372>`_
| `variant <https://reviews.llvm.org/D131372>`_",None,Kent Ross,|Complete|
diff --git a/libcxx/include/optional b/libcxx/include/optional
index a387de473f30e..8895ed152dc82 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -16,107 +16,126 @@
// C++1z
namespace std {
- // 23.6.3, optional for object types
- template <class T> class optional;
+ // [optional.optional], class template optional
+ template <class T>
+ class optional;
- // 23.6.4, no-value state indicator
+ template<class T>
+ concept is-derived-from-optional = requires(const T& t) { // exposition only
+ []<class U>(const optional<U>&){ }(t);
+ };
+
+ // [optional.nullopt], no-value state indicator
struct nullopt_t{see below };
inline constexpr nullopt_t nullopt(unspecified );
- // 23.6.5, class bad_optional_access
+ // [optional.bad.access], class bad_optional_access
class bad_optional_access;
- // 23.6.6, relational operators
+ // [optional.relops], relational operators
template <class T, class U>
- constexpr bool operator==(const optional<T>&, const optional<U>&);
+ constexpr bool operator==(const optional<T>&, const optional<U>&);
template <class T, class U>
- constexpr bool operator!=(const optional<T>&, const optional<U>&);
+ constexpr bool operator!=(const optional<T>&, const optional<U>&);
template <class T, class U>
- constexpr bool operator<(const optional<T>&, const optional<U>&);
+ constexpr bool operator<(const optional<T>&, const optional<U>&);
template <class T, class U>
- constexpr bool operator>(const optional<T>&, const optional<U>&);
+ constexpr bool operator>(const optional<T>&, const optional<U>&);
template <class T, class U>
- constexpr bool operator<=(const optional<T>&, const optional<U>&);
+ constexpr bool operator<=(const optional<T>&, const optional<U>&);
template <class T, class U>
- constexpr bool operator>=(const optional<T>&, const optional<U>&);
-
- // 23.6.7 comparison with nullopt
- template <class T> constexpr bool operator==(const optional<T>&, nullopt_t) noexcept;
- template <class T> constexpr bool operator==(nullopt_t, const optional<T>&) noexcept;
- template <class T> constexpr bool operator!=(const optional<T>&, nullopt_t) noexcept;
- template <class T> constexpr bool operator!=(nullopt_t, const optional<T>&) noexcept;
- template <class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept;
- template <class T> constexpr bool operator<(nullopt_t, const optional<T>&) noexcept;
- template <class T> constexpr bool operator<=(const optional<T>&, nullopt_t) noexcept;
- template <class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept;
- template <class T> constexpr bool operator>(const optional<T>&, nullopt_t) noexcept;
- template <class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept;
- template <class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept;
- template <class T> constexpr bool operator>=(nullopt_t, const optional<T>&) noexcept;
-
- // 23.6.8, comparison with T
- template <class T, class U> constexpr bool operator==(const optional<T>&, const U&);
- template <class T, class U> constexpr bool operator==(const T&, const optional<U>&);
- template <class T, class U> constexpr bool operator!=(const optional<T>&, const U&);
- template <class T, class U> constexpr bool operator!=(const T&, const optional<U>&);
- template <class T, class U> constexpr bool operator<(const optional<T>&, const U&);
- template <class T, class U> constexpr bool operator<(const T&, const optional<U>&);
- template <class T, class U> constexpr bool operator<=(const optional<T>&, const U&);
- template <class T, class U> constexpr bool operator<=(const T&, const optional<U>&);
- template <class T, class U> constexpr bool operator>(const optional<T>&, const U&);
- template <class T, class U> constexpr bool operator>(const T&, const optional<U>&);
- template <class T, class U> constexpr bool operator>=(const optional<T>&, const U&);
- template <class T, class U> constexpr bool operator>=(const T&, const optional<U>&);
-
- // 23.6.9, specialized algorithms
- template <class T> void swap(optional<T>&, optional<T>&) noexcept(see below ); // constexpr in C++20
- template <class T> constexpr optional<see below > make_optional(T&&);
- template <class T, class... Args>
+ constexpr bool operator>=(const optional<T>&, const optional<U>&);
+ template<class T, three_way_comparable_with<T> U>
+ constexpr compare_three_way_result_t<T, U>
+ operator<=>(const optional<T>&, const optional<U>&); // since C++20
+
+ // [optional.nullops], comparison with nullopt
+ template<class T> constexpr bool operator==(const optional<T>&, nullopt_t) noexcept;
+ template<class T> constexpr bool operator==(nullopt_t, const optional<T>&) noexcept; // until C++17
+ template<class T> constexpr bool operator!=(const optional<T>&, nullopt_t) noexcept; // until C++17
+ template<class T> constexpr bool operator!=(nullopt_t, const optional<T>&) noexcept; // until C++17
+ template<class T> constexpr bool operator<(const optional<T>&, nullopt_t) noexcept; // until C++17
+ template<class T> constexpr bool operator<(nullopt_t, const optional<T>&) noexcept; // until C++17
+ template<class T> constexpr bool operator<=(const optional<T>&, nullopt_t) noexcept; // until C++17
+ template<class T> constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept; // until C++17
+ template<class T> constexpr bool operator>(const optional<T>&, nullopt_t) noexcept; // until C++17
+ template<class T> constexpr bool operator>(nullopt_t, const optional<T>&) noexcept; // until C++17
+ template<class T> constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept; // until C++17
+ template<class T> constexpr bool operator>=(nullopt_t, const optional<T>&) noexcept; // until C++17
+ template<class T>
+ constexpr strong_ordering operator<=>(const optional<T>&, nullopt_t) noexcept; // since C++20
+
+ // [optional.comp.with.t], comparison with T
+ template<class T, class U> constexpr bool operator==(const optional<T>&, const U&);
+ template<class T, class U> constexpr bool operator==(const T&, const optional<U>&);
+ template<class T, class U> constexpr bool operator!=(const optional<T>&, const U&);
+ template<class T, class U> constexpr bool operator!=(const T&, const optional<U>&);
+ template<class T, class U> constexpr bool operator<(const optional<T>&, const U&);
+ template<class T, class U> constexpr bool operator<(const T&, const optional<U>&);
+ template<class T, class U> constexpr bool operator<=(const optional<T>&, const U&);
+ template<class T, class U> constexpr bool operator<=(const T&, const optional<U>&);
+ template<class T, class U> constexpr bool operator>(const optional<T>&, const U&);
+ template<class T, class U> constexpr bool operator>(const T&, const optional<U>&);
+ template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&);
+ template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&);
+ template<class T, class U>
+ requires (!is-derived-from-optional<U>) && three_way_comparable_with<T, U>
+ constexpr compare_three_way_result_t<T, U>
+ operator<=>(const optional<T>&, const U&); // since C++20
+
+ // [optional.specalg], specialized algorithms
+ template<class T>
+ void swap(optional<T>&, optional<T>&) noexcept(see below ); // constexpr in C++20
+
+ template<class T>
+ constexpr optional<see below > make_optional(T&&);
+ template<class T, class... Args>
constexpr optional<T> make_optional(Args&&... args);
- template <class T, class U, class... Args>
+ template<class T, class U, class... Args>
constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args);
- // 23.6.10, hash support
- template <class T> struct hash;
- template <class T> struct hash<optional<T>>;
+ // [optional.hash], hash support
+ template<class T> struct hash;
+ template<class T> struct hash<optional<T>>;
- template <class T> class optional {
+ template<class T>
+ class optional {
public:
using value_type = T;
- // 23.6.3.1, constructors
+ // [optional.ctor], constructors
constexpr optional() noexcept;
constexpr optional(nullopt_t) noexcept;
constexpr optional(const optional &);
constexpr optional(optional &&) noexcept(see below);
- template <class... Args> constexpr explicit optional(in_place_t, Args &&...);
- template <class U, class... Args>
+ template<class... Args>
+ constexpr explicit optional(in_place_t, Args &&...);
+ template<class U, class... Args>
constexpr explicit optional(in_place_t, initializer_list<U>, Args &&...);
- template <class U = T>
+ template<class U = T>
constexpr explicit(see-below) optional(U &&);
- template <class U>
- explicit(see-below) optional(const optional<U> &); // constexpr in C++20
- template <class U>
- explicit(see-below) optional(optional<U> &&); // constexpr in C++20
+ template<class U>
+ explicit(see-below) optional(const optional<U> &); // constexpr in C++20
+ template<class U>
+ explicit(see-below) optional(optional<U> &&); // constexpr in C++20
- // 23.6.3.2, destructor
+ // [optional.dtor], destructor
~optional(); // constexpr in C++20
- // 23.6.3.3, assignment
- optional &operator=(nullopt_t) noexcept; // constexpr in C++20
+ // [optional.assign], assignment
+ optional &operator=(nullopt_t) noexcept; // constexpr in C++20
constexpr optional &operator=(const optional &);
constexpr optional &operator=(optional &&) noexcept(see below);
- template <class U = T> optional &operator=(U &&); // constexpr in C++20
- template <class U> optional &operator=(const optional<U> &); // constexpr in C++20
- template <class U> optional &operator=(optional<U> &&); // constexpr in C++20
- template <class... Args> T& emplace(Args &&...); // constexpr in C++20
- template <class U, class... Args>
- T& emplace(initializer_list<U>, Args &&...); // constexpr in C++20
-
- // 23.6.3.4, swap
+ template<class U = T> optional &operator=(U &&); // constexpr in C++20
+ template<class U> optional &operator=(const optional<U> &); // constexpr in C++20
+ template<class U> optional &operator=(optional<U> &&); // constexpr in C++20
+ template<class... Args> T& emplace(Args &&...); // constexpr in C++20
+ template<class U, class... Args> T& emplace(initializer_list<U>, Args &&...); // constexpr in C++20
+
+ // [optional.swap], swap
void swap(optional &) noexcept(see below ); // constexpr in C++20
- // 23.6.3.5, observers
+ // [optional.observe], observers
constexpr T const *operator->() const;
constexpr T *operator->();
constexpr T const &operator*() const &;
@@ -129,8 +148,8 @@ namespace std {
constexpr T &value() &;
constexpr T &&value() &&;
constexpr const T &&value() const &&;
- template <class U> constexpr T value_or(U &&) const &;
- template <class U> constexpr T value_or(U &&) &&;
+ template<class U> constexpr T value_or(U &&) const &;
+ template<class U> constexpr T value_or(U &&) &&;
// [optional.monadic], monadic operations
template<class F> constexpr auto and_then(F&& f) &; // since C++23
@@ -144,15 +163,15 @@ namespace std {
template<class F> constexpr optional or_else(F&& f) &&; // since C++23
template<class F> constexpr optional or_else(F&& f) const&; // since C++23
- // 23.6.3.6, modifiers
- void reset() noexcept; // constexpr in C++20
+ // [optional.mod], modifiers
+ void reset() noexcept; // constexpr in C++20
private:
- T *val; // exposition only
+ T *val; // exposition only
};
-template<class T>
- optional(T) -> optional<T>;
+ template<class T>
+ optional(T) -> optional<T>;
} // namespace std
@@ -160,6 +179,8 @@ template<class T>
#include <__assert> // all public C++ headers provide the assertion handler
#include <__availability>
+#include <__compare/compare_three_way_result.h>
+#include <__compare/three_way_comparable.h>
#include <__concepts/invocable.h>
#include <__config>
#include <__functional/hash.h>
@@ -633,6 +654,14 @@ using __optional_sfinae_assign_base_t = __sfinae_assign_base<
template<class _Tp>
class optional;
+
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Tp>
+concept __is_derived_from_optional = requires(const _Tp& __t) { []<class __Up>(const optional<__Up>&) {}(__t); };
+
+# endif // _LIBCPP_STD_VER >= 20
+
template <class _Tp>
struct __is_std_optional : false_type {};
template <class _Tp> struct __is_std_optional<optional<_Tp>> : true_type {};
@@ -1288,6 +1317,18 @@ operator>=(const optional<_Tp>& __x, const optional<_Up>& __y)
return *__x >= *__y;
}
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Tp, three_way_comparable_with<_Tp> _Up>
+_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up>
+operator<=>(const optional<_Tp>& __x, const optional<_Up>& __y) {
+ if (__x && __y)
+ return *__x <=> *__y;
+ return __x.has_value() <=> __y.has_value();
+}
+
+#endif // _LIBCPP_STD_VER >= 20
+
// Comparisons with nullopt
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY constexpr
@@ -1297,6 +1338,8 @@ operator==(const optional<_Tp>& __x, nullopt_t) noexcept
return !static_cast<bool>(__x);
}
+#if _LIBCPP_STD_VER <= 17
+
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY constexpr
bool
@@ -1385,6 +1428,15 @@ operator>=(nullopt_t, const optional<_Tp>& __x) noexcept
return !static_cast<bool>(__x);
}
+#else // _LIBCPP_STD_VER <= 17
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept {
+ return __x.has_value() <=> false;
+}
+
+#endif // _LIBCPP_STD_VER <= 17
+
// Comparisons with T
template <class _Tp, class _Up>
_LIBCPP_INLINE_VISIBILITY constexpr
@@ -1530,6 +1582,17 @@ operator>=(const _Tp& __v, const optional<_Up>& __x)
return static_cast<bool>(__x) ? __v >= *__x : true;
}
+#if _LIBCPP_STD_VER >= 20
+
+template <class _Tp, class _Up>
+ requires(!__is_derived_from_optional<_Up>) && three_way_comparable_with<_Tp, _Up>
+_LIBCPP_HIDE_FROM_ABI constexpr compare_three_way_result_t<_Tp, _Up>
+operator<=>(const optional<_Tp>& __x, const _Up& __v) {
+ return __x.has_value() ? *__x <=> __v : strong_ordering::less;
+}
+
+#endif // _LIBCPP_STD_VER >= 20
+
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
diff --git a/libcxx/test/std/utilities/optional/optional.comp_with_t/compare.three_way.pass.cpp b/libcxx/test/std/utilities/optional/optional.comp_with_t/compare.three_way.pass.cpp
new file mode 100644
index 0000000000000..18abbdc1229d0
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.comp_with_t/compare.three_way.pass.cpp
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <optional>
+
+// [optional.comp.with.t], comparison with T
+
+// template<class T, class U>
+// requires (!is-derived-from-optional<U>) && three_way_comparable_with<T, U>
+// constexpr compare_three_way_result_t<T, U>
+// operator<=>(const optional<T>&, const U&);
+
+#include <cassert>
+#include <compare>
+#include <optional>
+
+#include "test_comparisons.h"
+
+struct SomeInt {
+ int value_;
+
+ constexpr explicit SomeInt(int value = 0) : value_(value) {}
+
+ auto operator<=>(const SomeInt&) const = default;
+};
+
+template <class T, class U>
+concept HasSpaceship = requires(T t, U u) { t <=> u; };
+
+// SFINAE tests.
+
+static_assert(std::three_way_comparable_with<std::optional<int>, std::optional<int>>);
+static_assert(HasSpaceship<std::optional<int>, std::optional<int>>);
+
+static_assert(std::three_way_comparable_with<std::optional<SomeInt>, std::optional<SomeInt>>);
+static_assert(HasSpaceship<std::optional<SomeInt>, std::optional<SomeInt>>);
+
+static_assert(!HasSpaceship<std::optional<int>, std::optional<SomeInt>>);
+
+// Runtime and static tests.
+
+constexpr void test_custom_integral() {
+ {
+ SomeInt t{3};
+ std::optional<SomeInt> op{3};
+ assert((t <=> op) == std::strong_ordering::equal);
+ assert(testOrder(t, op, std::strong_ordering::equal));
+ }
+ {
+ SomeInt t{2};
+ std::optional<SomeInt> op{3};
+ assert((t <=> op) == std::strong_ordering::less);
+ assert(testOrder(t, op, std::strong_ordering::less));
+ }
+ {
+ SomeInt t{3};
+ std::optional<SomeInt> op{2};
+ assert((t <=> op) == std::strong_ordering::greater);
+ assert(testOrder(t, op, std::strong_ordering::greater));
+ }
+}
+
+constexpr void test_int() {
+ {
+ int t{3};
+ std::optional<int> op{3};
+ assert((t <=> op) == std::strong_ordering::equal);
+ assert(testOrder(t, op, std::strong_ordering::equal));
+ }
+ {
+ int t{2};
+ std::optional<int> op{3};
+ assert((t <=> op) == std::strong_ordering::less);
+ assert(testOrder(t, op, std::strong_ordering::less));
+ }
+ {
+ int t{3};
+ std::optional<int> op{2};
+ assert((t <=> op) == std::strong_ordering::greater);
+ assert(testOrder(t, op, std::strong_ordering::greater));
+ }
+}
+
+constexpr bool test() {
+ test_custom_integral();
+ test_int();
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test());
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/optional/optional.nullops/compare.three_way.pass.cpp b/libcxx/test/std/utilities/optional/optional.nullops/compare.three_way.pass.cpp
new file mode 100644
index 0000000000000..9acc9b7909d0d
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.nullops/compare.three_way.pass.cpp
@@ -0,0 +1,50 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <optional>
+
+// [optional.nullops], comparison with nullopt
+
+// template<class T>
+// constexpr strong_ordering operator<=>(const optional<T>&, nullopt_t) noexcept;
+
+#include <cassert>
+#include <compare>
+#include <optional>
+
+#include "test_comparisons.h"
+
+constexpr bool test() {
+ {
+ std::optional<int> op;
+ assert((std::nullopt <=> op) == std::strong_ordering::equal);
+ assert(testOrder(std::nullopt, op, std::strong_ordering::equal));
+ assert((op <=> std::nullopt) == std::strong_ordering::equal);
+ assert(testOrder(op, std::nullopt, std::strong_ordering::equal));
+ }
+ {
+ std::optional<int> op{1};
+ assert((std::nullopt <=> op) == std::strong_ordering::less);
+ assert(testOrder(std::nullopt, op, std::strong_ordering::less));
+ }
+ {
+ std::optional<int> op{1};
+ assert((op <=> std::nullopt) == std::strong_ordering::greater);
+ assert(testOrder(op, std::nullopt, std::strong_ordering::greater));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test());
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/optional/optional.relops/compare.three_way.pass.cpp b/libcxx/test/std/utilities/optional/optional.relops/compare.three_way.pass.cpp
new file mode 100644
index 0000000000000..b00fe46f37ff5
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.relops/compare.three_way.pass.cpp
@@ -0,0 +1,69 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <optional>
+
+// [optional.relops], relational operators
+
+// template<class T, three_way_comparable_with<T> U>
+// constexpr compare_three_way_result_t<T, U>
+// operator<=>(const optional<T>&, const optional<U>&);
+
+#include <cassert>
+#include <compare>
+#include <optional>
+
+#include "test_comparisons.h"
+
+constexpr bool test() {
+ {
+ std::optional<int> op1;
+ std::optional<int> op2;
+
+ assert((op1 <=> op2) == std::strong_ordering::equal);
+ assert(testOrder(op1, op2, std::strong_ordering::equal));
+ }
+ {
+ std::optional<int> op1{3};
+ std::optional<int> op2{3};
+ assert((op1 <=> op1) == std::strong_ordering::equal);
+ assert(testOrder(op1, op1, std::strong_ordering::equal));
+ assert((op1 <=> op2) == std::strong_ordering::equal);
+ assert(testOrder(op1, op2, std::strong_ordering::equal));
+ assert((op2 <=> op1) == std::strong_ordering::equal);
+ assert(testOrder(op2, op1, std::strong_ordering::equal));
+ }
+ {
+ std::optional<int> op;
+ std::optional<int> op1{2};
+ std::optional<int> op2{3};
+ assert((op <=> op2) == std::strong_ordering::less);
+ assert(testOrder(op, op2, std::strong_ordering::less));
+ assert((op1 <=> op2) == std::strong_ordering::less);
+ assert(testOrder(op1, op2, std::strong_ordering::less));
+ }
+ {
+ std::optional<int> op;
+ std::optional<int> op1{3};
+ std::optional<int> op2{2};
+ assert((op1 <=> op) == std::strong_ordering::greater);
+ assert(testOrder(op1, op, std::strong_ordering::greater));
+ assert((op1 <=> op2) == std::strong_ordering::greater);
+ assert(testOrder(op1, op2, std::strong_ordering::greater));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ assert(test());
+ static_assert(test());
+ return 0;
+}
More information about the libcxx-commits
mailing list