[libcxx-commits] [libcxx] b06049b - [libc++][NFC] Add more tests to `move_{iterator, sentinel}`.
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue May 24 19:56:42 PDT 2022
Author: Konstantin Varlamov
Date: 2022-05-24T19:56:12-07:00
New Revision: b06049bc3b79be4a037a60dec4ad19a68e196a8f
URL: https://github.com/llvm/llvm-project/commit/b06049bc3b79be4a037a60dec4ad19a68e196a8f
DIFF: https://github.com/llvm/llvm-project/commit/b06049bc3b79be4a037a60dec4ad19a68e196a8f.diff
LOG: [libc++][NFC] Add more tests to `move_{iterator,sentinel}`.
More test coverage for the parts added by the One Ranges Proposal.
Differential Revision: https://reviews.llvm.org/D124906
Added:
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_move.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_swap.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.-/sentinel.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/base.pass.cpp
Modified:
libcxx/include/__iterator/move_iterator.h
libcxx/include/__iterator/move_sentinel.h
libcxx/include/iterator
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/difference_type.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.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/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
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp
libcxx/test/support/test_iterators.h
Removed:
libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/tested_elsewhere.pass.cpp
################################################################################
diff --git a/libcxx/include/__iterator/move_iterator.h b/libcxx/include/__iterator/move_iterator.h
index 5beb8319d172..e0c7e73a9cc3 100644
--- a/libcxx/include/__iterator/move_iterator.h
+++ b/libcxx/include/__iterator/move_iterator.h
@@ -87,10 +87,13 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
>::type reference;
#endif // _LIBCPP_STD_VER > 17
-#if _LIBCPP_STD_VER > 17
- _LIBCPP_HIDE_FROM_ABI constexpr
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {}
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
+ move_iterator& operator++() { ++__current_; return *this; }
+
+#if _LIBCPP_STD_VER > 17
_LIBCPP_HIDE_FROM_ABI constexpr
move_iterator() requires is_constructible_v<_Iter> : __current_() {}
@@ -117,9 +120,6 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
_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>
@@ -130,9 +130,6 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
_LIBCPP_HIDE_FROM_ABI constexpr
void operator++(int) { ++__current_; }
#else
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
- explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {}
-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
move_iterator() : __current_() {}
@@ -163,8 +160,6 @@ class _LIBCPP_TEMPLATE_VIS move_iterator
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
reference operator[](
diff erence_type __n) const { return static_cast<reference>(__current_[__n]); }
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
- 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
diff --git a/libcxx/include/__iterator/move_sentinel.h b/libcxx/include/__iterator/move_sentinel.h
index abacc91be842..5adf877b3490 100644
--- a/libcxx/include/__iterator/move_sentinel.h
+++ b/libcxx/include/__iterator/move_sentinel.h
@@ -31,7 +31,7 @@ class _LIBCPP_TEMPLATE_VIS move_sentinel
move_sentinel() = default;
_LIBCPP_HIDE_FROM_ABI constexpr
- explicit move_sentinel(_Sent __s) : __last_(_VSTD::move(__s)) {}
+ explicit move_sentinel(_Sent __s) : __last_(std::move(__s)) {}
template <class _S2>
requires convertible_to<const _S2&, _Sent>
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
index 1f0390e83a59..e98372527cc0 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -386,12 +386,13 @@ constexpr insert_iterator<Container> inserter(Container& x, ranges::iterator_t<C
template <class Iterator>
class move_iterator {
public:
- typedef Iterator iterator_type;
- typedef typename iterator_traits<Iterator>::
diff erence_type
diff erence_type;
- typedef Iterator pointer;
- typedef typename iterator_traits<Iterator>::value_type value_type;
- typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
- typedef value_type&& reference;
+ using iterator_type = Iterator;
+ using iterator_concept = input_iterator_tag; // From C++20
+ using iterator_category = see below; // not always present starting from C++20
+ using value_type = iter_value_t<Iterator>; // Until C++20, iterator_traits<Iterator>::value_type
+ using
diff erence_type = iter_
diff erence_t<Iterator>; // Until C++20, iterator_traits<Iterator>::
diff erence_type;
+ using pointer = Iterator;
+ using reference = iter_rvalue_reference_t<Iterator>; // Until C++20, value_type&&
constexpr move_iterator(); // all the constexprs are in C++17
constexpr explicit move_iterator(Iterator i);
@@ -399,18 +400,40 @@ public:
constexpr move_iterator(const move_iterator<U>& u);
template <class U>
constexpr move_iterator& operator=(const move_iterator<U>& u);
- constexpr iterator_type base() const;
+
+ constexpr iterator_type base() const; // Until C++20
+ constexpr const Iterator& base() const & noexcept; // From C++20
+ constexpr Iterator base() &&; // From C++20
+
constexpr reference operator*() const;
- constexpr pointer operator->() const;
+ constexpr pointer operator->() const; // Removed in C++20
constexpr move_iterator& operator++();
- constexpr move_iterator operator++(int);
+ constexpr auto operator++(int); // Return type was move_iterator until C++20
constexpr move_iterator& operator--();
constexpr move_iterator operator--(int);
constexpr move_iterator operator+(
diff erence_type n) const;
constexpr move_iterator& operator+=(
diff erence_type n);
constexpr move_iterator operator-(
diff erence_type n) const;
constexpr move_iterator& operator-=(
diff erence_type n);
- constexpr unspecified operator[](
diff erence_type n) const;
+ constexpr reference operator[](
diff erence_type n) const; // Return type unspecified until C++20
+
+ template<sentinel_for<Iterator> S>
+ friend constexpr bool
+ operator==(const move_iterator& x, const move_sentinel<S>& y); // Since C++20
+ template<sized_sentinel_for<Iterator> S>
+ friend constexpr iter_
diff erence_t<Iterator>
+ operator-(const move_sentinel<S>& x, const move_iterator& y); // Since C++20
+ template<sized_sentinel_for<Iterator> S>
+ friend constexpr iter_
diff erence_t<Iterator>
+ operator-(const move_iterator& x, const move_sentinel<S>& y); // Since C++20
+ friend constexpr iter_rvalue_reference_t<Iterator>
+ iter_move(const move_iterator& i)
+ noexcept(noexcept(ranges::iter_move(i.current))); // Since C++20
+ template<indirectly_swappable<Iterator> Iterator2>
+ friend constexpr void
+ iter_swap(const move_iterator& x, const move_iterator<Iterator2>& y)
+ noexcept(noexcept(ranges::iter_swap(x.current, y.current))); // Since C++20
+
private:
Iterator current; // exposition only
};
@@ -452,6 +475,23 @@ constexpr move_iterator<Iterator> operator+( // constexpr in C++17
template <class Iterator> // constexpr in C++17
constexpr move_iterator<Iterator> make_move_iterator(const Iterator& i);
+template<semiregular S>
+class move_sentinel {
+public:
+ constexpr move_sentinel();
+ constexpr explicit move_sentinel(S s);
+ template<class S2>
+ requires convertible_to<const S2&, S>
+ constexpr move_sentinel(const move_sentinel<S2>& s);
+ template<class S2>
+ requires assignable_from<S&, const S2&>
+ constexpr move_sentinel& operator=(const move_sentinel<S2>& s);
+
+ constexpr S base() const;
+private:
+ S last; // exposition only
+};
+
// [default.sentinel], default sentinel
struct default_sentinel_t;
inline constexpr default_sentinel_t default_sentinel{};
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_move.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_move.pass.cpp
new file mode 100644
index 000000000000..a9e6d17720ab
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_move.pass.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+//
+// friend constexpr iter_rvalue_reference_t<Iterator>
+// iter_move(const move_iterator& i)
+// noexcept(noexcept(ranges::iter_move(i.current))); // Since C++20
+
+#include <iterator>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include "test_iterators.h"
+#include "test_macros.h"
+
+int global;
+
+template <bool IsNoexcept>
+struct MaybeNoexceptMove {
+ int x;
+ using value_type = int;
+ using
diff erence_type = ptr
diff _t;
+
+ constexpr friend value_type&& iter_move(MaybeNoexceptMove) noexcept(IsNoexcept) {
+ return std::move(global);
+ }
+
+ int& operator*() const { static int a; return a; }
+
+ MaybeNoexceptMove& operator++();
+ MaybeNoexceptMove operator++(int);
+};
+using ThrowingBase = MaybeNoexceptMove<false>;
+using NoexceptBase = MaybeNoexceptMove<true>;
+static_assert(std::input_iterator<ThrowingBase>);
+ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(std::declval<ThrowingBase>()));
+ASSERT_NOEXCEPT(std::ranges::iter_move(std::declval<NoexceptBase>()));
+
+constexpr bool test() {
+ // Can use `iter_move` with a regular array.
+ {
+ int a[] = {0, 1, 2};
+
+ std::move_iterator<int*> i(a);
+ static_assert(std::same_as<decltype(iter_move(i)), int&&>);
+ assert(iter_move(i) == 0);
+
+ ++i;
+ assert(iter_move(i) == 1);
+ }
+
+ // Check that the `iter_move` customization point is being used.
+ {
+ int a[] = {0, 1, 2};
+
+ int iter_move_invocations = 0;
+ adl::Iterator base = adl::Iterator::TrackMoves(a, iter_move_invocations);
+ std::move_iterator<adl::Iterator> i(base);
+ int x = iter_move(i);
+ assert(x == 0);
+ assert(iter_move_invocations == 1);
+ }
+
+ // Check the `noexcept` specification.
+ {
+ using ThrowingIter = std::move_iterator<ThrowingBase>;
+ ASSERT_NOT_NOEXCEPT(iter_move(std::declval<ThrowingIter>()));
+ using NoexceptIter = std::move_iterator<NoexceptBase>;
+ ASSERT_NOEXCEPT(iter_move(std::declval<NoexceptIter>()));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_swap.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_swap.pass.cpp
new file mode 100644
index 000000000000..075930dcb0a0
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.nonmember/iter_swap.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+//
+// template<indirectly_swappable<Iterator> Iterator2>
+// friend constexpr void
+// iter_swap(const move_iterator& x, const move_iterator<Iterator2>& y)
+// noexcept(noexcept(ranges::iter_swap(x.current, y.current))); // Since C++20
+
+#include <iterator>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <bool IsNoexcept>
+struct MaybeNoexceptSwap {
+ using value_type = int;
+ using
diff erence_type = ptr
diff _t;
+
+ constexpr friend void iter_swap(MaybeNoexceptSwap, MaybeNoexceptSwap) noexcept(IsNoexcept) {
+ }
+
+ int& operator*() const { static int x; return x; }
+
+ MaybeNoexceptSwap& operator++();
+ MaybeNoexceptSwap operator++(int);
+};
+using ThrowingBase = MaybeNoexceptSwap<false>;
+using NoexceptBase = MaybeNoexceptSwap<true>;
+static_assert(std::input_iterator<ThrowingBase>);
+ASSERT_NOT_NOEXCEPT(std::ranges::iter_swap(std::declval<ThrowingBase>(), std::declval<ThrowingBase>()));
+ASSERT_NOEXCEPT(std::ranges::iter_swap(std::declval<NoexceptBase>(), std::declval<NoexceptBase>()));
+
+constexpr bool test() {
+ // Can use `iter_swap` with a regular array.
+ {
+ int a[] = {0, 1, 2};
+
+ std::move_iterator b(a);
+ std::move_iterator e(a + 2);
+ assert(a[0] == 0);
+ assert(a[2] == 2);
+
+ static_assert(std::same_as<decltype(iter_swap(b, e)), void>);
+ iter_swap(b, e);
+ assert(a[0] == 2);
+ assert(a[2] == 0);
+ }
+
+ // Check that the `iter_swap` customization point is being used.
+ {
+ int iter_swap_invocations = 0;
+ adl::Iterator base1 = adl::Iterator::TrackSwaps(iter_swap_invocations);
+ adl::Iterator base2 = adl::Iterator::TrackSwaps(iter_swap_invocations);
+ std::move_iterator<adl::Iterator> i1(base1), i2(base2);
+ iter_swap(i1, i2);
+ assert(iter_swap_invocations == 1);
+
+ iter_swap(i2, i1);
+ assert(iter_swap_invocations == 2);
+ }
+
+ // Check the `noexcept` specification.
+ {
+ using ThrowingIter = std::move_iterator<ThrowingBase>;
+ ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<ThrowingIter>(), std::declval<ThrowingIter>()));
+ using NoexceptIter = std::move_iterator<NoexceptBase>;
+ ASSERT_NOEXCEPT(iter_swap(std::declval<NoexceptIter>(), std::declval<NoexceptIter>()));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.-/sentinel.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.-/sentinel.pass.cpp
new file mode 100644
index 000000000000..d84a38c8c6e0
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.-/sentinel.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_iterator
+
+// template<sized_sentinel_for<Iterator> S>
+// friend constexpr iter_
diff erence_t<Iterator>
+// operator-(const move_sentinel<S>& x, const move_iterator& y); // Since C++20
+// template<sized_sentinel_for<Iterator> S>
+// friend constexpr iter_
diff erence_t<Iterator>
+// operator-(const move_iterator& x, const move_sentinel<S>& y); // Since C++20
+
+#include <iterator>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+// The `operator-` calls the underlying iterator and sentinel'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);
+ constexpr friend
diff erence_type operator-(const CustomIt& a, const CustomIt& b) { return a.p_ - b.p_; }
+ int *p_ = nullptr;
+};
+
+template <class It, class Sent = sized_sentinel<It>>
+constexpr void test_one() {
+ int arr[] = {3, 1, 4};
+
+ const std::move_iterator<It> it_a{It(arr)};
+ const std::move_iterator<It> it_b{It(arr + 1)};
+
+ const std::move_sentinel<Sent> sent_a{Sent(It(arr))};
+ const std::move_sentinel<Sent> sent_b{Sent(It(arr + 1))};
+ const std::move_sentinel<Sent> sent_c{Sent(It(arr + 2))};
+
+ ASSERT_SAME_TYPE(decltype(it_a - sent_a), std::iter_
diff erence_t<It>);
+ ASSERT_SAME_TYPE(decltype(sent_a - it_a), std::iter_
diff erence_t<It>);
+
+ // it_a
+ assert(it_a - sent_a == 0);
+ assert(sent_a - it_a == 0);
+
+ assert(it_a - sent_b == -1);
+ assert(sent_b - it_a == 1);
+
+ assert(it_a - sent_c == -2);
+ assert(sent_c - it_a == 2);
+
+ // it_b
+ assert(it_b - sent_a == 1);
+ assert(sent_a - it_b == -1);
+
+ assert(it_b - sent_b == 0);
+ assert(sent_b - it_b == 0);
+
+ assert(it_b - sent_c == -1);
+ assert(sent_c - it_b == 1);
+}
+
+constexpr bool test() {
+ 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*>();
+ test_one<contiguous_iterator<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.iter.ops/move.iter.op.const/default.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
index 04d3d6e1866a..d095182c560d 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.const/default.pass.cpp
@@ -13,33 +13,42 @@
// move_iterator();
//
// constexpr in C++17
+//
+// requires the underlying iterator to be default-constructible (extension).
#include <iterator>
+#include <type_traits>
#include "test_macros.h"
#include "test_iterators.h"
+#if TEST_STD_VER > 17
+struct NoDefaultCtr : forward_iterator<int*> {
+ NoDefaultCtr() = delete;
+};
+
+LIBCPP_STATIC_ASSERT( std::is_default_constructible_v<std::move_iterator<forward_iterator<int*>>>);
+LIBCPP_STATIC_ASSERT(!std::is_default_constructible_v<std::move_iterator<NoDefaultCtr>>);
+#endif
+
template <class It>
-void
-test()
-{
+void test() {
std::move_iterator<It> r;
(void)r;
}
-int main(int, char**)
-{
- // we don't have a test iterator that is both input and default-constructible, so not testing that case
- test<forward_iterator<char*> >();
- test<bidirectional_iterator<char*> >();
- test<random_access_iterator<char*> >();
- test<char*>();
+int main(int, char**) {
+ // we don't have a test iterator that is both input and default-constructible, so not testing that case
+ test<forward_iterator<char*> >();
+ test<bidirectional_iterator<char*> >();
+ test<random_access_iterator<char*> >();
+ test<char*>();
#if TEST_STD_VER > 14
- {
+ {
constexpr std::move_iterator<const char *> it;
(void)it;
- }
+ }
#endif
return 0;
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/base.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/base.pass.cpp
new file mode 100644
index 000000000000..6e348b59be16
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/base.pass.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <iterator>
+//
+// constexpr iterator_type base() const; // Until C++20
+// constexpr const Iterator& base() const & noexcept; // From C++20
+// constexpr Iterator base() &&; // From C++20
+
+#include <iterator>
+
+#include <utility>
+#include "test_iterators.h"
+#include "test_macros.h"
+
+struct MoveOnlyIterator {
+ using It = int*;
+
+ It it_;
+
+ using iterator_category = std::input_iterator_tag;
+ using value_type = int;
+ using
diff erence_type = std::ptr
diff _t;
+ using reference = int&;
+
+ TEST_CONSTEXPR explicit MoveOnlyIterator(It it) : it_(it) {}
+ MoveOnlyIterator(MoveOnlyIterator&&) = default;
+ MoveOnlyIterator& operator=(MoveOnlyIterator&&) = default;
+ MoveOnlyIterator(const MoveOnlyIterator&) = delete;
+ MoveOnlyIterator& operator=(const MoveOnlyIterator&) = delete;
+
+ TEST_CONSTEXPR reference operator*() const { return *it_; }
+
+ TEST_CONSTEXPR_CXX14 MoveOnlyIterator& operator++() { ++it_; return *this; }
+ TEST_CONSTEXPR_CXX14 MoveOnlyIterator operator++(int) { return MoveOnlyIterator(it_++); }
+
+ friend TEST_CONSTEXPR bool operator==(const MoveOnlyIterator& x, const MoveOnlyIterator& y) {return x.it_ == y.it_;}
+ friend TEST_CONSTEXPR bool operator!=(const MoveOnlyIterator& x, const MoveOnlyIterator& y) {return x.it_ != y.it_;}
+
+ friend TEST_CONSTEXPR It base(const MoveOnlyIterator& i) { return i.it_; }
+};
+
+#if TEST_STD_VER > 17
+static_assert( std::input_iterator<MoveOnlyIterator>);
+#endif
+static_assert(!std::is_copy_constructible<MoveOnlyIterator>::value, "");
+
+template <class It>
+TEST_CONSTEXPR_CXX14 void test_one() {
+ // Non-const lvalue.
+ {
+ int a[] = {1, 2, 3};
+
+ auto i = std::move_iterator<It>(It(a));
+#if TEST_STD_VER > 17
+ ASSERT_SAME_TYPE(decltype(i.base()), const It&);
+ ASSERT_NOEXCEPT(i.base());
+#else
+ ASSERT_SAME_TYPE(decltype(i.base()), It);
+#endif
+ assert(i.base() == It(a));
+
+ ++i;
+ assert(i.base() == It(a + 1));
+ }
+
+ // Const lvalue.
+ {
+ int a[] = {1, 2, 3};
+
+ const auto i = std::move_iterator<It>(It(a));
+#if TEST_STD_VER > 17
+ ASSERT_SAME_TYPE(decltype(i.base()), const It&);
+ ASSERT_NOEXCEPT(i.base());
+#else
+ ASSERT_SAME_TYPE(decltype(i.base()), It);
+#endif
+ assert(i.base() == It(a));
+ }
+
+ // Rvalue.
+ {
+ int a[] = {1, 2, 3};
+
+ auto i = std::move_iterator<It>(It(a));
+ ASSERT_SAME_TYPE(decltype(std::move(i).base()), It);
+ assert(std::move(i).base() == It(a));
+ }
+}
+
+TEST_CONSTEXPR_CXX14 bool test() {
+ 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*>>();
+#endif
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+#if TEST_STD_VER > 14
+ static_assert(test());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/tested_elsewhere.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/tested_elsewhere.pass.cpp
deleted file mode 100644
index 1f764da05d6b..000000000000
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.conv/tested_elsewhere.pass.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-int main(int, char**)
-{
-
- return 0;
-}
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp
index a33bb08fa097..e2b831b717b9 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.incr/post.pass.cpp
@@ -10,9 +10,7 @@
// move_iterator
-// move_iterator operator++(int);
-//
-// constexpr in C++17
+// constexpr auto operator++(int); // Return type was move_iterator until C++20
#include <iterator>
#include <cassert>
@@ -31,30 +29,27 @@ void test_single_pass(It i, It x) {
#endif
template <class It>
-void
-test(It i, It x)
-{
+void test(It i, It x) {
std::move_iterator<It> r(i);
std::move_iterator<It> rr = r++;
assert(r.base() == x);
assert(rr.base() == i);
}
-int main(int, char**)
-{
- char s[] = "123";
+int main(int, char**) {
+ char s[] = "123";
#if TEST_STD_VER > 17
- test_single_pass(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s + 1));
+ test_single_pass(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s + 1));
#else
- test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s+1));
+ test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s+1));
#endif
- test(forward_iterator<char*>(s), forward_iterator<char*>(s+1));
- test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s+1));
- test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1));
- test(s, s+1);
+ test(forward_iterator<char*>(s), forward_iterator<char*>(s+1));
+ test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s+1));
+ test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1));
+ test(s, s+1);
#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);
@@ -63,7 +58,32 @@ int main(int, char**)
constexpr MI it3 = std::make_move_iterator(p) ++;
static_assert(it1 == it3, "");
static_assert(it2 != it3, "");
- }
+ }
+#endif
+
+#if TEST_STD_VER > 17
+ // Forward iterators return a copy.
+ {
+ int a[] = {1, 2, 3};
+ using MoveIter = std::move_iterator<forward_iterator<int*>>;
+
+ MoveIter i = MoveIter(forward_iterator<int*>(a));
+ ASSERT_SAME_TYPE(decltype(i++), MoveIter);
+ auto j = i++;
+ assert(base(j.base()) == a);
+ assert(base(i.base()) == a + 1);
+ }
+
+ // Non-forward iterators return void.
+ {
+ int a[] = {1, 2, 3};
+ using MoveIter = std::move_iterator<cpp20_input_iterator<int*>>;
+
+ MoveIter i = MoveIter(cpp20_input_iterator<int*>(a));
+ ASSERT_SAME_TYPE(decltype(i++), void);
+ i++;
+ assert(base(i.base()) == a + 1);
+ }
#endif
return 0;
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/
diff erence_type.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/
diff erence_type.pass.cpp
index ecf3b61058b7..df199873ffae 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/
diff erence_type.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.index/
diff erence_type.pass.cpp
@@ -10,10 +10,7 @@
// move_iterator
-// requires RandomAccessIterator<Iter>
-// unspecified operator[](
diff erence_type n) const;
-//
-// constexpr in C++17
+// constexpr reference operator[](
diff erence_type n) const; // Return type unspecified until C++20
#include <iterator>
#include <cassert>
@@ -65,5 +62,20 @@ int main(int, char**)
}
#endif
+#if TEST_STD_VER > 17
+ // Ensure the `iter_move` customization point is being used.
+ {
+ int a[] = {0, 1, 2};
+
+ int iter_moves = 0;
+ adl::Iterator i = adl::Iterator::TrackMoves(a, iter_moves);
+ std::move_iterator<adl::Iterator> mi(i);
+
+ auto x = mi[0];
+ assert(x == 0);
+ assert(iter_moves == 1);
+ }
+#endif
+
return 0;
}
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp
index e6e826d83525..22f601e6ca30 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iter.ops/move.iter.op.star/op_star.pass.cpp
@@ -18,6 +18,7 @@
#include <cassert>
#include <memory>
+#include "test_iterators.h"
#include "test_macros.h"
class A
@@ -47,28 +48,42 @@ struct do_nothing
};
-int main(int, char**)
-{
- {
- A a;
- test(&a, A());
- }
+int main(int, char**) {
+ {
+ A a;
+ test(&a, A());
+ }
#if TEST_STD_VER >= 11
- {
- int i;
- std::unique_ptr<int, do_nothing> p(&i);
- test(&p, std::unique_ptr<int, do_nothing>(&i));
- }
+ {
+ int i;
+ std::unique_ptr<int, do_nothing> p(&i);
+ test(&p, std::unique_ptr<int, do_nothing>(&i));
+ }
#endif
#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 == p[0], "");
static_assert(*it2 == p[1], "");
- }
+ }
+#endif
+
+#if TEST_STD_VER > 17
+ // Ensure the `iter_move` customization point is being used.
+ {
+ int a[] = {0, 1, 2};
+
+ int iter_moves = 0;
+ adl::Iterator i = adl::Iterator::TrackMoves(a, iter_moves);
+ std::move_iterator<adl::Iterator> mi(i);
+
+ auto x = *mi;
+ assert(x == 0);
+ assert(iter_moves == 1);
+ }
#endif
return 0;
diff --git a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp
index 2d0dadfeec8f..f262b4d29eeb 100644
--- a/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/move.iterators/move.iterator/types.pass.cpp
@@ -15,11 +15,13 @@
// template <InputIterator Iter>
// class move_iterator {
// public:
-// typedef Iter iterator_type;
-// typedef Iter::
diff erence_type
diff erence_type;
-// typedef Iter pointer;
-// typedef Iter::value_type value_type;
-// typedef value_type&& reference;
+// using iterator_type = Iterator;
+// using iterator_concept = input_iterator_tag; // From C++20
+// using iterator_category = see below; // not always present starting from C++20
+// using value_type = iter_value_t<Iterator>; // Until C++20, iterator_traits<Iterator>::value_type
+// using
diff erence_type = iter_
diff erence_t<Iterator>; // Until C++20, iterator_traits<Iterator>::
diff erence_type;
+// using pointer = Iterator;
+// using reference = iter_rvalue_reference_t<Iterator>; // Until C++20, value_type&&
// };
#include <iterator>
@@ -28,6 +30,37 @@
#include "test_macros.h"
#include "test_iterators.h"
+struct FooIter {
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = void*;
+ using
diff erence_type = void*;
+ using pointer = void*;
+ using reference = char&;
+ bool& operator*() const;
+};
+
+#if TEST_STD_VER > 17
+template <>
+struct std::indirectly_readable_traits<FooIter> {
+ using value_type = int;
+};
+template <>
+struct std::incrementable_traits<FooIter> {
+ using
diff erence_type = char;
+};
+#endif
+
+#if TEST_STD_VER > 17
+// Not using `FooIter::value_type`.
+static_assert(std::is_same_v<typename std::move_iterator<FooIter>::value_type, int>);
+// Not using `FooIter::
diff erence_type`.
+static_assert(std::is_same_v<typename std::move_iterator<FooIter>::
diff erence_type, char>);
+static_assert(std::is_same_v<typename std::reverse_iterator<FooIter>::reference, bool&>);
+
+#else
+static_assert(std::is_same<typename std::reverse_iterator<FooIter>::reference, char&>::value, "");
+#endif
+
template <class ValueType, class Reference>
struct DummyIt {
typedef std::forward_iterator_tag iterator_category;
@@ -40,71 +73,79 @@ struct DummyIt {
};
template <class It>
-void
-test()
-{
- typedef std::move_iterator<It> R;
- typedef std::iterator_traits<It> T;
- static_assert((std::is_same<typename R::iterator_type, It>::value), "");
- static_assert((std::is_same<typename R::
diff erence_type, typename T::
diff erence_type>::value), "");
- static_assert((std::is_same<typename R::pointer, It>::value), "");
- static_assert((std::is_same<typename R::value_type, typename T::value_type>::value), "");
- static_assert((std::is_same<typename R::reference, typename R::value_type&&>::value), "");
+void test() {
+ typedef std::move_iterator<It> R;
+ typedef std::iterator_traits<It> T;
+ static_assert((std::is_same<typename R::iterator_type, It>::value), "");
+ static_assert((std::is_same<typename R::
diff erence_type, typename T::
diff erence_type>::value), "");
+ static_assert((std::is_same<typename R::pointer, It>::value), "");
+ static_assert((std::is_same<typename R::value_type, typename T::value_type>::value), "");
+
#if TEST_STD_VER > 17
- if constexpr (std::is_same_v<typename T::iterator_category, std::contiguous_iterator_tag>) {
- static_assert((std::is_same<typename R::iterator_category, std::random_access_iterator_tag>::value), "");
- } else {
- static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
- }
+ static_assert((std::is_same_v<typename R::reference, std::iter_rvalue_reference_t<It>>), "");
#else
+ static_assert((std::is_same<typename R::reference, typename R::value_type&&>::value), "");
+#endif
+
+#if TEST_STD_VER > 17
+ if constexpr (std::is_same_v<typename T::iterator_category, std::contiguous_iterator_tag>) {
+ static_assert((std::is_same<typename R::iterator_category, std::random_access_iterator_tag>::value), "");
+ } else {
static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
+ }
+#else
+ static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
+#endif
+
+#if TEST_STD_VER > 17
+ static_assert(std::is_same_v<typename R::iterator_concept, std::input_iterator_tag>);
#endif
}
-int main(int, char**)
-{
- test<cpp17_input_iterator<char*> >();
- test<forward_iterator<char*> >();
- test<bidirectional_iterator<char*> >();
- test<random_access_iterator<char*> >();
- test<char*>();
+int main(int, char**) {
+ test<cpp17_input_iterator<char*> >();
+ test<forward_iterator<char*> >();
+ test<bidirectional_iterator<char*> >();
+ test<random_access_iterator<char*> >();
+ test<char*>();
+
#if TEST_STD_VER >= 11
- {
- typedef DummyIt<int, int> T;
- typedef std::move_iterator<T> It;
- static_assert(std::is_same<It::reference, int>::value, "");
- }
- {
- typedef DummyIt<int, std::reference_wrapper<int> > T;
- typedef std::move_iterator<T> It;
- static_assert(std::is_same<It::reference, std::reference_wrapper<int> >::value, "");
- }
- {
- // Check that move_iterator uses whatever reference type it's given
- // when it's not a reference.
- typedef DummyIt<int, long > T;
- typedef std::move_iterator<T> It;
- static_assert(std::is_same<It::reference, long>::value, "");
- }
- {
- typedef DummyIt<int, int&> T;
- typedef std::move_iterator<T> It;
- static_assert(std::is_same<It::reference, int&&>::value, "");
- }
- {
- typedef DummyIt<int, int&&> T;
- typedef std::move_iterator<T> It;
- static_assert(std::is_same<It::reference, int&&>::value, "");
- }
+ {
+ typedef DummyIt<int, int> T;
+ typedef std::move_iterator<T> It;
+ static_assert(std::is_same<It::reference, int>::value, "");
+ }
+ {
+ typedef DummyIt<int, std::reference_wrapper<int> > T;
+ typedef std::move_iterator<T> It;
+ static_assert(std::is_same<It::reference, std::reference_wrapper<int> >::value, "");
+ }
+ {
+ // Check that move_iterator uses whatever reference type it's given
+ // when it's not a reference.
+ typedef DummyIt<int, long > T;
+ typedef std::move_iterator<T> It;
+ static_assert(std::is_same<It::reference, long>::value, "");
+ }
+ {
+ typedef DummyIt<int, int&> T;
+ typedef std::move_iterator<T> It;
+ static_assert(std::is_same<It::reference, int&&>::value, "");
+ }
+ {
+ typedef DummyIt<int, int&&> T;
+ typedef std::move_iterator<T> It;
+ static_assert(std::is_same<It::reference, int&&>::value, "");
+ }
#endif
#if TEST_STD_VER > 17
- test<contiguous_iterator<char*>>();
- static_assert(std::is_same_v<typename std::move_iterator<forward_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
- static_assert(std::is_same_v<typename std::move_iterator<bidirectional_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
- static_assert(std::is_same_v<typename std::move_iterator<random_access_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
- static_assert(std::is_same_v<typename std::move_iterator<contiguous_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
- static_assert(std::is_same_v<typename std::move_iterator<char*>::iterator_concept, std::input_iterator_tag>);
+ test<contiguous_iterator<char*>>();
+ static_assert(std::is_same_v<typename std::move_iterator<forward_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
+ static_assert(std::is_same_v<typename std::move_iterator<bidirectional_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
+ static_assert(std::is_same_v<typename std::move_iterator<random_access_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
+ static_assert(std::is_same_v<typename std::move_iterator<contiguous_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
+ static_assert(std::is_same_v<typename std::move_iterator<char*>::iterator_concept, std::input_iterator_tag>);
#endif
return 0;
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
index 03ef6e2b085f..57f9ad70b7ad 100644
--- 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
@@ -21,7 +21,7 @@
#include <concepts>
struct NonAssignable {
- NonAssignable& operator=(int i);
+ NonAssignable& operator=(int i);
};
static_assert(std::semiregular<NonAssignable>);
static_assert(std::is_assignable_v<NonAssignable, int>);
@@ -29,17 +29,22 @@ static_assert(!std::assignable_from<NonAssignable, int>);
constexpr bool test()
{
+ // Assigning from an lvalue.
{
std::move_sentinel<int> m(42);
std::move_sentinel<long> m2;
m2 = m;
assert(m2.base() == 42L);
}
+
+ // Assigning from an rvalue.
{
std::move_sentinel<long> m2;
m2 = std::move_sentinel<int>(43);
assert(m2.base() == 43L);
}
+
+ // SFINAE checks.
{
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*>>);
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
index bfb202ac36b6..b3b0293c3d48 100644
--- 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
@@ -22,6 +22,7 @@
constexpr bool test()
{
+ // The sentinel type is a value.
{
auto m = std::move_sentinel<int>(42);
const auto& cm = m;
@@ -34,6 +35,8 @@ constexpr bool test()
ASSERT_SAME_TYPE(decltype(std::move(m).base()), int);
ASSERT_SAME_TYPE(decltype(std::move(cm).base()), int);
}
+
+ // The sentinel type is a pointer.
{
int a[] = {1, 2, 3};
auto m = std::move_sentinel<const int*>(a);
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
index 88e0f77ea39f..80dc4de73116 100644
--- 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
@@ -19,6 +19,7 @@
void test()
{
+ // Pointer.
{
using It = int*;
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -28,6 +29,8 @@ void test()
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>>);
}
+
+ // `Cpp17InputIterator`.
{
using It = cpp17_input_iterator<int*>;
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
@@ -35,6 +38,8 @@ void test()
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>>);
}
+
+ // `std::input_iterator`.
{
using It = cpp20_input_iterator<int*>;
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
@@ -42,6 +47,8 @@ void test()
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>>);
}
+
+ // `std::forward_iterator`.
{
using It = forward_iterator<int*>;
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -51,6 +58,8 @@ void test()
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>>);
}
+
+ // `std::bidirectional_iterator`.
{
using It = bidirectional_iterator<int*>;
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -60,6 +69,8 @@ void test()
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>>);
}
+
+ // `std::random_access_iterator`.
{
using It = random_access_iterator<int*>;
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -69,6 +80,8 @@ void test()
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>>);
}
+
+ // `std::contiguous_iterator`.
{
using It = contiguous_iterator<int*>;
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
@@ -78,6 +91,8 @@ void test()
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>>);
}
+
+ // `std::contiguous_iterator` with the spaceship operator.
{
using It = three_way_contiguous_iterator<int*>;
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
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
index b77d4836cd4e..5f5be0c7f159 100644
--- 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
@@ -31,15 +31,20 @@ static_assert(!std::convertible_to<long, NonConvertible>);
constexpr bool test()
{
+ // Constructing from an lvalue.
{
std::move_sentinel<int> m(42);
std::move_sentinel<long> m2 = m;
assert(m2.base() == 42L);
}
+
+ // Constructing from an rvalue.
{
std::move_sentinel<long> m2 = std::move_sentinel<int>(43);
assert(m2.base() == 43L);
}
+
+ // SFINAE checks.
{
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*>>);
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
index 655825de7d6f..c446373eff2b 100644
--- 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
@@ -19,14 +19,20 @@
constexpr bool test()
{
+
+ // The underlying sentinel is an integer.
{
std::move_sentinel<int> m;
assert(m.base() == 0);
}
+
+ // The underlying sentinel is a pointer.
{
std::move_sentinel<int*> m;
assert(m.base() == nullptr);
}
+
+ // The underlying sentinel is a user-defined type with an explicit default constructor.
{
struct S {
explicit S() = default;
@@ -35,6 +41,7 @@ constexpr bool test()
std::move_sentinel<S> m;
assert(m.base().i == 3);
}
+
return true;
}
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
index 226a24a2bee8..1fc2843f465a 100644
--- 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
@@ -19,17 +19,22 @@
constexpr bool test()
{
+ // The underlying sentinel is an integer.
{
static_assert(!std::is_convertible_v<int, std::move_sentinel<int>>);
std::move_sentinel<int> m(42);
assert(m.base() == 42);
}
+
+ // The underlying sentinel is a pointer.
{
static_assert(!std::is_convertible_v<int*, std::move_sentinel<int*>>);
int i = 42;
std::move_sentinel<int*> m(&i);
assert(m.base() == &i);
}
+
+ // The underlying sentinel is a user-defined type with an explicit default constructor.
{
struct S {
explicit S() = default;
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
index fef17c5d188b..9519eb2a9fad 100644
--- 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
@@ -38,30 +38,25 @@ static_assert( HasNotEquals<std::move_iterator<const int*>, std::move_sentinel<i
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 void 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)>);
}
-constexpr bool test()
-{
+constexpr bool test() {
test_one<cpp17_input_iterator<char*>>();
test_one<cpp20_input_iterator<char*>>();
test_one<forward_iterator<char*>>();
@@ -75,8 +70,7 @@ constexpr bool test()
return true;
}
-int main(int, char**)
-{
+int main(int, char**) {
test();
static_assert(test());
diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
index acf91784ef9b..712425a0c44f 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_move.pass.cpp
@@ -20,48 +20,9 @@
#include <cassert>
#include <type_traits>
#include <utility>
+#include "test_iterators.h"
#include "test_macros.h"
-namespace adl {
-
-struct Iterator {
- using value_type = int;
- using
diff erence_type = ptr
diff _t;
-
- value_type* ptr_ = nullptr;
- int* iter_move_invocations_ = nullptr;
-
- constexpr Iterator() = default;
- constexpr explicit Iterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {}
-
- constexpr value_type& operator*() const { return *ptr_; }
-
- Iterator& operator++() { ++ptr_; return *this; }
- Iterator operator++(int) {
- Iterator prev = *this;
- ++ptr_;
- return prev;
- }
-
- constexpr Iterator& operator--() { --ptr_; return *this; }
- constexpr Iterator operator--(int) {
- Iterator prev = *this;
- --ptr_;
- return prev;
- }
-
- constexpr friend value_type&& iter_move(Iterator iter) {
- if (iter.iter_move_invocations_) {
- ++(*iter.iter_move_invocations_);
- }
- return std::move(*iter);
- }
-
- friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
-};
-
-} // namespace adl
-
constexpr bool test() {
// Can use `iter_move` with a regular array.
{
@@ -76,13 +37,13 @@ constexpr bool test() {
assert(iter_move(ri) == 1);
}
- // Ensure the `iter_move` customization point is being used.
+ // Check that the `iter_move` customization point is being used.
{
constexpr int N = 3;
int a[N] = {0, 1, 2};
int iter_move_invocations = 0;
- adl::Iterator i(a + N, iter_move_invocations);
+ adl::Iterator i = adl::Iterator::TrackMoves(a + N, iter_move_invocations);
std::reverse_iterator<adl::Iterator> ri(i);
int x = iter_move(ri);
assert(x == 2);
diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
index 3ae27368007a..aaad0eb51e2f 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/reverse.iter.nonmember/iter_swap.pass.cpp
@@ -22,47 +22,9 @@
#include <cassert>
#include <type_traits>
#include <utility>
+#include "test_iterators.h"
#include "test_macros.h"
-namespace adl {
-
-struct Iterator {
- using value_type = int;
- using
diff erence_type = ptr
diff _t;
-
- value_type* ptr_ = nullptr;
- int* iter_swap_invocations_ = nullptr;
-
- constexpr Iterator() = default;
- constexpr explicit Iterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {}
-
- value_type& operator*() const { return *ptr_; }
-
- Iterator& operator++() { ++ptr_; return *this; }
- Iterator operator++(int) {
- Iterator prev = *this;
- ++ptr_;
- return prev;
- }
-
- Iterator& operator--() { --ptr_; return *this; }
- Iterator operator--(int) {
- Iterator prev = *this;
- --ptr_;
- return prev;
- }
-
- constexpr friend void iter_swap(Iterator a, Iterator) {
- if (a.iter_swap_invocations_) {
- ++(*a.iter_swap_invocations_);
- }
- }
-
- friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
-};
-
-} // namespace adl
-
constexpr bool test() {
// Can use `iter_swap` with a regular array.
{
@@ -80,15 +42,17 @@ constexpr bool test() {
assert(a[2] == 0);
}
- // Ensure the `iter_swap` customization point is being used.
+ // Check that the `iter_swap` customization point is being used.
{
int iter_swap_invocations = 0;
- adl::Iterator i1(iter_swap_invocations), i2(iter_swap_invocations);
- std::reverse_iterator<adl::Iterator> ri1(i1), ri2(i2);
- iter_swap(i1, i2);
+ int a[] = {0, 1, 2};
+ adl::Iterator base1 = adl::Iterator::TrackSwaps(a + 1, iter_swap_invocations);
+ adl::Iterator base2 = adl::Iterator::TrackSwaps(a + 2, iter_swap_invocations);
+ std::reverse_iterator<adl::Iterator> ri1(base1), ri2(base2);
+ iter_swap(ri1, ri2);
assert(iter_swap_invocations == 1);
- iter_swap(i2, i1);
+ iter_swap(ri2, ri1);
assert(iter_swap_invocations == 2);
}
diff --git a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
index 419df883f102..f8c9ce72daa9 100644
--- a/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
+++ b/libcxx/test/std/iterators/predef.iterators/reverse.iterators/types.compile.pass.cpp
@@ -82,7 +82,9 @@ struct std::incrementable_traits<FooIter> {
using
diff erence_type = char;
};
+// Not using `FooIter::value_type`.
static_assert(std::is_same_v<typename std::reverse_iterator<FooIter>::value_type, int>);
+// Not using `FooIter::
diff erence_type`.
static_assert(std::is_same_v<typename std::reverse_iterator<FooIter>::
diff erence_type, char>);
#endif
diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp
index 7b648d110a83..39f81a4a5e39 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_move.pass.cpp
@@ -22,40 +22,40 @@
namespace adl {
template <bool IsNoexcept = false>
-struct Iterator {
+struct MaybeNoexceptIterator {
using value_type = int;
using
diff erence_type = ptr
diff _t;
value_type* ptr_ = nullptr;
int* iter_move_invocations_ = nullptr;
- constexpr Iterator() = default;
- constexpr explicit Iterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {}
+ constexpr MaybeNoexceptIterator() = default;
+ constexpr explicit MaybeNoexceptIterator(int* p, int& iter_moves) : ptr_(p), iter_move_invocations_(&iter_moves) {}
constexpr value_type& operator*() const { return *ptr_; }
- Iterator& operator++() { ++ptr_; return *this; }
- Iterator operator++(int) {
- Iterator prev = *this;
+ MaybeNoexceptIterator& operator++() { ++ptr_; return *this; }
+ MaybeNoexceptIterator operator++(int) {
+ MaybeNoexceptIterator prev = *this;
++ptr_;
return prev;
}
- constexpr Iterator& operator--() { --ptr_; return *this; }
- constexpr Iterator operator--(int) {
- Iterator prev = *this;
+ constexpr MaybeNoexceptIterator& operator--() { --ptr_; return *this; }
+ constexpr MaybeNoexceptIterator operator--(int) {
+ MaybeNoexceptIterator prev = *this;
--ptr_;
return prev;
}
- constexpr friend value_type&& iter_move(Iterator iter) noexcept(IsNoexcept) {
+ constexpr friend value_type&& iter_move(MaybeNoexceptIterator iter) noexcept(IsNoexcept) {
if (iter.iter_move_invocations_) {
++(*iter.iter_move_invocations_);
}
return std::move(*iter);
}
- friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
+ friend bool operator==(const MaybeNoexceptIterator& lhs, const MaybeNoexceptIterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
};
template <bool IsNoexcept = false>
@@ -68,8 +68,12 @@ struct View : std::ranges::view_base {
constexpr View(int& iter_move_invocations) : iter_moves(&iter_move_invocations) {
}
- constexpr adl::Iterator<IsNoexcept> begin() { return adl::Iterator<IsNoexcept>(a, *iter_moves); }
- constexpr adl::Iterator<IsNoexcept> end() { return adl::Iterator<IsNoexcept>(a + N, *iter_moves); }
+ constexpr adl::MaybeNoexceptIterator<IsNoexcept> begin() {
+ return adl::MaybeNoexceptIterator<IsNoexcept>(a, *iter_moves);
+ }
+ constexpr adl::MaybeNoexceptIterator<IsNoexcept> end() {
+ return adl::MaybeNoexceptIterator<IsNoexcept>(a + N, *iter_moves);
+ }
};
} // namespace adl
@@ -134,7 +138,7 @@ constexpr bool test() {
using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>;
using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type;
using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>;
- ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::Iterator<false>>()));
+ ASSERT_NOT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::MaybeNoexceptIterator<false>>()));
ASSERT_NOT_NOEXCEPT(iter_move(std::declval<ThrowingIter>()));
}
@@ -142,7 +146,7 @@ constexpr bool test() {
using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>;
using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type;
using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>;
- ASSERT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::Iterator<true>>()));
+ ASSERT_NOEXCEPT(std::ranges::iter_move(std::declval<adl::MaybeNoexceptIterator<true>>()));
ASSERT_NOEXCEPT(iter_move(std::declval<NoexceptIter>()));
}
}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp
index 52bf8d20fe82..4bcbcafaeab9 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/range.lazy.split.inner/iter_swap.pass.cpp
@@ -23,39 +23,41 @@
namespace adl {
template <bool IsNoexcept = false>
-struct Iterator {
+struct MaybeNoexceptIterator {
using value_type = int;
using
diff erence_type = ptr
diff _t;
value_type* ptr_ = nullptr;
int* iter_swap_invocations_ = nullptr;
- constexpr Iterator() = default;
- constexpr explicit Iterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {}
+ constexpr MaybeNoexceptIterator() = default;
+ constexpr explicit MaybeNoexceptIterator(int& iter_swaps) : iter_swap_invocations_(&iter_swaps) {}
value_type& operator*() const { return *ptr_; }
- Iterator& operator++() { ++ptr_; return *this; }
- Iterator operator++(int) {
- Iterator prev = *this;
+ MaybeNoexceptIterator& operator++() { ++ptr_; return *this; }
+ MaybeNoexceptIterator operator++(int) {
+ MaybeNoexceptIterator prev = *this;
++ptr_;
return prev;
}
- Iterator& operator--() { --ptr_; return *this; }
- Iterator operator--(int) {
- Iterator prev = *this;
+ MaybeNoexceptIterator& operator--() { --ptr_; return *this; }
+ MaybeNoexceptIterator operator--(int) {
+ MaybeNoexceptIterator prev = *this;
--ptr_;
return prev;
}
- constexpr friend void iter_swap(Iterator a, Iterator) noexcept(IsNoexcept) {
+ constexpr friend void iter_swap(MaybeNoexceptIterator a, MaybeNoexceptIterator) noexcept(IsNoexcept) {
if (a.iter_swap_invocations_) {
++(*a.iter_swap_invocations_);
}
}
- friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
+ friend bool operator==(const MaybeNoexceptIterator& lhs, const MaybeNoexceptIterator& rhs) {
+ return lhs.ptr_ == rhs.ptr_;
+ }
};
template <bool IsNoexcept = false>
@@ -66,8 +68,12 @@ struct View : std::ranges::view_base {
constexpr View(int& iter_swap_invocations) : iter_swaps(&iter_swap_invocations) {
}
- constexpr adl::Iterator<IsNoexcept> begin() { return adl::Iterator<IsNoexcept>(*iter_swaps); }
- constexpr adl::Iterator<IsNoexcept> end() { return adl::Iterator<IsNoexcept>(*iter_swaps); }
+ constexpr adl::MaybeNoexceptIterator<IsNoexcept> begin() {
+ return adl::MaybeNoexceptIterator<IsNoexcept>(*iter_swaps);
+ }
+ constexpr adl::MaybeNoexceptIterator<IsNoexcept> end() {
+ return adl::MaybeNoexceptIterator<IsNoexcept>(*iter_swaps);
+ }
};
} // namespace adl
@@ -189,8 +195,9 @@ constexpr bool test() {
using ThrowingSplitView = std::ranges::lazy_split_view<adl::View<false>, adl::View<false>>;
using ThrowingValueType = std::ranges::iterator_t<ThrowingSplitView>::value_type;
using ThrowingIter = std::ranges::iterator_t<ThrowingValueType>;
- ASSERT_NOT_NOEXCEPT(
- std::ranges::iter_swap(std::declval<adl::Iterator<false>>(), std::declval<adl::Iterator<false>>()));
+ ASSERT_NOT_NOEXCEPT(std::ranges::iter_swap(
+ std::declval<adl::MaybeNoexceptIterator<false>>(),
+ std::declval<adl::MaybeNoexceptIterator<false>>()));
ASSERT_NOT_NOEXCEPT(iter_swap(std::declval<ThrowingIter>(), std::declval<ThrowingIter>()));
}
@@ -198,8 +205,9 @@ constexpr bool test() {
using NoexceptSplitView = std::ranges::lazy_split_view<adl::View<true>, adl::View<true>>;
using NoexceptValueType = std::ranges::iterator_t<NoexceptSplitView>::value_type;
using NoexceptIter = std::ranges::iterator_t<NoexceptValueType>;
- ASSERT_NOEXCEPT(
- std::ranges::iter_swap(std::declval<adl::Iterator<true>>(), std::declval<adl::Iterator<true>>()));
+ ASSERT_NOEXCEPT(std::ranges::iter_swap(
+ std::declval<adl::MaybeNoexceptIterator<true>>(),
+ std::declval<adl::MaybeNoexceptIterator<true>>()));
ASSERT_NOEXCEPT(iter_swap(std::declval<NoexceptIter>(), std::declval<NoexceptIter>()));
}
}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp
index 44317ad9e1bc..c317efca64b2 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move.pass.cpp
@@ -41,40 +41,6 @@ struct NotConvertibleFromInt {};
static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_move), int*, int*, NotConvertibleFromInt*,
NotConvertibleFromInt*>);
-namespace adl {
-
-static int iter_move_invocations = 0;
-
-template <class T>
-struct Iterator {
- using value_type = T;
- using
diff erence_type = int;
- using iterator_concept = std::input_iterator_tag;
-
- T* ptr = nullptr;
-
- Iterator() = default;
- explicit Iterator(int* p) : ptr(p) {}
-
- T& operator*() const { return *ptr; }
-
- Iterator& operator++() { ++ptr; return *this; }
- Iterator operator++(int) {
- Iterator prev = *this;
- ++ptr;
- return prev;
- }
-
- friend T&& iter_move(Iterator iter) {
- ++iter_move_invocations;
- return std::move(*iter);
- }
-
- friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr == rhs.ptr; }
-};
-
-} // namespace adl
-
int main(int, char**) {
// An empty range -- no default constructors should be invoked.
{
@@ -411,17 +377,18 @@ int main(int, char**) {
constexpr int N = 3;
int in[N] = {1, 2, 3};
Buffer<int, N> out;
- adl::Iterator<int> begin(in);
- adl::Iterator<int> end(in + N);
+ int iter_moves = 0;
+ adl::Iterator begin = adl::Iterator::TrackMoves(in, iter_moves);
+ adl::Iterator end = adl::Iterator::TrackMoves(in + N, iter_moves);
std::ranges::uninitialized_move(begin, end, out.begin(), out.end());
- assert(adl::iter_move_invocations == 3);
- adl::iter_move_invocations = 0;
+ assert(iter_moves == 3);
+ iter_moves = 0;
std::ranges::subrange range(begin, end);
std::ranges::uninitialized_move(range, out);
- assert(adl::iter_move_invocations == 3);
- adl::iter_move_invocations = 0;
+ assert(iter_moves == 3);
+ iter_moves = 0;
}
return 0;
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp
index edd0e7811bc8..70a68880e0f4 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.move/ranges_uninitialized_move_n.pass.cpp
@@ -24,8 +24,8 @@
#include "../buffer.h"
#include "../counted.h"
-#include "test_macros.h"
#include "test_iterators.h"
+#include "test_macros.h"
// TODO(varconst): consolidate the ADL checks into a single file.
// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
@@ -38,40 +38,6 @@ struct NotConvertibleFromInt {};
static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_move_n), int*, size_t, NotConvertibleFromInt*,
NotConvertibleFromInt*>);
-namespace adl {
-
-static int iter_move_invocations = 0;
-
-template <class T>
-struct Iterator {
- using value_type = T;
- using
diff erence_type = int;
- using iterator_concept = std::input_iterator_tag;
-
- T* ptr = nullptr;
-
- Iterator() = default;
- explicit Iterator(int* p) : ptr(p) {}
-
- T& operator*() const { return *ptr; }
-
- Iterator& operator++() { ++ptr; return *this; }
- Iterator operator++(int) {
- Iterator prev = *this;
- ++ptr;
- return prev;
- }
-
- friend T&& iter_move(Iterator iter) {
- ++iter_move_invocations;
- return std::move(*iter);
- }
-
- friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr == rhs.ptr; }
-};
-
-} // namespace adl
-
int main(int, char**) {
// An empty range -- no default constructors should be invoked.
{
@@ -187,17 +153,18 @@ int main(int, char**) {
constexpr int N = 3;
int in[N] = {1, 2, 3};
Buffer<int, N> out;
- adl::Iterator<int> begin(in);
- adl::Iterator<int> end(in + N);
+ int iter_moves = 0;
+ adl::Iterator begin = adl::Iterator::TrackMoves(in, iter_moves);
+ adl::Iterator end = adl::Iterator::TrackMoves(in + N, iter_moves);
std::ranges::uninitialized_move(begin, end, out.begin(), out.end());
- assert(adl::iter_move_invocations == 3);
- adl::iter_move_invocations = 0;
+ assert(iter_moves == 3);
+ iter_moves = 0;
std::ranges::subrange range(begin, end);
std::ranges::uninitialized_move(range, out);
- assert(adl::iter_move_invocations == 3);
- adl::iter_move_invocations = 0;
+ assert(iter_moves == 3);
+ iter_moves = 0;
}
return 0;
diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index 9377b5fc5609..6d3a8e2699ed 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -721,6 +721,77 @@ class sized_sentinel {
private:
decltype(base(std::declval<It>())) base_;
};
+
+namespace adl {
+
+class Iterator {
+ public:
+ using value_type = int;
+ using
diff erence_type = ptr
diff _t;
+
+ private:
+ value_type* ptr_ = nullptr;
+ int* iter_moves_ = nullptr;
+ int* iter_swaps_ = nullptr;
+
+ constexpr Iterator(int* p, int* iter_moves, int* iter_swaps)
+ : ptr_(p)
+ , iter_moves_(iter_moves)
+ , iter_swaps_(iter_swaps) {}
+
+ public:
+ constexpr Iterator() = default;
+ static constexpr Iterator TrackMoves(int* p, int& iter_moves) {
+ return Iterator(p, &iter_moves, /*iter_swaps=*/nullptr);
+ }
+ static constexpr Iterator TrackSwaps(int& iter_swaps) {
+ return Iterator(/*p=*/nullptr, /*iter_moves=*/nullptr, &iter_swaps);
+ }
+ static constexpr Iterator TrackSwaps(int* p, int& iter_swaps) {
+ return Iterator(p, /*iter_moves=*/nullptr, &iter_swaps);
+ }
+
+ constexpr int iter_moves() const { assert(iter_moves_); return *iter_moves_; }
+ constexpr int iter_swaps() const { assert(iter_swaps_); return *iter_swaps_; }
+
+ constexpr value_type& operator*() const { return *ptr_; }
+
+ constexpr Iterator operator+(
diff erence_type n) const {
+ return Iterator(ptr_ + n, iter_moves_, iter_swaps_);
+ }
+
+ constexpr Iterator& operator++() { ++ptr_; return *this; }
+ constexpr Iterator operator++(int) {
+ Iterator prev = *this;
+ ++ptr_;
+ return prev;
+ }
+
+ constexpr Iterator& operator--() { --ptr_; return *this; }
+ constexpr Iterator operator--(int) {
+ Iterator prev = *this;
+ --ptr_;
+ return prev;
+ }
+
+ constexpr friend void iter_swap(Iterator a, Iterator) {
+ if (a.iter_swaps_) {
+ ++(*a.iter_swaps_);
+ }
+ }
+
+ constexpr friend value_type&& iter_move(Iterator iter) {
+ if (iter.iter_moves_) {
+ ++(*iter.iter_moves_);
+ }
+ return std::move(*iter);
+ }
+
+ constexpr friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
+};
+
+} // namespace adl
+
#endif // TEST_STD_VER > 17
#endif // SUPPORT_TEST_ITERATORS_H
More information about the libcxx-commits
mailing list