Index: libcxx/include/__iterator/reverse_iterator.h =================================================================== --- libcxx/include/__iterator/reverse_iterator.h +++ libcxx/include/__iterator/reverse_iterator.h @@ -193,6 +193,16 @@ return __x.base() >= __y.base(); } +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR) && !defined(_LIBCPP_HAS_NO_CONCEPTS) +template _Iter2> +inline _LIBCPP_INLINE_VISIBILITY constexpr +compare_three_way_result_t<_Iter1, _Iter2> +operator<=>(const reverse_iterator<_Iter1>& __x, const reverse_iterator<_Iter2>& __y) +{ + return __y.base() <=> __x.base(); +} +#endif + #ifndef _LIBCPP_CXX03_LANG template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 Index: libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cmp/three-way.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.cmp/three-way.pass.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// reverse_iterator + +// template Iterator2> +// constexpr compare_three_way_result_t +// operator<=>(const reverse_iterator& x, +// const reverse_iterator& y); + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +template +constexpr void test(ItL l, ItR r, Ord x) { + const std::reverse_iterator l1(l); + const std::reverse_iterator r1(r); + ASSERT_SAME_TYPE(decltype(l1 <=> r1), Ord); + assert((l1 <=> r1) == x); +} + +struct Iter { + using iterator_category = std::bidirectional_iterator_tag; + using pointer = char*; + using reference = char&; + using value_type = char; + using difference_type = double; + + constexpr Iter(double value): m_value(value) {} + double m_value; +private: + friend bool operator==(const Iter& l, const Iter& r) = default; + friend std::partial_ordering operator<=>(const Iter& l, const Iter& r) = default; +}; + +struct ConstIter { + using iterator_category = std::bidirectional_iterator_tag; + using pointer = const char*; + using reference = const char&; + using value_type = const char; + using difference_type = double; + + constexpr ConstIter(double value): m_value(value) {} + constexpr ConstIter(Iter it): m_value(it.m_value) {} + double m_value; +private: + friend bool operator==(const ConstIter& l, const ConstIter& r) = default; + friend std::partial_ordering operator<=>(const ConstIter& l, const ConstIter& r) = default; +}; + +constexpr bool tests() { + char s[] = "1234567890"; + test(three_way_contiguous_iterator(s), + three_way_contiguous_iterator(s), + std::strong_ordering::equal); + test(three_way_contiguous_iterator(s), + three_way_contiguous_iterator(s+1), + std::strong_ordering::greater); + test(three_way_contiguous_iterator(s+1), + three_way_contiguous_iterator(s), + std::strong_ordering::less); + + test(s, s, std::strong_ordering::equal); + test(s, s+1, std::strong_ordering::greater); + test(s+1, s, std::strong_ordering::less); + + const char* cs = s; + test(cs, s, std::strong_ordering::equal); + test(cs, s+1, std::strong_ordering::greater); + test(cs+1, s, std::strong_ordering::less); + + constexpr double nan = std::numeric_limits::quiet_NaN(); + test(Iter(0), ConstIter(nan), std::partial_ordering::unordered); + test(Iter(nan), Iter(6), std::partial_ordering::unordered); + test(ConstIter(0), Iter(1), std::partial_ordering::greater); + test(ConstIter(3), Iter(2), std::partial_ordering::less); + test(ConstIter(7), Iter(7), std::partial_ordering::equivalent); + + return true; +} + +int main(int, char**) { + tests(); + static_assert(tests()); + return 0; +}