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 index 4a76f0716345..f8da9e7c1e0d 100644 --- 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 @@ -13,67 +13,58 @@ #include -#include #include #include "test_iterators.h" +#include "test_macros.h" -using range_t = std::array; +template +constexpr void check(int* first, std::iter_difference_t n, int* expected) { + using Difference = std::iter_difference_t; + Difference const M = (expected - first); // expected travel distance (which may be negative) + auto abs = [](auto x) { return x < 0 ? -x : x; }; -template -constexpr void check_move_forward(std::ptrdiff_t const n) { - auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - auto first = stride_counting_iterator(It(range.begin())); - std::ranges::advance(first, n); - - assert(first.base().base() == range.begin() + n); - if constexpr (std::random_access_iterator) { - 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); + { + It it(first); + std::ranges::advance(it, n); + assert(base(it) == expected); + ASSERT_SAME_TYPE(decltype(std::ranges::advance(it, n)), void); } -} -template -constexpr void check_move_backward(std::ptrdiff_t const n) { - auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - auto first = stride_counting_iterator(It(range.begin() + n)); - std::ranges::advance(first, -n); - assert(first.base().base() == range.begin()); - - if constexpr (std::random_access_iterator) { - 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); + // Count operations + if constexpr (Count) { + auto it = stride_counting_iterator(It(first)); + std::ranges::advance(it, n); + if constexpr (std::random_access_iterator) { + assert(it.stride_count() <= 1); + } else { + assert(it.stride_count() == abs(M)); + } } } constexpr bool test() { - check_move_forward >(1); - check_move_forward >(2); - check_move_forward >(3); - check_move_forward >(4); - check_move_forward >(5); - check_move_forward >(6); - check_move_forward >(7); + int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - check_move_backward >(4); - check_move_backward >(5); - check_move_backward >(6); + // Check advancing forward + for (int n = 0; n != 10; ++n) { + check>( range, n, range+n); + check>( range, n, range+n); + check>( range, n, range+n); + check>(range, n, range+n); + check>(range, n, range+n); + check>( range, n, range+n); + check( range, n, range+n); + check >( range, n, range+n); + } - // Zero should be checked for each case and each overload - check_move_forward >(0); - check_move_forward >(0); - check_move_forward >(0); - check_move_forward >(0); - check_move_forward >(0); - check_move_forward >(0); - check_move_backward >(0); - check_move_backward >(0); + // Check advancing backward + for (int n = 0; n != 10; ++n) { + check>(range+9, -n, range+9 - n); + check>(range+9, -n, range+9 - n); + check>( range+9, -n, range+9 - n); + check( range+9, -n, range+9 - n); + } return true; } 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 index a3fa81374098..104e912e3c35 100644 --- 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 @@ -13,68 +13,90 @@ #include -#include #include #include +#include +#include #include "test_iterators.h" #include "../types.h" -using range_t = std::array; - -struct expected_t { - range_t::const_iterator coordinate; - std::ptrdiff_t result; -}; - -template -constexpr void check_forward_sized_sentinel(std::ptrdiff_t n, expected_t expected, range_t& range) { +template +constexpr void check_forward(int* first, int* last, std::iter_difference_t n, int* expected) { using Difference = std::iter_difference_t; - auto current = stride_counting_iterator(It(range.begin())); - Difference const result = std::ranges::advance(current, n, distance_apriori_sentinel(range.size())); - assert(current.base().base() == expected.coordinate); - assert(result == expected.result); + Difference const M = (expected - first); // expected travel distance - if constexpr (std::random_access_iterator) { - 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)); + { + It it(first); + auto sent = sentinel_wrapper(It(last)); + std::same_as auto result = std::ranges::advance(it, n, sent); + assert(result == n - M); + assert(base(it) == expected); + } + + // Count operations + if constexpr (Count) { + auto it = stride_counting_iterator(It(first)); + auto sent = sentinel_wrapper(stride_counting_iterator(It(last))); + (void)std::ranges::advance(it, n, sent); + // We don't have a sized sentinel, so we have to increment one-by-one + // regardless of the iterator category. + assert(it.stride_count() == M); + assert(it.stride_displacement() == M); } } -template -constexpr void check_backward_sized_sentinel(std::ptrdiff_t n, expected_t expected, range_t& range) { +template +constexpr void check_forward_sized_sentinel(int* first, int* last, std::iter_difference_t n, int* expected) { using Difference = std::iter_difference_t; - auto current = stride_counting_iterator(It(range.end())); - Difference const result = std::ranges::advance(current, -n, stride_counting_iterator(It(range.begin()))); - assert(current.base().base() == expected.coordinate); - assert(result == expected.result); + Difference const size = (last - first); + Difference const M = (expected - first); // expected travel distance - assert(current.stride_count() == 0 || current.stride_count() == 1); - assert(current.stride_displacement() == current.stride_count()); + { + It it(first); + auto sent = distance_apriori_sentinel(size); + std::same_as auto result = std::ranges::advance(it, n, sent); + assert(result == n - M); + assert(base(it) == expected); + } + + // Count operations + { + auto it = stride_counting_iterator(It(first)); + auto sent = distance_apriori_sentinel(size); + (void)std::ranges::advance(it, n, sent); + if constexpr (std::random_access_iterator) { + assert(it.stride_count() <= 1); + assert(it.stride_displacement() <= 1); + } else { + assert(it.stride_count() == M); + assert(it.stride_displacement() == M); + } + } } -template -constexpr void check_forward(std::ptrdiff_t n, expected_t expected, range_t& range) { +template +constexpr void check_backward(int* first, int* last, std::iter_difference_t n, int* expected) { + static_assert(std::random_access_iterator, "This test doesn't support non random access iterators"); using Difference = std::iter_difference_t; - auto current = stride_counting_iterator(It(range.begin())); - Difference const result = std::ranges::advance(current, n, sentinel_wrapper(It(range.end()))); - assert(current.base().base() == expected.coordinate); - assert(result == expected.result); - assert(current.stride_count() == n - result); -} + Difference const M = (expected - last); // expected travel distance (which is negative) -template -constexpr void check_backward(std::ptrdiff_t n, expected_t expected, range_t& range) { - using Difference = std::iter_difference_t; - auto current = stride_counting_iterator(It(range.end())); - Difference const result = std::ranges::advance(current, -n, stride_counting_iterator(It(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()); + { + It it(last); + It sent(first); + std::same_as auto result = std::ranges::advance(it, n, sent); + assert(result == n - M); + assert(base(it) == expected); + } + + // Count operations + { + auto it = stride_counting_iterator(It(last)); + auto sent = stride_counting_iterator(It(first)); + (void)std::ranges::advance(it, n, sent); + assert(it.stride_count() <= 1); + assert(it.stride_displacement() <= 1); + } } struct iota_iterator { @@ -95,40 +117,42 @@ static_assert(std::bidirectional_iterator); static_assert(std::sized_sentinel_for); constexpr bool test() { - auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - check_forward_sized_sentinel >(1, {range.begin() + 1, 0}, range); - // cpp20_input_iterator not copyable, so is omitted - check_forward_sized_sentinel >(3, {range.begin() + 3, 0}, range); - check_forward_sized_sentinel >(4, {range.begin() + 4, 0}, range); - check_forward_sized_sentinel >(5, {range.begin() + 5, 0}, range); - check_forward_sized_sentinel >(6, {range.begin() + 6, 0}, range); + int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - // bidirectional_iterator omitted because the `n < 0` case requires `same_as` - check_backward_sized_sentinel >(5, {range.begin() + 5, 0}, range); - check_backward_sized_sentinel >(6, {range.begin() + 4, 0}, range); + for (int size = 0; size != 10; ++size) { + for (int n = 0; n != 20; ++n) { - // distance == range.size() - check_forward_sized_sentinel >(10, {range.end(), 0}, range); - check_backward_sized_sentinel >(10, {range.begin(), 0}, range); + { + int* expected = n > size ? range + size : range + n; + check_forward>( range, range+size, n, expected); + check_forward>( range, range+size, n, expected); + check_forward>( range, range+size, n, expected); + check_forward>(range, range+size, n, expected); + check_forward>(range, range+size, n, expected); + check_forward>( range, range+size, n, expected); + check_forward( range, range+size, n, expected); - // distance > range.size() - check_forward_sized_sentinel >(1000, {range.end(), 990}, range); - check_backward_sized_sentinel >(1000, {range.begin(), -990}, range); + check_forward_sized_sentinel>( range, range+size, n, expected); + check_forward_sized_sentinel>( range, range+size, n, expected); + check_forward_sized_sentinel>( range, range+size, n, expected); + check_forward_sized_sentinel>(range, range+size, n, expected); + check_forward_sized_sentinel>(range, range+size, n, expected); + check_forward_sized_sentinel>( range, range+size, n, expected); + check_forward_sized_sentinel( range, range+size, n, expected); + } - check_forward >(1, {range.begin() + 1, 0}, range); - check_forward >(3, {range.begin() + 3, 0}, range); - check_forward >(4, {range.begin() + 4, 0}, range); - check_forward >(5, {range.begin() + 5, 0}, range); - check_forward >(6, {range.begin() + 6, 0}, range); - check_backward >(8, {range.begin() + 2, 0}, range); - - // distance == range.size() - check_forward >(10, {range.end(), 0}, range); - check_backward >(10, {range.begin(), 0}, range); - - // distance > range.size() - check_forward >(1000, {range.end(), 990}, range); - check_backward >(1000, {range.begin(), -990}, range); + { + // Note that we can only test ranges::advance with a negative n for iterators that + // are sized sentinels for themselves, because ranges::advance is UB otherwise. + // In particular, that excludes bidirectional_iterators since those are not sized sentinels. + // TODO: Enable these tests once we fix the bug in ranges::advance + // int* expected = n > size ? range : range + size - n; + // check_backward>(range, range+size, -n, expected); + // check_backward>( range, range+size, -n, expected); + // check_backward( range, range+size, -n, expected); + } + } + } // regression-test that INT_MIN doesn't cause any undefined behavior { 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 index 71ead2f9f962..0760572faccb 100644 --- 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 @@ -13,112 +13,108 @@ #include -#include #include #include -#include "test_iterators.h" #include "../types.h" +#include "test_iterators.h" +#include "test_macros.h" -using range_t = std::array; +template +constexpr void check_assignable(int* first, int* last, int* expected) { + { + It it(first); + auto sent = assignable_sentinel(It(last)); + std::ranges::advance(it, sent); + ASSERT_SAME_TYPE(decltype(std::ranges::advance(it, sent)), void); + assert(base(it) == expected); + } -template -constexpr void check_assignable_case() { - auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + // Count operations + if constexpr (Count) { + auto it = stride_counting_iterator(It(first)); + auto sent = assignable_sentinel(stride_counting_iterator(It(last))); + std::ranges::advance(it, sent); + assert(base(it.base()) == expected); + assert(it.stride_count() == 0); // because we got here by assigning from last, not by incrementing + } +} - for (std::ptrdiff_t n = 0; n != 9; ++n) { - { - It first(range.begin()); - Sent last(It(range.begin() + n)); - std::ranges::advance(first, last); - assert(base(first) == range.begin() + n); - } +template +constexpr void check_sized_sentinel(int* first, int* last, int* expected) { + auto size = (last - first); - // Count operations - if constexpr (std::is_same_v) { - stride_counting_iterator first(It(range.begin())); - stride_counting_iterator last(It(range.begin() + n)); - std::ranges::advance(first, last); - assert(first.base().base() == range.begin() + n); - assert(first.stride_count() == 0); // because we got here by assigning from last, not by incrementing + { + It it(first); + auto sent = distance_apriori_sentinel(size); + std::ranges::advance(it, sent); + ASSERT_SAME_TYPE(decltype(std::ranges::advance(it, sent)), void); + assert(base(it) == expected); + } + + // Count operations + if constexpr (Count) { + auto it = stride_counting_iterator(It(first)); + auto sent = distance_apriori_sentinel(size); + std::ranges::advance(it, sent); + if constexpr (std::random_access_iterator) { + assert(it.stride_count() == 1); + } else { + assert(it.stride_count() == size); } } } -template -constexpr void check_sized_sentinel_case() { - auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; +template +constexpr void check_sentinel(int* first, int* last, int* expected) { + auto size = (last - first); - for (std::ptrdiff_t n = 0; n != 9; ++n) { - { - It first(range.begin()); - distance_apriori_sentinel last(n); - std::ranges::advance(first, last); - assert(base(first) == range.begin() + n); - } - - // Count operations - { - stride_counting_iterator first(It(range.begin())); - distance_apriori_sentinel last(n); - std::ranges::advance(first, last); - - assert(first.base().base() == range.begin() + n); - if constexpr (std::random_access_iterator) { - assert(first.stride_count() == 1); - assert(first.stride_displacement() == 1); - } else { - assert(first.stride_count() == n); - assert(first.stride_displacement() == n); - } - } + { + It it(first); + auto sent = sentinel_wrapper(It(last)); + std::ranges::advance(it, sent); + ASSERT_SAME_TYPE(decltype(std::ranges::advance(it, sent)), void); + assert(base(it) == expected); } -} -template -constexpr void check_sentinel_case() { - auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - - for (std::ptrdiff_t n = 0; n != 9; ++n) { - { - It first(range.begin()); - sentinel_wrapper last(It(range.begin() + n)); - std::ranges::advance(first, last); - assert(base(first) == range.begin() + n); - } - - // Count operations - { - stride_counting_iterator first(It(range.begin())); - sentinel_wrapper last(It(range.begin() + n)); - std::ranges::advance(first, last); - assert(first.base() == last); - assert(first.stride_count() == n); - } + // Count operations + if constexpr (Count) { + auto it = stride_counting_iterator(It(first)); + auto sent = sentinel_wrapper(stride_counting_iterator(It(last))); + std::ranges::advance(it, sent); + assert(it.stride_count() == size); } } constexpr bool test() { - using It = range_t::const_iterator; - check_assignable_case, sentinel_wrapper>>(); - check_assignable_case>(); - check_assignable_case>(); - check_assignable_case>(); - check_assignable_case>(); + int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - check_sized_sentinel_case>(); - check_sized_sentinel_case>(); - check_sized_sentinel_case>(); - check_sized_sentinel_case>(); - check_sized_sentinel_case>(); - check_sized_sentinel_case>(); + for (int n = 0; n != 10; ++n) { + check_assignable>( range, range+n, range+n); + check_assignable>( range, range+n, range+n); + check_assignable>( range, range+n, range+n); + check_assignable>(range, range+n, range+n); + check_assignable>(range, range+n, range+n); + check_assignable>( range, range+n, range+n); + check_assignable( range, range+n, range+n); + + check_sized_sentinel>( range, range+n, range+n); + check_sized_sentinel>( range, range+n, range+n); + check_sized_sentinel>( range, range+n, range+n); + check_sized_sentinel>(range, range+n, range+n); + check_sized_sentinel>(range, range+n, range+n); + check_sized_sentinel>( range, range+n, range+n); + check_sized_sentinel( range, range+n, range+n); + + check_sentinel>( range, range+n, range+n); + check_sentinel>( range, range+n, range+n); + check_sentinel>( range, range+n, range+n); + check_sentinel>(range, range+n, range+n); + check_sentinel>(range, range+n, range+n); + check_sentinel>( range, range+n, range+n); + check_sentinel( range, range+n, range+n); + } - check_sentinel_case>(); - // cpp20_input_iterator not copyable, so is omitted - check_sentinel_case>(); - check_sentinel_case>(); - check_sentinel_case>(); - check_sentinel_case>(); return true; } 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 5c8c0ae84196..972b410cf2f2 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 @@ -12,29 +12,34 @@ // ranges::next(it) #include + #include +#include +#include #include "test_iterators.h" template -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 void check(int* first, int* expected) { + It it(first); + std::same_as auto result = std::ranges::next(std::move(it)); + assert(base(result) == expected); } constexpr bool test() { - check>(); - check>(); - check>(); - check>(); - check>(); - check>(); - check>(); + int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + for (int n = 0; n != 9; ++n) { + check>( range+n, range+n+1); + check>( range+n, range+n+1); + check>( range+n, range+n+1); + check>(range+n, range+n+1); + check>(range+n, range+n+1); + check>( range+n, range+n+1); + check>( range+n, range+n+1); + check( range+n, range+n+1); + } + return true; } 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 447d3a9d3d45..0bc400dde1b4 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 @@ -14,55 +14,41 @@ #include #include +#include #include #include "test_iterators.h" -template -constexpr void check_steps(It it, std::ptrdiff_t n, int const* expected) { - { - It result = std::ranges::next(std::move(it), n); - assert(&*result == expected); - } - - // Count the number of operations - { - stride_counting_iterator strided_it(std::move(it)); - stride_counting_iterator result = std::ranges::next(std::move(strided_it), n); - assert(&*result == expected); - if constexpr (std::random_access_iterator) { - 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); - } - } +template +constexpr void check(int* first, std::iter_difference_t n, int* expected) { + It it(first); + std::same_as auto result = std::ranges::next(std::move(it), n); + assert(base(result) == expected); } 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 next() forward + for (int n = 0; n != 10; ++n) { + check>( range, n, range+n); + check>( range, n, range+n); + check>( range, n, range+n); + check>(range, n, range+n); + check>(range, n, range+n); + check>( range, n, range+n); + check( range, n, range+n); + check >( range, n, range+n); + } - 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 next() backward + for (int n = 0; n != 10; ++n) { + check>(range+9, -n, range+9 - n); + check>(range+9, -n, range+9 - n); + check>( range+9, -n, range+9 - n); + check( range+9, -n, range+9 - n); + } - 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; } 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 3c0e9d89ea64..5cfbbf3c5a15 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 @@ -12,56 +12,38 @@ // ranges::next(it, n, bound) #include + #include -#include +#include +#include #include "test_iterators.h" -template -constexpr void check(It it, std::ptrdiff_t n, Sent last) { - { - It result = std::ranges::next(it, n, last); - assert(result == last); - } +template +constexpr void check(int* first, int* last, std::iter_difference_t n, int* expected) { + It it(first); + auto sent = sentinel_wrapper(It(last)); - // Count the number of operations - if constexpr (std::is_same_v) { - stride_counting_iterator strided_it(it); - stride_counting_iterator strided_last(last); - stride_counting_iterator result = std::ranges::next(strided_it, n, strided_last); - assert(result == strided_last); - if constexpr (std::random_access_iterator) { - 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 { - std::ptrdiff_t const abs_n = n < 0 ? -n : n; - assert(result.stride_count() == abs_n); - assert(result.stride_displacement() == n); - } - } + std::same_as auto result = std::ranges::next(std::move(it), n, sent); + assert(base(result) == expected); } constexpr bool test() { int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - check(cpp17_input_iterator(&range[0]), 1, sentinel_wrapper(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])); + for (int size = 0; size != 10; ++size) { + for (int n = 0; n != 20; ++n) { + int* expected = n > size ? range + size : range + n; + check>( range, range+size, n, expected); + check>( range, range+size, n, expected); + check>( range, range+size, n, expected); + check>(range, range+size, n, expected); + check>(range, range+size, n, expected); + check>( range, range+size, n, expected); + check( range, range+size, n, expected); + } + } - check(cpp17_input_iterator(&range[0]), 0, sentinel_wrapper(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; } 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 950fd77401a7..633a6bd7b6de 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 @@ -13,101 +13,68 @@ #include -#include #include +#include #include -#include "test_iterators.h" #include "../types.h" +#include "test_iterators.h" -using range_t = std::array; - -template -constexpr void check_assignable(int* it, int* last, int const* expected) { - { - It result = std::ranges::next(It(it), assignable_sentinel(It(last))); - assert(base(result) == expected); - } - - // Count operations - if constexpr (Count) { - auto strided_it = stride_counting_iterator(It(it)); - auto strided_last = assignable_sentinel(stride_counting_iterator(It(last))); - stride_counting_iterator result = std::ranges::next(std::move(strided_it), std::move(strided_last)); - assert(base(result.base()) == expected); - assert(result.stride_count() == 0); // because we got here by assigning from last, not by incrementing - } +template +constexpr void check_assignable(int* first, int* last, int* expected) { + It it(first); + auto sent = assignable_sentinel(It(last)); + It result = std::ranges::next(std::move(it), sent); + assert(base(result) == expected); } template -constexpr void check_sized_sentinel(int* it, int* last, int const* expected) { - auto n = (last - it); +constexpr void check_sized_sentinel(int* first, int* last, int* expected) { + auto size = (last - first); - { - auto sent = distance_apriori_sentinel(n); - auto result = std::ranges::next(It(it), sent); - assert(base(result) == expected); - } - - // Count operations - { - auto strided_it = stride_counting_iterator(It(it)); - auto sent = distance_apriori_sentinel(n); - auto result = std::ranges::next(std::move(strided_it), sent); - assert(base(result.base()) == expected); - - if constexpr (std::random_access_iterator) { - 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); - } - } + It it(first); + auto sent = distance_apriori_sentinel(size); + std::same_as auto result = std::ranges::next(std::move(it), sent); + assert(base(result) == expected); } -template -constexpr void check_sentinel(int* it, int* last, int const* expected) { - auto n = (last - it); - - { - auto sent = sentinel_wrapper(It(last)); - It result = std::ranges::next(It(it), sent); - assert(base(result) == expected); - } - - // Count operations - if constexpr (Count) { - auto strided_it = stride_counting_iterator(It(it)); - auto sent = sentinel_wrapper(stride_counting_iterator(It(last))); - stride_counting_iterator result = std::ranges::next(std::move(strided_it), sent); - assert(base(result.base()) == expected); - assert(result.stride_count() == n); // must have used ++ until it hit the sentinel - } +template +constexpr void check_sentinel(int* first, int* last, int* expected) { + It it(first); + auto sent = sentinel_wrapper(It(last)); + std::same_as auto result = std::ranges::next(std::move(it), sent); + assert(base(result) == expected); } constexpr bool test() { int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - check_assignable>( &range[0], &range[2], &range[2]); - check_assignable>( &range[0], &range[3], &range[3]); - check_assignable>(&range[0], &range[4], &range[4]); - check_assignable>(&range[0], &range[5], &range[5]); - check_assignable>( &range[0], &range[6], &range[6]); + for (int n = 0; n != 10; ++n) { + check_assignable>( range, range+n, range+n); + check_assignable>( range, range+n, range+n); + check_assignable>( range, range+n, range+n); + check_assignable>(range, range+n, range+n); + check_assignable>(range, range+n, range+n); + check_assignable>( range, range+n, range+n); + check_assignable( range, range+n, range+n); - check_sized_sentinel>( &range[0], &range[7], &range[7]); - check_sized_sentinel>( &range[0], &range[6], &range[6]); - check_sized_sentinel>( &range[0], &range[5], &range[5]); - check_sized_sentinel>(&range[0], &range[4], &range[4]); - check_sized_sentinel>(&range[0], &range[3], &range[3]); - check_sized_sentinel>( &range[0], &range[2], &range[2]); + check_sized_sentinel>( range, range+n, range+n); + check_sized_sentinel>( range, range+n, range+n); + check_sized_sentinel>( range, range+n, range+n); + check_sized_sentinel>(range, range+n, range+n); + check_sized_sentinel>(range, range+n, range+n); + check_sized_sentinel>( range, range+n, range+n); + check_sized_sentinel( range, range+n, range+n); + + check_sentinel>( range, range+n, range+n); + check_sentinel>( range, range+n, range+n); + check_sentinel>( range, range+n, range+n); + check_sentinel>(range, range+n, range+n); + check_sentinel>(range, range+n, range+n); + check_sentinel>( range, range+n, range+n); + check_sentinel( range, range+n, range+n); + } - check_sentinel>( &range[0], &range[1], &range[1]); - // cpp20_input_iterator not copyable, so is omitted - check_sentinel>( &range[0], &range[3], &range[3]); - check_sentinel>(&range[0], &range[4], &range[4]); - check_sentinel>(&range[0], &range[5], &range[5]); - check_sentinel>( &range[0], &range[6], &range[6]); return true; } 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 c7d1d8be2c5b..334b674adeb7 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 @@ -17,23 +17,26 @@ #include "test_iterators.h" template -constexpr void check() { - int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; - assert(std::ranges::prev(It(&range[1])) == It(&range[0])); - 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])); - assert(std::ranges::prev(It(&range[10])) == It(&range[9])); +constexpr void check(int* first, int* expected) { + It it(first); + std::same_as auto result = std::ranges::prev(std::move(it)); + assert(base(result) == expected); } constexpr bool test() { - check>(); - check>(); - check>(); - check(); + int range[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + for (int n = 1; n != 10; ++n) { + check>(range+n, range+n-1); + check>(range+n, range+n-1); + check>( range+n, range+n-1); + check( range+n, range+n-1); + } + return true; } + int main(int, char**) { test(); static_assert(test()); 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 cb6d2aac2c07..2a4cee39fdbc 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 @@ -12,40 +12,39 @@ // ranges::prev(it, n) #include + #include +#include #include #include "test_iterators.h" -template -constexpr void check(It it, std::ptrdiff_t n, int const* expected) { - stride_counting_iterator result = std::ranges::prev(stride_counting_iterator(std::move(it)), n); - assert(result.base().base() == expected); - - if constexpr (std::random_access_iterator) { - assert(result.stride_count() <= 1); - // we can't say anything about the stride displacement, cause we could be using -= or +=. - } else { - std::ptrdiff_t const abs_n = n < 0 ? -n : n; - assert(result.stride_count() == abs_n); - assert(result.stride_displacement() == -n); - } +template +constexpr void check(int* first, std::iter_difference_t n, int* expected) { + It it(first); + std::same_as auto result = std::ranges::prev(std::move(it), n); + assert(base(result) == expected); } 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]); + // Check prev() forward + for (int n = 0; n != 10; ++n) { + check>(range+n, n, range); + check>(range+n, n, range); + check>( range+n, n, range); + check( range+n, n, range); + } - 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]); + // Check prev() backward + for (int n = 0; n != 10; ++n) { + check>(range, -n, range+n); + check>(range, -n, range+n); + check>( range, -n, range+n); + check( range, -n, range+n); + } - 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; } 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 1ca6b6f4eddb..d998f0ddb90c 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 @@ -12,52 +12,38 @@ // ranges::prev(it, n, bound) #include + #include +#include +#include #include "test_iterators.h" -template -constexpr void check(It it, std::ptrdiff_t n, It last) { - auto abs = [](auto x) { return x < 0 ? -x : x; }; +template +constexpr void check(int* first, int* last, std::iter_difference_t n, int* expected) { + It it(last); + It sent(first); // for std::ranges::prev, the sentinel *must* have the same type as the iterator - { - It result = std::ranges::prev(it, n, last); - assert(result == last); - } - - // Count the number of operations - { - stride_counting_iterator strided_it(it); - stride_counting_iterator strided_last(last); - stride_counting_iterator result = std::ranges::prev(strided_it, n, strided_last); - assert(result == strided_last); - if constexpr (std::random_access_iterator) { - 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); - } - } + std::same_as auto result = std::ranges::prev(std::move(it), n, std::move(sent)); + assert(base(result) == expected); } +// TODO: Re-enable once we fix the bug in ranges::advance constexpr bool test() { +#if 0 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])); + for (int size = 0; size != 10; ++size) { + for (int n = 0; n != 20; ++n) { + int* expected = n > size ? range : range + size - n; + check>(range, range+size, n, expected); + check>(range, range+size, n, expected); + check>( range, range+size, n, expected); + check( range, range+size, n, expected); + } + } +#endif - 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[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; } diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/types.h b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/types.h index 71704c973451..433731e5dd68 100644 --- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/types.h +++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/types.h @@ -14,6 +14,8 @@ #include #include +#include "test_iterators.h" // for the fallthrough base() function + class distance_apriori_sentinel { public: distance_apriori_sentinel() = default;