diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -164,6 +164,13 @@ template friend class _LIBCPP_TEMPLATE_VIS span; }; +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return __x.base() == __y.base(); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -171,6 +178,17 @@ return __x.base() == __y.base(); } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ +#if _LIBCPP_DEBUG_LEVEL == 2 + _LIBCPP_ASSERT(__get_const_db()->__less_than_comparable(&__x, &__y), + "Attempted to compare incomparable iterators"); +#endif + return __x.base() < __y.base(); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -182,6 +200,13 @@ return __x.base() < __y.base(); } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return !(__x == __y); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -189,6 +214,13 @@ return !(__x == __y); } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return __y < __x; +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -196,6 +228,13 @@ return __y < __x; } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return !(__x < __y); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT @@ -203,6 +242,13 @@ return !(__x < __y); } +template +_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG +bool operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT +{ + return !(__y < __x); +} + template _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG bool operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT diff --git a/libcxx/test/std/containers/iterator.rel_ops.compile.pass.cpp b/libcxx/test/std/containers/iterator.rel_ops.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/containers/iterator.rel_ops.compile.pass.cpp @@ -0,0 +1,140 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-filesystem-library + +// Make sure the various containers' iterators are not broken by the use of `std::rel_ops`. + +#include // for std::rel_ops + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +#if TEST_STD_VER >= 11 +#include "filesystem_include.h" +#endif + +#if TEST_STD_VER >= 17 +#include +#endif + +#if TEST_STD_VER >= 20 +#include +#endif + +using namespace std::rel_ops; + +template +void test_eq(It it, ConstIt cit) { + (void)(it == it); + (void)(it != it); + (void)(it == cit); + (void)(it != cit); + (void)(cit == it); + (void)(cit != it); + (void)(cit == cit); + (void)(cit != cit); +} + +template +void test_lt(It it, ConstIt cit) { + (void)(it < it); + (void)(it <= it); + (void)(it > it); + (void)(it >= it); + (void)(it < cit); + (void)(it <= cit); + (void)(it > cit); + (void)(it >= cit); + (void)(cit < it); + (void)(cit <= it); + (void)(cit > it); + (void)(cit >= it); + (void)(cit < cit); + (void)(cit <= cit); + (void)(cit > cit); + (void)(cit >= cit); + + // Test subtraction too, even though std::rel_ops shouldn't affect it. + + (void)(it - it); + (void)(it - cit); + (void)(cit - it); + (void)(cit - cit); +} + +template +void test_forward() { + // There is no need to distinguish "forward" from "bidirectional." + // libc++ already can't handle `c.rbegin() >= c.rbegin()` in the + // presence of std::rel_ops, and neither can Microsoft nor libstdc++. + + Container c; + typename Container::iterator it = c.begin(); + typename Container::const_iterator cit = c.begin(); + test_eq(it, cit); +} + +template +void test_random_access() { + Container c; + typename Container::iterator it = c.begin(); + typename Container::const_iterator cit = c.begin(); + test_eq(it, cit); + test_lt(it, cit); +} + +template void test_random_access >(); +template void test_random_access >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_random_access(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_forward >(); +template void test_random_access >(); + +#if TEST_STD_VER >= 11 +void test_directory_iterators() { + fs::directory_iterator it; + test_eq(it, it); + + fs::recursive_directory_iterator rdit; + test_eq(rdit, rdit); +} + +template void test_forward(); +#endif + +#if TEST_STD_VER >= 17 +template void test_random_access(); +#endif + +#if TEST_STD_VER >= 20 +void test_span() { + std::span c; + std::span::iterator it = c.begin(); // span has no const_iterator + test_eq(it, it); + test_lt(it, it); +} +#endif