diff --git a/stl/inc/mdspan b/stl/inc/mdspan index ff1766909f1..638943cb4cb 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -601,7 +601,7 @@ public: _Strides.back() = 1; for (rank_type _Idx = extents_type::_Rank - 1; _Idx-- > 0;) { // TRANSITION USE `_Multiply_with_overflow_check` IN DEBUG MODE - _Strides[_Idx] = _Strides[_Idx + 1] * _Exts.extent(_Idx + 1); + _Strides[_Idx] = static_cast(_Strides[_Idx + 1] * _Exts.extent(_Idx + 1)); } } } @@ -752,7 +752,7 @@ public: } for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { - if (_Left.stride(_Idx) != _Right.stride(_Idx)) { + if (_STD cmp_not_equal(_Left.stride(_Idx), _Right.stride(_Idx))) { return false; } } @@ -786,7 +786,7 @@ private: template _NODISCARD constexpr index_type _Index_impl(index_sequence<_Seq...>, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); - return ((_Indices * _Strides[_Seq]) + ... + 0); + return static_cast(((_Indices * _Strides[_Seq]) + ... + 0)); } }; diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index 842065b9051..4fd9306bcfe 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -3,9 +3,11 @@ #pragma once +#include #include #include #include +#include #include #include @@ -156,3 +158,64 @@ constexpr bool check_accessor_policy_requirements() { static_assert(detail::CheckMemberFunctionsOfAccessorPolicy); return true; } + +namespace details { + template + constexpr void check_members_with_mixed_extents(Fn&& fn) { + auto select_extent = [](size_t e) consteval { + return e == std::dynamic_extent ? std::min(sizeof...(Extents), size_t{3}) : e; + }; + + // Check signed integers + fn(std::extents{select_extent(Extents)...}); + fn(std::extents{select_extent(Extents)...}); + fn(std::extents{select_extent(Extents)...}); + fn(std::extents{select_extent(Extents)...}); + fn(std::extents{select_extent(Extents)...}); + + // Check unsigned integers + fn(std::extents{select_extent(Extents)...}); + fn(std::extents{select_extent(Extents)...}); + fn(std::extents{select_extent(Extents)...}); + fn(std::extents{select_extent(Extents)...}); + fn(std::extents{select_extent(Extents)...}); + } + + template + constexpr void check_members_with_various_extents_impl(Fn&& fn, std::index_sequence) { + auto static_or_dynamic = [](size_t i) consteval { + return i == 0 ? std::dynamic_extent : std::min(sizeof...(Seq), size_t{3}); + }; + + if constexpr (sizeof...(Seq) <= 1) { + check_members_with_mixed_extents<>(std::forward(fn)); + } else if constexpr (sizeof...(Seq) <= 2) { + (check_members_with_mixed_extents(std::forward(fn)), ...); + } else if constexpr (sizeof...(Seq) <= 4) { + (check_members_with_mixed_extents( + std::forward(fn)), + ...); + } else if constexpr (sizeof...(Seq) <= 8) { + (check_members_with_mixed_extents(std::forward(fn)), + ...); + } else if constexpr (sizeof...(Seq) <= 16) { + (check_members_with_mixed_extents(std::forward(fn)), + ...); + } else { + static_assert(sizeof...(Seq) <= 16, "We don't need more testing."); + } + } +} // namespace details + +template +constexpr void check_members_with_various_extents(Fn&& fn) { + details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<1>{}); + details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<2>{}); + details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<4>{}); + details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<8>{}); +#ifndef _PREFAST_ + details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<16>{}); +#endif // _PREFAST_ +} diff --git a/tests/std/tests/P0009R18_mdspan_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp index 83cf926a70a..e7fa0109883 100644 --- a/tests/std/tests/P0009R18_mdspan_extents/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -15,7 +15,7 @@ using namespace std; template -constexpr void do_check_members(index_sequence) { +constexpr void check_members(index_sequence) { using Ext = extents; // Each specialization of extents models regular and is trivially copyable @@ -80,11 +80,6 @@ constexpr void do_check_members(index_sequence) { } } -template -constexpr void check_members() { - do_check_members(make_index_sequence{}); -} - constexpr void check_construction_from_other_extents() { { // Check construction from too big or too small other extents using Ext = extents; @@ -292,16 +287,14 @@ constexpr void check_equality_operator() { } constexpr bool test() { - check_members(); - check_members(); - check_members(); - check_members(); - check_members(); - check_members(); + check_members_with_various_extents([](const extents&) { + check_members(make_index_sequence{}); + }); check_construction_from_other_extents(); check_construction_from_extents_pack(); check_construction_from_array_and_span(); check_equality_operator(); + return true; } diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index 4322e1c8648..fdae36b7555 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -14,7 +14,7 @@ using namespace std; template -constexpr void do_check_members(const extents& ext, index_sequence) { +constexpr void check_members(const extents& ext, index_sequence) { using Ext = extents; using Mapping = layout_left::mapping; @@ -144,11 +144,6 @@ constexpr void do_check_members(const extents& ext, index } } -template -constexpr void check_members(extents ext) { - do_check_members(ext, make_index_sequence{}); -} - constexpr void check_construction_from_other_left_mapping() { { // Check invalid construction using Mapping = layout_left::mapping>; @@ -356,18 +351,17 @@ constexpr void check_correctness() { } constexpr bool test() { - check_members(extents{}); - check_members(extents{}); - check_members(extents{}); - check_members(extents{3}); - check_members(extents{4, 5}); - check_members(extents{3, 3, 3}); + check_members_with_various_extents( + [](const extents& ext) { + check_members(ext, make_index_sequence{}); + }); check_construction_from_other_left_mapping(); check_construction_from_other_right_mapping(); check_construction_from_other_stride_mapping(); check_call_operator(); check_comparisons(); check_correctness(); + return true; } diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp index 4810d8a3621..64f2e77f2ca 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -14,7 +14,7 @@ using namespace std; template -constexpr void do_check_members(const extents& ext, index_sequence) { +constexpr void check_members(const extents& ext, index_sequence) { using Ext = extents; using Mapping = layout_right::mapping; @@ -51,6 +51,8 @@ constexpr void do_check_members(const extents& ext, index using Ext2 = extents; using Mapping2 = layout_right::mapping; +#pragma warning(push) // TRANSITION, "/analyze:only" BUG? +#pragma warning(disable : 28020) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call { // Check construction from other layout_right::mapping Mapping m1{ext}; Mapping2 m2{m1}; @@ -138,11 +140,7 @@ constexpr void do_check_members(const extents& ext, index assert(!(m != m)); // Other tests are defined in 'check_comparisons' function } -} - -template -constexpr void check_members(extents ext) { - do_check_members(ext, make_index_sequence{}); +#pragma warning(pop) // TRANSITION, "/analyze:only" BUG? } constexpr void check_construction_from_other_right_mapping() { @@ -367,18 +365,17 @@ constexpr void check_correctness() { } constexpr bool test() { - check_members(extents{}); - check_members(extents{}); - check_members(extents{}); - check_members(extents{3}); - check_members(extents{4, 5}); - check_members(extents{3, 3, 3}); + check_members_with_various_extents( + [](const extents& ext) { + check_members(ext, make_index_sequence{}); + }); check_construction_from_other_right_mapping(); check_construction_from_other_left_mapping(); check_construction_from_other_stride_mapping(); check_call_operator(); check_comparisons(); check_correctness(); + return true; } diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index 960c7fe4e69..7900fa7c80e 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#include #include #include #include @@ -13,9 +14,16 @@ using namespace std; -template +struct CmpEqual { + template + [[nodiscard]] constexpr bool operator()(T t, U u) const noexcept { + return cmp_equal(t, u); + } +}; + +template constexpr void do_check_members(const extents& ext, - const array& strs, index_sequence) { + const array& strs, index_sequence) { using Ext = extents; using Strides = array; using Mapping = layout_stride::mapping; @@ -50,16 +58,16 @@ constexpr void do_check_members(const extents& ext, { // Check construction from extents_type and array Mapping m{ext, strs}; assert(m.extents() == ext); - assert(m.strides() == strs); + assert(ranges::equal(m.strides(), strs, CmpEqual{})); static_assert(is_nothrow_constructible_v); // Other tests are defined in 'check_construction_from_extents_and_array' function [FIXME] } { // Check construction from extents_type and span - using Span = span; + using Span = span; Mapping m{ext, Span{strs}}; assert(m.extents() == ext); - assert(m.strides() == strs); + assert(ranges::equal(m.strides(), strs, CmpEqual{})); static_assert(is_nothrow_constructible_v); // Other tests are defined in 'check_construction_from_extents_and_array' function [FIXME] } @@ -86,7 +94,7 @@ constexpr void do_check_members(const extents& ext, { // Check 'strides' function same_as decltype(auto) strs2 = m.strides(); - assert(strs2 == strs); + assert(ranges::equal(strs2, strs, CmpEqual{})); static_assert(noexcept(m.strides())); } @@ -119,7 +127,7 @@ constexpr void do_check_members(const extents& ext, { // Check 'stride' function for (size_t i = 0; i < strs.size(); ++i) { same_as decltype(auto) s = m.stride(i); - assert(strs[i] == s); + assert(cmp_equal(strs[i], s)); } } @@ -131,15 +139,46 @@ constexpr void do_check_members(const extents& ext, #pragma warning(pop) // TRANSITION, "/analyze:only" BUG? } +template +constexpr void check_members_with_different_strides_index_type( + extents ext, const array& strides) { + array test_strides; + ranges::transform(strides, test_strides.begin(), [](auto i) { return static_cast(i); }); + do_check_members(ext, test_strides, make_index_sequence{}); +} + template -constexpr void check_members(extents ext, const array& strides) { - do_check_members(ext, strides, make_index_sequence{}); +constexpr void check_members(extents ext, const array& strides) { + // Check signed strides + check_members_with_different_strides_index_type(ext, strides); + check_members_with_different_strides_index_type(ext, strides); + check_members_with_different_strides_index_type(ext, strides); + check_members_with_different_strides_index_type(ext, strides); + check_members_with_different_strides_index_type(ext, strides); + + // Check unsigned strides + check_members_with_different_strides_index_type(ext, strides); + check_members_with_different_strides_index_type(ext, strides); + check_members_with_different_strides_index_type(ext, strides); + check_members_with_different_strides_index_type(ext, strides); + check_members_with_different_strides_index_type(ext, strides); } constexpr bool test() { - check_members(extents{}, array{}); - check_members(extents{}, array{1}); - check_members(extents{3}, array{1, 3}); + // Check signed integers + check_members(extents{5}, array{1}); + check_members(extents{}, array{1, 6}); + check_members(extents{3}, array{1, 3}); + check_members(extents{}, array{1}); + check_members(extents{3}, array{1, 3, 6}); + + // Check unsigned integers + check_members(extents{5}, array{1}); + check_members(extents{}, array{1, 6}); + check_members(extents{3}, array{1, 3}); + check_members(extents{}, array{1}); + check_members(extents{3}, array{1, 3, 6}); + // TRANSITION more tests return true; }