From 8d3252a8987818171878a26e4298b4b5dbf2a7e9 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Wed, 24 Jul 2024 19:42:48 +0200 Subject: [PATCH] [libc++][spaceship] Implements X::iterator container requirements. (#99343) This implements the requirements for the container iterator requirements for array, deque, vector, and `vector`. Implements: - LWG3352 strong_equality isn't a thing Implements parts of: - P1614R2 The Mothership has Landed Fixes: https://github.com/llvm/llvm-project/issues/62486 --- libcxx/docs/Status/Cxx20Issues.csv | 2 +- libcxx/docs/Status/SpaceshipProjects.csv | 2 +- libcxx/include/__bit_reference | 14 +++ libcxx/include/__iterator/bounded_iter.h | 24 +++++ libcxx/include/__iterator/wrap_iter.h | 23 +++++ libcxx/include/deque | 29 +++++- .../bounded_iter/comparison.pass.cpp | 14 ++- .../sequences/array/iterators.pass.cpp | 18 ++++ .../sequences/deque/iterators.pass.cpp | 29 ++++++ .../sequences/vector.bool/iterators.pass.cpp | 37 ++++++++ .../sequences/vector/iterators.pass.cpp | 49 +++++++++- .../span.iterators/iterator.pass.cpp | 92 +++++++++++++++++++ .../string.view.iterators/iterators.pass.cpp | 85 +++++++++++++++++ libcxx/test/support/test_iterators.h | 2 + 14 files changed, 413 insertions(+), 7 deletions(-) create mode 100644 libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp create mode 100644 libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index 4f8118b5a35fb0..55a0f85203a153 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -264,7 +264,7 @@ "`3349 `__","Missing ``__cpp_lib_constexpr_complex``\ for P0415R1","Prague","|Complete|","16.0" "`3350 `__","Simplify return type of ``lexicographical_compare_three_way``\ ","Prague","|Complete|","17.0","|spaceship|" "`3351 `__","``ranges::enable_safe_range``\ should not be constrained","Prague","|Complete|","15.0","|ranges|" -"`3352 `__","``strong_equality``\ isn't a thing","Prague","|Nothing To Do|","","|spaceship|" +"`3352 `__","``strong_equality``\ isn't a thing","Prague","|Complete|","19.0","|spaceship|" "`3354 `__","``has_strong_structural_equality``\ has a meaningless definition","Prague","|Nothing To Do|","","|spaceship|" "`3355 `__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|" "`3356 `__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0" diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv index e1cf2044cfd789..4dc43cdbbd08fd 100644 --- a/libcxx/docs/Status/SpaceshipProjects.csv +++ b/libcxx/docs/Status/SpaceshipProjects.csv @@ -83,7 +83,7 @@ Section,Description,Dependencies,Assignee,Complete "| `[string.view.synop] `_ | `[string.view.comparison] `_",| `basic_string_view `_,None,Mark de Wever,|Complete| - `5.7 Clause 22: Containers library `_,,,, -| `[container.requirements.general] `_,|,None,Unassigned,|Not Started| +| `[container.requirements.general] `_,|,None,Mark de Wever,|Complete| | `[array.syn] `_ (`general `_),| `array `_,[expos.only.func],"| Adrian Vogelsgesang | Hristo Hristov",|Complete| | `[deque.syn] `_ (`general `_),| `deque `_,[expos.only.func],Hristo Hristov,|Complete| diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index 606069d98be727..22637d43974123 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -16,6 +16,7 @@ #include <__bit/countr.h> #include <__bit/invert_if.h> #include <__bit/popcount.h> +#include <__compare/ordering.h> #include <__config> #include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> @@ -913,6 +914,7 @@ public: return __x.__seg_ == __y.__seg_ && __x.__ctz_ == __y.__ctz_; } +#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 friend bool operator!=(const __bit_iterator& __x, const __bit_iterator& __y) { return !(__x == __y); @@ -937,6 +939,18 @@ public: operator>=(const __bit_iterator& __x, const __bit_iterator& __y) { return !(__x < __y); } +#else // _LIBCPP_STD_VER <= 17 + _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering + operator<=>(const __bit_iterator& __x, const __bit_iterator& __y) { + if (__x.__seg_ < __y.__seg_) + return strong_ordering::less; + + if (__x.__seg_ == __y.__seg_) + return __x.__ctz_ <=> __y.__ctz_; + + return strong_ordering::greater; + } +#endif // _LIBCPP_STD_VER <= 17 private: _LIBCPP_HIDE_FROM_ABI diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h index ce0823b8c97e45..8a81c9ffbfc3fc 100644 --- a/libcxx/include/__iterator/bounded_iter.h +++ b/libcxx/include/__iterator/bounded_iter.h @@ -11,6 +11,8 @@ #define _LIBCPP___ITERATOR_BOUNDED_ITER_H #include <__assert> +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> @@ -201,10 +203,15 @@ struct __bounded_iter { operator==(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ == __y.__current_; } + +#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool operator!=(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ != __y.__current_; } +#endif + + // TODO(mordante) disable these overloads in the LLVM 20 release. _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR friend bool operator<(__bounded_iter const& __x, __bounded_iter const& __y) _NOEXCEPT { return __x.__current_ < __y.__current_; @@ -222,6 +229,23 @@ struct __bounded_iter { return __x.__current_ >= __y.__current_; } +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI constexpr friend strong_ordering + operator<=>(__bounded_iter const& __x, __bounded_iter const& __y) noexcept { + if constexpr (three_way_comparable<_Iterator, strong_ordering>) { + return __x.__current_ <=> __y.__current_; + } else { + if (__x.__current_ < __y.__current_) + return strong_ordering::less; + + if (__x.__current_ == __y.__current_) + return strong_ordering::equal; + + return strong_ordering::greater; + } + } +#endif // _LIBCPP_STD_VER >= 20 + private: template friend struct pointer_traits; diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 252d13b26c9e25..56183c0ee794d0 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -10,6 +10,8 @@ #ifndef _LIBCPP___ITERATOR_WRAP_ITER_H #define _LIBCPP___ITERATOR_WRAP_ITER_H +#include <__compare/ordering.h> +#include <__compare/three_way_comparable.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__memory/addressof.h> @@ -131,6 +133,7 @@ operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXC return __x.base() < __y.base(); } +#if _LIBCPP_STD_VER <= 17 template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { @@ -142,7 +145,9 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEXCEPT { return !(__x == __y); } +#endif +// TODO(mordante) disable these overloads in the LLVM 20 release. template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) _NOEXCEPT { @@ -179,6 +184,24 @@ operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) _NOEX return !(__y < __x); } +#if _LIBCPP_STD_VER >= 20 +template +_LIBCPP_HIDE_FROM_ABI constexpr strong_ordering +operator<=>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) noexcept { + if constexpr (three_way_comparable_with<_Iter1, _Iter2, strong_ordering>) { + return __x.base() <=> __y.base(); + } else { + if (__x.base() < __y.base()) + return strong_ordering::less; + + if (__x.base() == __y.base()) + return strong_ordering::equal; + + return strong_ordering::greater; + } +} +#endif // _LIBCPP_STD_VER >= 20 + template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 #ifndef _LIBCPP_CXX03_LANG diff --git a/libcxx/include/deque b/libcxx/include/deque index 4fc994a6e229b8..e73135a8647b98 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -376,10 +376,13 @@ public: return __x.__ptr_ == __y.__ptr_; } +#if _LIBCPP_STD_VER <= 17 _LIBCPP_HIDE_FROM_ABI friend bool operator!=(const __deque_iterator& __x, const __deque_iterator& __y) { return !(__x == __y); } +#endif + // TODO(mordante) disable these overloads in the LLVM 20 release. _LIBCPP_HIDE_FROM_ABI friend bool operator<(const __deque_iterator& __x, const __deque_iterator& __y) { return __x.__m_iter_ < __y.__m_iter_ || (__x.__m_iter_ == __y.__m_iter_ && __x.__ptr_ < __y.__ptr_); } @@ -396,6 +399,29 @@ public: return !(__x < __y); } +#if _LIBCPP_STD_VER >= 20 + _LIBCPP_HIDE_FROM_ABI friend strong_ordering operator<=>(const __deque_iterator& __x, const __deque_iterator& __y) { + if (__x.__m_iter_ < __y.__m_iter_) + return strong_ordering::less; + + if (__x.__m_iter_ == __y.__m_iter_) { + if constexpr (three_way_comparable) { + return __x.__ptr_ <=> __y.__ptr_; + } else { + if (__x.__ptr_ < __y.__ptr_) + return strong_ordering::less; + + if (__x.__ptr_ == __y.__ptr_) + return strong_ordering::equal; + + return strong_ordering::greater; + } + } + + return strong_ordering::greater; + } +#endif // _LIBCPP_STD_VER >= 20 + private: _LIBCPP_HIDE_FROM_ABI explicit __deque_iterator(__map_iterator __m, pointer __p) _NOEXCEPT : __m_iter_(__m), @@ -2530,8 +2556,7 @@ inline _LIBCPP_HIDE_FROM_ABI bool operator<=(const deque<_Tp, _Allocator>& __x, template _LIBCPP_HIDE_FROM_ABI __synth_three_way_result<_Tp> operator<=>(const deque<_Tp, _Allocator>& __x, const deque<_Tp, _Allocator>& __y) { - return std::lexicographical_compare_three_way( - __x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); + return std::lexicographical_compare_three_way(__x.begin(), __x.end(), __y.begin(), __y.end(), std::__synth_three_way); } #endif // _LIBCPP_STD_VER <= 17 diff --git a/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp b/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp index 9c5df5da55b9c6..cef2157469c8f0 100644 --- a/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp +++ b/libcxx/test/libcxx/iterators/bounded_iter/comparison.pass.cpp @@ -11,6 +11,7 @@ // // Comparison operators +#include #include <__iterator/bounded_iter.h> #include "test_iterators.h" @@ -59,6 +60,12 @@ TEST_CONSTEXPR_CXX14 bool tests() { assert(iter1 >= iter1); } +#if TEST_STD_VER >= 20 + // P1614 + std::same_as decltype(auto) r1 = iter1 <=> iter2; + assert(r1 == std::strong_ordering::less); +#endif + return true; } @@ -69,8 +76,11 @@ int main(int, char**) { #endif #if TEST_STD_VER > 17 - tests >(); - static_assert(tests >(), ""); + tests>(); + static_assert(tests>()); + + tests>(); + static_assert(tests>()); #endif return 0; diff --git a/libcxx/test/std/containers/sequences/array/iterators.pass.cpp b/libcxx/test/std/containers/sequences/array/iterators.pass.cpp index 106bc45c709988..710994c68295ef 100644 --- a/libcxx/test/std/containers/sequences/array/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/iterators.pass.cpp @@ -148,6 +148,15 @@ TEST_CONSTEXPR_CXX17 bool tests() assert(std::rbegin(c) != std::rend(c)); assert(std::cbegin(c) != std::cend(c)); assert(std::crbegin(c) != std::crend(c)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = cii <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif } { typedef std::array C; @@ -189,6 +198,15 @@ TEST_CONSTEXPR_CXX17 bool tests() assert(std::rbegin(c) == std::rend(c)); assert(std::cbegin(c) == std::cend(c)); assert(std::crbegin(c) == std::crend(c)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = cii <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif } } #endif diff --git a/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp b/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp index 1f06ffde41ac2d..484a2961fdb0c9 100644 --- a/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/iterators.pass.cpp @@ -41,7 +41,27 @@ int main(int, char**) i = c.begin(); C::const_iterator j; j = c.cbegin(); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + // When the allocator does not have operator<=> then the iterator uses a + // fallback to provide operator<=>. + // Make sure to test with an allocator that does not have operator<=>. + static_assert(!std::three_way_comparable, std::strong_ordering>); + static_assert(std::three_way_comparable); + + std::same_as decltype(auto) r1 = i <=> j; + assert(r1 == std::strong_ordering::equal); +# endif } #endif #if TEST_STD_VER > 11 @@ -74,6 +94,15 @@ int main(int, char**) // assert ( cii != c.begin()); // assert ( cii != c.cend()); // assert ( ii1 != c.end()); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = cii <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif // TEST_STD_VER > 20 } #endif diff --git a/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp index 9aaaac7a5557fd..1e4877e8d24430 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/iterators.pass.cpp @@ -77,7 +77,21 @@ TEST_CONSTEXPR_CXX20 bool tests() C::iterator i = c.begin(); C::iterator j = c.end(); assert(std::distance(i, j) == 0); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r = i <=> j; + assert(r == std::strong_ordering::equal); +# endif } { typedef bool T; @@ -86,7 +100,21 @@ TEST_CONSTEXPR_CXX20 bool tests() C::const_iterator i = c.begin(); C::const_iterator j = c.end(); assert(std::distance(i, j) == 0); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r = i <=> j; + assert(r == std::strong_ordering::equal); +# endif } { typedef bool T; @@ -131,6 +159,15 @@ TEST_CONSTEXPR_CXX20 bool tests() assert ( (cii >= ii1 )); assert (cii - ii1 == 0); assert (ii1 - cii == 0); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = cii <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif // TEST_STD_VER > 20 } #endif diff --git a/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp b/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp index 70e0e35767e091..0aa7ad0d42ed72 100644 --- a/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/iterators.pass.cpp @@ -87,7 +87,27 @@ TEST_CONSTEXPR_CXX20 bool tests() C::iterator i = c.begin(); C::iterator j = c.end(); assert(std::distance(i, j) == 0); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + // When the allocator does not have operator<=> then the iterator uses a + // fallback to provide operator<=>. + // Make sure to test with an allocator that does not have operator<=>. + static_assert(!std::three_way_comparable, std::strong_ordering>); + static_assert(std::three_way_comparable); + + std::same_as decltype(auto) r1 = i <=> j; + assert(r1 == std::strong_ordering::equal); +# endif } { typedef int T; @@ -96,7 +116,26 @@ TEST_CONSTEXPR_CXX20 bool tests() C::const_iterator i = c.begin(); C::const_iterator j = c.end(); assert(std::distance(i, j) == 0); + assert(i == j); + assert(!(i != j)); + + assert(!(i < j)); + assert((i <= j)); + + assert(!(i > j)); + assert((i >= j)); + +# if TEST_STD_VER >= 20 + // When the allocator does not have operator<=> then the iterator uses a + // fallback to provide operator<=>. + // Make sure to test with an allocator that does not have operator<=>. + static_assert(!std::three_way_comparable, std::strong_ordering>); + static_assert(std::three_way_comparable); + + std::same_as decltype(auto) r1 = i <=> j; + assert(r1 == std::strong_ordering::equal); +# endif } { typedef int T; @@ -164,8 +203,16 @@ TEST_CONSTEXPR_CXX20 bool tests() assert ( (cii >= ii1 )); assert (cii - ii1 == 0); assert (ii1 - cii == 0); +# if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = cii <=> ii2; + assert(r2 == std::strong_ordering::equal); +# endif // TEST_STD_VER > 20 } -#endif +#endif // TEST_STD_VER > 11 return true; } diff --git a/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp new file mode 100644 index 00000000000000..13a7628e6043d9 --- /dev/null +++ b/libcxx/test/std/containers/views/views.span/span.iterators/iterator.pass.cpp @@ -0,0 +1,92 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// class iterator + +#include +#include +#include +#include +#include +#include // __cpp_lib_ranges_as_const is not defined in span. + +#include "test_macros.h" + +template +constexpr void test_type() { + using C = std::span; + typename C::iterator ii1{}, ii2{}; + typename C::iterator ii4 = ii1; + // TODO Test against C++23 after implementing + // P2278R4 cbegin should always return a constant iterator + // The means adjusting the #ifdef to guard against C++23. +#ifdef __cpp_lib_ranges_as_const + typename C::const_iterator cii{}; +#endif + assert(ii1 == ii2); + assert(ii1 == ii4); +#ifdef __cpp_lib_ranges_as_const + assert(ii1 == cii); +#endif + + assert(!(ii1 != ii2)); +#ifdef __cpp_lib_ranges_as_const + assert(!(ii1 != cii)); +#endif + + T v; + C c{&v, 1}; + assert(c.begin() == std::begin(c)); + assert(c.rbegin() == std::rbegin(c)); +#ifdef __cpp_lib_ranges_as_const + assert(c.cbegin() == std::cbegin(c)); + assert(c.crbegin() == std::crbegin(c)); +#endif + + assert(c.end() == std::end(c)); + assert(c.rend() == std::rend(c)); +#ifdef __cpp_lib_ranges_as_const + assert(c.cend() == std::cend(c)); + assert(c.crend() == std::crend(c)); +#endif + + assert(std::begin(c) != std::end(c)); + assert(std::rbegin(c) != std::rend(c)); +#ifdef __cpp_lib_ranges_as_const + assert(std::cbegin(c) != std::cend(c)); + assert(std::crbegin(c) != std::crend(c)); +#endif + + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + +#ifdef __cpp_lib_ranges_as_const + std::same_as decltype(auto) r2 = cii <=> ii2; + assert(r2 == std::strong_ordering::equal); +#endif +} + +constexpr bool test() { + test_type(); + test_type(); + test_type(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test(), ""); + + return 0; +} diff --git a/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp b/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp new file mode 100644 index 00000000000000..75d492bf7b3c64 --- /dev/null +++ b/libcxx/test/std/strings/string.view/string.view.iterators/iterators.pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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: !stdlib=libc++ && (c++03 || c++11 || c++14) + +// + +// class iterator + +#include +#include +#include +#include + +#include "test_macros.h" +#include "make_string.h" + +template +TEST_CONSTEXPR_CXX14 void test_type() { + using C = std::basic_string_view; + typename C::iterator ii1 = typename C::iterator(), ii2 = typename C::iterator(); + typename C::iterator ii4 = ii1; + typename C::const_iterator cii = typename C::const_iterator(); + assert(ii1 == ii2); + assert(ii1 == ii4); + assert(ii1 == cii); + + assert(!(ii1 != ii2)); + assert(!(ii1 != cii)); + +#if TEST_STD_VER >= 17 + C c = MAKE_STRING_VIEW(CharT, "abc"); + assert(c.begin() == std::begin(c)); + assert(c.rbegin() == std::rbegin(c)); + assert(c.cbegin() == std::cbegin(c)); + assert(c.crbegin() == std::crbegin(c)); + + assert(c.end() == std::end(c)); + assert(c.rend() == std::rend(c)); + assert(c.cend() == std::cend(c)); + assert(c.crend() == std::crend(c)); + + assert(std::begin(c) != std::end(c)); + assert(std::rbegin(c) != std::rend(c)); + assert(std::cbegin(c) != std::cend(c)); + assert(std::crbegin(c) != std::crend(c)); +#endif + +#if TEST_STD_VER >= 20 + // P1614 + LWG3352 + std::same_as decltype(auto) r1 = ii1 <=> ii2; + assert(r1 == std::strong_ordering::equal); + + std::same_as decltype(auto) r2 = ii1 <=> ii2; + assert(r2 == std::strong_ordering::equal); +#endif +} + +TEST_CONSTEXPR_CXX14 bool test() { + test_type(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test_type(); +#endif +#ifndef TEST_HAS_NO_CHAR8_T + test_type(); +#endif + test_type(); + test_type(); + + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 14 + static_assert(test(), ""); +#endif + + return 0; +} diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index 31564a39773173..95d1b7df0007ca 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -389,6 +389,8 @@ class contiguous_iterator friend TEST_CONSTEXPR bool operator> (const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ > y.it_;} friend TEST_CONSTEXPR bool operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {return x.it_ >= y.it_;} + // Note no operator<=>, use three_way_contiguous_iterator for testing operator<=> + friend TEST_CONSTEXPR It base(const contiguous_iterator& i) { return i.it_; } template