Skip to content

Commit 61c0029

Browse files
committed
adapt 'check_backward' test so that it can test bidirectional iterators as well
1 parent 2a3ea3b commit 61c0029

File tree

1 file changed

+37
-22
lines changed

1 file changed

+37
-22
lines changed

libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ constexpr void check_forward_sized_sentinel(int* first, int* last, std::iter_dif
8888

8989
template <typename It>
9090
constexpr void check_backward(int* first, int* last, std::iter_difference_t<It> n, int* expected) {
91-
static_assert(std::random_access_iterator<It>, "This test doesn't support non random access iterators");
91+
// Check preconditions for `advance` when called with negative `n`:
92+
// <https://eel.is/c++draft/iterators#range.iter.op.advance-5>
93+
assert(n < 0);
94+
static_assert(std::bidirectional_iterator<It>);
95+
9296
using Difference = std::iter_difference_t<It>;
9397
Difference const M = (expected - last); // expected travel distance (which is negative)
9498

@@ -104,10 +108,34 @@ constexpr void check_backward(int* first, int* last, std::iter_difference_t<It>
104108
{
105109
auto it = stride_counting_iterator(It(last));
106110
auto sent = stride_counting_iterator(It(first));
111+
static_assert(std::bidirectional_iterator<stride_counting_iterator<It>>);
112+
107113
(void)std::ranges::advance(it, n, sent);
108-
assert(it.stride_count() <= 1);
109-
assert(it.stride_displacement() <= 1);
110-
assert(it.equals_count() == 0);
114+
115+
if constexpr (std::sized_sentinel_for<It, It>) {
116+
if (expected == first) {
117+
// In this case, the algorithm can just do `it = std::move(sent);`
118+
// instead of doing iterator arithmetic:
119+
// <https://eel.is/c++draft/iterators#range.iter.op.advance-4.1>
120+
assert(it.stride_count() == 0);
121+
assert(it.stride_displacement() == 0);
122+
} else {
123+
assert(it.stride_count() == 1);
124+
assert(it.stride_displacement() == 1);
125+
}
126+
assert(it.equals_count() == 0);
127+
} else {
128+
assert(it.stride_count() == -M);
129+
assert(it.stride_displacement() == M);
130+
if (-n > -M) {
131+
// We "hit" the bound, so there is one extra equality check.
132+
assert(it.equals_count() == -M + 1);
133+
} else {
134+
assert(it.equals_count() == -M);
135+
}
136+
// In any case, there must not be more than `-n` bounds checks.
137+
assert(it.equals_count() <= -n);
138+
}
111139
}
112140
}
113141

@@ -201,11 +229,12 @@ constexpr bool test() {
201229
check_forward_sized_sentinel<int*>( range, range+size, n, expected);
202230
}
203231

204-
{
205-
// Note that we can only test ranges::advance with a negative n for iterators that
206-
// are sized sentinels for themselves, because ranges::advance is UB otherwise.
207-
// In particular, that excludes bidirectional_iterators since those are not sized sentinels.
232+
// Exclude the `n == 0` case for the backwards checks.
233+
// Input and forward iterators are not tested as the backwards case does
234+
// not apply for them.
235+
if (n > 0) {
208236
int* expected = n > size ? range : range + size - n;
237+
check_backward<bidirectional_iterator<int*>>(range, range+size, -n, expected);
209238
check_backward<random_access_iterator<int*>>(range, range+size, -n, expected);
210239
check_backward<contiguous_iterator<int*>>( range, range+size, -n, expected);
211240
check_backward<int*>( range, range+size, -n, expected);
@@ -226,20 +255,6 @@ constexpr bool test() {
226255
assert(i == iota_iterator{INT_MIN+1});
227256
}
228257

229-
// Check that we don't do an unneeded bounds check when decrementing a
230-
// `bidirectional_iterator` that doesn't model `sized_sentinel_for`.
231-
{
232-
static_assert(std::bidirectional_iterator<bidirectional_iterator<iota_iterator>>);
233-
static_assert(
234-
!std::sized_sentinel_for<bidirectional_iterator<iota_iterator>, bidirectional_iterator<iota_iterator>>);
235-
236-
auto it = stride_counting_iterator(bidirectional_iterator(iota_iterator{+1}));
237-
auto sent = stride_counting_iterator(bidirectional_iterator(iota_iterator{-2}));
238-
assert(std::ranges::advance(it, -3, sent) == 0);
239-
assert(base(base(it)) == iota_iterator{-2});
240-
assert(it.equals_count() == 3);
241-
}
242-
243258
return true;
244259
}
245260

0 commit comments

Comments
 (0)