diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 8f86197b54a..fa7ed45da95 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -249,6 +249,15 @@ public: return _Result; } + // TRANSITION, LWG ISSUE? I believe that this function should return 'index_type' + _NODISCARD constexpr index_type _Rev_prod_of_extents(const rank_type _Idx) const noexcept { + index_type _Result = 1; + for (rank_type _Dim = _Idx + 1; _Dim < rank(); ++_Dim) { + _Result *= extent(_Dim); + } + return _Result; + } + _NODISCARD static _CONSTEVAL bool _Is_index_space_size_representable() { if constexpr (rank_dynamic() == 0 && rank() > 0) { return _STD in_range((_Extents * ...)); @@ -354,12 +363,11 @@ public: if constexpr (extents_type::rank() > 0) { const bool _Verify = [&](index_sequence<_Indices...>) { index_type _Prod = 1; - return ( - (_Other.stride(_Indices) - == (_Indices + 1 == extents_type::rank() - ? _Prod - : _STD exchange(_Prod, static_cast(_Prod * _Exts.extent(_Indices + 1))))) - && ...); + return ((_Other.stride(_Indices) + == (_Indices == extents_type::rank() - 1 + ? _Prod + : _STD exchange(_Prod, static_cast(_Prod * _Exts.extent(_Indices))))) + && ...); } (make_index_sequence{}); _STL_VERIFY(_Verify, "For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to " @@ -456,24 +464,52 @@ public: constexpr mapping() noexcept = default; constexpr mapping(const mapping&) noexcept = default; - constexpr mapping(const extents_type& _Exts_) noexcept : _Exts(_Exts_) {} + constexpr mapping(const extents_type& _Exts_) noexcept : _Exts(_Exts_) { + // TRANSITION, CHECK [mdspan.layout.right.cons]/1 (REQUIRES '_Multiply_with_overflow_check' FROM #3561) + } template requires is_constructible_v constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& _Other) noexcept - : _Exts(_Other.extents()) {} + : _Exts(_Other.extents()) { + _STL_VERIFY(_STD in_range(_Other.required_span_size()), + "Value of other.required_span_size() must be representable as a value of type index_type (N4944 " + "[mdspan.layout.right.cons]/4)."); + } template requires (extents_type::rank() <= 1) && is_constructible_v constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_left::mapping<_OtherExtents>& _Other) noexcept - : _Exts(_Other.extents()) {} + : _Exts(_Other.extents()) { + _STL_VERIFY(_STD in_range(_Other.required_span_size()), + "Value of other.required_span_size() must be representable as a value of type index_type (N4944 " + "[mdspan.layout.right.cons]/7)."); + } template requires is_constructible_v constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::template mapping<_OtherExtents>& _Other) - : _Exts(_Other.extents()) {} + : _Exts(_Other.extents()) { + if constexpr (extents_type::rank() > 0) { + const bool _Verify = [&](index_sequence<_Indices...>) { + index_type _Prod = stride(0); + return ( + (_Other.stride(_Indices) + == (_Indices == extents_type::rank() - 1 + ? _Prod + : _STD exchange(_Prod, static_cast(_Prod / _Exts.extent(_Indices + 1))))) + && ...); + } + (make_index_sequence{}); + _STL_VERIFY(_Verify, "For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to " + "extents().rev-prod-of-extents(r) (N4944 [mdspan.layout.right.cons]/10.1)."); + } + _STL_VERIFY(_STD in_range(_Other.required_span_size()), + "Value of other.required_span_size() must be representable as a value of type index_type (N4944 " + "[mdspan.layout.right.cons]/10.2)."); + } constexpr mapping& operator=(const mapping&) noexcept = default; @@ -482,19 +518,14 @@ public: } _NODISCARD constexpr index_type required_span_size() const noexcept { - index_type _Result = 1; - for (rank_type _Dim = 0; _Dim < extents_type::rank(); ++_Dim) { - _Result *= _Exts.extent(_Dim); - } - return _Result; + return _Exts._Fwd_prod_of_extents(extents_type::rank()); } - template - requires (sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) - && (is_nothrow_constructible_v && ...) - _NODISCARD constexpr index_type operator()(_Indices... _Idx) const noexcept { - return _Index_impl...>( - static_cast(_Idx)..., make_index_sequence{}); + template + requires (sizeof...(_IndexTypes) == extents_type::rank()) && (is_convertible_v<_IndexTypes, index_type> && ...) + && (is_nothrow_constructible_v && ...) + _NODISCARD constexpr index_type operator()(_IndexTypes... _Indices) const noexcept { + return _Index_impl(make_index_sequence{}, static_cast(_Indices)...); } _NODISCARD static constexpr bool is_always_unique() noexcept { @@ -509,27 +540,24 @@ public: return true; } - _NODISCARD constexpr bool is_unique() const noexcept { + _NODISCARD static constexpr bool is_unique() noexcept { return true; } - _NODISCARD constexpr bool is_exhaustive() const noexcept { + _NODISCARD static constexpr bool is_exhaustive() noexcept { return true; } - _NODISCARD constexpr bool is_strided() const noexcept { + _NODISCARD static constexpr bool is_strided() noexcept { return true; } - _NODISCARD constexpr index_type stride(const rank_type _Rank) const noexcept + _NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept requires (extents_type::rank() > 0) { - index_type _Result = 1; - for (rank_type _Dim = _Rank + 1; _Dim < extents_type::rank(); ++_Dim) { - _Result *= _Exts.extent(_Dim); - } - - return _Result; + _STL_VERIFY(_Idx < extents_type::rank(), + "Value of i must be less than extents_type::rank() (N4944 [mdspan.layout.right.obs]/6)."); + return _Exts._Rev_prod_of_extents(_Idx); } template @@ -541,10 +569,11 @@ public: private: extents_type _Exts{}; - template - constexpr index_type _Index_impl(_IndexType... _Idx, index_sequence<_Seq...>) const noexcept { + template + _NODISCARD constexpr index_type _Index_impl(index_sequence<_Seq...>, _IndexTypes... _Indices) const noexcept { + _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); index_type _Result = 0; - ((void) (_Result = _Idx + _Exts.extent(_Seq) * _Result), ...); + ((_Result = static_cast(_Indices + _Exts.extent(_Seq) * _Result)), ...); return _Result; } }; diff --git a/tests/std/test.lst b/tests/std/test.lst index 7e133eec9d8..a6bbfee0801 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -235,6 +235,8 @@ tests\P0009R18_mdspan_extents tests\P0009R18_mdspan_extents_death tests\P0009R18_mdspan_layout_left tests\P0009R18_mdspan_layout_left_death +tests\P0009R18_mdspan_layout_right +tests\P0009R18_mdspan_layout_right_death tests\P0019R8_atomic_ref tests\P0024R2_parallel_algorithms_adjacent_difference tests\P0024R2_parallel_algorithms_adjacent_find diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index f9f74fed954..4322e1c8648 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -13,11 +13,6 @@ using namespace std; -template -concept CanInvokeCallOperatorOfMapping = requires(Mapping m, Indices... i) { - { m(i...) } -> same_as; - }; - template constexpr void do_check_members(const extents& ext, index_sequence) { using Ext = extents; @@ -83,9 +78,12 @@ constexpr void do_check_members(const extents& ext, index #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 layout_stride::mapping - array strides{1}; - for (size_t i = 1; i < Ext::rank(); ++i) { - strides[i] = static_cast(strides[i - 1] * ext.extent(i)); + array strides{}; + if constexpr (Ext::rank() > 0) { + strides.front() = 1; + for (size_t i = 1; i < Ext::rank(); ++i) { + strides[i] = static_cast(strides[i - 1] * ext.extent(i - 1)); + } } using StrideMapping = layout_stride::mapping; @@ -141,6 +139,7 @@ constexpr void do_check_members(const extents& ext, index { // Check comparisons assert(m == m); + assert(!(m != m)); // Other tests are defined in 'check_comparisons' function } } @@ -215,6 +214,12 @@ constexpr void check_construction_from_other_stride_mapping() { static_assert(!is_constructible_v>>); } + { // Check correctness + using Ext = extents; + layout_stride::mapping stride_mapping{Ext{}, array{1, 4, 12, 24, 72}}; + [[maybe_unused]] layout_left::mapping m{stride_mapping}; + } + { // Check implicit conversions static_assert( !NotImplicitlyConstructibleFrom>, layout_stride::mapping>>); @@ -230,25 +235,25 @@ constexpr void check_construction_from_other_stride_mapping() { constexpr void check_call_operator() { { // Check call with invalid amount of indices using Mapping = layout_left::mapping>; - static_assert(!CanInvokeCallOperatorOfMapping); - static_assert(!CanInvokeCallOperatorOfMapping); - static_assert(CanInvokeCallOperatorOfMapping); - static_assert(!CanInvokeCallOperatorOfMapping); + static_assert(!CheckCallOperatorOfLayoutMapping); + static_assert(!CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(!CheckCallOperatorOfLayoutMapping); } { // Check call with invalid types using Mapping = layout_left::mapping>; - static_assert(CanInvokeCallOperatorOfMapping); - static_assert(CanInvokeCallOperatorOfMapping); - static_assert(CanInvokeCallOperatorOfMapping>); - static_assert(CanInvokeCallOperatorOfMapping>); - static_assert(!CanInvokeCallOperatorOfMapping); + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(!CheckCallOperatorOfLayoutMapping); } { // Check call with types that might throw during conversion using Mapping = layout_left::mapping>; - static_assert(CanInvokeCallOperatorOfMapping>); - static_assert(!CanInvokeCallOperatorOfMapping>); + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(!CheckCallOperatorOfLayoutMapping>); } { // Check various mappings diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/env.lst b/tests/std/tests/P0009R18_mdspan_layout_right/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_layout_right/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp new file mode 100644 index 00000000000..620183f2ac0 --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -0,0 +1,390 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include + +#include "test_mdspan_support.hpp" + +using namespace std; + +template +constexpr void do_check_members(const extents& ext, index_sequence) { + using Ext = extents; + using Mapping = layout_right::mapping; + + // layout_right meets the layout mapping policy requirements and is a trivial type + static_assert(check_layout_mapping_policy_requirements()); + static_assert(is_trivial_v); + + // layout_right::mapping is a trivially copyable type that models regular for each Ext + static_assert(is_trivially_copyable_v); + static_assert(regular); + + // Check member types + static_assert(same_as); + static_assert(same_as); + static_assert(same_as); + static_assert(same_as); + static_assert(same_as); + + { // Check default and copy constructor + Mapping m; + Mapping cpy = m; + assert(cpy == m); + static_assert(is_nothrow_default_constructible_v); + static_assert(is_nothrow_copy_constructible_v); + } + + { // Check construction from extents_type + Mapping m{ext}; + assert(m.extents() == ext); + static_assert(is_nothrow_constructible_v); + } + + using OtherIndexType = long long; + using Ext2 = extents; + using Mapping2 = layout_right::mapping; + + { // Check construction from other layout_right::mapping + Mapping m1{ext}; + Mapping2 m2{m1}; + assert(m1 == m2); + static_assert(is_nothrow_constructible_v); + // Other tests are defined in 'check_construction_from_other_right_mapping' function + } + + { // Check construction from layout_left::mapping + using LeftMapping = layout_left::mapping; + if constexpr (Ext::rank() <= 1) { + LeftMapping left_mapping{ext}; + [[maybe_unused]] Mapping m1{left_mapping}; + [[maybe_unused]] Mapping2 m2{left_mapping}; + assert(m1 == m2); + static_assert(is_nothrow_constructible_v); + static_assert(is_nothrow_constructible_v); + } else { + static_assert(!is_constructible_v); + static_assert(!is_constructible_v); + } + // Other tests are defined in 'check_construction_from_other_left_mapping' function + } + + { // Check construction from layout_stride::mapping + array strides{}; + if constexpr (Ext::rank() > 0) { + strides.back() = 1; + for (size_t i = Ext::rank() - 1; i-- > 0;) { + strides[i] = static_cast(strides[i + 1] * ext.extent(i + 1)); + } + } + + using StrideMapping = layout_stride::mapping; + StrideMapping stride_mapping{ext, strides}; + [[maybe_unused]] Mapping m{stride_mapping}; + // Other tests are defined in 'check_construction_from_other_stride_mapping' function + } + + Mapping m{ext}; // For later use + + { // Check 'extents' function + assert(m.extents() == ext); + static_assert(noexcept(m.extents())); + } + + { // Check 'required_span_size' function + const IndexType expected_value = static_cast((ext.extent(Indices) * ... * 1)); + assert(m.required_span_size() == expected_value); + static_assert(noexcept(m.required_span_size())); + } + + { // Check operator() + assert(m(((void) Indices, 0)...) == 0); + assert(m((ext.extent(Indices) - 1)...) == static_cast((ext.extent(Indices) * ... * 1)) - 1); + static_assert(noexcept(m(((void) Indices, 0)...))); + static_assert(noexcept(m((ext.extent(Indices) - 1)...))); + // Other tests are defined in 'check_call_operator' function + } + + { // Check 'is_always_[unique/exhaustive/strided]' functions + static_assert(Mapping::is_always_unique()); + static_assert(Mapping::is_always_exhaustive()); + static_assert(Mapping::is_always_strided()); + } + + { // Check 'is_[unique/exhaustive/strided]' functions + static_assert(Mapping::is_unique()); + static_assert(Mapping::is_exhaustive()); + static_assert(Mapping::is_strided()); + } + + if constexpr (Ext::rank() > 0) { // Check 'stride' function + const IndexType expected_stride0 = static_cast((ext.extent(Indices) * ... * 1) / ext.extent(0)); + assert(m.stride(0) == expected_stride0); + assert(m.stride(Ext::rank() - 1) == 1); + static_assert(noexcept(m.stride(Ext::rank() - 1))); + static_assert(noexcept(m.stride(0))); + } else { + static_assert(!CheckStrideMemberFunction); + } + + { // Check comparisons + assert(m == m); + 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{}); +} + +constexpr void check_construction_from_other_right_mapping() { + { // Check invalid construction + using Mapping = layout_right::mapping>; + static_assert(!is_constructible_v>>); + static_assert(!is_constructible_v>>); + } + + { // Check implicit conversions + static_assert(!NotImplicitlyConstructibleFrom>, + layout_right::mapping>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_right::mapping>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_right::mapping>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_right::mapping>>); + } +} + +constexpr void check_construction_from_other_left_mapping() { + { // Check construction from layout_left::mapping with various values of E::rank() + static_assert( + is_constructible_v>, layout_left::mapping>>); + static_assert( + is_constructible_v>, layout_left::mapping>>); + static_assert( + !is_constructible_v>, layout_left::mapping>>); + static_assert( + !is_constructible_v>, layout_left::mapping>>); + } + + { // Check construction from layout_left::mapping when E is invalid + using Mapping = layout_right::mapping>; + static_assert(!is_constructible_v>>); + static_assert(!is_constructible_v>>); + } + + { // Check implicit conversions + static_assert(!NotImplicitlyConstructibleFrom>, + layout_left::mapping>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_left::mapping>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_left::mapping>>); + } +} + +constexpr void check_construction_from_other_stride_mapping() { + { // Check construction from layout_stride::mapping with various values of E::rank() + static_assert( + is_constructible_v>, layout_stride::mapping>>); + static_assert( + is_constructible_v>, layout_stride::mapping>>); + static_assert( + is_constructible_v>, layout_stride::mapping>>); + static_assert( + is_constructible_v>, layout_stride::mapping>>); + } + + { // Check construction from layout_stride::mapping when E is invalid + using Mapping = layout_right::mapping>; + static_assert(!is_constructible_v>>); + static_assert(!is_constructible_v>>); + } + + { // Check correctness + using Ext = extents; + layout_stride::mapping stride_mapping{Ext{}, array{72, 24, 12, 4, 1}}; + [[maybe_unused]] layout_right::mapping m{stride_mapping}; + } + + { // Check implicit conversions + static_assert( + !NotImplicitlyConstructibleFrom>, layout_stride::mapping>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_stride::mapping>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_stride::mapping>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_stride::mapping>>); + } +} + +constexpr void check_call_operator() { + { // Check call with invalid amount of indices + using Mapping = layout_right::mapping>; + static_assert(!CheckCallOperatorOfLayoutMapping); + static_assert(!CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(!CheckCallOperatorOfLayoutMapping); + } + + { // Check call with invalid types + using Mapping = layout_right::mapping>; + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(!CheckCallOperatorOfLayoutMapping); + } + + { // Check call with types that might throw during conversion + using Mapping = layout_right::mapping>; + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(!CheckCallOperatorOfLayoutMapping>); + } + + { // Check various mappings + layout_right::mapping> m1; + assert(m1() == 0); + + layout_right::mapping> m2{dextents{4}}; + assert(m2(0) == 0); + assert(m2(1) == 1); + assert(m2(2) == 2); + assert(m2(3) == 3); + + layout_right::mapping> m3; + assert(m3(0, 0) == 0); + assert(m3(0, 1) == 1); + assert(m3(1, 0) == 5); + assert(m3(1, 1) == 6); + assert(m3(1, 2) == 7); + assert(m3(2, 1) == 11); + assert(m3(2, 2) == 12); + assert(m3(3, 4) == 19); + } +} + +constexpr void check_comparisons() { + using StaticMapping = layout_right::mapping>; + using DynamicMapping = layout_right::mapping>; + + { // Check equality_comparable_with concept + static_assert(equality_comparable_with); + static_assert(!equality_comparable_with>>); + static_assert(!equality_comparable_with>>); + } + + { // Check correctness + StaticMapping m1; + DynamicMapping m2{dextents{4, 4}}; + DynamicMapping m3{dextents{2, 2}}; + assert(m1 == m2); + assert(m2 != m3); + assert(m1 != m3); + } +} + +constexpr void check_correctness() { + { // empty extents + const array vals{}; + mdspan, layout_right> nothing{vals.data()}; + assert(nothing.size() == 1); + } + + { // regular vector + const array vals{2, 1, 0}; + mdspan, layout_right> vec{vals.data()}; + + // TRANSITION, use operator[] + assert(vec(0) == 2); + assert(vec(1) == 1); + assert(vec(2) == 0); + } + + { // 4x3 matrix with row-major order + const array vals{11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + mdspan, layout_right> matrix{vals.data()}; + + // TRANSITION, use operator[] + assert(matrix(0, 0) == 11); + assert(matrix(0, 2) == 9); + assert(matrix(1, 1) == 7); + assert(matrix(2, 0) == 5); + assert(matrix(2, 2) == 3); + assert(matrix(3, 1) == 1); + } + + { // 4x3x2 tensor + const array vals{23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + mdspan, layout_right> tensor{vals.data(), 4, 3, 2}; + + // TRANSITION, use operator[] + assert(tensor(0, 0, 0) == 23); + assert(tensor(0, 0, 1) == 22); + assert(tensor(0, 1, 0) == 21); + assert(tensor(0, 1, 1) == 20); + assert(tensor(1, 0, 0) == 17); + assert(tensor(1, 0, 1) == 16); + assert(tensor(1, 1, 0) == 15); + assert(tensor(1, 1, 1) == 14); + assert(tensor(2, 2, 1) == 6); + assert(tensor(3, 2, 1) == 0); + } + + { // 3x2x3x2 tensor + const array vals{35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; + mdspan, layout_right> tensor{vals.data(), 2, 2}; + + // TRANSITION, use operator[] + assert(tensor(0, 0, 0, 0) == 35); + assert(tensor(0, 0, 0, 1) == 34); + assert(tensor(0, 0, 1, 0) == 33); + assert(tensor(0, 0, 1, 1) == 32); + assert(tensor(0, 1, 0, 0) == 29); + assert(tensor(0, 1, 0, 1) == 28); + assert(tensor(0, 1, 1, 0) == 27); + assert(tensor(0, 1, 1, 1) == 26); + assert(tensor(1, 0, 0, 0) == 23); + assert(tensor(1, 0, 0, 1) == 22); + assert(tensor(1, 0, 1, 0) == 21); + assert(tensor(1, 0, 1, 1) == 20); + assert(tensor(1, 1, 0, 0) == 17); + assert(tensor(1, 1, 0, 1) == 16); + assert(tensor(1, 1, 1, 0) == 15); + assert(tensor(1, 1, 1, 1) == 14); + assert(tensor(2, 0, 2, 0) == 7); + assert(tensor(2, 1, 2, 1) == 0); + } +} + +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_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; +} + +int main() { + static_assert(test()); + test(); +} diff --git a/tests/std/tests/P0009R18_mdspan_layout_right_death/env.lst b/tests/std/tests/P0009R18_mdspan_layout_right_death/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_layout_right_death/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp new file mode 100644 index 00000000000..449227a7143 --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_layout_right_death/test.cpp @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include + +using namespace std; + +// TRANSITION, Test Construction From extents_type + +void test_construction_from_other_right_mapping() { + layout_right::mapping> m1{dextents{256}}; + // Value of other.required_span_size() must be representable as a value of type index_type + layout_right::mapping> m2{m1}; +} + +void test_construction_from_other_left_mapping() { + layout_left::mapping> m1{dextents{256}}; + // Value of other.required_span_size() must be representable as a value of type index_type + layout_right::mapping> m2{m1}; +} + +#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 +void test_construction_from_other_stride_mapping_1() { + using Ext = extents; + layout_stride::mapping m1{Ext{}, array{3, 1}}; + // For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to + // extents().rev-prod-of-extents(r) + layout_right::mapping m2{m1}; +} + +void test_construction_from_other_stride_mapping_2() { + layout_stride::mapping> m1{dextents{256}, array{1}}; + // Value of other.required_span_size() must be representable as a value of type index_type + layout_right::mapping> m2{m1}; +} +#pragma warning(pop) // TRANSITION, "/analyze:only" BUG? + +void test_stride_function() { + layout_right::mapping> m; + // Value of i must be less than extents_type::rank() + (void) m.stride(1); +} + +int main(int argc, char* argv[]) { + std_testing::death_test_executive exec; + exec.add_death_tests({ + // TRANSITION Construction From extents_type + test_construction_from_other_right_mapping, + test_construction_from_other_left_mapping, + test_construction_from_other_stride_mapping_1, + test_construction_from_other_stride_mapping_2, + test_stride_function, + }); + return exec.run(argc, argv); +}