Skip to content

Commit

Permalink
<ranges>: Fix cartesian_product_view::size in debug mode (#3733)
Browse files Browse the repository at this point in the history
  • Loading branch information
JMazurkiewicz authored May 31, 2023
1 parent d08d14c commit 0d47d98
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 8 deletions.
22 changes: 14 additions & 8 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -9991,11 +9991,14 @@ namespace ranges {
{
return [&]<size_t... _Indices>(index_sequence<_Indices...>) {
#if _CONTAINER_DEBUG_LEVEL > 0
const array _Sizes = {static_cast<_Size_type<false>>(_RANGES size(_STD get<_Indices>(_Bases)))...};
const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...);
if (_Any_zero) {
return _Size_type<false>{0};
}

_Size_type<false> _Product{1};
const bool _Overflow =
(_Mul_overflow(
_Product, static_cast<_Size_type<false>>(_RANGES size(_STD get<_Indices>(_Bases))), _Product)
|| ...);
const bool _Overflow = (_Mul_overflow(_Product, _Sizes[_Indices], _Product) || ...);
_STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 "
"[range.cartesian.view]/10).");
return _Product;
Expand All @@ -10010,11 +10013,14 @@ namespace ranges {
{
return [&]<size_t... _Indices>(index_sequence<_Indices...>) {
#if _CONTAINER_DEBUG_LEVEL > 0
const array _Sizes = {static_cast<_Size_type<true>>(_RANGES size(_STD get<_Indices>(_Bases)))...};
const bool _Any_zero = ((_Sizes[_Indices] == 0) || ...);
if (_Any_zero) {
return _Size_type<true>{0};
}

_Size_type<true> _Product{1};
const bool _Overflow =
(_Mul_overflow(
_Product, static_cast<_Size_type<true>>(_RANGES size(_STD get<_Indices>(_Bases))), _Product)
|| ...);
const bool _Overflow = (_Mul_overflow(_Product, _Sizes[_Indices], _Product) || ...);
_STL_VERIFY(!_Overflow, "Size of cartesian product cannot be represented by size type (N4950 "
"[range.cartesian.view]/10).");
return _Product;
Expand Down
13 changes: 13 additions & 0 deletions tests/std/tests/P2374R4_views_cartesian_product/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -973,6 +973,16 @@ namespace check_recommended_practice_implementation { // MSVC STL specific behav
STATIC_ASSERT(sizeof(range_difference_t<cartesian_product_view<all_t<Vec>, all_t<Vec>>>) > sizeof(ptrdiff_t));
} // namespace check_recommended_practice_implementation

// GH-3733: cartesian_product_view would incorrectly reject a call to size() claiming that big*big*big*0 is not
// representable as range_size_t because big*big*big is not.
constexpr void test_gh_3733() {
const auto r1 = views::repeat(0, (numeric_limits<ptrdiff_t>::max)());
const auto r2 = views::repeat(1, 0);
const auto cart = views::cartesian_product(r1, r1, r1, r2);
assert(cart.size() == 0);
assert(as_const(cart).size() == 0);
}

int main() {
// Check views
{ // ... copyable
Expand Down Expand Up @@ -1029,4 +1039,7 @@ int main() {
STATIC_ASSERT((instantiation_test(), true));
#endif // TRANSITION, GH-1030
instantiation_test();

STATIC_ASSERT((test_gh_3733(), true));
test_gh_3733();
}

0 comments on commit 0d47d98

Please sign in to comment.