diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -104,7 +104,7 @@ `3123 `__,"``duration`` constructor from representation shouldn't be effectively non-throwing","October 2021","","","|chrono|" `3146 `__,"Excessive unwrapping in ``std::ref/cref``","October 2021","|Complete|","14.0" `3152 `__,"``common_type`` and ``common_reference`` have flaws in common","October 2021","","" -`3293 `__,"``move_iterator operator+()`` has incorrect constraints","October 2021","","","|ranges|" +`3293 `__,"``move_iterator operator+()`` has incorrect constraints","October 2021","|Complete|","15.0","|ranges|" `3361 `__,"``safe_range`` case","October 2021","|Nothing To Do|","","|ranges|" `3392 `__,"``ranges::distance()`` cannot be used on a move-only iterator with a sized sentinel","October 2021","|Complete|","14.0","|ranges|" `3407 `__,"Some problems with the wording changes of P1739R4","October 2021","","","|ranges|" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -270,6 +270,7 @@ __iterator/iterator_traits.h __iterator/mergeable.h __iterator/move_iterator.h + __iterator/move_sentinel.h __iterator/next.h __iterator/ostream_iterator.h __iterator/ostreambuf_iterator.h diff --git a/libcxx/include/__iterator/move_iterator.h b/libcxx/include/__iterator/move_iterator.h --- a/libcxx/include/__iterator/move_iterator.h +++ b/libcxx/include/__iterator/move_iterator.h @@ -10,8 +10,20 @@ #ifndef _LIBCPP___ITERATOR_MOVE_ITERATOR_H #define _LIBCPP___ITERATOR_MOVE_ITERATOR_H +#include <__compare/compare_three_way_result.h> +#include <__compare/three_way_comparable.h> +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/derived_from.h> +#include <__concepts/same_as.h> #include <__config> +#include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iter_move.h> +#include <__iterator/iter_swap.h> #include <__iterator/iterator_traits.h> +#include <__iterator/move_sentinel.h> +#include <__iterator/readable_traits.h> #include <__utility/move.h> #include @@ -21,20 +33,48 @@ _LIBCPP_BEGIN_NAMESPACE_STD +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) +template +struct __move_iter_category_base {}; + +template + requires requires { typename iterator_traits<_Iter>::iterator_category; } +struct __move_iter_category_base<_Iter> { + using iterator_category = _If< + derived_from::iterator_category, random_access_iterator_tag>, + random_access_iterator_tag, + typename iterator_traits<_Iter>::iterator_category + >; +}; + +template +concept __move_iter_comparable = requires { + { declval() == declval<_Sent>() } -> convertible_to; +}; +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + template class _LIBCPP_TEMPLATE_VIS move_iterator +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + : public __move_iter_category_base<_Iter> +#endif { public: -#if _LIBCPP_STD_VER > 17 - typedef input_iterator_tag iterator_concept; -#endif - +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + using iterator_type = _Iter; + using iterator_concept = input_iterator_tag; + // iterator_category is inherited and not always present + using value_type = iter_value_t<_Iter>; + using difference_type = iter_difference_t<_Iter>; + using pointer = _Iter; + using reference = iter_rvalue_reference_t<_Iter>; +#else typedef _Iter iterator_type; typedef _If< __is_cpp17_random_access_iterator<_Iter>::value, random_access_iterator_tag, typename iterator_traits<_Iter>::iterator_category - > iterator_category; + > iterator_category; typedef typename iterator_traits::value_type value_type; typedef typename iterator_traits::difference_type difference_type; typedef iterator_type pointer; @@ -50,11 +90,56 @@ typedef typename iterator_traits::reference reference; #endif +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + _LIBCPP_HIDE_FROM_ABI constexpr + explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr + move_iterator() requires is_constructible_v<_Iter> : __current_() {} + + template + requires (!_IsSame<_Up, _Iter>::value) && convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr + move_iterator(const move_iterator<_Up>& __u) : __current_(__u.base()) {} + + template + requires (!_IsSame<_Up, _Iter>::value) && + convertible_to && + assignable_from<_Iter&, const _Up&> + _LIBCPP_HIDE_FROM_ABI constexpr + move_iterator& operator=(const move_iterator<_Up>& __u) { + __current_ = __u.base(); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const & noexcept { return __current_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return std::move(__current_); } + + _LIBCPP_HIDE_FROM_ABI constexpr + reference operator*() const { return ranges::iter_move(__current_); } + _LIBCPP_HIDE_FROM_ABI constexpr + reference operator[](difference_type __n) const { return ranges::iter_move(__current_ + __n); } + + _LIBCPP_HIDE_FROM_ABI constexpr + move_iterator& operator++() { ++__current_; return *this; } + + _LIBCPP_HIDE_FROM_ABI constexpr + auto operator++(int) + requires forward_iterator<_Iter> + { + move_iterator __tmp(*this); ++__current_; return __tmp; + } + + _LIBCPP_HIDE_FROM_ABI constexpr + void operator++(int) { ++__current_; } +#else _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 - move_iterator() : __current_() {} + explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {} _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 - explicit move_iterator(_Iter __i) : __current_(_VSTD::move(__i)) {} + move_iterator() : __current_() {} template ::value && is_convertible::value @@ -87,6 +172,8 @@ move_iterator& operator++() { ++__current_; return *this; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator operator++(int) { move_iterator __tmp(*this); ++__current_; return __tmp; } +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator--() { --__current_; return *this; } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -100,7 +187,48 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator& operator-=(difference_type __n) { __current_ -= __n; return *this; } +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + bool operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y) + requires __move_iter_comparable<_Iter, _Sent> + { + return __x.base() == __y.base(); + } + + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_difference_t<_Iter> operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y) + { + return __x.base() - __y.base(); + } + + template _Sent> + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_difference_t<_Iter> operator-(const move_iterator& __x, const move_sentinel<_Sent>& __y) + { + return __x.base() - __y.base(); + } + + friend _LIBCPP_HIDE_FROM_ABI constexpr + iter_rvalue_reference_t<_Iter> iter_move(const move_iterator& __i) + noexcept(noexcept(ranges::iter_move(__i.__current_))) + { + return ranges::iter_move(__i.__current_); + } + + template _It2> + friend _LIBCPP_HIDE_FROM_ABI constexpr + void iter_swap(const move_iterator& __x, const move_iterator<_It2>& __y) + noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_))) + { + return ranges::iter_swap(__x.__current_, __y.__current_); + } +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + private: + template friend class move_iterator; + _Iter __current_; }; @@ -111,12 +239,14 @@ return __x.base() == __y.base(); } +#if _LIBCPP_STD_VER <= 17 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 bool operator!=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) { return __x.base() != __y.base(); } +#endif // _LIBCPP_STD_VER <= 17 template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -146,6 +276,20 @@ return __x.base() >= __y.base(); } +#if _LIBCPP_STD_VER > 17 +# ifdef _LIBCPP_HAS_NO_CONCEPTS +template +# else +template _Iter2> +# endif // _LIBCPP_HAS_NO_CONCEPTS +inline _LIBCPP_HIDE_FROM_ABI constexpr +auto operator<=>(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y) + -> compare_three_way_result_t<_Iter1, _Iter2> +{ + return __x.base() <=> __y.base(); +} +#endif // _LIBCPP_STD_VER > 17 + #ifndef _LIBCPP_CXX03_LANG template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 @@ -164,6 +308,15 @@ } #endif +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) +template +inline _LIBCPP_HIDE_FROM_ABI constexpr +move_iterator<_Iter> operator+(iter_difference_t<_Iter> __n, const move_iterator<_Iter>& __x) + requires requires { { __x.base() + __n } -> same_as<_Iter>; } +{ + return __x + __n; +} +#else template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator<_Iter> @@ -171,13 +324,14 @@ { return move_iterator<_Iter>(__x.base() + __n); } +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14 move_iterator<_Iter> make_move_iterator(_Iter __i) { - return move_iterator<_Iter>(_VSTD::move(__i)); + return move_iterator<_Iter>(std::move(__i)); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__iterator/move_sentinel.h b/libcxx/include/__iterator/move_sentinel.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/move_sentinel.h @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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___ITERATOR_MOVE_SENTINEL_H +#define _LIBCPP___ITERATOR_MOVE_SENTINEL_H + +#include <__concepts/assignable.h> +#include <__concepts/convertible_to.h> +#include <__concepts/semiregular.h> +#include <__config> +#include <__utility/move.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_CONCEPTS) + +template +class _LIBCPP_TEMPLATE_VIS move_sentinel +{ +public: + _LIBCPP_HIDE_FROM_ABI + move_sentinel() = default; + + _LIBCPP_HIDE_FROM_ABI constexpr + explicit move_sentinel(_Sent __s) : __last_(_VSTD::move(__s)) {} + + template + requires convertible_to + _LIBCPP_HIDE_FROM_ABI constexpr + move_sentinel(const move_sentinel<_S2>& __s) : __last_(__s.base()) {} + + template + requires assignable_from<_Sent&, const _S2&> + _LIBCPP_HIDE_FROM_ABI constexpr + move_sentinel& operator=(const move_sentinel<_S2>& __s) + { __last_ = __s.base(); return *this; } + + constexpr _Sent base() const { return __last_; } + +private: + _Sent __last_ = _Sent(); +}; + +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ITERATOR_MOVE_SENTINEL_H diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -660,6 +660,7 @@ #include <__iterator/iterator_traits.h> #include <__iterator/mergeable.h> #include <__iterator/move_iterator.h> +#include <__iterator/move_sentinel.h> #include <__iterator/next.h> #include <__iterator/ostream_iterator.h> #include <__iterator/ostreambuf_iterator.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -661,6 +661,7 @@ module iterator_traits { private header "__iterator/iterator_traits.h" } module mergeable { private header "__iterator/mergeable.h" } module move_iterator { private header "__iterator/move_iterator.h" } + module move_sentinel { private header "__iterator/move_sentinel.h" } module next { private header "__iterator/next.h" } module ostream_iterator { private header "__iterator/ostream_iterator.h" } module ostreambuf_iterator { diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.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: '__iterator/move_sentinel.h'}} +#include <__iterator/move_sentinel.h> diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_eq.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_eq.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_eq.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_eq.pass.cpp @@ -10,10 +10,8 @@ // move_iterator -// template -// requires HasEqualTo -// bool -// operator==(const move_iterator& x, const move_iterator& y); +// template +// bool operator==(const move_iterator& x, const move_iterator& y); // // constexpr in C++17 @@ -23,40 +21,60 @@ #include "test_macros.h" #include "test_iterators.h" +// move_iterator's operator== calls the underlying iterator's operator== +struct CustomIt { + using value_type = int; + using difference_type = int; + using reference = int&; + using pointer = int*; + using iterator_category = std::input_iterator_tag; + CustomIt() = default; + TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {} + int& operator*() const; + CustomIt& operator++(); + CustomIt operator++(int); + TEST_CONSTEXPR_CXX17 friend bool operator==(const CustomIt& a, const CustomIt& b) { return a.p_ == b.p_; } + int *p_ = nullptr; +}; + template -void -test(It l, It r, bool x) +TEST_CONSTEXPR_CXX17 void test_one() { - const std::move_iterator r1(l); - const std::move_iterator r2(r); - assert((r1 == r2) == x); + int a[] = {3, 1, 4}; + const std::move_iterator r1 = std::move_iterator(It(a)); + const std::move_iterator r2 = std::move_iterator(It(a)); + const std::move_iterator r3 = std::move_iterator(It(a + 2)); + ASSERT_SAME_TYPE(decltype(r1 == r2), bool); + assert( (r1 == r1)); + assert( (r1 == r2)); + assert( (r2 == r1)); + assert(!(r1 == r3)); + assert(!(r3 == r1)); } -int main(int, char**) +TEST_CONSTEXPR_CXX17 bool test() { - char s[] = "1234567890"; - test(cpp17_input_iterator(s), cpp17_input_iterator(s), true); - test(cpp17_input_iterator(s), cpp17_input_iterator(s+1), false); - test(forward_iterator(s), forward_iterator(s), true); - test(forward_iterator(s), forward_iterator(s+1), false); - test(bidirectional_iterator(s), bidirectional_iterator(s), true); - test(bidirectional_iterator(s), bidirectional_iterator(s+1), false); - test(random_access_iterator(s), random_access_iterator(s), true); - test(random_access_iterator(s), random_access_iterator(s+1), false); - test(s, s, true); - test(s, s+1, false); + test_one(); + test_one >(); + test_one >(); + test_one >(); + test_one >(); + test_one(); + test_one(); + +#if TEST_STD_VER > 17 + test_one>(); + test_one>(); +#endif + return true; +} + +int main(int, char**) +{ + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p + 5); - constexpr MI it3 = std::make_move_iterator(p); - static_assert(!(it1 == it2), ""); - static_assert( (it1 == it3), ""); - static_assert(!(it2 == it3), ""); - } + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gt.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gt.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gt.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gt.pass.cpp @@ -10,10 +10,8 @@ // move_iterator -// template -// requires HasLess -// bool -// operator>(const move_iterator& x, const move_iterator& y); +// template +// bool operator>(const move_iterator& x, const move_iterator& y); // // constexpr in C++17 @@ -23,36 +21,51 @@ #include "test_macros.h" #include "test_iterators.h" +// move_iterator's operator> calls the underlying iterator's operator> +struct CustomIt { + using value_type = int; + using difference_type = int; + using reference = int&; + using pointer = int*; + using iterator_category = std::input_iterator_tag; + CustomIt() = default; + TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {} + int& operator*() const; + CustomIt& operator++(); + CustomIt operator++(int); + TEST_CONSTEXPR_CXX17 friend bool operator>(const CustomIt& a, const CustomIt& b) { return a.p_ > b.p_; } + int *p_ = nullptr; +}; + template -void -test(It l, It r, bool x) +TEST_CONSTEXPR_CXX17 void test_one() { - const std::move_iterator r1(l); - const std::move_iterator r2(r); - assert((r1 > r2) == x); + int a[] = {3, 1, 4}; + const std::move_iterator r1 = std::move_iterator(It(a)); + const std::move_iterator r2 = std::move_iterator(It(a+2)); + ASSERT_SAME_TYPE(decltype(r1 > r2), bool); + assert(!(r1 > r1)); + assert(!(r1 > r2)); + assert( (r2 > r1)); } -int main(int, char**) +TEST_CONSTEXPR_CXX17 bool test() { - char s[] = "1234567890"; - test(random_access_iterator(s), random_access_iterator(s), false); - test(random_access_iterator(s), random_access_iterator(s+1), false); - test(random_access_iterator(s+1), random_access_iterator(s), true); - test(s, s, false); - test(s, s+1, false); - test(s+1, s, true); + test_one(); + test_one(); + test_one(); + test_one >(); +#if TEST_STD_VER > 17 + test_one>(); +#endif + return true; +} +int main(int, char**) +{ + assert(test()); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p + 5); - constexpr MI it3 = std::make_move_iterator(p); - static_assert(!(it1 > it2), ""); - static_assert(!(it1 > it3), ""); - static_assert( (it2 > it3), ""); - } + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gte.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gte.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gte.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gte.pass.cpp @@ -10,10 +10,8 @@ // move_iterator -// template -// requires HasLess -// bool -// operator>=(const move_iterator& x, const move_iterator& y); +// template +// bool operator>=(const move_iterator& x, const move_iterator& y); // // constexpr in C++17 @@ -23,36 +21,51 @@ #include "test_macros.h" #include "test_iterators.h" +// move_iterator's operator>= calls the underlying iterator's operator>= +struct CustomIt { + using value_type = int; + using difference_type = int; + using reference = int&; + using pointer = int*; + using iterator_category = std::input_iterator_tag; + CustomIt() = default; + TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {} + int& operator*() const; + CustomIt& operator++(); + CustomIt operator++(int); + TEST_CONSTEXPR_CXX17 friend bool operator>=(const CustomIt& a, const CustomIt& b) { return a.p_ >= b.p_; } + int *p_ = nullptr; +}; + template -void -test(It l, It r, bool x) +TEST_CONSTEXPR_CXX17 void test_one() { - const std::move_iterator r1(l); - const std::move_iterator r2(r); - assert((r1 >= r2) == x); + int a[] = {3, 1, 4}; + const std::move_iterator r1 = std::move_iterator(It(a)); + const std::move_iterator r2 = std::move_iterator(It(a+2)); + ASSERT_SAME_TYPE(decltype(r1 >= r2), bool); + assert( (r1 >= r1)); + assert(!(r1 >= r2)); + assert( (r2 >= r1)); } -int main(int, char**) +TEST_CONSTEXPR_CXX17 bool test() { - char s[] = "1234567890"; - test(random_access_iterator(s), random_access_iterator(s), true); - test(random_access_iterator(s), random_access_iterator(s+1), false); - test(random_access_iterator(s+1), random_access_iterator(s), true); - test(s, s, true); - test(s, s+1, false); - test(s+1, s, true); + test_one(); + test_one(); + test_one(); + test_one >(); +#if TEST_STD_VER > 17 + test_one>(); +#endif + return true; +} +int main(int, char**) +{ + assert(test()); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p + 5); - constexpr MI it3 = std::make_move_iterator(p); - static_assert(!(it1 >= it2), ""); - static_assert( (it1 >= it3), ""); - static_assert( (it2 >= it3), ""); - } + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lt.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lt.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lt.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lt.pass.cpp @@ -10,10 +10,8 @@ // move_iterator -// template -// requires HasLess -// bool -// operator<(const move_iterator& x, const move_iterator& y); +// template +// bool operator<(const move_iterator& x, const move_iterator& y); // // constexpr in C++17 @@ -23,36 +21,51 @@ #include "test_macros.h" #include "test_iterators.h" +// move_iterator's operator< calls the underlying iterator's operator< +struct CustomIt { + using value_type = int; + using difference_type = int; + using reference = int&; + using pointer = int*; + using iterator_category = std::input_iterator_tag; + CustomIt() = default; + TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {} + int& operator*() const; + CustomIt& operator++(); + CustomIt operator++(int); + TEST_CONSTEXPR_CXX17 friend bool operator<(const CustomIt& a, const CustomIt& b) { return a.p_ < b.p_; } + int *p_ = nullptr; +}; + template -void -test(It l, It r, bool x) +TEST_CONSTEXPR_CXX17 void test_one() { - const std::move_iterator r1(l); - const std::move_iterator r2(r); - assert((r1 < r2) == x); + int a[] = {3, 1, 4}; + const std::move_iterator r1 = std::move_iterator(It(a)); + const std::move_iterator r2 = std::move_iterator(It(a + 2)); + ASSERT_SAME_TYPE(decltype(r1 < r2), bool); + assert(!(r1 < r1)); + assert( (r1 < r2)); + assert(!(r2 < r1)); } -int main(int, char**) +TEST_CONSTEXPR_CXX17 bool test() { - char s[] = "1234567890"; - test(random_access_iterator(s), random_access_iterator(s), false); - test(random_access_iterator(s), random_access_iterator(s+1), true); - test(random_access_iterator(s+1), random_access_iterator(s), false); - test(s, s, false); - test(s, s+1, true); - test(s+1, s, false); + test_one(); + test_one(); + test_one(); + test_one >(); +#if TEST_STD_VER > 17 + test_one>(); +#endif + return true; +} +int main(int, char**) +{ + assert(test()); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p + 5); - constexpr MI it3 = std::make_move_iterator(p); - static_assert( (it1 < it2), ""); - static_assert(!(it1 < it3), ""); - static_assert(!(it2 < it3), ""); - } + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lte.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lte.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lte.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lte.pass.cpp @@ -10,10 +10,8 @@ // move_iterator -// template -// requires HasLess -// bool -// operator<=(const move_iterator& x, const move_iterator& y); +// template +// bool operator<=(const move_iterator& x, const move_iterator& y); // // constexpr in C++17 @@ -23,36 +21,51 @@ #include "test_macros.h" #include "test_iterators.h" +// move_iterator's operator<= calls the underlying iterator's operator<= +struct CustomIt { + using value_type = int; + using difference_type = int; + using reference = int&; + using pointer = int*; + using iterator_category = std::input_iterator_tag; + CustomIt() = default; + TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {} + int& operator*() const; + CustomIt& operator++(); + CustomIt operator++(int); + TEST_CONSTEXPR_CXX17 friend bool operator<=(const CustomIt& a, const CustomIt& b) { return a.p_ <= b.p_; } + int *p_ = nullptr; +}; + template -void -test(It l, It r, bool x) +TEST_CONSTEXPR_CXX17 void test_one() { - const std::move_iterator r1(l); - const std::move_iterator r2(r); - assert((r1 <= r2) == x); + int a[] = {3, 1, 4}; + const std::move_iterator r1 = std::move_iterator(It(a)); + const std::move_iterator r2 = std::move_iterator(It(a + 2)); + ASSERT_SAME_TYPE(decltype(r1 <= r2), bool); + assert( (r1 <= r1)); + assert( (r1 <= r2)); + assert(!(r2 <= r1)); } -int main(int, char**) +TEST_CONSTEXPR_CXX17 bool test() { - char s[] = "1234567890"; - test(random_access_iterator(s), random_access_iterator(s), true); - test(random_access_iterator(s), random_access_iterator(s+1), true); - test(random_access_iterator(s+1), random_access_iterator(s), false); - test(s, s, true); - test(s, s+1, true); - test(s+1, s, false); + test_one(); + test_one(); + test_one(); + test_one >(); +#if TEST_STD_VER > 17 + test_one>(); +#endif + return true; +} +int main(int, char**) +{ + assert(test()); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p + 5); - constexpr MI it3 = std::make_move_iterator(p); - static_assert( (it1 <= it2), ""); - static_assert( (it1 <= it3), ""); - static_assert(!(it2 <= it3), ""); - } + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_neq.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_neq.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_neq.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_neq.pass.cpp @@ -23,40 +23,66 @@ #include "test_macros.h" #include "test_iterators.h" +// In C++17, move_iterator's operator!= calls the underlying iterator's operator!= +// In C++20, move_iterator's operator== calls the underlying iterator's operator== +struct CustomIt { + using value_type = int; + using difference_type = int; + using reference = int&; + using pointer = int*; + using iterator_category = std::input_iterator_tag; + CustomIt() = default; + TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {} + int& operator*() const; + CustomIt& operator++(); + CustomIt operator++(int); +#if TEST_STD_VER > 17 + friend constexpr bool operator==(const CustomIt& a, const CustomIt& b) { return a.p_ == b.p_; } + friend bool operator!=(const CustomIt& a, const CustomIt& b) = delete; +#else + friend TEST_CONSTEXPR_CXX17 bool operator!=(const CustomIt& a, const CustomIt& b) { return a.p_ != b.p_; } +#endif + int *p_ = nullptr; +}; + template -void -test(It l, It r, bool x) +TEST_CONSTEXPR_CXX17 void test_one() { - const std::move_iterator r1(l); - const std::move_iterator r2(r); - assert((r1 != r2) == x); + int a[] = {3, 1, 4}; + const std::move_iterator r1 = std::move_iterator(It(a)); + const std::move_iterator r2 = std::move_iterator(It(a)); + const std::move_iterator r3 = std::move_iterator(It(a + 2)); + ASSERT_SAME_TYPE(decltype(r1 != r2), bool); + assert(!(r1 != r1)); + assert(!(r1 != r2)); + assert(!(r2 != r1)); + assert( (r1 != r3)); + assert( (r3 != r1)); } -int main(int, char**) +TEST_CONSTEXPR_CXX17 bool test() { - char s[] = "1234567890"; - test(cpp17_input_iterator(s), cpp17_input_iterator(s), false); - test(cpp17_input_iterator(s), cpp17_input_iterator(s+1), true); - test(forward_iterator(s), forward_iterator(s), false); - test(forward_iterator(s), forward_iterator(s+1), true); - test(bidirectional_iterator(s), bidirectional_iterator(s), false); - test(bidirectional_iterator(s), bidirectional_iterator(s+1), true); - test(random_access_iterator(s), random_access_iterator(s), false); - test(random_access_iterator(s), random_access_iterator(s+1), true); - test(s, s, false); - test(s, s+1, true); + test_one(); + test_one >(); + test_one >(); + test_one >(); + test_one >(); + test_one(); + test_one(); + +#if TEST_STD_VER > 17 + test_one>(); + test_one>(); +#endif + return true; +} + +int main(int, char**) +{ + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p + 5); - constexpr MI it3 = std::make_move_iterator(p); - static_assert( (it1 != it2), ""); - static_assert(!(it1 != it3), ""); - static_assert( (it2 != it3), ""); - } + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_spaceship.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_spaceship.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_spaceship.pass.cpp @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// 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-has-no-concepts + +// + +// move_iterator + +// template Iter2> +// constexpr auto operator<=>(const move_iterator& x, const move_iterator& y) +// -> compare_three_way_result_t; + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + + +template concept HasEquals = requires (T t, U u) { t == u; }; +template concept HasSpaceship = requires (T t, U u) { t <=> u; }; + +static_assert(!HasSpaceship, std::move_iterator>); +static_assert( HasSpaceship, std::move_iterator>); +static_assert( HasSpaceship, std::move_iterator>); +static_assert( HasSpaceship, std::move_iterator>); +static_assert(!HasSpaceship>, std::move_iterator>>); +static_assert(!HasSpaceship>, std::move_iterator>>); +static_assert(!HasSpaceship>, std::move_iterator>>); +static_assert( HasSpaceship>, std::move_iterator>>); + +static_assert(!HasSpaceship, std::move_sentinel>); +static_assert(!HasSpaceship>, std::move_sentinel>>); + +void test_spaceshippable_but_not_three_way_comparable() { + struct A { + using value_type = int; + using difference_type = int; + int& operator*() const; + A& operator++(); + A operator++(int); + std::strong_ordering operator<=>(const A&) const; + }; + struct B { + using value_type = int; + using difference_type = int; + int& operator*() const; + B& operator++(); + B operator++(int); + std::strong_ordering operator<=>(const B&) const; + bool operator==(const A&) const; + std::strong_ordering operator<=>(const A&) const; + }; + static_assert( std::input_iterator); + static_assert( std::input_iterator); + static_assert( HasEquals); + static_assert( HasSpaceship); + static_assert(!std::three_way_comparable_with); + static_assert( HasEquals, std::move_iterator>); + static_assert(!HasSpaceship, std::move_iterator>); +} + +template +constexpr void test_two() +{ + int a[] = {3, 1, 4}; + const std::move_iterator i1 = std::move_iterator(It(a)); + const std::move_iterator i2 = std::move_iterator(It(a + 2)); + const std::move_iterator j1 = std::move_iterator(Jt(a)); + const std::move_iterator j2 = std::move_iterator(Jt(a + 2)); + ASSERT_SAME_TYPE(decltype(i1 <=> i2), std::strong_ordering); + assert((i1 <=> i1) == std::strong_ordering::equal); + assert((i1 <=> i2) == std::strong_ordering::less); + assert((i2 <=> i1) == std::strong_ordering::greater); + ASSERT_SAME_TYPE(decltype(i1 <=> j2), std::strong_ordering); + assert((i1 <=> j1) == std::strong_ordering::equal); + assert((i1 <=> j2) == std::strong_ordering::less); + assert((i2 <=> j1) == std::strong_ordering::greater); +} + +constexpr bool test() +{ + test_two(); + test_two(); + test_two(); + test_two(); + test_two, three_way_contiguous_iterator>(); + return true; +} + +int main(int, char**) +{ + assert(test()); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp @@ -16,33 +16,73 @@ #include #include +#include #include "test_macros.h" #include "test_iterators.h" template -void -test(It i) +TEST_CONSTEXPR_CXX17 bool test() { - std::move_iterator r(i); - assert(r.base() == i); + static_assert( std::is_constructible, const It&>::value, ""); + static_assert( std::is_constructible, It&&>::value, ""); + static_assert(!std::is_convertible >::value, ""); + static_assert(!std::is_convertible >::value, ""); + + char s[] = "123"; + { + It it = It(s); + std::move_iterator r(it); + assert(base(r.base()) == s); + } + { + It it = It(s); + std::move_iterator r(std::move(it)); + assert(base(r.base()) == s); + } + return true; +} + +template +TEST_CONSTEXPR_CXX17 bool test_moveonly() +{ + static_assert(!std::is_constructible, const It&>::value, ""); + static_assert( std::is_constructible, It&&>::value, ""); + static_assert(!std::is_convertible >::value, ""); + static_assert(!std::is_convertible >::value, ""); + + char s[] = "123"; + { + It it = It(s); + std::move_iterator r(std::move(it)); + assert(base(r.base()) == s); + } + return true; } int main(int, char**) { - char s[] = "123"; - test(cpp17_input_iterator(s)); - test(forward_iterator(s)); - test(bidirectional_iterator(s)); - test(random_access_iterator(s)); - test(s); + test >(); + test >(); + test >(); + test >(); + test(); + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - constexpr std::move_iterator it(p); - static_assert(it.base() == p); - } + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test>()); + static_assert(test()); + static_assert(test()); +#endif + +#if TEST_STD_VER > 17 + test>(); + test_moveonly>(); + static_assert(test>()); + static_assert(test_moveonly>()); #endif return 0; diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp @@ -13,35 +13,41 @@ // pointer operator->() const; // // constexpr in C++17 +// removed in C++20 #include #include #include "test_macros.h" -template -void -test(It i) +#if TEST_STD_VER > 17 +template +concept HasArrow = requires (T t) { + t.operator->(); +}; +static_assert(!HasArrow>); +static_assert(!HasArrow&>); +static_assert(!HasArrow&&>); +#endif // TEST_STD_VER > 17 + +TEST_CONSTEXPR_CXX17 bool test() { - std::move_iterator r(i); - assert(r.operator->() == i); +#if TEST_STD_VER <= 17 + char a[] = "123456789"; + std::move_iterator it1 = std::make_move_iterator(a); + std::move_iterator it2 = std::make_move_iterator(a + 1); + assert(it1.operator->() == a); + assert(it2.operator->() == a + 1); +#endif + return true; } int main(int, char**) { - char s[] = "123"; - test(s); - + test(); #if TEST_STD_VER > 14 - { - constexpr const char *p = "123456789"; - typedef std::move_iterator MI; - constexpr MI it1 = std::make_move_iterator(p); - constexpr MI it2 = std::make_move_iterator(p+1); - static_assert(it1.operator->() == p, ""); - static_assert(it2.operator->() == p + 1, ""); - } + static_assert(test()); #endif - return 0; + return 0; } diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp @@ -12,16 +12,128 @@ #include -using iterator = std::move_iterator; - -static_assert(std::input_iterator); -static_assert(!std::forward_iterator); -static_assert(!std::indirectly_writable); -static_assert(std::incrementable); -static_assert(std::sentinel_for); -static_assert(std::sized_sentinel_for); -static_assert(!std::indirectly_movable); -static_assert(!std::indirectly_movable_storable); -static_assert(!std::indirectly_copyable); -static_assert(!std::indirectly_copyable_storable); -static_assert(!std::indirectly_swappable); +#include "test_iterators.h" +#include "test_macros.h" + +void test() +{ + { + using iterator = std::move_iterator>; + + LIBCPP_STATIC_ASSERT(!std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert(!std::sentinel_for); // not copyable + static_assert(!std::sized_sentinel_for); + static_assert(!std::indirectly_movable); + static_assert(!std::indirectly_movable_storable); + static_assert(!std::indirectly_copyable); + static_assert(!std::indirectly_copyable_storable); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + LIBCPP_STATIC_ASSERT(!std::default_initializable); + static_assert(!std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert(!std::sentinel_for); // not copyable + static_assert(!std::sized_sentinel_for); + static_assert(!std::indirectly_movable); + static_assert(!std::indirectly_movable_storable); + static_assert(!std::indirectly_copyable); + static_assert(!std::indirectly_copyable_storable); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert(!std::indirectly_movable); + static_assert(!std::indirectly_movable_storable); + static_assert(!std::indirectly_copyable); + static_assert(!std::indirectly_copyable_storable); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert(!std::sized_sentinel_for); + static_assert(!std::indirectly_movable); + static_assert(!std::indirectly_movable_storable); + static_assert(!std::indirectly_copyable); + static_assert(!std::indirectly_copyable_storable); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert(!std::indirectly_movable); + static_assert(!std::indirectly_movable_storable); + static_assert(!std::indirectly_copyable); + static_assert(!std::indirectly_copyable_storable); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator>; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert(!std::indirectly_movable); + static_assert(!std::indirectly_movable_storable); + static_assert(!std::indirectly_copyable); + static_assert(!std::indirectly_copyable_storable); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } + { + using iterator = std::move_iterator; + + static_assert( std::default_initializable); + static_assert( std::copyable); + static_assert( std::input_iterator); + static_assert(!std::forward_iterator); + static_assert( std::sentinel_for); + static_assert( std::sized_sentinel_for); + static_assert(!std::indirectly_movable); + static_assert(!std::indirectly_movable_storable); + static_assert(!std::indirectly_copyable); + static_assert(!std::indirectly_copyable_storable); + static_assert( std::indirectly_readable); + static_assert(!std::indirectly_writable); + static_assert( std::indirectly_swappable); + } +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// move_sentinel + +// template +// requires assignable_from +// constexpr move_sentinel& operator=(const move_sentinel& s); + +#include +#include +#include + +struct NonAssignable { + NonAssignable& operator=(int i); +}; +static_assert(std::semiregular); +static_assert(std::is_assignable_v); +static_assert(!std::assignable_from); + +constexpr bool test() +{ + { + std::move_sentinel m(42); + std::move_sentinel m2; + m2 = m; + assert(m2.base() == 42L); + } + { + std::move_sentinel m2; + m2 = std::move_sentinel(43); + assert(m2.base() == 43L); + } + { + static_assert( std::is_assignable_v, std::move_sentinel>); + static_assert(!std::is_assignable_v, std::move_sentinel>); + static_assert( std::is_assignable_v, std::move_sentinel>); + static_assert(!std::is_assignable_v, std::move_sentinel>); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// move_sentinel + +// constexpr S base() const; + +#include +#include + +#include "test_macros.h" + +constexpr bool test() +{ + { + auto m = std::move_sentinel(42); + const auto& cm = m; + assert(m.base() == 42); + assert(cm.base() == 42); + assert(std::move(m).base() == 42); + assert(std::move(cm).base() == 42); + ASSERT_SAME_TYPE(decltype(m.base()), int); + ASSERT_SAME_TYPE(decltype(cm.base()), int); + ASSERT_SAME_TYPE(decltype(std::move(m).base()), int); + ASSERT_SAME_TYPE(decltype(std::move(cm).base()), int); + } + { + int a[] = {1, 2, 3}; + auto m = std::move_sentinel(a); + const auto& cm = m; + assert(m.base() == a); + assert(cm.base() == a); + assert(std::move(m).base() == a); + assert(std::move(cm).base() == a); + ASSERT_SAME_TYPE(decltype(m.base()), const int*); + ASSERT_SAME_TYPE(decltype(cm.base()), const int*); + ASSERT_SAME_TYPE(decltype(std::move(m).base()), const int*); + ASSERT_SAME_TYPE(decltype(std::move(cm).base()), const int*); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-no-incomplete-ranges + +// + +// template +// class move_sentinel; + +#include + +#include "test_iterators.h" + +void test() +{ + { + using It = int*; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert( std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = cpp17_input_iterator; + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = cpp20_input_iterator; + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = forward_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert(!std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = bidirectional_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert(!std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = random_access_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert( std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = contiguous_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert( std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } + { + using It = three_way_contiguous_iterator; + static_assert( std::sentinel_for, std::move_iterator>); + static_assert( std::sized_sentinel_for, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert(!std::sized_sentinel_for>, std::move_iterator>); + static_assert( std::sentinel_for>, std::move_iterator>); + static_assert( std::sized_sentinel_for>, std::move_iterator>); + } +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/constraints.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/constraints.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/constraints.compile.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// class move_sentinel; + +#include + +template +concept HasMoveSentinel = requires { + typename std::move_sentinel; +}; + +struct Semiregular {}; + +struct NotSemiregular { + NotSemiregular(int); +}; + +static_assert( HasMoveSentinel); +static_assert( HasMoveSentinel); +static_assert( HasMoveSentinel); +static_assert(!HasMoveSentinel); diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// move_sentinel + +// template +// requires convertible_to +// constexpr move_sentinel(const move_sentinel& s); + +#include +#include +#include + +struct NonConvertible { + explicit NonConvertible(); + NonConvertible(int i); + explicit NonConvertible(long i) = delete; +}; +static_assert(std::semiregular); +static_assert(std::is_convertible_v); +static_assert(!std::convertible_to); + +constexpr bool test() +{ + { + std::move_sentinel m(42); + std::move_sentinel m2 = m; + assert(m2.base() == 42L); + } + { + std::move_sentinel m2 = std::move_sentinel(43); + assert(m2.base() == 43L); + } + { + static_assert( std::is_convertible_v, std::move_sentinel>); + static_assert( std::is_convertible_v, std::move_sentinel>); + static_assert(!std::is_convertible_v, std::move_sentinel>); + static_assert( std::is_convertible_v, std::move_sentinel>); + static_assert(!std::is_convertible_v, std::move_sentinel>); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// move_sentinel + +// constexpr move_sentinel(); + +#include +#include + +constexpr bool test() +{ + { + std::move_sentinel m; + assert(m.base() == 0); + } + { + std::move_sentinel m; + assert(m.base() == nullptr); + } + { + struct S { + explicit S() = default; + int i = 3; + }; + std::move_sentinel m; + assert(m.base().i == 3); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// move_sentinel + +// constexpr explicit move_sentinel(S s); + +#include +#include + +constexpr bool test() +{ + { + static_assert(!std::is_convertible_v>); + std::move_sentinel m(42); + assert(m.base() == 42); + } + { + static_assert(!std::is_convertible_v>); + int i = 42; + std::move_sentinel m(&i); + assert(m.base() == &i); + } + { + struct S { + explicit S() = default; + constexpr explicit S(int j) : i(j) {} + int i = 3; + }; + static_assert(!std::is_convertible_v>); + std::move_sentinel m(S(42)); + assert(m.base().i == 42); + } + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp @@ -0,0 +1,84 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// move_sentinel + +// template +// constexpr bool operator==(const move_iterator& x, const move_sentinel& y); + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +template concept HasEquals = requires (T t, U u) { t == u; }; +template concept HasNotEquals = requires (T t, U u) { t != u; }; +template concept HasLess = requires (T t, U u) { t < u; }; + +static_assert(!HasEquals, std::move_sentinel>); +static_assert(!HasNotEquals, std::move_sentinel>); +static_assert(!HasLess, std::move_sentinel>); + +static_assert( HasEquals, std::move_sentinel>); +static_assert( HasNotEquals, std::move_sentinel>); +static_assert(!HasLess, std::move_sentinel>); + +static_assert( HasEquals, std::move_sentinel>); +static_assert( HasNotEquals, std::move_sentinel>); +static_assert(!HasLess, std::move_sentinel>); + +template +constexpr bool test_one() +{ + { + char s[] = "abc"; + const auto it = std::move_iterator(It(s)); + const auto sent1 = std::move_sentinel>(sentinel_wrapper(It(s))); + const auto sent2 = std::move_sentinel>(sentinel_wrapper(It(s + 1))); + ASSERT_SAME_TYPE(decltype(it == sent1), bool); + assert( (it == sent1)); + assert(!(it != sent1)); + assert(!(it == sent2)); + assert( (it != sent2)); + assert( (sent1 == it)); + assert(!(sent1 != it)); + assert(!(sent2 == it)); + assert( (sent2 != it)); + static_assert(!HasEquals); + static_assert(!HasLess); + } + return true; +} + +constexpr bool test() +{ + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one>(); + test_one(); + test_one(); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +}