[libcxx-commits] [libcxx] 2fb026e - Implement move_sentinel and C++20 move_iterator.
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Apr 13 06:51:54 PDT 2022
Author: Arthur O'Dwyer
Date: 2022-04-13T09:51:43-04:00
New Revision: 2fb026ee4d1a612f55d3f179b42b223d00ec8eda
URL: https://github.com/llvm/llvm-project/commit/2fb026ee4d1a612f55d3f179b42b223d00ec8eda
DIFF: https://github.com/llvm/llvm-project/commit/2fb026ee4d1a612f55d3f179b42b223d00ec8eda.diff
LOG: Implement move_sentinel and C++20 move_iterator.
Differential Revision: https://reviews.llvm.org/D117656
Added:
libcxx/include/__iterator/move_sentinel.h
libcxx/test/libcxx/diagnostics/detail.headers/iterator/move_sentinel.module.verify.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_spaceship.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/assign.converting.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/concept_conformance.compile.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/constraints.compile.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.converting.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.default.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/ctor.sentinel.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/op_eq.pass.cpp
Modified:
libcxx/docs/Status/Cxx2bIssues.csv
libcxx/include/CMakeLists.txt
libcxx/include/__iterator/move_iterator.h
libcxx/include/iterator
libcxx/include/module.modulemap
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_eq.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gt.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_gte.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lt.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_lte.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.comp/op_neq.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/iter.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.ref/op_arrow.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/iterator_concept_conformance.compile.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv
index a9c67cf0714c1..7adfbf251ceb7 100644
--- a/libcxx/docs/Status/Cxx2bIssues.csv
+++ b/libcxx/docs/Status/Cxx2bIssues.csv
@@ -104,7 +104,7 @@
`3123 <https://wg21.link/LWG3123>`__,"``duration`` constructor from representation shouldn't be effectively non-throwing","October 2021","","","|chrono|"
`3146 <https://wg21.link/LWG3146>`__,"Excessive unwrapping in ``std::ref/cref``","October 2021","|Complete|","14.0"
`3152 <https://wg21.link/LWG3152>`__,"``common_type`` and ``common_reference`` have flaws in common","October 2021","",""
-`3293 <https://wg21.link/LWG3293>`__,"``move_iterator operator+()`` has incorrect constraints","October 2021","","","|ranges|"
+`3293 <https://wg21.link/LWG3293>`__,"``move_iterator operator+()`` has incorrect constraints","October 2021","|Complete|","15.0","|ranges|"
`3361 <https://wg21.link/LWG3361>`__,"``safe_range<SomeRange&>`` case","October 2021","|Nothing To Do|","","|ranges|"
`3392 <https://wg21.link/LWG3392>`__,"``ranges::distance()`` cannot be used on a move-only iterator with a sized sentinel","October 2021","|Complete|","14.0","|ranges|"
`3407 <https://wg21.link/LWG3407>`__,"Some problems with the wording changes of P1739R4","October 2021","","","|ranges|"
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 3b628406eac0f..a5e2f093f1173 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -270,6 +270,7 @@ set(files
__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
index e157b71a2f281..4776878f1f175 100644
--- 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 <type_traits>
@@ -21,20 +33,48 @@
_LIBCPP_BEGIN_NAMESPACE_STD
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
+template<class _Iter, class = void>
+struct __move_iter_category_base {};
+
+template<class _Iter>
+ requires requires { typename iterator_traits<_Iter>::iterator_category; }
+struct __move_iter_category_base<_Iter> {
+ using iterator_category = _If<
+ derived_from<typename iterator_traits<_Iter>::iterator_category, random_access_iterator_tag>,
+ random_access_iterator_tag,
+ typename iterator_traits<_Iter>::iterator_category
+ >;
+};
+
+template<class _Iter, class _Sent>
+concept __move_iter_comparable = requires {
+ { declval<const _Iter&>() == declval<_Sent>() } -> convertible_to<bool>;
+};
+#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
+
template <class _Iter>
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
diff erence_type = iter_
diff erence_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<iterator_type>::value_type value_type;
typedef typename iterator_traits<iterator_type>::
diff erence_type
diff erence_type;
typedef iterator_type pointer;
@@ -50,11 +90,56 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
typedef typename iterator_traits<iterator_type>::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 <class _Up>
+ requires (!_IsSame<_Up, _Iter>::value) && convertible_to<const _Up&, _Iter>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ move_iterator(const move_iterator<_Up>& __u) : __current_(__u.base()) {}
+
+ template <class _Up>
+ requires (!_IsSame<_Up, _Iter>::value) &&
+ convertible_to<const _Up&, _Iter> &&
+ 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[](
diff erence_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 <class _Up, class = __enable_if_t<
!is_same<_Up, _Iter>::value && is_convertible<const _Up&, _Iter>::value
@@ -87,6 +172,8 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
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 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
move_iterator& operator-=(
diff erence_type __n) { __current_ -= __n; return *this; }
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
+ template<sentinel_for<_Iter> _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<sized_sentinel_for<_Iter> _Sent>
+ friend _LIBCPP_HIDE_FROM_ABI constexpr
+ iter_
diff erence_t<_Iter> operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y)
+ {
+ return __x.base() - __y.base();
+ }
+
+ template<sized_sentinel_for<_Iter> _Sent>
+ friend _LIBCPP_HIDE_FROM_ABI constexpr
+ iter_
diff erence_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<indirectly_swappable<_Iter> _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<class _It2> friend class move_iterator;
+
_Iter __current_;
};
@@ -111,12 +239,14 @@ bool operator==(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& _
return __x.base() == __y.base();
}
+#if _LIBCPP_STD_VER <= 17
template <class _Iter1, class _Iter2>
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 <class _Iter1, class _Iter2>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
@@ -146,6 +276,20 @@ bool operator>=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& _
return __x.base() >= __y.base();
}
+#if _LIBCPP_STD_VER > 17
+# ifdef _LIBCPP_HAS_NO_CONCEPTS
+template <class _Iter1, class _Iter2>
+# else
+template <class _Iter1, three_way_comparable_with<_Iter1> _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 <class _Iter1, class _Iter2>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
@@ -164,6 +308,15 @@ operator-(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y)
}
#endif
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
+template <class _Iter>
+inline _LIBCPP_HIDE_FROM_ABI constexpr
+move_iterator<_Iter> operator+(iter_
diff erence_t<_Iter> __n, const move_iterator<_Iter>& __x)
+ requires requires { { __x.base() + __n } -> same_as<_Iter>; }
+{
+ return __x + __n;
+}
+#else
template <class _Iter>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
move_iterator<_Iter>
@@ -171,13 +324,14 @@ operator+(typename move_iterator<_Iter>::
diff erence_type __n, const move_iterato
{
return move_iterator<_Iter>(__x.base() + __n);
}
+#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
template <class _Iter>
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
index 0000000000000..fce56d62583ac
--- /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 <semiregular _Sent>
+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 <class _S2>
+ requires convertible_to<const _S2&, _Sent>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ move_sentinel(const move_sentinel<_S2>& __s) : __last_(__s.base()) {}
+
+ template <class _S2>
+ 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
index 4060c2d9d4fd0..1f0390e83a59f 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -660,6 +660,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
#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
index 6cfa65c5fd8a0..044809fd7b0ff 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -661,6 +661,7 @@ module std [system] {
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
index 0000000000000..3c41e1a9db5c4
--- /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
index 933dc68e61d78..b50299bad4add 100644
--- 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 <InputIterator Iter1, InputIterator Iter2>
-// requires HasEqualTo<Iter1, Iter2>
-// bool
-// operator==(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
+// template <class Iter1, class Iter2>
+// bool operator==(const move_iterator<Iter1>& x, const move_iterator<Iter2>& 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
diff erence_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 <class It>
-void
-test(It l, It r, bool x)
+TEST_CONSTEXPR_CXX17 void test_one()
{
- const std::move_iterator<It> r1(l);
- const std::move_iterator<It> r2(r);
- assert((r1 == r2) == x);
+ int a[] = {3, 1, 4};
+ const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> r2 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> r3 = std::move_iterator<It>(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<char*>(s), cpp17_input_iterator<char*>(s), true);
- test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s+1), false);
- test(forward_iterator<char*>(s), forward_iterator<char*>(s), true);
- test(forward_iterator<char*>(s), forward_iterator<char*>(s+1), false);
- test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s), true);
- test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s+1), false);
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s), true);
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), false);
- test(s, s, true);
- test(s, s+1, false);
+ test_one<CustomIt>();
+ test_one<cpp17_input_iterator<int*> >();
+ test_one<forward_iterator<int*> >();
+ test_one<bidirectional_iterator<int*> >();
+ test_one<random_access_iterator<int*> >();
+ test_one<int*>();
+ test_one<const int*>();
+
+#if TEST_STD_VER > 17
+ test_one<contiguous_iterator<int*>>();
+ test_one<three_way_contiguous_iterator<int*>>();
+#endif
+ return true;
+}
+
+int main(int, char**)
+{
+ test();
#if TEST_STD_VER > 14
- {
- constexpr const char *p = "123456789";
- typedef std::move_iterator<const char *> 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
index 3da38b3766641..7e599fe299028 100644
--- 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 <RandomAccessIterator Iter1, RandomAccessIterator Iter2>
-// requires HasLess<Iter2, Iter1>
-// bool
-// operator>(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
+// template <class Iter1, class Iter2>
+// bool operator>(const move_iterator<Iter1>& x, const move_iterator<Iter2>& 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
diff erence_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 <class It>
-void
-test(It l, It r, bool x)
+TEST_CONSTEXPR_CXX17 void test_one()
{
- const std::move_iterator<It> r1(l);
- const std::move_iterator<It> r2(r);
- assert((r1 > r2) == x);
+ int a[] = {3, 1, 4};
+ const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> r2 = std::move_iterator<It>(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<char*>(s), random_access_iterator<char*>(s), false);
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), false);
- test(random_access_iterator<char*>(s+1), random_access_iterator<char*>(s), true);
- test(s, s, false);
- test(s, s+1, false);
- test(s+1, s, true);
+ test_one<CustomIt>();
+ test_one<int*>();
+ test_one<const int*>();
+ test_one<random_access_iterator<int*> >();
+#if TEST_STD_VER > 17
+ test_one<contiguous_iterator<int*>>();
+#endif
+ return true;
+}
+int main(int, char**)
+{
+ assert(test());
#if TEST_STD_VER > 14
- {
- constexpr const char *p = "123456789";
- typedef std::move_iterator<const char *> 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
index dceb411515252..04e081da217c7 100644
--- 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 <RandomAccessIterator Iter1, RandomAccessIterator Iter2>
-// requires HasLess<Iter1, Iter2>
-// bool
-// operator>=(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
+// template <class Iter1, class Iter2>
+// bool operator>=(const move_iterator<Iter1>& x, const move_iterator<Iter2>& 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
diff erence_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 <class It>
-void
-test(It l, It r, bool x)
+TEST_CONSTEXPR_CXX17 void test_one()
{
- const std::move_iterator<It> r1(l);
- const std::move_iterator<It> r2(r);
- assert((r1 >= r2) == x);
+ int a[] = {3, 1, 4};
+ const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> r2 = std::move_iterator<It>(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<char*>(s), random_access_iterator<char*>(s), true);
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), false);
- test(random_access_iterator<char*>(s+1), random_access_iterator<char*>(s), true);
- test(s, s, true);
- test(s, s+1, false);
- test(s+1, s, true);
+ test_one<CustomIt>();
+ test_one<int*>();
+ test_one<const int*>();
+ test_one<random_access_iterator<int*> >();
+#if TEST_STD_VER > 17
+ test_one<contiguous_iterator<int*>>();
+#endif
+ return true;
+}
+int main(int, char**)
+{
+ assert(test());
#if TEST_STD_VER > 14
- {
- constexpr const char *p = "123456789";
- typedef std::move_iterator<const char *> 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
index 675e55f7881db..24ccfa63d0af2 100644
--- 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 <RandomAccessIterator Iter1, RandomAccessIterator Iter2>
-// requires HasLess<Iter1, Iter2>
-// bool
-// operator<(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
+// template <class Iter1, class Iter2>
+// bool operator<(const move_iterator<Iter1>& x, const move_iterator<Iter2>& 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
diff erence_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 <class It>
-void
-test(It l, It r, bool x)
+TEST_CONSTEXPR_CXX17 void test_one()
{
- const std::move_iterator<It> r1(l);
- const std::move_iterator<It> r2(r);
- assert((r1 < r2) == x);
+ int a[] = {3, 1, 4};
+ const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> r2 = std::move_iterator<It>(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<char*>(s), random_access_iterator<char*>(s), false);
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), true);
- test(random_access_iterator<char*>(s+1), random_access_iterator<char*>(s), false);
- test(s, s, false);
- test(s, s+1, true);
- test(s+1, s, false);
+ test_one<CustomIt>();
+ test_one<int*>();
+ test_one<const int*>();
+ test_one<random_access_iterator<int*> >();
+#if TEST_STD_VER > 17
+ test_one<contiguous_iterator<int*>>();
+#endif
+ return true;
+}
+int main(int, char**)
+{
+ assert(test());
#if TEST_STD_VER > 14
- {
- constexpr const char *p = "123456789";
- typedef std::move_iterator<const char *> 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
index a2ac0b7a6f7bb..6de8dae8aa96b 100644
--- 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 <RandomAccessIterator Iter1, RandomAccessIterator Iter2>
-// requires HasLess<Iter2, Iter1>
-// bool
-// operator<=(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
+// template <class Iter1, class Iter2>
+// bool operator<=(const move_iterator<Iter1>& x, const move_iterator<Iter2>& 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
diff erence_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 <class It>
-void
-test(It l, It r, bool x)
+TEST_CONSTEXPR_CXX17 void test_one()
{
- const std::move_iterator<It> r1(l);
- const std::move_iterator<It> r2(r);
- assert((r1 <= r2) == x);
+ int a[] = {3, 1, 4};
+ const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> r2 = std::move_iterator<It>(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<char*>(s), random_access_iterator<char*>(s), true);
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), true);
- test(random_access_iterator<char*>(s+1), random_access_iterator<char*>(s), false);
- test(s, s, true);
- test(s, s+1, true);
- test(s+1, s, false);
+ test_one<CustomIt>();
+ test_one<int*>();
+ test_one<const int*>();
+ test_one<random_access_iterator<int*> >();
+#if TEST_STD_VER > 17
+ test_one<contiguous_iterator<int*>>();
+#endif
+ return true;
+}
+int main(int, char**)
+{
+ assert(test());
#if TEST_STD_VER > 14
- {
- constexpr const char *p = "123456789";
- typedef std::move_iterator<const char *> 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
index 808ea7b8d267b..51982adeeb6bd 100644
--- 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
diff erence_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 <class It>
-void
-test(It l, It r, bool x)
+TEST_CONSTEXPR_CXX17 void test_one()
{
- const std::move_iterator<It> r1(l);
- const std::move_iterator<It> r2(r);
- assert((r1 != r2) == x);
+ int a[] = {3, 1, 4};
+ const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> r2 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> r3 = std::move_iterator<It>(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<char*>(s), cpp17_input_iterator<char*>(s), false);
- test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s+1), true);
- test(forward_iterator<char*>(s), forward_iterator<char*>(s), false);
- test(forward_iterator<char*>(s), forward_iterator<char*>(s+1), true);
- test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s), false);
- test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s+1), true);
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s), false);
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), true);
- test(s, s, false);
- test(s, s+1, true);
+ test_one<CustomIt>();
+ test_one<cpp17_input_iterator<int*> >();
+ test_one<forward_iterator<int*> >();
+ test_one<bidirectional_iterator<int*> >();
+ test_one<random_access_iterator<int*> >();
+ test_one<int*>();
+ test_one<const int*>();
+
+#if TEST_STD_VER > 17
+ test_one<contiguous_iterator<int*>>();
+ test_one<three_way_contiguous_iterator<int*>>();
+#endif
+ return true;
+}
+
+int main(int, char**)
+{
+ test();
#if TEST_STD_VER > 14
- {
- constexpr const char *p = "123456789";
- typedef std::move_iterator<const char *> 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
index 0000000000000..dc9238a529fb0
--- /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
+
+// <iterator>
+
+// move_iterator
+
+// template <class Iter1, three_way_comparable_with<Iter1> Iter2>
+// constexpr auto operator<=>(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y)
+// -> compare_three_way_result_t<Iter1, Iter2>;
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+
+template<class T, class U> concept HasEquals = requires (T t, U u) { t == u; };
+template<class T, class U> concept HasSpaceship = requires (T t, U u) { t <=> u; };
+
+static_assert(!HasSpaceship<std::move_iterator<int*>, std::move_iterator<char*>>);
+static_assert( HasSpaceship<std::move_iterator<int*>, std::move_iterator<int*>>);
+static_assert( HasSpaceship<std::move_iterator<int*>, std::move_iterator<const int*>>);
+static_assert( HasSpaceship<std::move_iterator<const int*>, std::move_iterator<const int*>>);
+static_assert(!HasSpaceship<std::move_iterator<forward_iterator<int*>>, std::move_iterator<forward_iterator<int*>>>);
+static_assert(!HasSpaceship<std::move_iterator<random_access_iterator<int*>>, std::move_iterator<random_access_iterator<int*>>>);
+static_assert(!HasSpaceship<std::move_iterator<contiguous_iterator<int*>>, std::move_iterator<contiguous_iterator<int*>>>);
+static_assert( HasSpaceship<std::move_iterator<three_way_contiguous_iterator<int*>>, std::move_iterator<three_way_contiguous_iterator<int*>>>);
+
+static_assert(!HasSpaceship<std::move_iterator<int*>, std::move_sentinel<int*>>);
+static_assert(!HasSpaceship<std::move_iterator<three_way_contiguous_iterator<int*>>, std::move_sentinel<three_way_contiguous_iterator<int*>>>);
+
+void test_spaceshippable_but_not_three_way_comparable() {
+ struct A {
+ using value_type = int;
+ using
diff erence_type = int;
+ int& operator*() const;
+ A& operator++();
+ A operator++(int);
+ std::strong_ordering operator<=>(const A&) const;
+ };
+ struct B {
+ using value_type = int;
+ using
diff erence_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<A>);
+ static_assert( std::input_iterator<B>);
+ static_assert( HasEquals<A, B>);
+ static_assert( HasSpaceship<A, B>);
+ static_assert(!std::three_way_comparable_with<A, B>);
+ static_assert( HasEquals<std::move_iterator<A>, std::move_iterator<B>>);
+ static_assert(!HasSpaceship<std::move_iterator<A>, std::move_iterator<B>>);
+}
+
+template <class It, class Jt>
+constexpr void test_two()
+{
+ int a[] = {3, 1, 4};
+ const std::move_iterator<It> i1 = std::move_iterator<It>(It(a));
+ const std::move_iterator<It> i2 = std::move_iterator<It>(It(a + 2));
+ const std::move_iterator<Jt> j1 = std::move_iterator<Jt>(Jt(a));
+ const std::move_iterator<Jt> j2 = std::move_iterator<Jt>(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<int*, int*>();
+ test_two<int*, const int*>();
+ test_two<const int*, int*>();
+ test_two<const int*, const int*>();
+ test_two<three_way_contiguous_iterator<int*>, three_way_contiguous_iterator<int*>>();
+ 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
index 64c1a43bd6e0e..f7830f73e5248 100644
--- 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 <iterator>
#include <cassert>
+#include <utility>
#include "test_macros.h"
#include "test_iterators.h"
template <class It>
-void
-test(It i)
+TEST_CONSTEXPR_CXX17 bool test()
{
- std::move_iterator<It> r(i);
- assert(r.base() == i);
+ static_assert( std::is_constructible<std::move_iterator<It>, const It&>::value, "");
+ static_assert( std::is_constructible<std::move_iterator<It>, It&&>::value, "");
+ static_assert(!std::is_convertible<const It&, std::move_iterator<It> >::value, "");
+ static_assert(!std::is_convertible<It&&, std::move_iterator<It> >::value, "");
+
+ char s[] = "123";
+ {
+ It it = It(s);
+ std::move_iterator<It> r(it);
+ assert(base(r.base()) == s);
+ }
+ {
+ It it = It(s);
+ std::move_iterator<It> r(std::move(it));
+ assert(base(r.base()) == s);
+ }
+ return true;
+}
+
+template <class It>
+TEST_CONSTEXPR_CXX17 bool test_moveonly()
+{
+ static_assert(!std::is_constructible<std::move_iterator<It>, const It&>::value, "");
+ static_assert( std::is_constructible<std::move_iterator<It>, It&&>::value, "");
+ static_assert(!std::is_convertible<const It&, std::move_iterator<It> >::value, "");
+ static_assert(!std::is_convertible<It&&, std::move_iterator<It> >::value, "");
+
+ char s[] = "123";
+ {
+ It it = It(s);
+ std::move_iterator<It> r(std::move(it));
+ assert(base(r.base()) == s);
+ }
+ return true;
}
int main(int, char**)
{
- char s[] = "123";
- test(cpp17_input_iterator<char*>(s));
- test(forward_iterator<char*>(s));
- test(bidirectional_iterator<char*>(s));
- test(random_access_iterator<char*>(s));
- test(s);
+ test<cpp17_input_iterator<char*> >();
+ test<forward_iterator<char*> >();
+ test<bidirectional_iterator<char*> >();
+ test<random_access_iterator<char*> >();
+ test<char*>();
+ test<const char*>();
#if TEST_STD_VER > 14
- {
- constexpr const char *p = "123456789";
- constexpr std::move_iterator<const char *> it(p);
- static_assert(it.base() == p);
- }
+ static_assert(test<cpp17_input_iterator<char*>>());
+ static_assert(test<forward_iterator<char*>>());
+ static_assert(test<bidirectional_iterator<char*>>());
+ static_assert(test<random_access_iterator<char*>>());
+ static_assert(test<char*>());
+ static_assert(test<const char*>());
+#endif
+
+#if TEST_STD_VER > 17
+ test<contiguous_iterator<char*>>();
+ test_moveonly<cpp20_input_iterator<char*>>();
+ static_assert(test<contiguous_iterator<char*>>());
+ static_assert(test_moveonly<cpp20_input_iterator<char*>>());
#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
index 6024f99fec3f1..8be60bc349dfc 100644
--- 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 <iterator>
#include <cassert>
#include "test_macros.h"
-template <class It>
-void
-test(It i)
+#if TEST_STD_VER > 17
+template <class T>
+concept HasArrow = requires (T t) {
+ t.operator->();
+};
+static_assert(!HasArrow<std::move_iterator<int*>>);
+static_assert(!HasArrow<std::move_iterator<int*>&>);
+static_assert(!HasArrow<std::move_iterator<int*>&&>);
+#endif // TEST_STD_VER > 17
+
+TEST_CONSTEXPR_CXX17 bool test()
{
- std::move_iterator<It> r(i);
- assert(r.operator->() == i);
+#if TEST_STD_VER <= 17
+ char a[] = "123456789";
+ std::move_iterator<char *> it1 = std::make_move_iterator(a);
+ std::move_iterator<char *> 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<const char *> 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
index 2df020c021ab4..844da40b8efcb 100644
--- 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 <iterator>
-using iterator = std::move_iterator<int*>;
-
-static_assert(std::input_iterator<iterator>);
-static_assert(!std::forward_iterator<iterator>);
-static_assert(!std::indirectly_writable<iterator, int>);
-static_assert(std::incrementable<iterator>);
-static_assert(std::sentinel_for<iterator, iterator>);
-static_assert(std::sized_sentinel_for<iterator, iterator>);
-static_assert(!std::indirectly_movable<int*, iterator>);
-static_assert(!std::indirectly_movable_storable<int*, iterator>);
-static_assert(!std::indirectly_copyable<int*, iterator>);
-static_assert(!std::indirectly_copyable_storable<int*, iterator>);
-static_assert(!std::indirectly_swappable<iterator, iterator>);
+#include "test_iterators.h"
+#include "test_macros.h"
+
+void test()
+{
+ {
+ using iterator = std::move_iterator<cpp17_input_iterator<int*>>;
+
+ LIBCPP_STATIC_ASSERT(!std::default_initializable<iterator>);
+ static_assert( std::copyable<iterator>);
+ static_assert( std::input_iterator<iterator>);
+ static_assert(!std::forward_iterator<iterator>);
+ static_assert(!std::sentinel_for<iterator, iterator>); // not copyable
+ static_assert(!std::sized_sentinel_for<iterator, iterator>);
+ static_assert(!std::indirectly_movable<int*, iterator>);
+ static_assert(!std::indirectly_movable_storable<int*, iterator>);
+ static_assert(!std::indirectly_copyable<int*, iterator>);
+ static_assert(!std::indirectly_copyable_storable<int*, iterator>);
+ static_assert( std::indirectly_readable<iterator>);
+ static_assert(!std::indirectly_writable<iterator, int>);
+ static_assert( std::indirectly_swappable<iterator, iterator>);
+ }
+ {
+ using iterator = std::move_iterator<cpp20_input_iterator<int*>>;
+
+ LIBCPP_STATIC_ASSERT(!std::default_initializable<iterator>);
+ static_assert(!std::copyable<iterator>);
+ static_assert( std::input_iterator<iterator>);
+ static_assert(!std::forward_iterator<iterator>);
+ static_assert(!std::sentinel_for<iterator, iterator>); // not copyable
+ static_assert(!std::sized_sentinel_for<iterator, iterator>);
+ static_assert(!std::indirectly_movable<int*, iterator>);
+ static_assert(!std::indirectly_movable_storable<int*, iterator>);
+ static_assert(!std::indirectly_copyable<int*, iterator>);
+ static_assert(!std::indirectly_copyable_storable<int*, iterator>);
+ static_assert( std::indirectly_readable<iterator>);
+ static_assert(!std::indirectly_writable<iterator, int>);
+ static_assert( std::indirectly_swappable<iterator, iterator>);
+ }
+ {
+ using iterator = std::move_iterator<forward_iterator<int*>>;
+
+ static_assert( std::default_initializable<iterator>);
+ static_assert( std::copyable<iterator>);
+ static_assert( std::input_iterator<iterator>);
+ static_assert(!std::forward_iterator<iterator>);
+ static_assert( std::sentinel_for<iterator, iterator>);
+ static_assert(!std::sized_sentinel_for<iterator, iterator>);
+ static_assert(!std::indirectly_movable<int*, iterator>);
+ static_assert(!std::indirectly_movable_storable<int*, iterator>);
+ static_assert(!std::indirectly_copyable<int*, iterator>);
+ static_assert(!std::indirectly_copyable_storable<int*, iterator>);
+ static_assert( std::indirectly_readable<iterator>);
+ static_assert(!std::indirectly_writable<iterator, int>);
+ static_assert( std::indirectly_swappable<iterator, iterator>);
+ }
+ {
+ using iterator = std::move_iterator<bidirectional_iterator<int*>>;
+
+ static_assert( std::default_initializable<iterator>);
+ static_assert( std::copyable<iterator>);
+ static_assert( std::input_iterator<iterator>);
+ static_assert(!std::forward_iterator<iterator>);
+ static_assert( std::sentinel_for<iterator, iterator>);
+ static_assert(!std::sized_sentinel_for<iterator, iterator>);
+ static_assert(!std::indirectly_movable<int*, iterator>);
+ static_assert(!std::indirectly_movable_storable<int*, iterator>);
+ static_assert(!std::indirectly_copyable<int*, iterator>);
+ static_assert(!std::indirectly_copyable_storable<int*, iterator>);
+ static_assert( std::indirectly_readable<iterator>);
+ static_assert(!std::indirectly_writable<iterator, int>);
+ static_assert( std::indirectly_swappable<iterator, iterator>);
+ }
+ {
+ using iterator = std::move_iterator<random_access_iterator<int*>>;
+
+ static_assert( std::default_initializable<iterator>);
+ static_assert( std::copyable<iterator>);
+ static_assert( std::input_iterator<iterator>);
+ static_assert(!std::forward_iterator<iterator>);
+ static_assert( std::sentinel_for<iterator, iterator>);
+ static_assert( std::sized_sentinel_for<iterator, iterator>);
+ static_assert(!std::indirectly_movable<int*, iterator>);
+ static_assert(!std::indirectly_movable_storable<int*, iterator>);
+ static_assert(!std::indirectly_copyable<int*, iterator>);
+ static_assert(!std::indirectly_copyable_storable<int*, iterator>);
+ static_assert( std::indirectly_readable<iterator>);
+ static_assert(!std::indirectly_writable<iterator, int>);
+ static_assert( std::indirectly_swappable<iterator, iterator>);
+ }
+ {
+ using iterator = std::move_iterator<contiguous_iterator<int*>>;
+
+ static_assert( std::default_initializable<iterator>);
+ static_assert( std::copyable<iterator>);
+ static_assert( std::input_iterator<iterator>);
+ static_assert(!std::forward_iterator<iterator>);
+ static_assert( std::sentinel_for<iterator, iterator>);
+ static_assert( std::sized_sentinel_for<iterator, iterator>);
+ static_assert(!std::indirectly_movable<int*, iterator>);
+ static_assert(!std::indirectly_movable_storable<int*, iterator>);
+ static_assert(!std::indirectly_copyable<int*, iterator>);
+ static_assert(!std::indirectly_copyable_storable<int*, iterator>);
+ static_assert( std::indirectly_readable<iterator>);
+ static_assert(!std::indirectly_writable<iterator, int>);
+ static_assert( std::indirectly_swappable<iterator, iterator>);
+ }
+ {
+ using iterator = std::move_iterator<int*>;
+
+ static_assert( std::default_initializable<iterator>);
+ static_assert( std::copyable<iterator>);
+ static_assert( std::input_iterator<iterator>);
+ static_assert(!std::forward_iterator<iterator>);
+ static_assert( std::sentinel_for<iterator, iterator>);
+ static_assert( std::sized_sentinel_for<iterator, iterator>);
+ static_assert(!std::indirectly_movable<int*, iterator>);
+ static_assert(!std::indirectly_movable_storable<int*, iterator>);
+ static_assert(!std::indirectly_copyable<int*, iterator>);
+ static_assert(!std::indirectly_copyable_storable<int*, iterator>);
+ static_assert( std::indirectly_readable<iterator>);
+ static_assert(!std::indirectly_writable<iterator, int>);
+ static_assert( std::indirectly_swappable<iterator, iterator>);
+ }
+}
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
index 0000000000000..cc033f660d395
--- /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
+
+// <iterator>
+
+// move_sentinel
+
+// template<class S2>
+// requires assignable_from<S&, const S2&>
+// constexpr move_sentinel& operator=(const move_sentinel<S2>& s);
+
+#include <iterator>
+#include <cassert>
+#include <concepts>
+
+struct NonAssignable {
+ NonAssignable& operator=(int i);
+};
+static_assert(std::semiregular<NonAssignable>);
+static_assert(std::is_assignable_v<NonAssignable, int>);
+static_assert(!std::assignable_from<NonAssignable, int>);
+
+constexpr bool test()
+{
+ {
+ std::move_sentinel<int> m(42);
+ std::move_sentinel<long> m2;
+ m2 = m;
+ assert(m2.base() == 42L);
+ }
+ {
+ std::move_sentinel<long> m2;
+ m2 = std::move_sentinel<int>(43);
+ assert(m2.base() == 43L);
+ }
+ {
+ static_assert( std::is_assignable_v<std::move_sentinel<int>, std::move_sentinel<long>>);
+ static_assert(!std::is_assignable_v<std::move_sentinel<int*>, std::move_sentinel<const int*>>);
+ static_assert( std::is_assignable_v<std::move_sentinel<const int*>, std::move_sentinel<int*>>);
+ static_assert(!std::is_assignable_v<std::move_sentinel<NonAssignable>, std::move_sentinel<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/base.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.sentinel/base.pass.cpp
new file mode 100644
index 0000000000000..2b8f17d4eebfd
--- /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
+
+// <iterator>
+
+// move_sentinel
+
+// constexpr S base() const;
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+
+constexpr bool test()
+{
+ {
+ auto m = std::move_sentinel<int>(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<const int*>(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
index 0000000000000..6d4e6abf96842
--- /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
+
+// <iterator>
+
+// template<semiregular S>
+// class move_sentinel;
+
+#include <iterator>
+
+#include "test_iterators.h"
+
+void test()
+{
+ {
+ using It = int*;
+ static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ }
+ {
+ using It = cpp17_input_iterator<int*>;
+ static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ }
+ {
+ using It = cpp20_input_iterator<int*>;
+ static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ }
+ {
+ using It = forward_iterator<int*>;
+ static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ }
+ {
+ using It = bidirectional_iterator<int*>;
+ static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ }
+ {
+ using It = random_access_iterator<int*>;
+ static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ }
+ {
+ using It = contiguous_iterator<int*>;
+ static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ }
+ {
+ using It = three_way_contiguous_iterator<int*>;
+ static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
+ static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
+ }
+}
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
index 0000000000000..a07cf470cf2c5
--- /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
+
+// <iterator>
+
+// template<semiregular S>
+// class move_sentinel;
+
+#include <iterator>
+
+template<class T>
+concept HasMoveSentinel = requires {
+ typename std::move_sentinel<T>;
+};
+
+struct Semiregular {};
+
+struct NotSemiregular {
+ NotSemiregular(int);
+};
+
+static_assert( HasMoveSentinel<int>);
+static_assert( HasMoveSentinel<int*>);
+static_assert( HasMoveSentinel<Semiregular>);
+static_assert(!HasMoveSentinel<NotSemiregular>);
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
index 0000000000000..ffd88be561be6
--- /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
+
+// <iterator>
+
+// move_sentinel
+
+// template<class S2>
+// requires convertible_to<const S2&, S>
+// constexpr move_sentinel(const move_sentinel<S2>& s);
+
+#include <iterator>
+#include <cassert>
+#include <concepts>
+
+struct NonConvertible {
+ explicit NonConvertible();
+ NonConvertible(int i);
+ explicit NonConvertible(long i) = delete;
+};
+static_assert(std::semiregular<NonConvertible>);
+static_assert(std::is_convertible_v<long, NonConvertible>);
+static_assert(!std::convertible_to<long, NonConvertible>);
+
+constexpr bool test()
+{
+ {
+ std::move_sentinel<int> m(42);
+ std::move_sentinel<long> m2 = m;
+ assert(m2.base() == 42L);
+ }
+ {
+ std::move_sentinel<long> m2 = std::move_sentinel<int>(43);
+ assert(m2.base() == 43L);
+ }
+ {
+ static_assert( std::is_convertible_v<std::move_sentinel<int>, std::move_sentinel<long>>);
+ static_assert( std::is_convertible_v<std::move_sentinel<int*>, std::move_sentinel<const int*>>);
+ static_assert(!std::is_convertible_v<std::move_sentinel<const int*>, std::move_sentinel<int*>>);
+ static_assert( std::is_convertible_v<std::move_sentinel<int>, std::move_sentinel<NonConvertible>>);
+ static_assert(!std::is_convertible_v<std::move_sentinel<long>, std::move_sentinel<NonConvertible>>);
+ }
+ 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
index 0000000000000..82e91e9ac1d0e
--- /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
+
+// <iterator>
+
+// move_sentinel
+
+// constexpr move_sentinel();
+
+#include <iterator>
+#include <cassert>
+
+constexpr bool test()
+{
+ {
+ std::move_sentinel<int> m;
+ assert(m.base() == 0);
+ }
+ {
+ std::move_sentinel<int*> m;
+ assert(m.base() == nullptr);
+ }
+ {
+ struct S {
+ explicit S() = default;
+ int i = 3;
+ };
+ std::move_sentinel<S> 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
index 0000000000000..ad1c3d82cef85
--- /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
+
+// <iterator>
+
+// move_sentinel
+
+// constexpr explicit move_sentinel(S s);
+
+#include <iterator>
+#include <cassert>
+
+constexpr bool test()
+{
+ {
+ static_assert(!std::is_convertible_v<int, std::move_sentinel<int>>);
+ std::move_sentinel<int> m(42);
+ assert(m.base() == 42);
+ }
+ {
+ static_assert(!std::is_convertible_v<int*, std::move_sentinel<int*>>);
+ int i = 42;
+ std::move_sentinel<int*> 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<S, std::move_sentinel<S>>);
+ std::move_sentinel<S> 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
index 0000000000000..fef17c5d188bb
--- /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
+
+// <iterator>
+
+// move_sentinel
+
+// template <class Iter, class Sent>
+// constexpr bool operator==(const move_iterator<Iter>& x, const move_sentinel<Sent>& y);
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+template<class T, class U> concept HasEquals = requires (T t, U u) { t == u; };
+template<class T, class U> concept HasNotEquals = requires (T t, U u) { t != u; };
+template<class T, class U> concept HasLess = requires (T t, U u) { t < u; };
+
+static_assert(!HasEquals<std::move_iterator<int*>, std::move_sentinel<char*>>);
+static_assert(!HasNotEquals<std::move_iterator<int*>, std::move_sentinel<char*>>);
+static_assert(!HasLess<std::move_iterator<int*>, std::move_sentinel<char*>>);
+
+static_assert( HasEquals<std::move_iterator<int*>, std::move_sentinel<const int*>>);
+static_assert( HasNotEquals<std::move_iterator<int*>, std::move_sentinel<const int*>>);
+static_assert(!HasLess<std::move_iterator<int*>, std::move_sentinel<const int*>>);
+
+static_assert( HasEquals<std::move_iterator<const int*>, std::move_sentinel<int*>>);
+static_assert( HasNotEquals<std::move_iterator<const int*>, std::move_sentinel<int*>>);
+static_assert(!HasLess<std::move_iterator<const int*>, std::move_sentinel<int*>>);
+
+template <class It>
+constexpr bool test_one()
+{
+ {
+ char s[] = "abc";
+ const auto it = std::move_iterator<It>(It(s));
+ const auto sent1 = std::move_sentinel<sentinel_wrapper<It>>(sentinel_wrapper<It>(It(s)));
+ const auto sent2 = std::move_sentinel<sentinel_wrapper<It>>(sentinel_wrapper<It>(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<decltype(sent1), decltype(sent1)>);
+ static_assert(!HasLess<decltype(sent1), decltype(sent1)>);
+ }
+ return true;
+}
+
+constexpr bool test()
+{
+ test_one<cpp17_input_iterator<char*>>();
+ test_one<cpp20_input_iterator<char*>>();
+ test_one<forward_iterator<char*>>();
+ test_one<bidirectional_iterator<char*>>();
+ test_one<random_access_iterator<char*>>();
+ test_one<contiguous_iterator<char*>>();
+ test_one<three_way_contiguous_iterator<char*>>();
+ test_one<char*>();
+ test_one<const char*>();
+
+ return true;
+}
+
+int main(int, char**)
+{
+ test();
+ static_assert(test());
+
+ return 0;
+}
More information about the libcxx-commits
mailing list