From b0c6229df92f058991658f63ec82e15cf18455e3 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 12 May 2025 14:24:17 +0200 Subject: [PATCH 1/4] Relocate `_Stride_extent_pair` alias --- stl/inc/mdspan | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index f11eda31a47..c8fd564a8ee 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -826,8 +826,9 @@ public: using layout_type = layout_stride; private: - using _Extents_base = _Maybe_fully_static_extents; - using _Strides_base = _Maybe_empty_array; + using _Extents_base = _Maybe_fully_static_extents; + using _Strides_base = _Maybe_empty_array; + using _Stride_extent_pair = pair; static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.stride.overview]/2)."); @@ -1111,7 +1112,6 @@ private: } _NODISCARD constexpr bool _Is_exhaustive_special_case() const noexcept { - using _Stride_extent_pair = pair; array<_Stride_extent_pair, extents_type::rank()> _Pairs; for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { rank_type _Ext = static_cast(this->_Exts.extent(_Idx)); From 62f2b1ea64b71287ec36f725f4528a9c13d3a250 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 12 May 2025 14:24:45 +0200 Subject: [PATCH 2/4] Implement precondition described in `[mdspan.layout.stride.cons]/4.3` --- stl/inc/mdspan | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index c8fd564a8ee..ea05bb61d5c 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -848,6 +848,7 @@ private: bool _Found_zero = false; bool _Overflow = false; index_type _Req_span_size = 0; + array<_Stride_extent_pair, extents_type::rank()> _Pairs; for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { const index_type _Stride = this->_Array[_Idx]; _STL_VERIFY(_Stride > 0, "Value of s[i] must be greater than 0 for all i in the range [0, rank_) " @@ -862,9 +863,22 @@ private: _Overflow = _Mul_overflow(static_cast(_Ext - 1), _Stride, _Prod) || _Add_overflow(_Req_span_size, _Prod, _Req_span_size); } + + _Pairs[_Idx] = {static_cast(_Stride), static_cast(_Ext)}; } _STL_VERIFY(_Found_zero || !_Overflow, "REQUIRED-SPAN-SIZE(e, s) must be representable as a value of type " "index_type (N4950 [mdspan.layout.stride.cons]/4.2)."); + + if (!_Found_zero) { + _RANGES sort(_Pairs); + for (rank_type _Idx = 1; _Idx < extents_type::_Rank; ++_Idx) { + _STL_VERIFY(_Pairs[_Idx].first >= _Pairs[_Idx - 1].first * _Pairs[_Idx - 1].second, + "If rank_ is greater than 0, then there must exist a permutation P of the integers in the " + "range [0, rank_), such that 's[p(i)] >= s[p(i-1)] * e.extent(p(i-1))' is true for all i in " + "the range [1, rank_), where p(i) is the i-th element of P (N5008 " + "[mdspan.layout.stride.cons]/4.3)."); + } + } } #endif // _ITERATOR_DEBUG_LEVEL != 0 } From 10a630739a47c98ad0198e56c54b85814b5f4e63 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 12 May 2025 10:45:23 +0200 Subject: [PATCH 3/4] Fix incorrect strides in the test code --- .../P0009R18_mdspan_layout_stride/test.cpp | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index 8e6f27ff054..eebbd167afe 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -386,7 +386,7 @@ constexpr void check_required_span_size() { using M1 = layout_stride::mapping>; static_assert(M1{}.required_span_size() == 0); - layout_stride::mapping> m2{dextents{3, 0, 3, 3}, array{1, 3, 1, 1}}; + layout_stride::mapping> m2{dextents{3, 0, 3, 3}, array{1, 3, 1, 3}}; assert(m2.required_span_size() == 0); } @@ -800,37 +800,37 @@ constexpr void check_correctness() { { // 3x2x2 tensor using E = extents; - const array vals{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; - layout_stride::mapping m{E{}, array{8, 1, 6}}; // non-exhaustive mapping + const array vals{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + layout_stride::mapping m{E{}, array{7, 1, 3}}; // non-exhaustive mapping assert(!m.is_exhaustive()); mdspan tensor{vals.data(), m}; #ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 assert((tensor[0, 0, 0] == 0)); - assert((tensor[0, 0, 1] == 6)); + assert((tensor[0, 0, 1] == 3)); assert((tensor[0, 1, 0] == 1)); - assert((tensor[0, 1, 1] == 7)); - assert((tensor[1, 0, 0] == 8)); - assert((tensor[1, 0, 1] == 14)); - assert((tensor[1, 1, 0] == 9)); - assert((tensor[1, 1, 1] == 15)); - assert((tensor[2, 0, 0] == 16)); - assert((tensor[2, 0, 1] == 22)); - assert((tensor[2, 1, 0] == 17)); - assert((tensor[2, 1, 1] == 23)); + assert((tensor[0, 1, 1] == 4)); + assert((tensor[1, 0, 0] == 7)); + assert((tensor[1, 0, 1] == 10)); + assert((tensor[1, 1, 0] == 8)); + assert((tensor[1, 1, 1] == 11)); + assert((tensor[2, 0, 0] == 14)); + assert((tensor[2, 0, 1] == 17)); + assert((tensor[2, 1, 0] == 15)); + assert((tensor[2, 1, 1] == 18)); #else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv assert((tensor[array{0, 0, 0}] == 0)); - assert((tensor[array{0, 0, 1}] == 6)); + assert((tensor[array{0, 0, 1}] == 3)); assert((tensor[array{0, 1, 0}] == 1)); - assert((tensor[array{0, 1, 1}] == 7)); - assert((tensor[array{1, 0, 0}] == 8)); - assert((tensor[array{1, 0, 1}] == 14)); - assert((tensor[array{1, 1, 0}] == 9)); - assert((tensor[array{1, 1, 1}] == 15)); - assert((tensor[array{2, 0, 0}] == 16)); - assert((tensor[array{2, 0, 1}] == 22)); - assert((tensor[array{2, 1, 0}] == 17)); - assert((tensor[array{2, 1, 1}] == 23)); + assert((tensor[array{0, 1, 1}] == 4)); + assert((tensor[array{1, 0, 0}] == 7)); + assert((tensor[array{1, 0, 1}] == 10)); + assert((tensor[array{1, 1, 0}] == 8)); + assert((tensor[array{1, 1, 1}] == 11)); + assert((tensor[array{2, 0, 0}] == 14)); + assert((tensor[array{2, 0, 1}] == 17)); + assert((tensor[array{2, 1, 0}] == 15)); + assert((tensor[array{2, 1, 1}] == 18)); #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ } From 9e9bb61f41ca2fb6ad88541e4c7f3296accf22fe Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 12 May 2025 10:45:42 +0200 Subject: [PATCH 4/4] Add extra death tests --- .../P0009R18_mdspan_layout_stride_death/test.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp index 2c1cb19e7df..f1c3b38a9cd 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride_death/test.cpp @@ -29,6 +29,12 @@ void test_construction_from_extents_and_array_2() { [[maybe_unused]] layout_stride::mapping m{Ext{}, array{2}}; } +void test_construction_from_extents_and_array_3() { + using Ext = extents; + const array a{29, 2, 6}; + // Incorrect strides + [[maybe_unused]] layout_stride::mapping m{Ext{}, a}; +} void test_construction_from_extents_and_span_1() { array a{-1}; @@ -44,6 +50,14 @@ void test_construction_from_extents_and_span_2() { [[maybe_unused]] layout_stride::mapping m{Ext{}, s}; } +void test_construction_from_extents_and_span_3() { + using Ext = extents; + array a{3, 1, 8, 3}; + const span s{a}; + // Incorrect strides + [[maybe_unused]] layout_stride::mapping m{Ext{}, s}; +} + void test_construction_from_strided_layout_mapping() { layout_right::mapping> m1; // Value of other.required_span_size() must be representable as a value of type index_type @@ -73,8 +87,10 @@ int main(int argc, char* argv[]) { test_default_construction, test_construction_from_extents_and_array_1, test_construction_from_extents_and_array_2, + test_construction_from_extents_and_array_3, test_construction_from_extents_and_span_1, test_construction_from_extents_and_span_2, + test_construction_from_extents_and_span_3, test_construction_from_strided_layout_mapping, test_call_operator, test_stride_with_empty_extents,