From cb5f69ddc8a7fc2782e91080b2ff3e4ccd8269cc Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 29 Mar 2023 23:35:39 +0200 Subject: [PATCH 01/17] Add `test_mdspan_support.hpp` header --- tests/std/include/test_mdspan_support.hpp | 28 +++++++++++++++++++ .../tests/P0009R18_mdspan_extents/test.cpp | 23 ++------------- 2 files changed, 30 insertions(+), 21 deletions(-) create mode 100644 tests/std/include/test_mdspan_support.hpp diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp new file mode 100644 index 00000000000..a0997ecb888 --- /dev/null +++ b/tests/std/include/test_mdspan_support.hpp @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include +#include + +enum class IsNothrow : bool { no, yes }; + +template +struct ConvertibleToInt { + constexpr operator Int() const noexcept(std::to_underlying(Nothrow)) { + return Int{1}; + } +}; + +struct NonConvertibleToAnything {}; + +template +constexpr void check_implicit_conversion(T); // not defined + +// clang-format off +template +concept NotImplicitlyConstructibleFrom = + std::constructible_from + && !requires(Args&&... args) { check_implicit_conversion({std::forward(args)...}); }; +// clang-format on diff --git a/tests/std/tests/P0009R18_mdspan_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp index bd6c2de05f5..f5546caee9f 100644 --- a/tests/std/tests/P0009R18_mdspan_extents/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -10,28 +10,9 @@ #include #include -using namespace std; - -enum class IsNothrow : bool { no, yes }; - -template -struct ConvertibleToInt { - constexpr operator Int() const noexcept(to_underlying(Nothrow)) { - return Int{1}; - } -}; +#include "test_mdspan_support.hpp" -struct NonConvertibleToAnything {}; - -template -constexpr void check_implicit_conversion(T); // not defined - -// clang-format off -template -concept NotImplicitlyConstructibleFrom = - constructible_from - && !requires(Args&&... args) { check_implicit_conversion({forward(args)...}); }; -// clang-format on +using namespace std; template constexpr void do_check_members(index_sequence) { From 9ad8c02076ae7f9a9edef53fd087dda33fc7b9a0 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 30 Mar 2023 15:01:50 +0200 Subject: [PATCH 02/17] Improve `layout_left` --- stl/inc/mdspan | 89 +++-- tests/std/include/test_mdspan_support.hpp | 91 ++++- tests/std/test.lst | 2 + .../tests/P0009R18_mdspan_extents/test.cpp | 2 - .../tests/P0009R18_mdspan_layout_left/env.lst | 4 + .../P0009R18_mdspan_layout_left/test.cpp | 370 ++++++++++++++++++ .../P0009R18_mdspan_layout_left_death/env.lst | 4 + .../test.cpp | 61 +++ 8 files changed, 587 insertions(+), 36 deletions(-) create mode 100644 tests/std/tests/P0009R18_mdspan_layout_left/env.lst create mode 100644 tests/std/tests/P0009R18_mdspan_layout_left/test.cpp create mode 100644 tests/std/tests/P0009R18_mdspan_layout_left_death/env.lst create mode 100644 tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 6a357a01b6c..22197b38787 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -240,6 +240,15 @@ public: } } + // TRANSITION, LWG ISSUE? I believe that this function should return 'index_type' + _NODISCARD constexpr index_type _Fwd_prod_of_extents(const rank_type _Idx) const noexcept { + index_type _Result = 1; + for (rank_type _Dim = 0; _Dim < _Idx; ++_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 * ...)); @@ -314,24 +323,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.left.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.left.cons]/4)."); + } template requires (extents_type::rank() <= 1) && is_constructible_v constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_right::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.left.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 = 1; + return ( + (_Other.stride(_Indices) + == (_Indices + 1 == extents_type::rank() + ? _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().fwd-prod-of-extents(r) (N4944 [mdspan.layout.left.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.left.cons]/10.2)."); + } constexpr mapping& operator=(const mapping&) noexcept = default; @@ -340,19 +377,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{}, _Indices...); } _NODISCARD static constexpr bool is_always_unique() noexcept { @@ -367,44 +399,40 @@ 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 = 0; _Dim < _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.left.obs]/6)."); + return _Exts._Fwd_prod_of_extents(_Idx); } template requires (extents_type::rank() == _OtherExtents::rank()) _NODISCARD_FRIEND constexpr bool operator==(const mapping& _Left, const mapping<_OtherExtents>& _Right) noexcept { - return _Left.extents() == _Right.extents(); + return _Left._Exts == _Right.extents(); } private: extents_type _Exts{}; - template - constexpr index_type _Index_impl(_IndexType... _Idx, index_sequence<_Seq...>) const noexcept { - // return _Extents::rank() > 0 ? ((_Idx * stride(_Seq)) + ... + 0) : 0; + template + constexpr index_type _Index_impl(index_sequence<_Seq...>, _IndexTypes... _Indices) const noexcept { index_type _Stride = 1; index_type _Result = 0; - (((_Result += _Idx * _Stride), (void) (_Stride *= _Exts.extent(_Seq))), ...); + (((_Result += static_cast(_Indices) * _Stride), (_Stride *= _Exts.extent(_Seq))), ...); return _Result; } }; @@ -789,7 +817,6 @@ public: template requires (is_convertible_v<_OtherIndexTypes, index_type> && ...) && (is_nothrow_constructible_v && ...) - && (sizeof...(_OtherIndexTypes) > 0) && (sizeof...(_OtherIndexTypes) == rank() || sizeof...(_OtherIndexTypes) == rank_dynamic()) && is_constructible_v && is_default_constructible_v constexpr explicit mdspan(data_handle_type _Ptr_, _OtherIndexTypes... _Exts) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index a0997ecb888..8dea01327f0 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -4,13 +4,17 @@ #pragma once #include +#include +#include #include +using namespace std; + enum class IsNothrow : bool { no, yes }; template struct ConvertibleToInt { - constexpr operator Int() const noexcept(std::to_underlying(Nothrow)) { + constexpr operator Int() const noexcept(to_underlying(Nothrow)) { return Int{1}; } }; @@ -23,6 +27,87 @@ constexpr void check_implicit_conversion(T); // not defined // clang-format off template concept NotImplicitlyConstructibleFrom = - std::constructible_from - && !requires(Args&&... args) { check_implicit_conversion({std::forward(args)...}); }; + constructible_from + && !requires(Args&&... args) { check_implicit_conversion({forward(args)...}); }; // clang-format on + +template +inline constexpr bool is_extents_v = false; + +template +inline constexpr bool is_extents_v> = true; + +template +inline constexpr bool is_mapping_of_v = + is_same_v, Mapping>; + +template +concept CheckNestedTypesOfLayoutMapping = + requires { + requires is_extents_v; + requires same_as; + requires same_as; + requires is_mapping_of_v; + }; + +template +concept CheckMemberFunctionsOfLayoutMapping = requires(const M m) { + { m.extents() } -> same_as; + { m.required_span_size() } -> same_as; + { m.is_unique() } -> same_as; + { m.is_exhaustive() } -> same_as; + { m.is_strided() } -> same_as; + }; + +template +concept CheckStaticFunctionsOfLayoutMapping = requires(const M m) { + { M::is_always_strided() } -> same_as; + { M::is_always_exhaustive() } -> same_as; + { M::is_always_unique() } -> same_as; + bool_constant::value; + bool_constant::value; + bool_constant::value; + }; + +template +concept CheckCallOperatorOfLayoutMapping = requires(const M m, Indices... i) { + { m(i...) } -> same_as; + { m(i...) == m(i...) } -> same_as; + }; +template +concept CheckStrideMemberFunc = requires(M mapping, typename M::rank_type i) { + { mapping.stride(i) } -> same_as; + }; + +template +constexpr bool check_layout_mapping_requirements() { + static_assert(copyable); + static_assert(equality_comparable); + static_assert(is_nothrow_move_constructible_v); + static_assert(is_nothrow_move_assignable_v); + static_assert(is_nothrow_swappable_v); + static_assert(CheckNestedTypesOfLayoutMapping); + static_assert(CheckMemberFunctionsOfLayoutMapping); + static_assert(CheckStaticFunctionsOfLayoutMapping); + + [](index_sequence) { + static_assert(CheckCallOperatorOfLayoutMapping); + } + (make_index_sequence{}); + + if constexpr (requires(M m, typename M::rank_type i) { m.stride(i); }) { + static_assert(CheckStrideMemberFunc); + } + + return true; +} + +template + requires is_extents_v +constexpr bool check_layout_mapping_policy_requirements() { + using X = MP::template mapping; + static_assert(check_layout_mapping_requirements()); + static_assert(same_as); + static_assert(same_as); + return true; +} diff --git a/tests/std/test.lst b/tests/std/test.lst index 06841dee535..7e133eec9d8 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -233,6 +233,8 @@ tests\P0009R18_mdspan tests\P0009R18_mdspan_default_accessor tests\P0009R18_mdspan_extents tests\P0009R18_mdspan_extents_death +tests\P0009R18_mdspan_layout_left +tests\P0009R18_mdspan_layout_left_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_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp index f5546caee9f..54ccb66200c 100644 --- a/tests/std/tests/P0009R18_mdspan_extents/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -12,8 +12,6 @@ #include "test_mdspan_support.hpp" -using namespace std; - template constexpr void do_check_members(index_sequence) { using Ext = extents; diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/env.lst b/tests/std/tests/P0009R18_mdspan_layout_left/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_layout_left/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_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp new file mode 100644 index 00000000000..19821d26bc0 --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -0,0 +1,370 @@ +// 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" + +template +concept CanInvokeCallOperatorOfMapping = requires(Mapping mapping, Indices... i) { + { mapping(i...) } -> same_as; + }; + +template +constexpr void do_check_members(const extents& ext, index_sequence) { + using Ext = extents; + using Mapping = layout_left::mapping; + + // Check layout mapping requirements + static_assert(check_layout_mapping_policy_requirements()); + + // layout_left​::​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 mapping; + Mapping copy = mapping; + assert(copy == mapping); + static_assert(is_nothrow_default_constructible_v); + static_assert(is_nothrow_copy_constructible_v); + } + + { // Check construction from extents_type + Mapping mapping{ext}; + assert(mapping.extents() == ext); + static_assert(is_nothrow_constructible_v); + } + + using OtherIndexType = long long; + using Ext2 = extents; + using Mapping2 = layout_left::mapping; + + { // Check construction from other layout_left::mapping + Mapping mapping{ext}; + Mapping2 mapping2{mapping}; + assert(mapping == mapping2); + static_assert(is_nothrow_constructible_v); + // Other tests are defined in 'check_construction_from_other_left_mapping' function + } + + { // Check construction from layout_right::mapping + using RightMapping = layout_right::mapping; + if constexpr (Ext::rank() <= 1) { + RightMapping right_mapping{ext}; + [[maybe_unused]] Mapping mapping{right_mapping}; + [[maybe_unused]] Mapping2 mapping2{right_mapping}; + assert(mapping == mapping2); + 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_right_mapping' function + } + +#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)); + } + + using StrideMapping = layout_stride::mapping; + StrideMapping stride_mapping{ext, strides}; + [[maybe_unused]] Mapping mapping{stride_mapping}; + // Other tests are defined in 'check_construction_from_other_stride_mapping' function + } +#pragma warning(pop) // TRANSITION, "/analyze:only" BUG? + + Mapping mapping{ext}; // For later use + + { // Check 'extents' function + assert(mapping.extents() == ext); + static_assert(noexcept(mapping.extents())); + } + + { // Check 'required_span_size' function + const IndexType expected_value = static_cast((ext.extent(Indices) * ... * 1)); + assert(mapping.required_span_size() == expected_value); + static_assert(noexcept(mapping.required_span_size())); + } + + { // Check operator() + assert(mapping(((void) Indices, 0)...) == 0); + assert(mapping((ext.extent(Indices) - 1)...) == static_cast((ext.extent(Indices) * ... * 1)) - 1); + static_assert(noexcept(mapping(((void) Indices, 0)...))); + static_assert(noexcept(mapping((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_value = + static_cast((ext.extent(Indices) * ... * 1) / ext.extent(Ext::rank() - 1)); + assert(mapping.stride(Ext::rank() - 1) == expected_value); + assert(mapping.stride(0) == 1); + static_assert(noexcept(mapping.stride(Ext::rank() - 1))); + static_assert(noexcept(mapping.stride(0))); + } else { + static_assert(!CheckStrideMemberFunc); + } + + { // Check comparisons + assert(mapping == mapping); + // 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_left_mapping() { + { // Check invalid construction + using Mapping = layout_left::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>>); + static_assert(NotImplicitlyConstructibleFrom>, + layout_left::mapping>>); + } +} + +constexpr void check_construction_from_other_right_mapping() { + { // Check construction from layout_right::mapping with various values of E::rank() + static_assert( + is_constructible_v>, layout_right::mapping>>); + static_assert( + is_constructible_v>, layout_right::mapping>>); + static_assert( + !is_constructible_v>, layout_right::mapping>>); + static_assert( + !is_constructible_v>, layout_right::mapping>>); + } + + { // Check construction from layout_right::mapping when E is invalid + using Mapping = layout_left::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>>); + } +} + +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_left::mapping>; + static_assert(!is_constructible_v>>); + static_assert(!is_constructible_v>>); + } + + { // 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_left::mapping>; + static_assert(!CanInvokeCallOperatorOfMapping); + static_assert(!CanInvokeCallOperatorOfMapping); + static_assert(CanInvokeCallOperatorOfMapping); + static_assert(!CanInvokeCallOperatorOfMapping); + } + + { // 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); + } + + { // Check call with types that might throw during conversion + using Mapping = layout_left::mapping>; + static_assert(CanInvokeCallOperatorOfMapping>); + static_assert(!CanInvokeCallOperatorOfMapping>); + } + + { // Check various mappings + layout_left::mapping> mapping1; + assert(mapping1() == 0); + + layout_left::mapping> mapping2; + assert(mapping2(0) == 0); + assert(mapping2(1) == 1); + assert(mapping2(2) == 2); + + layout_left::mapping> mapping3{dextents{5, 6}}; + assert(mapping3(0, 0) == 0); + assert(mapping3(1, 0) == 1); + assert(mapping3(0, 1) == 5); + assert(mapping3(1, 1) == 6); + assert(mapping3(2, 1) == 7); + assert(mapping3(1, 2) == 11); + assert(mapping3(4, 5) == 29); + } +} + +constexpr void check_comparisons() { + using StaticMapping = layout_left::mapping>; + using DynamicMapping = layout_left::mapping>; + + { // Check equality_comparable_with concept + static_assert(equality_comparable_with); + static_assert(!equality_comparable_with>>); + static_assert(!equality_comparable_with>>); + } + + { // Check correctness + StaticMapping mapping1; + DynamicMapping mapping2{dextents{3}}; + DynamicMapping mapping3{dextents{2}}; + assert(mapping1 == mapping2); + assert(mapping2 != mapping3); + assert(mapping1 != mapping3); + } +} + +constexpr void check_correctness() { + { // empty extents + const array values{}; + mdspan, layout_left> nothing{values.data()}; + assert(nothing.size() == 1); + } + + { // regular vector + const array values{0, 1, 2}; + mdspan, layout_left> vec{values.data()}; + + // TRANSITION, use operator[] + assert(vec(0) == 0); + assert(vec(1) == 1); + assert(vec(2) == 2); + } + + { // 3x2 matrix with column-major order + const array values{0, 1, 2, 3, 4, 5}; + mdspan, layout_left> matrix{values.data()}; + + // TRANSITION, use operator[] + assert(matrix(0, 0) == 0); + assert(matrix(1, 0) == 1); + assert(matrix(2, 0) == 2); + assert(matrix(0, 1) == 3); + assert(matrix(1, 1) == 4); + assert(matrix(2, 1) == 5); + } + + { // 3x2x4 tensor + const array values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + mdspan, layout_left> tensor{values.data(), 3, 2, 4}; + + // TRANSITION, use operator[] + assert(tensor(0, 0, 0) == 0); + assert(tensor(2, 0, 0) == 2); + assert(tensor(1, 1, 1) == 10); + assert(tensor(0, 0, 3) == 18); + assert(tensor(2, 2, 2) == 20); + assert(tensor(2, 1, 3) == 23); + } + + { // 2x3x2x3 tensor + const array values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; + mdspan, layout_left> tensor{values.data(), 2, 3}; + + // TRANSITION, use operator[] + assert(tensor(0, 0, 0, 0) == 0); + assert(tensor(1, 0, 0, 0) == 1); + assert(tensor(0, 1, 1, 0) == 8); + assert(tensor(0, 0, 0, 1) == 12); + assert(tensor(0, 0, 0, 2) == 24); + assert(tensor(0, 2, 0, 2) == 28); + assert(tensor(1, 2, 1, 2) == 35); + } +} + +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_left_mapping(); + check_construction_from_other_right_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_left_death/env.lst b/tests/std/tests/P0009R18_mdspan_layout_left_death/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_layout_left_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_left_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp new file mode 100644 index 00000000000..774bfc5c953 --- /dev/null +++ b/tests/std/tests/P0009R18_mdspan_layout_left_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_left_mapping() { + layout_left::mapping> mapping1{dextents{256}}; + // Value of other.required_span_size() must be representable as a value of type index_type + layout_left::mapping> mapping2{mapping1}; +} + +void test_construction_from_other_right_mapping() { + layout_right::mapping> mapping1{dextents{256}}; + // Value of other.required_span_size() must be representable as a value of type index_type + layout_left::mapping> mapping2{mapping1}; +} + +#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 mapping1{Ext{}, array{1, 1}}; + // For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to + // extents().fwd-prod-of-extents(r) + layout_left::mapping mapping2{mapping1}; +} + +void test_construction_from_other_stride_mapping_2() { + layout_stride::mapping> mapping1{dextents{256}, array{1}}; + // Value of other.required_span_size() must be representable as a value of type index_type + layout_left::mapping> mapping2{mapping1}; +} +#pragma warning(pop) // TRANSITION, "/analyze:only" BUG? + +void test_stride_function() { + layout_left::mapping> mapping; + // Value of i must be less than extents_type::rank() + (void) mapping.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_left_mapping, + test_construction_from_other_right_mapping, + test_construction_from_other_stride_mapping_1, + test_construction_from_other_stride_mapping_2, + test_stride_function, + }); + return exec.run(argc, argv); +} From cfcba7298d075bc56f7fdf609c74807ed5f3ec5a Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 30 Mar 2023 15:12:22 +0200 Subject: [PATCH 03/17] Fix warnings --- stl/inc/mdspan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 22197b38787..c6f56aa2b8e 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -873,8 +873,8 @@ public: requires (is_convertible_v<_OtherIndexTypes, index_type> && ...) && (is_nothrow_constructible_v && ...) && (sizeof...(_OtherIndexTypes) == rank()) - _NODISCARD constexpr reference operator()(const _OtherIndexTypes... _Indices) const { - return _Acc.access(_Ptr, _Map(static_cast(_STD move(_Indices))...)); + _NODISCARD constexpr reference operator()(_OtherIndexTypes... _Indices) const { + return _Acc.access(_Ptr, static_cast(_Map(static_cast(_STD move(_Indices))...))); } template From 5fbd829123ce9a6eb1926d8c7a4655ff58c04b21 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 30 Mar 2023 15:13:36 +0200 Subject: [PATCH 04/17] Fix typo from previous PR Comment: https://github.com/microsoft/STL/pull/3593#discussion_r1148917756 --- tests/std/tests/P0009R18_mdspan_extents/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0009R18_mdspan_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp index 54ccb66200c..1017482a5a3 100644 --- a/tests/std/tests/P0009R18_mdspan_extents/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -216,7 +216,7 @@ constexpr void check_construction_from_array_and_span() { static_assert(!is_constructible_v>); } - { // Check construciton with integers with mismatched signs + { // Check construction with integers with mismatched signs using Ext = extents; array arr = {4ull}; From babbfc3c29051d11a0a443eecbbbbefec2e64856 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 30 Mar 2023 15:15:06 +0200 Subject: [PATCH 05/17] Fix initialization Comment: https://github.com/microsoft/STL/pull/3593#discussion_r1148923347 --- stl/inc/mdspan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index c6f56aa2b8e..10d160401b8 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -587,7 +587,7 @@ public: && is_nothrow_constructible_v #endif // ^^^ no workaround ^^^ constexpr mapping(const extents_type& _Exts_, const span<_OtherIndexType, extents_type::rank()> _Strides_) noexcept - : _Exts{_Exts_} { + : _Exts(_Exts_) { for (rank_type _Idx = 0; _Idx < extents_type::rank(); ++_Idx) { _Strides[_Idx] = _Strides_[_Idx]; } @@ -604,7 +604,7 @@ public: #endif // ^^^ no workaround ^^^ constexpr mapping( const extents_type& _Exts_, const array<_OtherIndexType, extents_type::rank()>& _Strides_) noexcept - : _Exts{_Exts_} { + : _Exts(_Exts_) { for (rank_type _Idx = 0; _Idx < extents_type::rank(); ++_Idx) { _Strides[_Idx] = _Strides_[_Idx]; } From cd9e59b46c182eb9c733869fe010d1d9fc8ab23a Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 30 Mar 2023 15:19:21 +0200 Subject: [PATCH 06/17] Fix `CheckCallOperatorOfLayoutMapping` concept --- tests/std/include/test_mdspan_support.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index 8dea01327f0..a3c37e708b5 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -69,11 +69,15 @@ concept CheckStaticFunctionsOfLayoutMapping = requires(const M m) { bool_constant::value; }; +// clang-format off template -concept CheckCallOperatorOfLayoutMapping = requires(const M m, Indices... i) { - { m(i...) } -> same_as; - { m(i...) == m(i...) } -> same_as; - }; +concept CheckCallOperatorOfLayoutMapping = + requires(const M m, Indices... i) { + { m(i...) } -> same_as; + { m(i...) == m(static_cast(i)...) } -> same_as; + }; +// clang-format on + template concept CheckStrideMemberFunc = requires(M mapping, typename M::rank_type i) { { mapping.stride(i) } -> same_as; From 9596d3a17e48358f8b42793e9f76c38903ea9f20 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 30 Mar 2023 15:42:33 +0200 Subject: [PATCH 07/17] Fix invisible codepoints lol --- tests/std/tests/P0009R18_mdspan_layout_left/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index 19821d26bc0..b455476be52 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -24,7 +24,7 @@ constexpr void do_check_members(const extents& ext, index // Check layout mapping requirements static_assert(check_layout_mapping_policy_requirements()); - // layout_left​::​mapping is a trivially copyable type that models regular for each Ext + // layout_left::mapping is a trivially copyable type that models regular for each Ext static_assert(is_trivially_copyable_v); static_assert(regular); From 452d451504d9c5838675889f577b49e862b9094b Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 30 Mar 2023 17:36:59 +0200 Subject: [PATCH 08/17] Add missing `typename` (Clang 16 accepted this code) --- tests/std/include/test_mdspan_support.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index a3c37e708b5..1f2db91ad73 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -109,7 +109,7 @@ constexpr bool check_layout_mapping_requirements() { template requires is_extents_v constexpr bool check_layout_mapping_policy_requirements() { - using X = MP::template mapping; + using X = typename MP::template mapping; static_assert(check_layout_mapping_requirements()); static_assert(same_as); static_assert(same_as); From ea6e4f09f4f8fc68bc83e32efde885df772b7ebf Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 30 Mar 2023 23:24:38 +0200 Subject: [PATCH 09/17] Remove extra newline --- tests/std/tests/P0009R18_mdspan_layout_left/test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index b455476be52..ea6680795d3 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -363,7 +363,6 @@ constexpr bool test() { return true; } - int main() { static_assert(test()); test(); From 6af59e55f3e2b2d4cc88a00a29c62aa934d5ffe1 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 31 Mar 2023 00:37:15 +0200 Subject: [PATCH 10/17] Cast to `index_type` before call to `_Index_impl` Comment: https://github.com/microsoft/STL/pull/3603#discussion_r1153780262 --- stl/inc/mdspan | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 10d160401b8..63d06b94ff3 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -384,7 +384,7 @@ public: 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{}, _Indices...); + return _Index_impl(make_index_sequence{}, static_cast(_Indices)...); } _NODISCARD static constexpr bool is_always_unique() noexcept { @@ -430,9 +430,10 @@ private: template constexpr index_type _Index_impl(index_sequence<_Seq...>, _IndexTypes... _Indices) const noexcept { + _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); index_type _Stride = 1; index_type _Result = 0; - (((_Result += static_cast(_Indices) * _Stride), (_Stride *= _Exts.extent(_Seq))), ...); + (((_Result += _Indices * _Stride), (_Stride *= _Exts.extent(_Seq))), ...); return _Result; } }; From a5bb282eb8681ad0feec89cc26f99f38da08c216 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 31 Mar 2023 00:38:16 +0200 Subject: [PATCH 11/17] Mark `_Index_impl` as `_NODISCARD` Comment: https://github.com/microsoft/STL/pull/3603#discussion_r1153822059 --- stl/inc/mdspan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 63d06b94ff3..8f86197b54a 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -429,7 +429,7 @@ private: extents_type _Exts{}; template - constexpr index_type _Index_impl(index_sequence<_Seq...>, _IndexTypes... _Indices) const noexcept { + _NODISCARD constexpr index_type _Index_impl(index_sequence<_Seq...>, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); index_type _Stride = 1; index_type _Result = 0; From 64400c5b7d4f8becad24335399329aed3832953e Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 31 Mar 2023 00:40:45 +0200 Subject: [PATCH 12/17] Don't use `using namespace std` in new header Comment: https://github.com/microsoft/STL/pull/3603#discussion_r1153798670 --- tests/std/include/test_mdspan_support.hpp | 62 +++++++++---------- .../tests/P0009R18_mdspan_extents/test.cpp | 2 + .../P0009R18_mdspan_layout_left/test.cpp | 2 + 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index 1f2db91ad73..c41c6be1a5c 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -8,13 +8,11 @@ #include #include -using namespace std; - enum class IsNothrow : bool { no, yes }; template struct ConvertibleToInt { - constexpr operator Int() const noexcept(to_underlying(Nothrow)) { + constexpr operator Int() const noexcept(std::to_underlying(Nothrow)) { return Int{1}; } }; @@ -27,77 +25,77 @@ constexpr void check_implicit_conversion(T); // not defined // clang-format off template concept NotImplicitlyConstructibleFrom = - constructible_from - && !requires(Args&&... args) { check_implicit_conversion({forward(args)...}); }; + std::constructible_from + && !requires(Args&&... args) { check_implicit_conversion({std::forward(args)...}); }; // clang-format on template inline constexpr bool is_extents_v = false; template -inline constexpr bool is_extents_v> = true; +inline constexpr bool is_extents_v> = true; template inline constexpr bool is_mapping_of_v = - is_same_v, Mapping>; + std::is_same_v, Mapping>; template concept CheckNestedTypesOfLayoutMapping = requires { requires is_extents_v; - requires same_as; - requires same_as; + requires std::same_as; + requires std::same_as; requires is_mapping_of_v; }; template concept CheckMemberFunctionsOfLayoutMapping = requires(const M m) { - { m.extents() } -> same_as; - { m.required_span_size() } -> same_as; - { m.is_unique() } -> same_as; - { m.is_exhaustive() } -> same_as; - { m.is_strided() } -> same_as; + { m.extents() } -> std::same_as; + { m.required_span_size() } -> std::same_as; + { m.is_unique() } -> std::same_as; + { m.is_exhaustive() } -> std::same_as; + { m.is_strided() } -> std::same_as; }; template concept CheckStaticFunctionsOfLayoutMapping = requires(const M m) { - { M::is_always_strided() } -> same_as; - { M::is_always_exhaustive() } -> same_as; - { M::is_always_unique() } -> same_as; - bool_constant::value; - bool_constant::value; - bool_constant::value; + { M::is_always_strided() } -> std::same_as; + { M::is_always_exhaustive() } -> std::same_as; + { M::is_always_unique() } -> std::same_as; + std::bool_constant::value; + std::bool_constant::value; + std::bool_constant::value; }; // clang-format off template concept CheckCallOperatorOfLayoutMapping = requires(const M m, Indices... i) { - { m(i...) } -> same_as; - { m(i...) == m(static_cast(i)...) } -> same_as; + { m(i...) } -> std::same_as; + { m(i...) == m(static_cast(i)...) } -> std::same_as; }; // clang-format on template concept CheckStrideMemberFunc = requires(M mapping, typename M::rank_type i) { - { mapping.stride(i) } -> same_as; + { mapping.stride(i) } -> std::same_as; }; template constexpr bool check_layout_mapping_requirements() { - static_assert(copyable); - static_assert(equality_comparable); - static_assert(is_nothrow_move_constructible_v); - static_assert(is_nothrow_move_assignable_v); - static_assert(is_nothrow_swappable_v); + static_assert(std::copyable); + static_assert(std::equality_comparable); + static_assert(std::is_nothrow_move_constructible_v); + static_assert(std::is_nothrow_move_assignable_v); + static_assert(std::is_nothrow_swappable_v); static_assert(CheckNestedTypesOfLayoutMapping); static_assert(CheckMemberFunctionsOfLayoutMapping); static_assert(CheckStaticFunctionsOfLayoutMapping); - [](index_sequence) { + [](std::index_sequence) { static_assert(CheckCallOperatorOfLayoutMapping); } - (make_index_sequence{}); + (std::make_index_sequence{}); if constexpr (requires(M m, typename M::rank_type i) { m.stride(i); }) { static_assert(CheckStrideMemberFunc); @@ -111,7 +109,7 @@ template constexpr bool check_layout_mapping_policy_requirements() { using X = typename MP::template mapping; static_assert(check_layout_mapping_requirements()); - static_assert(same_as); - static_assert(same_as); + static_assert(std::same_as); + static_assert(std::same_as); return true; } diff --git a/tests/std/tests/P0009R18_mdspan_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp index 1017482a5a3..83cf926a70a 100644 --- a/tests/std/tests/P0009R18_mdspan_extents/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -12,6 +12,8 @@ #include "test_mdspan_support.hpp" +using namespace std; + template constexpr void do_check_members(index_sequence) { using Ext = extents; diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index ea6680795d3..75f0bb09c74 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -11,6 +11,8 @@ #include "test_mdspan_support.hpp" +using namespace std; + template concept CanInvokeCallOperatorOfMapping = requires(Mapping mapping, Indices... i) { { mapping(i...) } -> same_as; From d57fd14498a1ca42fdac7058b840ae529e75a8e1 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 31 Mar 2023 00:41:37 +0200 Subject: [PATCH 13/17] `test_mdspan_support.hpp`: Add missing `` include Comment: https://github.com/microsoft/STL/pull/3603#discussion_r1153800507 --- tests/std/include/test_mdspan_support.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index c41c6be1a5c..ea7af25a7f5 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include #include From e295c44ea8e5df4a397082063f06da3d2e607a38 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 31 Mar 2023 00:45:02 +0200 Subject: [PATCH 14/17] `CheckStrideMemberFunc` -> `CheckStrideMemberFunction` Comment: https://github.com/microsoft/STL/pull/3603#discussion_r1153803217 --- tests/std/include/test_mdspan_support.hpp | 8 ++++---- tests/std/tests/P0009R18_mdspan_layout_left/test.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index ea7af25a7f5..16d66474179 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -78,9 +78,9 @@ concept CheckCallOperatorOfLayoutMapping = // clang-format on template -concept CheckStrideMemberFunc = requires(M mapping, typename M::rank_type i) { - { mapping.stride(i) } -> std::same_as; - }; +concept CheckStrideMemberFunction = requires(M mapping, typename M::rank_type i) { + { mapping.stride(i) } -> std::same_as; + }; template constexpr bool check_layout_mapping_requirements() { @@ -99,7 +99,7 @@ constexpr bool check_layout_mapping_requirements() { (std::make_index_sequence{}); if constexpr (requires(M m, typename M::rank_type i) { m.stride(i); }) { - static_assert(CheckStrideMemberFunc); + static_assert(CheckStrideMemberFunction); } 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 75f0bb09c74..1dc635457a7 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -135,7 +135,7 @@ constexpr void do_check_members(const extents& ext, index static_assert(noexcept(mapping.stride(Ext::rank() - 1))); static_assert(noexcept(mapping.stride(0))); } else { - static_assert(!CheckStrideMemberFunc); + static_assert(!CheckStrideMemberFunction); } { // Check comparisons From 91d025899c06f5f0c37d335f665fd61872682708 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 31 Mar 2023 00:47:13 +0200 Subject: [PATCH 15/17] Don't use `mapping` identifier, just `m` (maybe with extra integer; `m1`) Comment: https://github.com/microsoft/STL/pull/3603#discussion_r1153846913 --- .../test.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp index 774bfc5c953..64fd0f7c728 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left_death/test.cpp @@ -13,38 +13,38 @@ using namespace std; // TRANSITION, Test Construction From extents_type void test_construction_from_other_left_mapping() { - layout_left::mapping> mapping1{dextents{256}}; + layout_left::mapping> m1{dextents{256}}; // Value of other.required_span_size() must be representable as a value of type index_type - layout_left::mapping> mapping2{mapping1}; + layout_left::mapping> m2{m1}; } void test_construction_from_other_right_mapping() { - layout_right::mapping> mapping1{dextents{256}}; + layout_right::mapping> m1{dextents{256}}; // Value of other.required_span_size() must be representable as a value of type index_type - layout_left::mapping> mapping2{mapping1}; + layout_left::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 mapping1{Ext{}, array{1, 1}}; + layout_stride::mapping m1{Ext{}, array{1, 1}}; // For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to // extents().fwd-prod-of-extents(r) - layout_left::mapping mapping2{mapping1}; + layout_left::mapping m2{m1}; } void test_construction_from_other_stride_mapping_2() { - layout_stride::mapping> mapping1{dextents{256}, array{1}}; + 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_left::mapping> mapping2{mapping1}; + layout_left::mapping> m2{m1}; } #pragma warning(pop) // TRANSITION, "/analyze:only" BUG? void test_stride_function() { - layout_left::mapping> mapping; + layout_left::mapping> m; // Value of i must be less than extents_type::rank() - (void) mapping.stride(1); + (void) m.stride(1); } int main(int argc, char* argv[]) { From a9df41458353613be2471a9d901899afdb65c6bc Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 31 Mar 2023 00:54:02 +0200 Subject: [PATCH 16/17] Again: don't use `mapping` identifier, just `m` (maybe with extra integer; `m1`) Also, don't use `copy`. Just `cpy`. Comment: https://github.com/microsoft/STL/pull/3603#discussion_r1153848585 --- .../P0009R18_mdspan_layout_left/test.cpp | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index 1dc635457a7..4feab7e135b 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -14,8 +14,8 @@ using namespace std; template -concept CanInvokeCallOperatorOfMapping = requires(Mapping mapping, Indices... i) { - { mapping(i...) } -> same_as; +concept CanInvokeCallOperatorOfMapping = requires(Mapping m, Indices... i) { + { m(i...) } -> same_as; }; template @@ -38,16 +38,16 @@ constexpr void do_check_members(const extents& ext, index static_assert(same_as); { // Check default and copy constructor - Mapping mapping; - Mapping copy = mapping; - assert(copy == mapping); + 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 mapping{ext}; - assert(mapping.extents() == ext); + Mapping m{ext}; + assert(m.extents() == ext); static_assert(is_nothrow_constructible_v); } @@ -56,9 +56,9 @@ constexpr void do_check_members(const extents& ext, index using Mapping2 = layout_left::mapping; { // Check construction from other layout_left::mapping - Mapping mapping{ext}; - Mapping2 mapping2{mapping}; - assert(mapping == mapping2); + Mapping m1{ext}; + Mapping2 m2{m1}; + assert(m1 == m2); static_assert(is_nothrow_constructible_v); // Other tests are defined in 'check_construction_from_other_left_mapping' function } @@ -67,9 +67,9 @@ constexpr void do_check_members(const extents& ext, index using RightMapping = layout_right::mapping; if constexpr (Ext::rank() <= 1) { RightMapping right_mapping{ext}; - [[maybe_unused]] Mapping mapping{right_mapping}; - [[maybe_unused]] Mapping2 mapping2{right_mapping}; - assert(mapping == mapping2); + [[maybe_unused]] Mapping m1{right_mapping}; + [[maybe_unused]] Mapping2 m2{right_mapping}; + assert(m1 == m2); static_assert(is_nothrow_constructible_v); static_assert(is_nothrow_constructible_v); } else { @@ -89,29 +89,29 @@ constexpr void do_check_members(const extents& ext, index using StrideMapping = layout_stride::mapping; StrideMapping stride_mapping{ext, strides}; - [[maybe_unused]] Mapping mapping{stride_mapping}; + [[maybe_unused]] Mapping m{stride_mapping}; // Other tests are defined in 'check_construction_from_other_stride_mapping' function } #pragma warning(pop) // TRANSITION, "/analyze:only" BUG? - Mapping mapping{ext}; // For later use + Mapping m{ext}; // For later use { // Check 'extents' function - assert(mapping.extents() == ext); - static_assert(noexcept(mapping.extents())); + 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(mapping.required_span_size() == expected_value); - static_assert(noexcept(mapping.required_span_size())); + assert(m.required_span_size() == expected_value); + static_assert(noexcept(m.required_span_size())); } { // Check operator() - assert(mapping(((void) Indices, 0)...) == 0); - assert(mapping((ext.extent(Indices) - 1)...) == static_cast((ext.extent(Indices) * ... * 1)) - 1); - static_assert(noexcept(mapping(((void) Indices, 0)...))); - static_assert(noexcept(mapping((ext.extent(Indices) - 1)...))); + 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 } @@ -130,16 +130,16 @@ constexpr void do_check_members(const extents& ext, index if constexpr (Ext::rank() > 0) { // Check 'stride' function const IndexType expected_value = static_cast((ext.extent(Indices) * ... * 1) / ext.extent(Ext::rank() - 1)); - assert(mapping.stride(Ext::rank() - 1) == expected_value); - assert(mapping.stride(0) == 1); - static_assert(noexcept(mapping.stride(Ext::rank() - 1))); - static_assert(noexcept(mapping.stride(0))); + assert(m.stride(Ext::rank() - 1) == expected_value); + assert(m.stride(0) == 1); + static_assert(noexcept(m.stride(Ext::rank() - 1))); + static_assert(noexcept(m.stride(0))); } else { static_assert(!CheckStrideMemberFunction); } { // Check comparisons - assert(mapping == mapping); + assert(m == m); // Other tests are defined in 'check_comparisons' function } } @@ -251,22 +251,22 @@ constexpr void check_call_operator() { } { // Check various mappings - layout_left::mapping> mapping1; - assert(mapping1() == 0); - - layout_left::mapping> mapping2; - assert(mapping2(0) == 0); - assert(mapping2(1) == 1); - assert(mapping2(2) == 2); - - layout_left::mapping> mapping3{dextents{5, 6}}; - assert(mapping3(0, 0) == 0); - assert(mapping3(1, 0) == 1); - assert(mapping3(0, 1) == 5); - assert(mapping3(1, 1) == 6); - assert(mapping3(2, 1) == 7); - assert(mapping3(1, 2) == 11); - assert(mapping3(4, 5) == 29); + layout_left::mapping> m1; + assert(m1() == 0); + + layout_left::mapping> m2; + assert(m2(0) == 0); + assert(m2(1) == 1); + assert(m2(2) == 2); + + layout_left::mapping> m3{dextents{5, 6}}; + assert(m3(0, 0) == 0); + assert(m3(1, 0) == 1); + assert(m3(0, 1) == 5); + assert(m3(1, 1) == 6); + assert(m3(2, 1) == 7); + assert(m3(1, 2) == 11); + assert(m3(4, 5) == 29); } } @@ -281,12 +281,12 @@ constexpr void check_comparisons() { } { // Check correctness - StaticMapping mapping1; - DynamicMapping mapping2{dextents{3}}; - DynamicMapping mapping3{dextents{2}}; - assert(mapping1 == mapping2); - assert(mapping2 != mapping3); - assert(mapping1 != mapping3); + StaticMapping m1; + DynamicMapping m2{dextents{3}}; + DynamicMapping m3{dextents{2}}; + assert(m1 == m2); + assert(m2 != m3); + assert(m1 != m3); } } From 60f32723cb4aec3aba7ab428e3ee79968603aeeb Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 31 Mar 2023 01:41:25 +0200 Subject: [PATCH 17/17] QUICK: Fix wrong tests and add a little bit of extra coverage --- tests/std/tests/P0009R18_mdspan_layout_left/test.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index 4feab7e135b..f9f74fed954 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -23,12 +23,13 @@ constexpr void do_check_members(const extents& ext, index using Ext = extents; using Mapping = layout_left::mapping; - // Check layout mapping requirements + // layout_left meets the layout mapping policy requirements and is a trivial type static_assert(check_layout_mapping_policy_requirements()); + static_assert(is_trivial_v); // layout_left::mapping is a trivially copyable type that models regular for each Ext - static_assert(is_trivially_copyable_v); - static_assert(regular); + static_assert(is_trivially_copyable_v); + static_assert(regular); // Check member types static_assert(same_as);