Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement (chunk_view<forward>|stride_view)::iterator::operator(\+=|-=) in O(1) #3023

Merged
merged 3 commits into from
Aug 12, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 36 additions & 23 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -5566,35 +5566,35 @@ namespace ranges {
requires random_access_range<_Base> {
if (_Off > 0) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off == 1 || _Count <= (numeric_limits<difference_type>::max)() / (_Off - 1),
_STL_VERIFY(_Count <= (numeric_limits<difference_type>::max)() / _Off,
"cannot advance chunk_view iterator past end (integer overflow)");
_STL_VERIFY(_RANGES distance(_Current, _End) > _Count * (_Off - 1),
"cannot advance chunk_view iterator past end");
if constexpr (sized_sentinel_for<_Base_sentinel, _Base_iterator>) {
_STL_VERIFY(_RANGES distance(_Current, _End) > _Count * (_Off - 1),
StephanTLavavej marked this conversation as resolved.
Show resolved Hide resolved
"cannot advance chunk_view iterator past end");
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Missing = _RANGES advance(_Current, _Count * _Off, _End);

// Per to-be-filed LWG issue (See GH-2995)
if constexpr (sized_sentinel_for<_Base_sentinel, _Base_iterator>) {
_Missing = _RANGES advance(_Current, _Count * _Off, _End);
} else {
_Current += static_cast<difference_type>(_Count * (_Off - 1));
_Missing = _RANGES advance(_Current, _Count, _End);
}
} else if (_Off < 0) {
_RANGES advance(_Current, _Count * _Off + _Missing);
_Current += static_cast<difference_type>(_Count * _Off + _Missing);
_Missing = 0;
}
return *this;
}

constexpr _Iterator& operator-=(const difference_type _Raw_off) /* not strengthened, see _RANGES advance */
constexpr _Iterator& operator-=(const difference_type _Off) /* not strengthened, see _RANGES advance */
requires random_access_range<_Base> {
const difference_type _Off = -_Raw_off;
if (_Off > 0) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off == 1 || _Count <= (numeric_limits<difference_type>::max)() / (_Off - 1),
"cannot advance chunk_view iterator past end (integer overflow)");
_STL_VERIFY(_RANGES distance(_Current, _End) > _Count * (_Off - 1),
"cannot advance chunk_view iterator past end");
_STL_VERIFY(_Off != (numeric_limits<difference_type>::min)(),
"cannot advance chunk_view iterator past end (integer overflow)");
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Missing = _RANGES advance(_Current, _Count * _Off, _End);
} else if (_Off < 0) {
_RANGES advance(_Current, _Count * _Off + _Missing);
_Missing = 0;
}
return *this;
return *this += -_Off;
}

_NODISCARD constexpr value_type operator[](const difference_type _Off) const
Expand Down Expand Up @@ -6470,20 +6470,33 @@ namespace ranges {
constexpr _Iterator& operator+=(const difference_type _Off) requires random_access_range<_Base> {
if (_Off > 0) {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off == 1 || _Stride <= (numeric_limits<difference_type>::max)() / (_Off - 1),
_STL_VERIFY(_Stride <= (numeric_limits<difference_type>::max)() / _Off,
"cannot advance stride_view iterator past end (integer overflow)");
_STL_VERIFY(_RANGES distance(_Current, _End) > _Stride * (_Off - 1),
"cannot advance stride_view iterator past end");
if constexpr (sized_sentinel_for<_Base_sentinel, _Base_iterator>) {
_STL_VERIFY(_RANGES distance(_Current, _End) > _Stride * (_Off - 1),
"cannot advance stride_view iterator past end");
}
#endif // _ITERATOR_DEBUG_LEVEL != 0
_Missing = _RANGES advance(_Current, _Stride * _Off, _End);

// Per to-be-filed LWG issue (See GH-2995)
if constexpr (sized_sentinel_for<_Base_sentinel, _Base_iterator>) {
_Missing = _RANGES advance(_Current, _Stride * _Off, _End);
} else {
_Current += static_cast<difference_type>(_Stride * (_Off - 1));
_Missing = _RANGES advance(_Current, _Stride, _End);
}
} else if (_Off < 0) {
_RANGES advance(_Current, _Stride * _Off + _Missing);
_Current += static_cast<difference_type>(_Stride * _Off + _Missing);
_Missing = 0;
}
return *this;
}

constexpr _Iterator& operator-=(const difference_type _Off) requires random_access_range<_Base> {
#if _ITERATOR_DEBUG_LEVEL != 0
_STL_VERIFY(_Off != (numeric_limits<difference_type>::min)(),
"cannot advance stride_view iterator past end (integer overflow)");
#endif // _ITERATOR_DEBUG_LEVEL != 0
return *this += -_Off;
}

Expand Down
7 changes: 7 additions & 0 deletions tests/std/tests/P1899R3_views_stride_death/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ void test_iterator_advance_past_end_with_integer_overflow() {
it += (numeric_limits<ptrdiff_t>::max)() / 2; // cannot advance stride_view iterator past end (integer overflow)
}

void test_iterator_advance_negative_min() {
auto v = ranges::stride_view(some_ints, 3);
auto it = v.begin();
it -= (numeric_limits<ptrdiff_t>::min)(); // cannot advance stride_view iterator past end (integer overflow)
}

int main(int argc, char* argv[]) {
std_testing::death_test_executive exec;

Expand All @@ -58,6 +64,7 @@ int main(int argc, char* argv[]) {
test_iterator_postincrement_past_end,
test_iterator_advance_past_end,
test_iterator_advance_past_end_with_integer_overflow,
test_iterator_advance_negative_min,
});
#else // ^^^ test everything / test only _CONTAINER_DEBUG_LEVEL case vvv
exec.add_death_tests({
Expand Down
21 changes: 21 additions & 0 deletions tests/std/tests/P2442R1_views_chunk_death/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,24 @@ void test_inner_iterator_dereference_at_end() {
(void) *it; // cannot dereference chunk_view end iterator
}

void test_fwd_iterator_advance_past_end() {
auto v = chunk_view{span{some_ints}, 2};
auto it = v.begin();
it += 5; // cannot advance chunk_view iterator past end
}

void test_fwd_iterator_advance_past_end_with_integer_overflow() {
auto v = chunk_view{span{some_ints}, 2};
auto it = v.begin();
it += (numeric_limits<ptrdiff_t>::max)() / 2; // cannot advance chunk_view iterator past end (integer overflow)
}

void test_fwd_iterator_advance_negative_min() {
auto v = chunk_view{span{some_ints}, 2};
auto it = v.begin();
it -= (numeric_limits<ptrdiff_t>::min)(); // cannot advance chunk_view iterator past end (integer overflow)
}

int main(int argc, char* argv[]) {
std_testing::death_test_executive exec;

Expand All @@ -88,6 +106,9 @@ int main(int argc, char* argv[]) {
test_inner_iterator_postincrement_past_end,
test_outer_iterator_dereference_at_end,
test_inner_iterator_dereference_at_end,
test_fwd_iterator_advance_past_end,
test_fwd_iterator_advance_past_end_with_integer_overflow,
test_fwd_iterator_advance_negative_min,
});
#else // ^^^ test everything / test only _CONTAINER_DEBUG_LEVEL cases vvv
exec.add_death_tests({
Expand Down