Skip to content

Commit

Permalink
<ranges>: Consistently check preconditions for iota_view and `_Co…
Browse files Browse the repository at this point in the history
…unted_fn` (#4616)
  • Loading branch information
frederick-vs-ja committed Apr 26, 2024
1 parent 4ab1364 commit bf1e9bd
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 8 deletions.
29 changes: 21 additions & 8 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -1381,24 +1381,35 @@ namespace ranges {
constexpr explicit iota_view(_Wi _Value_) noexcept(
is_nothrow_move_constructible_v<_Wi> && is_nothrow_default_constructible_v<_Bo>) // strengthened
: _Value(_STD move(_Value_)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (totally_ordered_with<_Wi, _Bo>) {
_STL_ASSERT(_Value_ <= _Bound, "Per N4950 [range.iota.view]/6, the first argument must not exceed the "
_STL_VERIFY(_Value_ <= _Bound, "Per N4981 [range.iota.view]/6, the first argument must not exceed the "
"value-initialized bound when their types are totally ordered.");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}

constexpr explicit iota_view(type_identity_t<_Wi> _Value_, type_identity_t<_Bo> _Bound_) noexcept(
is_nothrow_move_constructible_v<_Wi> && is_nothrow_move_constructible_v<_Bo>) // strengthened
: _Value(_STD move(_Value_)), _Bound(_STD move(_Bound_)) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (totally_ordered_with<_Wi, _Bo>) {
_STL_ASSERT(_Value_ <= _Bound_, "Per N4950 [range.iota.view]/8, the first argument must not exceed the "
_STL_VERIFY(_Value_ <= _Bound_, "Per N4981 [range.iota.view]/8, the first argument must not exceed the "
"second when their types are totally ordered.");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}

constexpr explicit iota_view(_It _First, _Se _Last) noexcept(
is_nothrow_move_constructible_v<_Wi> && is_nothrow_move_constructible_v<_Bo>) // strengthened
: _Value(_STD move(_First._Current)), _Bound(_STD move(_Bound_from(_Last))) {}
: _Value(_STD move(_First._Current)), _Bound(_STD move(_Bound_from(_Last))) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (totally_ordered_with<_Wi, _Bo>) {
_STL_VERIFY(_Value <= _Bound, "Per N4981 [range.iota.view]/8 and /10, the iterator must not exceed the "
"sentinel when their types are totally ordered.");
}
#endif // _CONTAINER_DEBUG_LEVEL > 0
}

_NODISCARD constexpr _It begin() const noexcept(is_nothrow_copy_constructible_v<_Wi>) /* strengthened */ {
return _It{_Value};
Expand Down Expand Up @@ -1524,7 +1535,7 @@ namespace ranges {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Current < (numeric_limits<_Index_type>::max)(),
"cannot increment repeat_view iterator past end (integer overflow)");
#endif
#endif // _CONTAINER_DEBUG_LEVEL > 0
++_Current;
return *this;
}
Expand Down Expand Up @@ -1655,7 +1666,7 @@ namespace ranges {
if constexpr (_Signed_integer_like<_Bo>) {
_STL_VERIFY(_Bound >= 0, "Bound must be >= 0");
}
#endif
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
_NODISCARD_CTOR constexpr explicit repeat_view(_Ty&& _Value_, _Bo _Bound_ = _Bo{}) noexcept(
is_nothrow_move_constructible_v<_Ty>) // strengthened
Expand All @@ -1664,7 +1675,7 @@ namespace ranges {
if constexpr (_Signed_integer_like<_Bo>) {
_STL_VERIFY(_Bound >= 0, "Bound must be >= 0");
}
#endif
#endif // _CONTAINER_DEBUG_LEVEL > 0
}
template <class... _TArgs, class... _BArgs>
requires constructible_from<_Ty, _TArgs...> && constructible_from<_Bo, _BArgs...>
Expand All @@ -1676,7 +1687,7 @@ namespace ranges {
if constexpr (_Signed_integer_like<_Bo>) {
_STL_VERIFY(_Bound >= 0, "Bound must be >= 0");
}
#endif
#endif // _CONTAINER_DEBUG_LEVEL > 0
}

_NODISCARD constexpr _Iterator begin() const noexcept /* strengthened */ {
Expand Down Expand Up @@ -5251,7 +5262,9 @@ namespace ranges {
requires (input_or_output_iterator<decay_t<_It>> && _Choice<_It>._Strategy != _St::_None)
_NODISCARD _STATIC_CALL_OPERATOR constexpr auto operator()(_It&& _First,
const iter_difference_t<decay_t<_It>> _Count) _CONST_CALL_OPERATOR noexcept(_Choice<_It>._No_throw) {
_STL_ASSERT(_Count >= 0, "The size passed to views::counted must be non-negative");
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Count >= 0, "The size passed to views::counted must be non-negative");
#endif // _CONTAINER_DEBUG_LEVEL > 0
constexpr _St _Strat = _Choice<_It>._Strategy;

if constexpr (_Strat == _St::_Span) {
Expand Down
49 changes: 49 additions & 0 deletions tests/std/tests/P0896R4_views_iota_death/test.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#define _CONTAINER_DEBUG_LEVEL 1

#include <ranges>
#include <vector>

Expand All @@ -12,6 +14,12 @@ void test_misordered_start_bound_int() {
ranges::iota_view{I{42}, I{1}};
}

template <class I>
void test_misordered_iterator_sentinel_int() {
ranges::iota_view iv{I{1}, I{42}};
decltype(iv){iv.end(), iv.begin()};
}

template <class UI>
void test_misordered_start_bound_uint_value_init() {
ranges::iota_view<UI, UI>{UI{42}};
Expand All @@ -23,12 +31,26 @@ void test_misordered_start_bound_ptr() {
ranges::iota_view{arr + 1, arr + 0};
}

template <class T>
void test_misordered_iterator_sentinel_ptr() {
T arr[1]{};
ranges::iota_view iv{arr + 0, arr + 1};
decltype(iv){iv.end(), iv.begin()};
}

template <class T>
void test_misordered_start_bound_vector_iter() {
vector<T> vec(1);
ranges::iota_view{vec.end(), vec.begin()};
}

template <class T>
void test_misordered_iterator_sentinel_vector_iter() {
vector<T> vec(1);
ranges::iota_view iv{vec.begin(), vec.end()};
decltype(iv){iv.end(), iv.begin()};
}

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

Expand All @@ -55,6 +77,25 @@ int main(int argc, char* argv[]) {
test_misordered_start_bound_int<char32_t>,
test_misordered_start_bound_int<wchar_t>,

test_misordered_iterator_sentinel_int<signed char>,
test_misordered_iterator_sentinel_int<unsigned char>,
test_misordered_iterator_sentinel_int<short>,
test_misordered_iterator_sentinel_int<unsigned short>,
test_misordered_iterator_sentinel_int<int>,
test_misordered_iterator_sentinel_int<unsigned int>,
test_misordered_iterator_sentinel_int<long>,
test_misordered_iterator_sentinel_int<unsigned long>,
test_misordered_iterator_sentinel_int<long long>,
test_misordered_iterator_sentinel_int<unsigned long long>,

test_misordered_iterator_sentinel_int<char>,
#ifdef __cpp_char8_t
test_misordered_iterator_sentinel_int<char8_t>,
#endif // __cpp_char8_t
test_misordered_iterator_sentinel_int<char16_t>,
test_misordered_iterator_sentinel_int<char32_t>,
test_misordered_iterator_sentinel_int<wchar_t>,

test_misordered_start_bound_uint_value_init<unsigned char>,
test_misordered_start_bound_uint_value_init<unsigned short>,
test_misordered_start_bound_uint_value_init<unsigned int>,
Expand All @@ -74,6 +115,14 @@ int main(int argc, char* argv[]) {
test_misordered_start_bound_vector_iter<char>,
test_misordered_start_bound_vector_iter<int>,
test_misordered_start_bound_vector_iter<S>,

test_misordered_iterator_sentinel_ptr<char>,
test_misordered_iterator_sentinel_ptr<int>,
test_misordered_iterator_sentinel_ptr<S>,

test_misordered_iterator_sentinel_vector_iter<char>,
test_misordered_iterator_sentinel_vector_iter<int>,
test_misordered_iterator_sentinel_vector_iter<S>,
});
#endif // _DEBUG

Expand Down

0 comments on commit bf1e9bd

Please sign in to comment.