Skip to content

Commit 8a2459d

Browse files
committed
add tests
1 parent 1f82b8f commit 8a2459d

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ constexpr void check_forward(int* first, int* last, std::iter_difference_t<It> n
4242
// regardless of the iterator category.
4343
assert(it.stride_count() == M);
4444
assert(it.stride_displacement() == M);
45+
if (n == 0) {
46+
assert(it.equals_count() == 0);
47+
} else {
48+
assert(it.equals_count() > 0);
49+
assert(it.equals_count() == M || it.equals_count() == M + 1);
50+
assert(it.equals_count() <= n);
51+
}
4552
}
4653
}
4754

@@ -95,6 +102,7 @@ constexpr void check_backward(int* first, int* last, std::iter_difference_t<It>
95102
(void)std::ranges::advance(it, n, sent);
96103
assert(it.stride_count() <= 1);
97104
assert(it.stride_displacement() <= 1);
105+
assert(it.equals_count() == 0);
98106
}
99107
}
100108

@@ -213,6 +221,20 @@ constexpr bool test() {
213221
assert(i == iota_iterator{INT_MIN+1});
214222
}
215223

224+
// Check that we don't do an unneeded bounds check when decrementing a
225+
// `bidirectional_iterator` that doesn't model `sized_sentinel_for`.
226+
{
227+
static_assert(std::bidirectional_iterator<bidirectional_iterator<iota_iterator>>);
228+
static_assert(!std::sized_sentinel_for<bidirectional_iterator<iota_iterator>,
229+
bidirectional_iterator<iota_iterator>>);
230+
231+
auto it = stride_counting_iterator(bidirectional_iterator(iota_iterator{+1}));
232+
auto sent = stride_counting_iterator(bidirectional_iterator(iota_iterator{-2}));
233+
assert(std::ranges::advance(it, -3, sent) == 0);
234+
assert(base(base(it)) == iota_iterator{-2});
235+
assert(it.equals_count() == 3);
236+
}
237+
216238
return true;
217239
}
218240

libcxx/test/support/test_iterators.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -725,11 +725,14 @@ struct common_input_iterator {
725725
# endif // TEST_STD_VER >= 20
726726

727727
// Iterator adaptor that counts the number of times the iterator has had a successor/predecessor
728-
// operation called. Has two recorders:
728+
// operation or an equality comparison operation called. Has three recorders:
729729
// * `stride_count`, which records the total number of calls to an op++, op--, op+=, or op-=.
730730
// * `stride_displacement`, which records the displacement of the calls. This means that both
731731
// op++/op+= will increase the displacement counter by 1, and op--/op-= will decrease the
732732
// displacement counter by 1.
733+
// * `equals_count`, which records the total number of calls to an op== or op!=. If compared
734+
// against a sentinel object, that sentinel object must call the `record_equality_comparison`
735+
// function so that the comparison is counted correctly.
733736
template <class It>
734737
class stride_counting_iterator {
735738
public:
@@ -754,6 +757,8 @@ class stride_counting_iterator {
754757

755758
constexpr difference_type stride_displacement() const { return stride_displacement_; }
756759

760+
constexpr difference_type equals_count() const { return equals_count_; }
761+
757762
constexpr decltype(auto) operator*() const { return *It(base_); }
758763

759764
constexpr decltype(auto) operator[](difference_type n) const { return It(base_)[n]; }
@@ -838,9 +843,15 @@ class stride_counting_iterator {
838843
return base(x) - base(y);
839844
}
840845

846+
constexpr void record_equality_comparison() const
847+
{
848+
++equals_count_;
849+
}
850+
841851
constexpr bool operator==(stride_counting_iterator const& other) const
842852
requires std::sentinel_for<It, It>
843853
{
854+
record_equality_comparison();
844855
return It(base_) == It(other.base_);
845856
}
846857

@@ -875,6 +886,7 @@ class stride_counting_iterator {
875886
decltype(base(std::declval<It>())) base_;
876887
difference_type stride_count_ = 0;
877888
difference_type stride_displacement_ = 0;
889+
mutable difference_type equals_count_ = 0;
878890
};
879891
template <class It>
880892
stride_counting_iterator(It) -> stride_counting_iterator<It>;
@@ -887,7 +899,14 @@ class sentinel_wrapper {
887899
public:
888900
explicit sentinel_wrapper() = default;
889901
constexpr explicit sentinel_wrapper(const It& it) : base_(base(it)) {}
890-
constexpr bool operator==(const It& other) const { return base_ == base(other); }
902+
constexpr bool operator==(const It& other) const {
903+
// If supported, record statistics about the equality operator call
904+
// inside `other`.
905+
if constexpr (requires { other.record_equality_comparison(); }) {
906+
other.record_equality_comparison();
907+
}
908+
return base_ == base(other);
909+
}
891910
friend constexpr It base(const sentinel_wrapper& s) { return It(s.base_); }
892911
private:
893912
decltype(base(std::declval<It>())) base_;

0 commit comments

Comments
 (0)