[libcxx-commits] [libcxx] 8e93aa3 - [libc++] Refactor the tests for std::prev, next and advance
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jun 14 05:13:32 PDT 2021
Author: Louis Dionne
Date: 2021-06-14T08:13:14-04:00
New Revision: 8e93aa304b3fbe57bb7d22f63681f1b9758e63a9
URL: https://github.com/llvm/llvm-project/commit/8e93aa304b3fbe57bb7d22f63681f1b9758e63a9
DIFF: https://github.com/llvm/llvm-project/commit/8e93aa304b3fbe57bb7d22f63681f1b9758e63a9.diff
LOG: [libc++] Refactor the tests for std::prev, next and advance
This started as an attempt to fix a GCC 11 warning of misplaced parentheses.
I then noticed that trying to fix the parentheses warning actually triggered
errors in the tests, showing that we were incorrectly assuming that the
implementation of ranges::advance was using operator+= or operator-=.
This commit fixes that issue and makes the tests easier to follow by
localizing the assertions it makes.
Differential Revision: https://reviews.llvm.org/D103272
Added:
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/constraints.compile.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/constraints.compile.pass.cpp
Modified:
libcxx/include/__iterator/advance.h
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count_sentinel.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count_sentinel.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/special_function.compile.pass.cpp
libcxx/test/support/test_iterators.h
Removed:
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/advance.pass.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/check_round_trip.h
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/constraints.verify.cpp
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/check_round_trip.h
libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/constraints.verify.cpp
################################################################################
diff --git a/libcxx/include/__iterator/advance.h b/libcxx/include/__iterator/advance.h
index f482d18d602ea..5ff6d39f5bc4c 100644
--- a/libcxx/include/__iterator/advance.h
+++ b/libcxx/include/__iterator/advance.h
@@ -70,11 +70,9 @@ namespace ranges {
// [range.iter.op.advance]
struct __advance_fn final : __function_like {
private:
- template <signed_integral _Tp>
- static constexpr make_unsigned_t<_Tp> __abs(_Tp const __n) noexcept {
- auto const __unsigned_n = __to_unsigned_like(__n);
- auto const __complement = ~__unsigned_n + 1;
- return __n < 0 ? __complement : __unsigned_n;
+ template <class _Tp>
+ static constexpr _Tp __abs(_Tp __n) noexcept {
+ return __n < 0 ? -__n : __n;
}
template <class _Ip>
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/advance.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/advance.pass.cpp
deleted file mode 100644
index e42cfd2e6ba57..0000000000000
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/advance.pass.cpp
+++ /dev/null
@@ -1,272 +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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: libcpp-no-concepts
-// UNSUPPORTED: gcc-10
-
-// ranges::advance
-
-#include <iterator>
-
-#include <array>
-#include <cassert>
-
-#include "test_standard_function.h"
-#include "test_iterators.h"
-
-static_assert(is_function_like<decltype(std::ranges::advance)>());
-
-using range_t = std::array<int, 10>;
-
-[[nodiscard]] constexpr bool operator==(output_iterator<int*> const x, output_iterator<int*> const y) {
- return x.base() == y.base();
-}
-
-template <std::input_or_output_iterator I>
-constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptr
diff _t const n) {
- auto const distance = n < 0 ? -n : n;
- assert(i.stride_count() == distance);
- assert(i.stride_displacement() == n);
-}
-
-template <std::random_access_iterator I>
-constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptr
diff _t const n) {
- assert(i.stride_count() == 0 || i.stride_count() == 1);
- assert(i.stride_displacement() == n < 0 ? -1 : 1);
-}
-
-namespace iterator_count {
-template <std::input_or_output_iterator I>
-constexpr void check_move_forward(std::ptr
diff _t const n) {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto first = stride_counting_iterator(I(range.begin()));
- std::ranges::advance(first, n);
- assert(std::move(first).base().base() == range.begin() + n);
- check_round_trip(first, n);
-}
-
-template <std::bidirectional_iterator I>
-constexpr void check_move_backward(std::ptr
diff _t const n) {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto first = stride_counting_iterator(I(range.begin() + n));
- std::ranges::advance(first, -n);
- assert(std::move(first).base().base() == range.begin());
- check_round_trip(first, -n);
-}
-
-[[nodiscard]] constexpr bool test() {
- check_move_forward<cpp17_input_iterator<range_t::const_iterator> >(1);
- check_move_forward<cpp20_input_iterator<range_t::const_iterator> >(2);
- check_move_forward<forward_iterator<range_t::const_iterator> >(3);
- check_move_forward<bidirectional_iterator<range_t::const_iterator> >(4);
- check_move_forward<random_access_iterator<range_t::const_iterator> >(5);
- check_move_forward<contiguous_iterator<range_t::const_iterator> >(6);
- check_move_forward<output_iterator<range_t::iterator> >(7);
-
- check_move_backward<bidirectional_iterator<range_t::const_iterator> >(4);
- check_move_backward<random_access_iterator<range_t::const_iterator> >(5);
- check_move_backward<contiguous_iterator<range_t::const_iterator> >(6);
-
- // Zero should be checked for each case and each overload
- check_move_forward<cpp17_input_iterator<range_t::const_iterator> >(0);
- check_move_forward<cpp20_input_iterator<range_t::const_iterator> >(0);
- check_move_forward<forward_iterator<range_t::const_iterator> >(0);
- check_move_forward<bidirectional_iterator<range_t::const_iterator> >(0);
- check_move_forward<random_access_iterator<range_t::const_iterator> >(0);
- check_move_forward<output_iterator<range_t::iterator> >(0);
- check_move_backward<bidirectional_iterator<range_t::const_iterator> >(0);
- check_move_backward<random_access_iterator<range_t::const_iterator> >(0);
-
- return true;
-}
-} // namespace iterator_count
-
-class distance_apriori_sentinel {
-public:
- distance_apriori_sentinel() = default;
- constexpr explicit distance_apriori_sentinel(std::ptr
diff _t const count) : count_(count) {}
-
- [[nodiscard]] constexpr bool operator==(std::input_or_output_iterator auto const&) const {
- assert(false && "
diff erence op should take precedence");
- return false;
- }
-
- [[nodiscard]] constexpr friend std::ptr
diff _t operator-(std::input_or_output_iterator auto const&,
- distance_apriori_sentinel const y) {
- return -y.count_;
- }
-
- [[nodiscard]] constexpr friend std::ptr
diff _t operator-(distance_apriori_sentinel const x,
- std::input_or_output_iterator auto const&) {
- return x.count_;
- }
-
-private:
- std::ptr
diff _t count_ = 0;
-};
-
-namespace iterator_sentinel {
-template <std::input_or_output_iterator I, std::sentinel_for<I> S = I>
-constexpr void check_assignable_case(std::ptr
diff _t const n) {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto first = stride_counting_iterator(I(range.begin()));
- std::ranges::advance(first, stride_counting_iterator(S(I(range.begin() + n))));
- assert(std::move(first).base().base() == range.begin() + n);
- assert(first.stride_count() == 0); // always zero, so don't use `check_round_trip`
-}
-
-template <std::input_or_output_iterator I>
-constexpr void check_sized_sentinel_case(std::ptr
diff _t const n) {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto first = stride_counting_iterator(I(range.begin()));
- std::ranges::advance(first, distance_apriori_sentinel(n));
- assert(std::move(first).base().base() == range.begin() + n);
- check_round_trip(first, n);
-}
-
-template <std::input_or_output_iterator I>
-constexpr void check_sentinel_case(std::ptr
diff _t const n) {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto first = stride_counting_iterator(I(range.begin()));
- auto const last = I(range.begin() + n);
- std::ranges::advance(first, sentinel_wrapper(last));
- assert(first.base() == last);
- assert(first.stride_count() == n); // always `n`, so don't use `check_round_trip`
-}
-
-[[nodiscard]] constexpr bool test() {
- check_assignable_case<cpp17_input_iterator<range_t::const_iterator> >(1);
- check_assignable_case<forward_iterator<range_t::const_iterator> >(3);
- check_assignable_case<bidirectional_iterator<range_t::const_iterator> >(4);
- check_assignable_case<random_access_iterator<range_t::const_iterator> >(5);
- check_assignable_case<contiguous_iterator<range_t::const_iterator> >(6);
- check_assignable_case<output_iterator<range_t::iterator> >(7);
-
- check_sized_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(7);
- check_sized_sentinel_case<cpp20_input_iterator<range_t::const_iterator> >(6);
- check_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(5);
- check_sized_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4);
- check_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(3);
- check_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(2);
- check_sized_sentinel_case<output_iterator<range_t::iterator> >(1);
-
- check_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(1);
- // cpp20_input_iterator not copyable, so is omitted
- check_sentinel_case<forward_iterator<range_t::const_iterator> >(3);
- check_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4);
- check_sentinel_case<random_access_iterator<range_t::const_iterator> >(5);
- check_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6);
- check_sentinel_case<output_iterator<range_t::iterator> >(7);
- return true;
-}
-} // namespace iterator_sentinel
-
-namespace iterator_count_sentinel {
-struct expected_t {
- range_t::const_iterator coordinate;
- std::ptr
diff _t result;
-};
-
-template <std::input_or_output_iterator I>
-constexpr void check_forward_sized_sentinel_case(std::ptr
diff _t const n, expected_t const expected, range_t& range) {
- auto current = stride_counting_iterator(I(range.begin()));
- auto const result = std::ranges::advance(current, n, distance_apriori_sentinel(range.size()));
- assert(current.base().base() == expected.coordinate);
- assert(result == expected.result);
- check_round_trip(current, n - expected.result);
-}
-
-template <std::random_access_iterator I>
-constexpr void check_backward_sized_sentinel_case(std::ptr
diff _t const n, expected_t const expected, range_t& range) {
- auto current = stride_counting_iterator(I(range.end()));
- auto const result = std::ranges::advance(current, -n, stride_counting_iterator(I(range.begin())));
- assert(current.base().base() == expected.coordinate);
- assert(result == expected.result);
- check_round_trip(current, n - expected.result);
-}
-
-template <std::input_or_output_iterator I>
-constexpr void check_forward_case(std::ptr
diff _t const n, expected_t const expected, range_t& range) {
- auto current = stride_counting_iterator(I(range.begin()));
- auto const result = std::ranges::advance(current, n, sentinel_wrapper(I(range.end())));
- assert(current.base().base() == expected.coordinate);
- assert(result == expected.result);
- assert(current.stride_count() == n - expected.result);
-}
-
-template <std::bidirectional_iterator I>
-constexpr void check_backward_case(std::ptr
diff _t const n, expected_t const expected, range_t& range) {
- auto current = stride_counting_iterator(I(range.end()));
- auto const result = std::ranges::advance(current, -n, stride_counting_iterator(I(range.begin())));
- assert(current.base().base() == expected.coordinate);
- assert(result == expected.result);
- assert(current.stride_count() == n + expected.result);
- assert(current.stride_count() == -current.stride_displacement());
-}
-
-[[nodiscard]] constexpr bool test() {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- check_forward_sized_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(1, {range.begin() + 1, 0}, range);
- // cpp20_input_iterator not copyable, so is omitted
- check_forward_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(3, {range.begin() + 3, 0}, range);
- check_forward_sized_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4, {range.begin() + 4, 0}, range);
- check_forward_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
- check_forward_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 6, 0}, range);
- check_forward_sized_sentinel_case<output_iterator<range_t::iterator> >(7, {range.begin() + 7, 0}, range);
-
- // bidirectional_iterator omitted because `n < 0` case requires `same_as<I, S>`
- check_backward_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0},
- range);
- check_backward_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 4, 0}, range);
-
- // disntance == range.size()
- check_forward_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(10, {range.end(), 0}, range);
- check_forward_sized_sentinel_case<output_iterator<range_t::iterator> >(10, {range.end(), 0}, range);
- check_backward_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(10, {range.begin(), 0}, range);
-
- // distance > range.size()
- check_forward_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(1000, {range.end(), 990}, range);
- check_forward_sized_sentinel_case<output_iterator<range_t::iterator> >(1000, {range.end(), 990}, range);
- check_backward_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(1000, {range.begin(), -990},
- range);
-
- check_forward_case<cpp17_input_iterator<range_t::const_iterator> >(1, {range.begin() + 1, 0}, range);
- check_forward_case<forward_iterator<range_t::const_iterator> >(3, {range.begin() + 3, 0}, range);
- check_forward_case<bidirectional_iterator<range_t::const_iterator> >(4, {range.begin() + 4, 0}, range);
- check_forward_case<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
- check_forward_case<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 6, 0}, range);
- check_forward_case<output_iterator<range_t::iterator> >(7, {range.begin() + 7, 0}, range);
- check_backward_case<bidirectional_iterator<range_t::const_iterator> >(8, {range.begin() + 2, 0}, range);
-
- // disntance == range.size()
- check_forward_case<forward_iterator<range_t::const_iterator> >(10, {range.end(), 0}, range);
- check_forward_case<output_iterator<range_t::iterator> >(10, {range.end(), 0}, range);
- check_backward_case<bidirectional_iterator<range_t::const_iterator> >(10, {range.begin(), 0}, range);
-
- // distance > range.size()
- check_forward_case<forward_iterator<range_t::const_iterator> >(1000, {range.end(), 990}, range);
- check_forward_case<output_iterator<range_t::iterator> >(1000, {range.end(), 990}, range);
- check_backward_case<bidirectional_iterator<range_t::const_iterator> >(1000, {range.begin(), -990}, range);
-
- return true;
-}
-} // namespace iterator_count_sentinel
-
-int main(int, char**) {
- static_assert(iterator_count::test());
- assert(iterator_count::test());
-
- static_assert(iterator_sentinel::test());
- assert(iterator_sentinel::test());
-
- static_assert(iterator_count_sentinel::test());
- assert(iterator_count_sentinel::test());
-
- return 0;
-}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count.pass.cpp
new file mode 100644
index 0000000000000..60fc2a302e7d1
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count.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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+
+// ranges::advance(it, n)
+
+#include <iterator>
+
+#include <array>
+#include <cassert>
+
+#include "test_standard_function.h"
+#include "test_iterators.h"
+
+static_assert(is_function_like<decltype(std::ranges::advance)>());
+
+using range_t = std::array<int, 10>;
+
+template <std::input_or_output_iterator I>
+constexpr void check_move_forward(std::ptr
diff _t const n) {
+ auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto first = stride_counting_iterator(I(range.begin()));
+ std::ranges::advance(first, n);
+
+ assert(first.base().base() == range.begin() + n);
+ if constexpr (std::random_access_iterator<I>) {
+ assert(first.stride_count() == 0 || first.stride_count() == 1);
+ assert(first.stride_displacement() == 1);
+ } else {
+ assert(first.stride_count() == n);
+ assert(first.stride_displacement() == n);
+ }
+}
+
+template <std::bidirectional_iterator I>
+constexpr void check_move_backward(std::ptr
diff _t const n) {
+ auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto first = stride_counting_iterator(I(range.begin() + n));
+ std::ranges::advance(first, -n);
+ assert(first.base().base() == range.begin());
+
+ if constexpr (std::random_access_iterator<I>) {
+ assert(first.stride_count() == 0 || first.stride_count() == 1);
+ assert(first.stride_displacement() == 1);
+ } else {
+ assert(first.stride_count() == n);
+ assert(first.stride_displacement() == -n);
+ }
+}
+
+constexpr bool test() {
+ check_move_forward<cpp17_input_iterator<range_t::const_iterator> >(1);
+ check_move_forward<cpp20_input_iterator<range_t::const_iterator> >(2);
+ check_move_forward<forward_iterator<range_t::const_iterator> >(3);
+ check_move_forward<bidirectional_iterator<range_t::const_iterator> >(4);
+ check_move_forward<random_access_iterator<range_t::const_iterator> >(5);
+ check_move_forward<contiguous_iterator<range_t::const_iterator> >(6);
+ check_move_forward<output_iterator<range_t::iterator> >(7);
+
+ check_move_backward<bidirectional_iterator<range_t::const_iterator> >(4);
+ check_move_backward<random_access_iterator<range_t::const_iterator> >(5);
+ check_move_backward<contiguous_iterator<range_t::const_iterator> >(6);
+
+ // Zero should be checked for each case and each overload
+ check_move_forward<cpp17_input_iterator<range_t::const_iterator> >(0);
+ check_move_forward<cpp20_input_iterator<range_t::const_iterator> >(0);
+ check_move_forward<forward_iterator<range_t::const_iterator> >(0);
+ check_move_forward<bidirectional_iterator<range_t::const_iterator> >(0);
+ check_move_forward<random_access_iterator<range_t::const_iterator> >(0);
+ check_move_forward<output_iterator<range_t::iterator> >(0);
+ check_move_backward<bidirectional_iterator<range_t::const_iterator> >(0);
+ check_move_backward<random_access_iterator<range_t::const_iterator> >(0);
+
+ return true;
+}
+
+int main(int, char**) {
+ static_assert(test());
+ assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp
new file mode 100644
index 0000000000000..128d298b4994c
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp
@@ -0,0 +1,145 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+
+// ranges::advance(it, n, sent)
+
+#include <iterator>
+
+#include <array>
+#include <cassert>
+
+#include "test_standard_function.h"
+#include "test_iterators.h"
+
+static_assert(is_function_like<decltype(std::ranges::advance)>());
+
+using range_t = std::array<int, 10>;
+
+class distance_apriori_sentinel {
+public:
+ distance_apriori_sentinel() = default;
+ constexpr explicit distance_apriori_sentinel(std::ptr
diff _t const count) : count_(count) {}
+
+ constexpr bool operator==(std::input_or_output_iterator auto const&) const {
+ assert(false && "
diff erence op should take precedence");
+ return false;
+ }
+
+ constexpr friend std::ptr
diff _t operator-(std::input_or_output_iterator auto const&,
+ distance_apriori_sentinel const y) {
+ return -y.count_;
+ }
+
+ constexpr friend std::ptr
diff _t operator-(distance_apriori_sentinel const x,
+ std::input_or_output_iterator auto const&) {
+ return x.count_;
+ }
+
+private:
+ std::ptr
diff _t count_ = 0;
+};
+
+struct expected_t {
+ range_t::const_iterator coordinate;
+ std::ptr
diff _t result;
+};
+
+template <std::input_or_output_iterator I>
+constexpr void check_forward_sized_sentinel(std::ptr
diff _t const n, expected_t const expected, range_t& range) {
+ auto current = stride_counting_iterator(I(range.begin()));
+ auto const result = std::ranges::advance(current, n, distance_apriori_sentinel(range.size()));
+ assert(current.base().base() == expected.coordinate);
+ assert(result == expected.result);
+
+ if constexpr (std::random_access_iterator<I>) {
+ assert(current.stride_count() == 0 || current.stride_count() == 1);
+ assert(current.stride_displacement() == current.stride_count());
+ } else {
+ assert(current.stride_count() == (n - result));
+ assert(current.stride_displacement() == (n - result));
+ }
+}
+
+template <std::random_access_iterator I>
+constexpr void check_backward_sized_sentinel(std::ptr
diff _t const n, expected_t const expected, range_t& range) {
+ auto current = stride_counting_iterator(I(range.end()));
+ auto const result = std::ranges::advance(current, -n, stride_counting_iterator(I(range.begin())));
+ assert(current.base().base() == expected.coordinate);
+ assert(result == expected.result);
+
+ assert(current.stride_count() == 0 || current.stride_count() == 1);
+ assert(current.stride_displacement() == current.stride_count());
+}
+
+template <std::input_or_output_iterator I>
+constexpr void check_forward(std::ptr
diff _t const n, expected_t const expected, range_t& range) {
+ auto current = stride_counting_iterator(I(range.begin()));
+ auto const result = std::ranges::advance(current, n, sentinel_wrapper(I(range.end())));
+ assert(current.base().base() == expected.coordinate);
+ assert(result == expected.result);
+ assert(current.stride_count() == n - result);
+}
+
+template <std::bidirectional_iterator I>
+constexpr void check_backward(std::ptr
diff _t const n, expected_t const expected, range_t& range) {
+ auto current = stride_counting_iterator(I(range.end()));
+ auto const result = std::ranges::advance(current, -n, stride_counting_iterator(I(range.begin())));
+ assert(current.base().base() == expected.coordinate);
+ assert(result == expected.result);
+ assert(current.stride_count() == n + result);
+ assert(current.stride_count() == -current.stride_displacement());
+}
+
+constexpr bool test() {
+ auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ check_forward_sized_sentinel<cpp17_input_iterator<range_t::const_iterator> >(1, {range.begin() + 1, 0}, range);
+ // cpp20_input_iterator not copyable, so is omitted
+ check_forward_sized_sentinel<forward_iterator<range_t::const_iterator> >(3, {range.begin() + 3, 0}, range);
+ check_forward_sized_sentinel<bidirectional_iterator<range_t::const_iterator> >(4, {range.begin() + 4, 0}, range);
+ check_forward_sized_sentinel<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
+ check_forward_sized_sentinel<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 6, 0}, range);
+
+ // bidirectional_iterator omitted because the `n < 0` case requires `same_as<I, S>`
+ check_backward_sized_sentinel<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
+ check_backward_sized_sentinel<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 4, 0}, range);
+
+ // distance == range.size()
+ check_forward_sized_sentinel<forward_iterator<range_t::const_iterator> >(10, {range.end(), 0}, range);
+ check_backward_sized_sentinel<random_access_iterator<range_t::const_iterator> >(10, {range.begin(), 0}, range);
+
+ // distance > range.size()
+ check_forward_sized_sentinel<forward_iterator<range_t::const_iterator> >(1000, {range.end(), 990}, range);
+ check_backward_sized_sentinel<random_access_iterator<range_t::const_iterator> >(1000, {range.begin(), -990}, range);
+
+ check_forward<cpp17_input_iterator<range_t::const_iterator> >(1, {range.begin() + 1, 0}, range);
+ check_forward<forward_iterator<range_t::const_iterator> >(3, {range.begin() + 3, 0}, range);
+ check_forward<bidirectional_iterator<range_t::const_iterator> >(4, {range.begin() + 4, 0}, range);
+ check_forward<random_access_iterator<range_t::const_iterator> >(5, {range.begin() + 5, 0}, range);
+ check_forward<contiguous_iterator<range_t::const_iterator> >(6, {range.begin() + 6, 0}, range);
+ check_backward<bidirectional_iterator<range_t::const_iterator> >(8, {range.begin() + 2, 0}, range);
+
+ // distance == range.size()
+ check_forward<forward_iterator<range_t::const_iterator> >(10, {range.end(), 0}, range);
+ check_backward<bidirectional_iterator<range_t::const_iterator> >(10, {range.begin(), 0}, range);
+
+ // distance > range.size()
+ check_forward<forward_iterator<range_t::const_iterator> >(1000, {range.end(), 990}, range);
+ check_backward<bidirectional_iterator<range_t::const_iterator> >(1000, {range.begin(), -990}, range);
+
+ return true;
+}
+
+int main(int, char**) {
+ static_assert(test());
+ assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp
new file mode 100644
index 0000000000000..1a740665f0c66
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp
@@ -0,0 +1,113 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+
+// ranges::advance(it, sent)
+
+#include <iterator>
+
+#include <array>
+#include <cassert>
+
+#include "test_standard_function.h"
+#include "test_iterators.h"
+
+static_assert(is_function_like<decltype(std::ranges::advance)>());
+
+using range_t = std::array<int, 10>;
+
+class distance_apriori_sentinel {
+public:
+ distance_apriori_sentinel() = default;
+ constexpr explicit distance_apriori_sentinel(std::ptr
diff _t const count) : count_(count) {}
+
+ constexpr bool operator==(std::input_or_output_iterator auto const&) const {
+ assert(false && "
diff erence op should take precedence");
+ return false;
+ }
+
+ constexpr friend std::ptr
diff _t operator-(std::input_or_output_iterator auto const&,
+ distance_apriori_sentinel const y) {
+ return -y.count_;
+ }
+
+ constexpr friend std::ptr
diff _t operator-(distance_apriori_sentinel const x,
+ std::input_or_output_iterator auto const&) {
+ return x.count_;
+ }
+
+private:
+ std::ptr
diff _t count_ = 0;
+};
+
+template <std::input_or_output_iterator I, std::sentinel_for<I> S = I>
+constexpr void check_assignable_case(std::ptr
diff _t const n) {
+ auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto first = stride_counting_iterator(I(range.begin()));
+ std::ranges::advance(first, stride_counting_iterator(S(I(range.begin() + n))));
+ assert(first.base().base() == range.begin() + n);
+ assert(first.stride_count() == 0); // because we got here by assigning from last, not by incrementing
+}
+
+template <std::input_or_output_iterator I>
+constexpr void check_sized_sentinel_case(std::ptr
diff _t const n) {
+ auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto first = stride_counting_iterator(I(range.begin()));
+ std::ranges::advance(first, distance_apriori_sentinel(n));
+
+ assert(first.base().base() == range.begin() + n);
+ if constexpr (std::random_access_iterator<I>) {
+ assert(first.stride_count() == 1);
+ assert(first.stride_displacement() == 1);
+ } else {
+ assert(first.stride_count() == n);
+ assert(first.stride_displacement() == n);
+ }
+}
+
+template <std::input_or_output_iterator I>
+constexpr void check_sentinel_case(std::ptr
diff _t const n) {
+ auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto first = stride_counting_iterator(I(range.begin()));
+ auto const last = I(range.begin() + n);
+ std::ranges::advance(first, sentinel_wrapper(last));
+ assert(first.base() == last);
+ assert(first.stride_count() == n);
+}
+
+constexpr bool test() {
+ check_assignable_case<cpp17_input_iterator<range_t::const_iterator> >(1);
+ check_assignable_case<forward_iterator<range_t::const_iterator> >(3);
+ check_assignable_case<bidirectional_iterator<range_t::const_iterator> >(4);
+ check_assignable_case<random_access_iterator<range_t::const_iterator> >(5);
+ check_assignable_case<contiguous_iterator<range_t::const_iterator> >(6);
+
+ check_sized_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(7);
+ check_sized_sentinel_case<cpp20_input_iterator<range_t::const_iterator> >(6);
+ check_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(5);
+ check_sized_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4);
+ check_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(3);
+ check_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(2);
+
+ check_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(1);
+ // cpp20_input_iterator not copyable, so is omitted
+ check_sentinel_case<forward_iterator<range_t::const_iterator> >(3);
+ check_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4);
+ check_sentinel_case<random_access_iterator<range_t::const_iterator> >(5);
+ check_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6);
+ return true;
+}
+
+int main(int, char**) {
+ static_assert(test());
+ assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/check_round_trip.h b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/check_round_trip.h
deleted file mode 100644
index ed2f6c218704f..0000000000000
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/check_round_trip.h
+++ /dev/null
@@ -1,31 +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
-//
-//===----------------------------------------------------------------------===//
-#ifndef LIBCXX_TEST_CHECK_ROUND_TRIP_H
-#define LIBCXX_TEST_CHECK_ROUND_TRIP_H
-
-#include "test_iterators.h"
-
-template <std::input_or_output_iterator I>
-constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptr
diff _t const n) {
- auto const distance = n < 0 ? -n : n;
- assert(i.stride_count() == distance);
- assert(i.stride_displacement() == n);
-}
-
-template <std::random_access_iterator I>
-constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptr
diff _t const n) {
- assert(i.stride_count() <= 1);
- assert(i.stride_displacement() == n < 0 ? -1 : 1);
-}
-
-template <std::input_or_output_iterator I>
-constexpr bool operator==(output_iterator<I> const& x, output_iterator<I> const& y) {
- return x.base() == y.base();
-}
-
-#endif // LIBCXX_TEST_CHECK_ROUND_TRIP_H
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/constraints.compile.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/constraints.compile.pass.cpp
new file mode 100644
index 0000000000000..8c65059a66b79
--- /dev/null
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/constraints.compile.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: gcc-10
+
+// ranges::next
+// Make sure we're SFINAE-friendly when the template argument constraints are not met.
+
+#include <iterator>
+
+#include <cstddef>
+#include <memory>
+#include <utility>
+
+template <class ...Args>
+concept has_ranges_next = requires (Args ...args) {
+ { std::ranges::next(std::forward<Args>(args)...) };
+};
+
+using It = std::unique_ptr<int>;
+static_assert(!has_ranges_next<It>);
+static_assert(!has_ranges_next<It, std::ptr
diff _t>);
+static_assert(!has_ranges_next<It, It>);
+static_assert(!has_ranges_next<It, std::ptr
diff _t, It>);
+
+// Test the test
+static_assert(has_ranges_next<int*, std::ptr
diff _t, int*>);
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/constraints.verify.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/constraints.verify.cpp
deleted file mode 100644
index 94646ddca947c..0000000000000
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/constraints.verify.cpp
+++ /dev/null
@@ -1,27 +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
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03, c++11, c++14, c++17
-// UNSUPPORTED: libcpp-no-concepts
-// UNSUPPORTED: gcc-10
-
-// ranges::next
-
-#include <iterator>
-
-#include <memory>
-
-#include "test_iterators.h"
-
-void proper_constraints() {
- auto p = std::unique_ptr<int>();
- std::ranges::next(p); // expected-error {{no matching function for call}}
- std::ranges::next(p, p); // expected-error {{no matching function for call}}
- std::ranges::next(p, 5); // expected-error {{no matching function for call}}
- std::ranges::next(p, 7); // expected-error {{no matching function for call}}
-}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator.pass.cpp
index 5aba47a6f7e30..5e69ffd723fec 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator.pass.cpp
@@ -10,32 +10,37 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
-// ranges::next(first, n)
+// ranges::next(it)
#include <iterator>
-
-#include <array>
#include <cassert>
-#include "check_round_trip.h"
#include "test_iterators.h"
-using range_t = std::array<int, 10>;
+template <class It>
+constexpr void check() {
+ int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ assert(&*std::ranges::next(It(&range[0])) == &range[1]);
+ assert(&*std::ranges::next(It(&range[1])) == &range[2]);
+ assert(&*std::ranges::next(It(&range[2])) == &range[3]);
+ assert(&*std::ranges::next(It(&range[3])) == &range[4]);
+ assert(&*std::ranges::next(It(&range[4])) == &range[5]);
+ assert(&*std::ranges::next(It(&range[5])) == &range[6]);
+}
-constexpr bool check_iterator() {
- constexpr auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- assert(std::ranges::next(cpp17_input_iterator(&range[0])) == cpp17_input_iterator(&range[1]));
- assert(std::ranges::next(cpp20_input_iterator(&range[1])).base() == &range[2]);
- assert(std::ranges::next(forward_iterator(&range[2])) == forward_iterator(&range[3]));
- assert(std::ranges::next(bidirectional_iterator(&range[3])) == bidirectional_iterator(&range[4]));
- assert(std::ranges::next(random_access_iterator(&range[4])) == random_access_iterator(&range[5]));
- assert(std::ranges::next(contiguous_iterator(&range[5])) == contiguous_iterator(&range[6]));
- assert(std::ranges::next(output_iterator(&range[6])).base() == &range[7]);
+constexpr bool test() {
+ check<cpp17_input_iterator<int*>>();
+ check<cpp20_input_iterator<int*>>();
+ check<forward_iterator<int*>>();
+ check<bidirectional_iterator<int*>>();
+ check<random_access_iterator<int*>>();
+ check<contiguous_iterator<int*>>();
+ check<output_iterator<int*>>();
return true;
}
int main(int, char**) {
- static_assert(check_iterator());
- check_iterator();
+ static_assert(test());
+ test();
return 0;
}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count.pass.cpp
index 539a8e017b37d..01217704ca100 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count.pass.cpp
@@ -10,52 +10,65 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
-// ranges::next(first, n)
+// ranges::next(it, n)
#include <iterator>
-#include <array>
#include <cassert>
+#include <utility>
-#include "check_round_trip.h"
#include "test_iterators.h"
-using range_t = std::array<int, 10>;
-
template <std::input_or_output_iterator I>
-constexpr void iterator_count_impl(I first, std::ptr
diff _t const n, range_t::const_iterator const expected) {
- auto result = std::ranges::next(stride_counting_iterator(std::move(first)), n);
- assert(std::move(result).base().base() == expected);
- check_round_trip(result, n);
+constexpr void check_steps(I it, std::ptr
diff _t n, int const* expected) {
+ {
+ auto result = std::ranges::next(std::move(it), n);
+ assert(&*result == expected);
+ }
+
+ // Count the number of operations
+ {
+ stride_counting_iterator strided_it(std::move(it));
+ auto result = std::ranges::next(std::move(strided_it), n);
+ assert(&*result == expected);
+ if constexpr (std::random_access_iterator<I>) {
+ assert(result.stride_count() == 1); // uses += exactly once
+ assert(result.stride_displacement() == 1);
+ } else {
+ auto const abs_n = n < 0 ? -n : n;
+ assert(result.stride_count() == abs_n);
+ assert(result.stride_displacement() == n);
+ }
+ }
}
-constexpr bool check_iterator_count() {
- constexpr auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-
- iterator_count_impl(cpp17_input_iterator(&range[0]), 1, &range[1]);
- iterator_count_impl(cpp20_input_iterator(&range[6]), 2, &range[8]);
- iterator_count_impl(forward_iterator(&range[0]), 3, &range[3]);
- iterator_count_impl(bidirectional_iterator(&range[2]), 6, &range[8]);
- iterator_count_impl(random_access_iterator(&range[3]), 4, &range[7]);
- iterator_count_impl(contiguous_iterator(&range[0]), 5, &range[5]);
- iterator_count_impl(output_iterator(&range[0]), 6, &range[6]);
-
- iterator_count_impl(cpp17_input_iterator(&range[0]), 0, &range[0]);
- iterator_count_impl(cpp20_input_iterator(&range[6]), 0, &range[6]);
- iterator_count_impl(forward_iterator(&range[0]), 0, &range[0]);
- iterator_count_impl(bidirectional_iterator(&range[2]), 0, &range[2]);
- iterator_count_impl(random_access_iterator(&range[3]), 0, &range[3]);
- iterator_count_impl(contiguous_iterator(&range[0]), 0, &range[0]);
- iterator_count_impl(output_iterator(&range[0]), 0, &range[0]);
-
- iterator_count_impl(bidirectional_iterator(&range[8]), -5, &range[3]);
- iterator_count_impl(random_access_iterator(&range[6]), -3, &range[3]);
- iterator_count_impl(contiguous_iterator(&range[4]), -1, &range[3]);
+constexpr bool test() {
+ int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ check_steps(cpp17_input_iterator(&range[0]), 1, &range[1]);
+ check_steps(cpp20_input_iterator(&range[6]), 2, &range[8]);
+ check_steps(forward_iterator(&range[0]), 3, &range[3]);
+ check_steps(bidirectional_iterator(&range[2]), 6, &range[8]);
+ check_steps(random_access_iterator(&range[3]), 4, &range[7]);
+ check_steps(contiguous_iterator(&range[0]), 5, &range[5]);
+ check_steps(output_iterator(&range[0]), 6, &range[6]);
+
+ check_steps(cpp17_input_iterator(&range[0]), 0, &range[0]);
+ check_steps(cpp20_input_iterator(&range[6]), 0, &range[6]);
+ check_steps(forward_iterator(&range[0]), 0, &range[0]);
+ check_steps(bidirectional_iterator(&range[2]), 0, &range[2]);
+ check_steps(random_access_iterator(&range[3]), 0, &range[3]);
+ check_steps(contiguous_iterator(&range[0]), 0, &range[0]);
+ check_steps(output_iterator(&range[0]), 0, &range[0]);
+
+ check_steps(bidirectional_iterator(&range[8]), -5, &range[3]);
+ check_steps(random_access_iterator(&range[6]), -3, &range[3]);
+ check_steps(contiguous_iterator(&range[4]), -1, &range[3]);
return true;
}
int main(int, char**) {
- static_assert(check_iterator_count());
- check_iterator_count();
+ static_assert(test());
+ test();
return 0;
}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count_sentinel.pass.cpp
index 696b48cc51005..6da7149ce38da 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count_sentinel.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_count_sentinel.pass.cpp
@@ -10,48 +10,63 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
-// ranges::next
+// ranges::next(it, n, bound)
#include <iterator>
-
-#include <array>
#include <cassert>
-#include "check_round_trip.h"
#include "test_iterators.h"
template <std::input_or_output_iterator I>
-constexpr void check_iterator_count_sentinel_impl(I first, std::ptr
diff _t const steps, I const last) {
- auto result = std::ranges::next(stride_counting_iterator(first), steps, stride_counting_iterator(last));
- assert(result == last);
- check_round_trip(result, steps);
+constexpr void check(I it, std::ptr
diff _t n, I last) {
+ {
+ auto result = std::ranges::next(it, n, last);
+ assert(result == last);
+ }
+
+ // Count the number of operations
+ {
+ stride_counting_iterator strided_it(it), strided_last(last);
+ auto result = std::ranges::next(strided_it, n, strided_last);
+ assert(result == strided_last);
+ if constexpr (std::random_access_iterator<I>) {
+ if (n == 0 || n >= (last - it)) {
+ assert(result.stride_count() == 0); // uses the assign-from-sentinel codepath
+ } else {
+ assert(result.stride_count() == 1); // uses += exactly once
+ }
+ } else {
+ auto const abs_n = n < 0 ? -n : n;
+ assert(result.stride_count() == abs_n);
+ assert(result.stride_displacement() == n);
+ }
+ }
}
-constexpr bool check_iterator_count_sentinel() {
- constexpr auto range = std::array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- check_iterator_count_sentinel_impl(cpp17_input_iterator(&range[0]), 1, cpp17_input_iterator(&range[1]));
- check_iterator_count_sentinel_impl(forward_iterator(&range[0]), 2, forward_iterator(&range[2]));
- check_iterator_count_sentinel_impl(bidirectional_iterator(&range[2]), 6, bidirectional_iterator(&range[8]));
- check_iterator_count_sentinel_impl(random_access_iterator(&range[3]), 2, random_access_iterator(&range[5]));
- check_iterator_count_sentinel_impl(contiguous_iterator(&range[0]), 5, contiguous_iterator(&range[5]));
- check_iterator_count_sentinel_impl(output_iterator(&range[3]), 2, output_iterator(&range[5]));
-
- check_iterator_count_sentinel_impl(cpp17_input_iterator(&range[0]), 0, cpp17_input_iterator(&range[0]));
- check_iterator_count_sentinel_impl(forward_iterator(&range[0]), 0, forward_iterator(&range[0]));
- check_iterator_count_sentinel_impl(bidirectional_iterator(&range[2]), 0, bidirectional_iterator(&range[2]));
- check_iterator_count_sentinel_impl(random_access_iterator(&range[3]), 0, random_access_iterator(&range[3]));
- check_iterator_count_sentinel_impl(contiguous_iterator(&range[0]), 0, contiguous_iterator(&range[0]));
- check_iterator_count_sentinel_impl(output_iterator(&range[3]), 0, output_iterator(&range[3]));
-
- check_iterator_count_sentinel_impl(bidirectional_iterator(&range[6]), -1, bidirectional_iterator(&range[5]));
- check_iterator_count_sentinel_impl(random_access_iterator(&range[7]), -2, random_access_iterator(&range[5]));
- check_iterator_count_sentinel_impl(contiguous_iterator(&range[8]), -3, contiguous_iterator(&range[5]));
+constexpr bool test() {
+ int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ check(cpp17_input_iterator(&range[0]), 1, cpp17_input_iterator(&range[1]));
+ check(forward_iterator(&range[0]), 2, forward_iterator(&range[2]));
+ check(bidirectional_iterator(&range[2]), 6, bidirectional_iterator(&range[8]));
+ check(random_access_iterator(&range[3]), 2, random_access_iterator(&range[5]));
+ check(contiguous_iterator(&range[0]), 5, contiguous_iterator(&range[5]));
+
+ check(cpp17_input_iterator(&range[0]), 0, cpp17_input_iterator(&range[0]));
+ check(forward_iterator(&range[0]), 0, forward_iterator(&range[0]));
+ check(bidirectional_iterator(&range[2]), 0, bidirectional_iterator(&range[2]));
+ check(random_access_iterator(&range[3]), 0, random_access_iterator(&range[3]));
+ check(contiguous_iterator(&range[0]), 0, contiguous_iterator(&range[0]));
+
+ check(bidirectional_iterator(&range[6]), -1, bidirectional_iterator(&range[5]));
+ check(random_access_iterator(&range[7]), -2, random_access_iterator(&range[5]));
+ check(contiguous_iterator(&range[8]), -3, contiguous_iterator(&range[5]));
return true;
}
int main(int, char**) {
- static_assert(check_iterator_count_sentinel());
- assert(check_iterator_count_sentinel());
+ static_assert(test());
+ assert(test());
return 0;
}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp
index 5945ba64b847a..c33a145d73f24 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp
@@ -10,14 +10,14 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
-// ranges::next
+// ranges::next(it, bound)
#include <iterator>
#include <array>
#include <cassert>
+#include <utility>
-#include "check_round_trip.h"
#include "test_iterators.h"
using range_t = std::array<int, 10>;
@@ -47,59 +47,96 @@ class distance_apriori_sentinel {
};
template <std::input_or_output_iterator I>
-constexpr void check_assignable_case(std::ptr
diff _t const n) {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto result =
- std::ranges::next(stride_counting_iterator(I(range.begin())), stride_counting_iterator(I(range.begin() + n)));
- assert(result.base().base() == range.begin() + n);
- assert(result.stride_count() == 0); // always zero, so don't use `check_round_trip`
+constexpr void check_assignable(I it, I last, int const* expected) {
+ {
+ auto result = std::ranges::next(std::move(it), std::move(last));
+ assert(&*result == expected);
+ }
+
+ // Count operations
+ {
+ auto strided_it = stride_counting_iterator(std::move(it));
+ auto strided_last = stride_counting_iterator(std::move(last));
+ auto result = std::ranges::next(std::move(strided_it), std::move(strided_last));
+ assert(&*result == expected);
+ assert(result.stride_count() == 0); // because we got here by assigning from last, not by incrementing
+ }
}
template <std::input_or_output_iterator I>
-constexpr void check_sized_sentinel_case(std::ptr
diff _t const n) {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto result = std::ranges::next(stride_counting_iterator(I(range.begin())), distance_apriori_sentinel(n));
- assert(std::move(result).base().base() == range.begin() + n);
- check_round_trip(result, n);
+constexpr void check_sized_sentinel(I it, I last, int const* expected) {
+ auto n = (last.base() - it.base());
+
+ {
+ auto sent = distance_apriori_sentinel(n);
+ auto result = std::ranges::next(std::move(it), sent);
+ assert(&*result == expected);
+ }
+
+ // Count operations
+ {
+ auto strided_it = stride_counting_iterator(std::move(it));
+ auto sent = distance_apriori_sentinel(n);
+ auto result = std::ranges::next(std::move(strided_it), sent);
+ assert(&*result == expected);
+
+ if constexpr (std::random_access_iterator<I>) {
+ assert(result.stride_count() == 1); // should have used exactly one +=
+ assert(result.stride_displacement() == 1);
+ } else {
+ assert(result.stride_count() == n);
+ assert(result.stride_displacement() == n);
+ }
+ }
}
template <std::input_or_output_iterator I>
-constexpr void check_sentinel_case(std::ptr
diff _t const n) {
- auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- auto const last = I(range.begin() + n);
- auto result = std::ranges::next(stride_counting_iterator(I(range.begin())), sentinel_wrapper(last));
- assert(std::move(result).base() == last);
- assert(result.stride_count() == n); // always `n`, so don't use `check_round_trip`
+constexpr void check_sentinel(I it, I last, int const* expected) {
+ auto n = (last.base() - it.base());
+
+ {
+ auto sent = sentinel_wrapper(last);
+ auto result = std::ranges::next(std::move(it), sent);
+ assert(&*result == expected);
+ }
+
+ // Count operations
+ {
+ auto strided_it = stride_counting_iterator(it);
+ auto sent = sentinel_wrapper(stride_counting_iterator(last));
+ auto result = std::ranges::next(std::move(strided_it), sent);
+ assert(&*result == expected);
+ assert(result.stride_count() == n); // must have used ++ until it hit the sentinel
+ }
}
-constexpr bool check_iterator_sentinel() {
- check_assignable_case<cpp17_input_iterator<range_t::const_iterator> >(1);
- check_assignable_case<forward_iterator<range_t::const_iterator> >(3);
- check_assignable_case<bidirectional_iterator<range_t::const_iterator> >(4);
- check_assignable_case<random_access_iterator<range_t::const_iterator> >(5);
- check_assignable_case<contiguous_iterator<range_t::const_iterator> >(6);
- check_assignable_case<output_iterator<range_t::iterator> >(7);
-
- check_sized_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(7);
- check_sized_sentinel_case<cpp20_input_iterator<range_t::const_iterator> >(6);
- check_sized_sentinel_case<forward_iterator<range_t::const_iterator> >(5);
- check_sized_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4);
- check_sized_sentinel_case<random_access_iterator<range_t::const_iterator> >(3);
- check_sized_sentinel_case<contiguous_iterator<range_t::const_iterator> >(2);
- check_sized_sentinel_case<output_iterator<range_t::iterator> >(1);
-
- check_sentinel_case<cpp17_input_iterator<range_t::const_iterator> >(1);
+constexpr bool test() {
+ int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ check_assignable(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[2]), &range[2]);
+ check_assignable(forward_iterator(&range[0]), forward_iterator(&range[3]), &range[3]);
+ check_assignable(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
+ check_assignable(random_access_iterator(&range[0]), random_access_iterator(&range[5]), &range[5]);
+ check_assignable(contiguous_iterator(&range[0]), contiguous_iterator(&range[6]), &range[6]);
+
+ check_sized_sentinel(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[7]), &range[7]);
+ check_sized_sentinel(cpp20_input_iterator(&range[0]), cpp20_input_iterator(&range[6]), &range[6]);
+ check_sized_sentinel(forward_iterator(&range[0]), forward_iterator(&range[5]), &range[5]);
+ check_sized_sentinel(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
+ check_sized_sentinel(random_access_iterator(&range[0]), random_access_iterator(&range[3]), &range[3]);
+ check_sized_sentinel(contiguous_iterator(&range[0]), contiguous_iterator(&range[2]), &range[2]);
+
+ check_sentinel(cpp17_input_iterator(&range[0]), cpp17_input_iterator(&range[1]), &range[1]);
// cpp20_input_iterator not copyable, so is omitted
- check_sentinel_case<forward_iterator<range_t::const_iterator> >(3);
- check_sentinel_case<bidirectional_iterator<range_t::const_iterator> >(4);
- check_sentinel_case<random_access_iterator<range_t::const_iterator> >(5);
- check_sentinel_case<contiguous_iterator<range_t::const_iterator> >(6);
- check_sentinel_case<output_iterator<range_t::iterator> >(7);
+ check_sentinel(forward_iterator(&range[0]), forward_iterator(&range[3]), &range[3]);
+ check_sentinel(bidirectional_iterator(&range[0]), bidirectional_iterator(&range[4]), &range[4]);
+ check_sentinel(random_access_iterator(&range[0]), random_access_iterator(&range[5]), &range[5]);
+ check_sentinel(contiguous_iterator(&range[0]), contiguous_iterator(&range[6]), &range[6]);
return true;
}
int main(int, char**) {
- static_assert(check_iterator_sentinel());
- check_iterator_sentinel();
+ static_assert(test());
+ test();
return 0;
}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/check_round_trip.h b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/check_round_trip.h
deleted file mode 100644
index a4c8f152e06fc..0000000000000
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/check_round_trip.h
+++ /dev/null
@@ -1,26 +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
-//
-//===----------------------------------------------------------------------===//
-#ifndef LIBCXX_TEST_PREV_CHECK_ROUND_TRIP_H
-#define LIBCXX_TEST_PREV_CHECK_ROUND_TRIP_H
-
-#include "test_iterators.h"
-
-template <std::input_or_output_iterator I>
-constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptr
diff _t const n) {
- auto const distance = n < 0 ? -n : n;
- assert(i.stride_count() == distance);
- assert(i.stride_displacement() == -n);
-}
-
-template <std::random_access_iterator I>
-constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptr
diff _t const n) {
- assert(i.stride_count() <= 1);
- assert(i.stride_displacement() == n < 0 ? -1 : 1);
-}
-
-#endif // LIBCXX_TEST_PREV_CHECK_ROUND_TRIP_H
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/constraints.verify.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/constraints.compile.pass.cpp
similarity index 50%
rename from libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/constraints.verify.cpp
rename to libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/constraints.compile.pass.cpp
index a05cdab3b6ee3..78265299340c7 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/constraints.verify.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/constraints.compile.pass.cpp
@@ -11,16 +11,23 @@
// UNSUPPORTED: gcc-10
// ranges::prev
+// Make sure we're SFINAE-friendly when the template argument constraints are not met.
#include <iterator>
-#include <array>
-
+#include <cstddef>
+#include <utility>
#include "test_iterators.h"
-void proper_constraints() {
- auto a = std::array{0, 1, 2};
- (void)std::ranges::prev(forward_iterator(a.begin())); // expected-error {{no matching function for call}}
- (void)std::ranges::prev(forward_iterator(a.begin()), 5); // expected-error {{no matching function for call}}
- (void)std::ranges::prev(forward_iterator(a.begin()), 7); // expected-error {{no matching function for call}}
-}
+template <class ...Args>
+concept has_ranges_prev = requires (Args ...args) {
+ { std::ranges::prev(std::forward<Args>(args)...) };
+};
+
+using It = forward_iterator<int*>;
+static_assert(!has_ranges_prev<It>);
+static_assert(!has_ranges_prev<It, std::ptr
diff _t>);
+static_assert(!has_ranges_prev<It, std::ptr
diff _t, It>);
+
+// Test the test
+static_assert(has_ranges_prev<int*, std::ptr
diff _t, int*>);
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator.pass.cpp
index 8e9faecbf5325..4bc642437224f 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator.pass.cpp
@@ -10,26 +10,31 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
-// ranges::prev(iterator)
+// ranges::prev(it)
#include <iterator>
-
-#include <array>
#include <cassert>
-#include "check_round_trip.h"
#include "test_iterators.h"
-constexpr bool check_iterator() {
- constexpr auto range = std::array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- assert(std::ranges::prev(bidirectional_iterator(&range[4])) == bidirectional_iterator(&range[3]));
- assert(std::ranges::prev(random_access_iterator(&range[5])) == random_access_iterator(&range[4]));
- assert(std::ranges::prev(contiguous_iterator(&range[6])) == contiguous_iterator(&range[5]));
+template <class It>
+constexpr void check() {
+ int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+ assert(std::ranges::prev(It(&range[4])) == It(&range[3]));
+ assert(std::ranges::prev(It(&range[5])) == It(&range[4]));
+ assert(std::ranges::prev(It(&range[6])) == It(&range[5]));
+}
+
+constexpr bool test() {
+ check<bidirectional_iterator<int*>>();
+ check<random_access_iterator<int*>>();
+ check<contiguous_iterator<int*>>();
+ check<int*>();
return true;
}
int main(int, char**) {
- static_assert(check_iterator());
- check_iterator();
+ static_assert(test());
+ test();
return 0;
}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count.pass.cpp
index f8e7a49996424..e8f7beb99ac08 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count.pass.cpp
@@ -10,43 +10,48 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
-// ranges::prev(iterator, count)
+// ranges::prev(it, n)
#include <iterator>
-
-#include <array>
#include <cassert>
+#include <utility>
-#include "check_round_trip.h"
#include "test_iterators.h"
-using range_t = std::array<int, 10>;
-
template <std::input_or_output_iterator I>
-constexpr void iterator_count_impl(I first, std::ptr
diff _t const n, range_t::const_iterator const expected) {
- auto result = std::ranges::prev(stride_counting_iterator(std::move(first)), n);
- assert(std::move(result).base().base() == expected);
- check_round_trip(result, n);
+constexpr void check(I it, std::ptr
diff _t n, int const* expected) {
+ auto result = std::ranges::prev(stride_counting_iterator(std::move(it)), n);
+ assert(result.base().base() == expected);
+
+ if constexpr (std::random_access_iterator<I>) {
+ assert(result.stride_count() <= 1);
+ // we can't say anything about the stride displacement, cause we could be using -= or +=.
+ } else {
+ auto const distance = n < 0 ? -n : n;
+ assert(result.stride_count() == distance);
+ assert(result.stride_displacement() == -n);
+ }
}
-constexpr bool check_iterator_count() {
- constexpr auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- iterator_count_impl(bidirectional_iterator(&range[8]), 6, &range[2]);
- iterator_count_impl(random_access_iterator(&range[7]), 4, &range[3]);
- iterator_count_impl(contiguous_iterator(&range[5]), 5, &range[0]);
+constexpr bool test() {
+ int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ check(bidirectional_iterator(&range[8]), 6, &range[2]);
+ check(random_access_iterator(&range[7]), 4, &range[3]);
+ check(contiguous_iterator(&range[5]), 5, &range[0]);
- iterator_count_impl(bidirectional_iterator(&range[2]), 0, &range[2]);
- iterator_count_impl(random_access_iterator(&range[3]), 0, &range[3]);
- iterator_count_impl(contiguous_iterator(&range[0]), 0, &range[0]);
+ check(bidirectional_iterator(&range[2]), 0, &range[2]);
+ check(random_access_iterator(&range[3]), 0, &range[3]);
+ check(contiguous_iterator(&range[0]), 0, &range[0]);
- iterator_count_impl(bidirectional_iterator(&range[3]), -5, &range[8]);
- iterator_count_impl(random_access_iterator(&range[3]), -3, &range[6]);
- iterator_count_impl(contiguous_iterator(&range[3]), -1, &range[4]);
+ check(bidirectional_iterator(&range[3]), -5, &range[8]);
+ check(random_access_iterator(&range[3]), -3, &range[6]);
+ check(contiguous_iterator(&range[3]), -1, &range[4]);
return true;
}
int main(int, char**) {
- static_assert(check_iterator_count());
- check_iterator_count();
+ static_assert(test());
+ test();
return 0;
}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count_sentinel.pass.cpp
index a93148c4ad5d5..5e1734b572a4e 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count_sentinel.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/iterator_count_sentinel.pass.cpp
@@ -10,42 +10,60 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
-// ranges::prev(iterator, count, sentinel)
+// ranges::prev(it, n, bound)
#include <iterator>
-
-#include <array>
#include <cassert>
-#include "check_round_trip.h"
#include "test_iterators.h"
-template <std::input_or_output_iterator I>
-constexpr void check_iterator_count_sentinel_impl(I first, std::ptr
diff _t const steps, I const last) {
- auto result = std::ranges::prev(stride_counting_iterator(first), steps, stride_counting_iterator(last));
- assert(result == last);
- check_round_trip(result, steps);
+template <std::bidirectional_iterator I>
+constexpr void check(I it, std::ptr
diff _t n, I last) {
+ auto abs = [](auto x) { return x < 0 ? -x : x; };
+
+ {
+ auto result = std::ranges::prev(it, n, last);
+ assert(result == last);
+ }
+
+ // Count the number of operations
+ {
+ stride_counting_iterator strided_it(it), strided_last(last);
+ auto result = std::ranges::prev(strided_it, n, strided_last);
+ assert(result == strided_last);
+ if constexpr (std::random_access_iterator<I>) {
+ if (n == 0 || abs(n) >= abs(last - it)) {
+ assert(result.stride_count() == 0); // uses the assign-from-sentinel codepath
+ } else {
+ assert(result.stride_count() == 1); // uses += exactly once
+ }
+ } else {
+ assert(result.stride_count() == abs(n));
+ assert(result.stride_displacement() == -n);
+ }
+ }
}
-constexpr bool check_iterator_count_sentinel() {
- constexpr auto range = std::array{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
- check_iterator_count_sentinel_impl(bidirectional_iterator(&range[8]), 6, bidirectional_iterator(&range[2]));
- check_iterator_count_sentinel_impl(random_access_iterator(&range[5]), 2, random_access_iterator(&range[3]));
- check_iterator_count_sentinel_impl(contiguous_iterator(&range[5]), 5, contiguous_iterator(&range[0]));
+constexpr bool test() {
+ int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+ check(bidirectional_iterator(&range[8]), 6, bidirectional_iterator(&range[2]));
+ check(random_access_iterator(&range[5]), 2, random_access_iterator(&range[3]));
+ check(contiguous_iterator(&range[5]), 5, contiguous_iterator(&range[0]));
- check_iterator_count_sentinel_impl(bidirectional_iterator(&range[2]), 0, bidirectional_iterator(&range[2]));
- check_iterator_count_sentinel_impl(random_access_iterator(&range[3]), 0, random_access_iterator(&range[3]));
- check_iterator_count_sentinel_impl(contiguous_iterator(&range[0]), 0, contiguous_iterator(&range[0]));
+ check(bidirectional_iterator(&range[2]), 0, bidirectional_iterator(&range[2]));
+ check(random_access_iterator(&range[3]), 0, random_access_iterator(&range[3]));
+ check(contiguous_iterator(&range[0]), 0, contiguous_iterator(&range[0]));
- check_iterator_count_sentinel_impl(bidirectional_iterator(&range[5]), -1, bidirectional_iterator(&range[6]));
- check_iterator_count_sentinel_impl(random_access_iterator(&range[5]), -2, random_access_iterator(&range[7]));
- check_iterator_count_sentinel_impl(contiguous_iterator(&range[5]), -3, contiguous_iterator(&range[8]));
+ check(bidirectional_iterator(&range[5]), -1, bidirectional_iterator(&range[6]));
+ check(random_access_iterator(&range[5]), -2, random_access_iterator(&range[7]));
+ check(contiguous_iterator(&range[5]), -3, contiguous_iterator(&range[8]));
return true;
}
int main(int, char**) {
- static_assert(check_iterator_count_sentinel());
- assert(check_iterator_count_sentinel());
+ static_assert(test());
+ assert(test());
return 0;
}
diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/special_function.compile.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/special_function.compile.pass.cpp
index d14fbb5e01faa..773f98e5c9928 100644
--- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/special_function.compile.pass.cpp
+++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/special_function.compile.pass.cpp
@@ -10,7 +10,7 @@
// UNSUPPORTED: libcpp-no-concepts
// UNSUPPORTED: gcc-10
-// ranges::next
+// ranges::prev
#include <iterator>
diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index 386e34f11ba23..3ab759358336f 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -729,7 +729,7 @@ class stride_counting_iterator {
constexpr explicit stride_counting_iterator(I current) : base_(std::move(current)) {}
- [[nodiscard]] constexpr I const& base() const& requires std::copyable<I> { return base_; }
+ [[nodiscard]] constexpr I const& base() const& { return base_; }
[[nodiscard]] constexpr I base() && { return std::move(base_); }
More information about the libcxx-commits
mailing list