From 4a03ebee6bd2efe402536c0a2370070842f6074b Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 12 Jun 2023 17:08:15 +0200 Subject: [PATCH 01/13] Improve `std::mdspan` tests --- .../std/tests/P0009R18_mdspan_mdspan/test.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp index a0e16d63392..44580c94dd0 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp @@ -339,9 +339,12 @@ struct TrivialAccessor { static_assert(check_accessor_policy_requirements>()); static_assert(is_trivial_v>); -constexpr void check_modeled_concepts() { - using Mds = mdspan, TrackingLayout, - AccessorWithCustomOffsetPolicy>; +template class AccessorTemplate> +constexpr void check_modeled_concepts_and_member_types() { + using Accessor = AccessorTemplate; + using Mds = mdspan; + + // Check modeled concepts static_assert(copyable); static_assert(is_nothrow_move_constructible_v); static_assert(is_nothrow_move_assignable_v); @@ -350,13 +353,8 @@ constexpr void check_modeled_concepts() { is_trivially_copyable_v == (is_trivially_copyable_v && is_trivially_copyable_v && is_trivially_copyable_v) ); -} -constexpr void check_member_types() { - using Ext = extents; - using Layout = layout_stride; - using Accessor = TrivialAccessor; - using Mds = mdspan; + // Check member types static_assert(same_as); static_assert(same_as); static_assert(same_as); @@ -1319,8 +1317,10 @@ constexpr void check_deduction_guides() { } constexpr bool test() { - check_modeled_concepts(); - check_member_types(); + check_modeled_concepts_and_member_types, layout_stride, TrivialAccessor>(); + check_modeled_concepts_and_member_types, TrackingLayout<>, + AccessorWithTrackingDataHandle>(); + check_modeled_concepts_and_member_types, layout_left, TrackingAccessor>(); check_observers(); check_default_constructor(); check_defaulted_copy_and_move_constructors(); From 4c3694cca7fac982db62b1fd30c6d48df7c950d9 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 12 Jun 2023 17:53:57 +0200 Subject: [PATCH 02/13] Improve `std::extents` tests --- tests/std/include/test_mdspan_support.hpp | 26 +- .../tests/P0009R18_mdspan_extents/test.cpp | 392 ++++++++++++++---- 2 files changed, 332 insertions(+), 86 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index 23b8902dc45..3163037be29 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -11,15 +11,35 @@ #include #include +enum class IsExplicit : bool { no, yes }; enum class IsNothrow : bool { no, yes }; -template +template struct ConvertibleToInt { - constexpr operator Int() const noexcept(std::to_underlying(Nothrow)) { - return Int{1}; + Int val = 1; + + constexpr explicit(std::to_underlying(Explicit)) operator Int() const noexcept(std::to_underlying(Nothrow)) { + return val; } }; +static_assert(std::is_aggregate_v>); +static_assert(std::is_convertible_v, int>); +static_assert(std::is_nothrow_convertible_v, int>); +static_assert(!std::is_nothrow_convertible_v, int>); +static_assert(std::is_convertible_v, int>); +static_assert(!std::is_convertible_v, int>); + +template +struct NonConstConvertibleToInt { + constexpr operator Int() noexcept; // not defined +}; + +static_assert(std::is_convertible_v, int>); +static_assert(!std::is_convertible_v, int>); +static_assert(std::is_nothrow_convertible_v, int>); +static_assert(!std::is_nothrow_convertible_v, int>); + struct NonConvertibleToAnything {}; namespace detail { diff --git a/tests/std/tests/P0009R18_mdspan_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp index e7fa0109883..1ed2d2f5848 100644 --- a/tests/std/tests/P0009R18_mdspan_extents/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -22,6 +22,13 @@ constexpr void check_members(index_sequence) { static_assert(regular); static_assert(is_trivially_copyable_v); + // Check implicit properties + static_assert(is_nothrow_copy_constructible_v); + static_assert(is_nothrow_move_constructible_v); + static_assert(is_nothrow_copy_assignable_v); + static_assert(is_nothrow_move_assignable_v); + static_assert(is_nothrow_swappable_v); + // Check member types static_assert(same_as); static_assert(same_as>); @@ -80,10 +87,42 @@ constexpr void check_members(index_sequence) { } } +constexpr void check_defaulted_default_constructor() { + { // All extents are static + using Ext = extents; + static_assert(is_nothrow_default_constructible_v); + + Ext ext; + assert(ext.extent(0) == 3); + assert(ext.extent(1) == 5); + assert(ext.extent(2) == 7); + } + + { // Some extents are static, some dynamic + using Ext = extents; + static_assert(is_nothrow_default_constructible_v); + + Ext ext; + assert(ext.extent(0) == 0); + assert(ext.extent(1) == 0); + assert(ext.extent(2) == 4); + } + + { // All extents are dynamic + using Ext = dextents; + static_assert(is_nothrow_default_constructible_v); + + Ext ext; + assert(ext.extent(0) == 0); + assert(ext.extent(1) == 0); + assert(ext.extent(2) == 0); + } +} + constexpr void check_construction_from_other_extents() { { // Check construction from too big or too small other extents using Ext = extents; - static_assert(!is_constructible_v); + static_assert(!is_constructible_v>); static_assert(!is_constructible_v>); } @@ -95,17 +134,44 @@ constexpr void check_construction_from_other_extents() { static_assert(!is_constructible_v, extents>); } - { // Check postconditions - extents ext{4, 4}; - extents ext2{ext}; - assert(ext == ext2); - assert(ext2.extent(0) == 4); + { // Check postconditions: static extents from static extents + extents ext; + extents ext2 = ext; + assert(ext2.extent(0) == 3); assert(ext2.extent(1) == 4); + assert(ext == ext2); + } - extents ext3{ext}; - assert(ext == ext3); - assert(ext3.extent(0) == 4); - assert(ext3.extent(1) == 4); + { // Check postconditions: dynamic extents from static extents + extents ext; + dextents ext2 = ext; + assert(ext2.extent(0) == 2); + assert(ext2.extent(1) == 3); + assert(ext == ext2); + } + + { // Check postconditions: dynamic extents from dynamic extents + dextents ext{5, 10}; + dextents ext2 = ext; + assert(ext2.extent(0) == 5); + assert(ext2.extent(1) == 10); + assert(ext == ext2); + } + + { // Check postconditions: static extents from dynamic extents + dextents ext{9, 6}; + extents ext2{ext}; // NB: explicit constructor + assert(ext2.extent(0) == 9); + assert(ext2.extent(1) == 6); + assert(ext == ext2); + } + + { // Check postconditions: wider index type to narrower index type + dextents ext{3, 5}; + dextents ext2{ext}; // NB: explicit constructor + assert(ext2.extent(0) == 3); + assert(ext2.extent(1) == 5); + assert(ext == ext2); } { // Check implicit conversions @@ -118,7 +184,7 @@ constexpr void check_construction_from_other_extents() { constexpr void check_construction_from_extents_pack() { { // Check construction from various types - using Ext = extents; + using Ext = extents; static_assert(is_nothrow_constructible_v); static_assert(!is_constructible_v); static_assert(is_nothrow_constructible_v); @@ -127,8 +193,10 @@ constexpr void check_construction_from_extents_pack() { { // Check construction from types (not) convertible to index_type using Ext = extents; static_assert(is_nothrow_constructible_v>); + static_assert(!is_nothrow_constructible_v>); static_assert(!is_constructible_v); static_assert(is_nothrow_constructible_v>); + static_assert(!is_nothrow_constructible_v>); static_assert(!is_constructible_v); } @@ -138,15 +206,47 @@ constexpr void check_construction_from_extents_pack() { static_assert(!is_constructible_v>); } - { // Check postconditions + { // Check postconditions when 'sizeof...(pack) == rank()' using Ext = extents; - Ext ext1a{4, ConvertibleToInt{}, 4}; - Ext ext1b{4, 1, 4}; - assert(ext1a == ext1b); + Ext ext{4, ConvertibleToInt{.val = 4}, 4}; + assert(ext.extent(0) == 4); + assert(ext.extent(1) == 4); + assert(ext.extent(2) == 4); + Ext ext2{4, 4, 4}; + assert(ext == ext2); + } - Ext ext2a{4, ConvertibleToInt{}}; - Ext ext2b{4, 1}; - assert(ext2a == ext2b); + { // Check postconditions when 'sizeof...(pack) == rank_dynamic()' + using Ext = extents; + Ext ext{3, ConvertibleToInt{.val = 3}}; + assert(ext.extent(0) == 3); + assert(ext.extent(1) == 3); + assert(ext.extent(2) == 5); + Ext ext2{3, 3}; + assert(ext == ext2); + } + + { // Check that elements from pack are passed through 'move' + using Ext = dextents; + struct FancyIndex { + constexpr operator integral auto() const& noexcept { + return 3; + } + + constexpr operator integral auto() const&& noexcept { + return 3; + } + + constexpr operator Ext::index_type() && noexcept { + return 4; + } + }; + + FancyIndex i; + Ext ext{FancyIndex{}, i, as_const(i)}; + assert(ext.extent(0) == 4); + assert(ext.extent(1) == 4); + assert(ext.extent(2) == 4); } { // Check construction from integers with mismatched signs @@ -167,48 +267,136 @@ constexpr void check_construction_from_extents_pack() { } constexpr void check_construction_from_array_and_span() { - { // Check construction from arrays/spans where [array/span].size() is equal to rank() - using Ext = extents; - - array arr1 = {1, 5}; - Ext ext1a{arr1}; - span s1{arr1}; - Ext ext1b{s1}; - assert(ext1a == ext1b); - static_assert(is_nothrow_constructible_v); - static_assert(is_nothrow_constructible_v); - - array, 2> arr2; - Ext ext2a{arr2}; - span s2{arr2}; - Ext ext2b{s2}; - assert(ext2a == ext2b); - static_assert(is_nothrow_constructible_v); - static_assert(is_nothrow_constructible_v); + { // Check construction from array/span where 'size()' is equal to 'rank()' and OtherIndexType models 'integral' + using Ext = extents; + array arr = {1, 5}; + Ext ext{arr}; + assert(ext.extent(0) == 1); + assert(ext.extent(1) == 5); + + Ext ext2{span{arr}}; + assert(ext == ext2); + + static_assert(is_nothrow_constructible_v); + static_assert(is_nothrow_constructible_v>); + } + + { // Check construction from array/span where 'size()' is equal to 'rank()' and OtherIndexType is class type + using Ext = extents; + array, 2> arr{{{.val = 3}, {.val = 5}}}; + Ext ext{arr}; + assert(ext.extent(0) == 3); + assert(ext.extent(1) == 5); + + const span s{arr}; + Ext ext2{s}; + assert(ext == ext2); + + static_assert(is_nothrow_constructible_v); + static_assert(is_nothrow_constructible_v); + } + + { // Check construction from array/span where 'size()' is equal to 'rank()' and OtherIndexType is "special" + using Ext = extents; + struct SpecialIndex { + constexpr operator integral auto() noexcept { + return 3; + } + constexpr operator integral auto() const noexcept { + return 5; + } + }; + + // Elements of 'arr' and 's' should be passed through 'as_const' + array arr; + Ext ext{arr}; + assert(ext.extent(0) == 5); + assert(ext.extent(1) == 5); + + span s{arr}; + Ext ext2{s}; + assert(ext == ext2); + } + + { // Check invalid construction from array/span where 'size()' is equal to 'rank()' + using Ext = extents; + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); static_assert(!is_constructible_v>); static_assert(!is_constructible_v>); } - { // Check construction from arrays/spans where [array/span].size() is equal to rank_dynamic() - using Ext = extents; + { // Check construction from array/span where 'size()' is equal to 'rank_dynamic()' and OtherIndexType models + // 'integral' + using Ext = extents; + array arr = {4, 4}; + Ext ext{arr}; + assert(ext.extent(0) == 3); + assert(ext.extent(1) == 4); + assert(ext.extent(2) == 3); + assert(ext.extent(3) == 4); + + Ext ext2{span{arr}}; + assert(ext == ext2); + + static_assert(is_nothrow_constructible_v); + static_assert(is_nothrow_constructible_v>); + } - array arr1 = {4, 4}; - Ext ext1a{arr1}; - span s1{arr1}; - Ext ext1b{s1}; - assert(ext1a == ext1b); - static_assert(is_nothrow_constructible_v); - static_assert(is_nothrow_constructible_v); + { // Check construction from array/span where 'size()' is equal to 'rank_dynamic()' and OtherIndexType is class type + using Ext = extents; + array, 2> arr{{{.val = 2}, {.val = 2}}}; + Ext ext{arr}; + assert(ext.extent(0) == 3); + assert(ext.extent(1) == 2); + assert(ext.extent(2) == 3); + assert(ext.extent(3) == 2); - array, 2> arr2; - Ext ext2a{arr2}; - span s2{arr2}; - Ext ext2b{s2}; - assert(ext2a == ext2b); - static_assert(is_nothrow_constructible_v); - static_assert(is_nothrow_constructible_v); + span s{arr}; + Ext ext2{s}; + assert(ext == ext2); + static_assert(is_nothrow_constructible_v); + static_assert(is_nothrow_constructible_v); + } + + { // Check construction from array/span where 'size()' is equal to 'rank_dynamic()' and OtherIndexType is "special" + using Ext = extents; + struct SpecialIndex { + constexpr operator integral auto() noexcept { + return 5; + } + + constexpr operator integral auto() const noexcept { + return 3; + } + }; + + // Elements of 'arr' and 's' should be passed through 'as_const' + array arr; + Ext ext{arr}; + assert(ext.extent(0) == 3); + assert(ext.extent(1) == 3); + assert(ext.extent(2) == 3); + + span s{arr}; + Ext ext2{s}; + assert(ext == ext2); + } + + { // Check invalid construction from array/span where 'size()' is equal to 'rank_dynamic()' + using Ext = extents; + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); + static_assert(!is_constructible_v, 2>>); static_assert(!is_constructible_v>); static_assert(!is_constructible_v>); } @@ -228,15 +416,7 @@ constexpr void check_construction_from_array_and_span() { array arr = {4ll}; (void) Ext{arr}; - - span s{arr}; - (void) Ext{s}; - } - - { // Check construction from arrays/spans with elements that may throw during conversion to index_type - using Ext = extents; - static_assert(!is_constructible_v, 2>>); - static_assert(!is_constructible_v, 2>>); + (void) Ext{span{arr}}; } { // Check construction from arrays/spans with invalid size @@ -262,27 +442,81 @@ constexpr void check_equality_operator() { extents e1; extents e2; extents e3; - assert(e1 != e2); + + same_as decltype(auto) cond = e1 != e2; + assert(cond); assert(e2 != e3); assert(e1 == e3); + + static_assert(noexcept(e1 != e2)); + static_assert(noexcept(e1 == e3)); } { // Some extents are static, some dynamic extents e1{1}; extents e2{2}; extents e3{3}; - assert(e1 != e2); + + same_as decltype(auto) cond = e1 != e2; + assert(cond); assert(e2 == e3); assert(e1 != e2); + + static_assert(noexcept(e1 != e2)); + static_assert(noexcept(e2 == e3)); } { // All extents are dynamic dextents e1{1, 2}; dextents e2{1, 2}; dextents e3{1, 3}; - assert(e1 == e2); + + same_as decltype(auto) cond = e1 == e2; + assert(cond); assert(e2 != e3); assert(e1 != e3); + + static_assert(noexcept(e1 == e2)); + static_assert(noexcept(e2 != e3)); + } + + { // Different ranks + static_assert(extents{} != extents{}); + static_assert(extents{} != extents{}); + static_assert(noexcept(extents{} != extents{})); + static_assert(noexcept(extents{} != extents{})); + } +} + +template +concept CanDeduceExtents = requires(Args&&... args) { extents{forward(args)...}; }; + +template +constexpr bool all_extents_dynamic = false; + +template +constexpr bool all_extents_dynamic, ExpectedRank> = + ((Extents == dynamic_extent) && ...) && (sizeof...(Extents) == ExpectedRank); + +constexpr void check_deduction_guide() { + { // Check 'CanDeduceExtents' concept + static_assert(CanDeduceExtents); + static_assert(CanDeduceExtents); + static_assert(CanDeduceExtents, int>); + static_assert(!CanDeduceExtents, int>); + static_assert(!CanDeduceExtents); + } + + { // Check correctness + extents ext{'1', 2, 3u, 4ll, ConvertibleToInt{.val = 5}}; + assert(ext.extent(0) == '1'); + assert(ext.extent(1) == 2); + assert(ext.extent(2) == 3); + assert(ext.extent(3) == 4); + assert(ext.extent(4) == 5); + + static_assert(all_extents_dynamic); + static_assert(same_as); } } @@ -290,35 +524,27 @@ constexpr bool test() { check_members_with_various_extents([](const extents&) { check_members(make_index_sequence{}); }); + check_defaulted_default_constructor(); check_construction_from_other_extents(); check_construction_from_extents_pack(); check_construction_from_array_and_span(); check_equality_operator(); + check_deduction_guide(); return true; } -template -constexpr bool all_extents_dynamic = false; - -template -constexpr bool all_extents_dynamic, ExpectedRank> = - ((Extents == dynamic_extent) && ...) && (sizeof...(Extents) == ExpectedRank); - -template -concept CanDeduceExtents = requires(Args&&... args) { extents{forward(args)...}; }; - -// Check deduction guide -using DG = decltype(extents{'1', 2, 3u, 4ll, ConvertibleToInt{}}); -static_assert(all_extents_dynamic); -static_assert(same_as); -static_assert(!CanDeduceExtents); - // Check dextents static_assert(all_extents_dynamic, 0>); -static_assert(all_extents_dynamic, 2>); -static_assert(all_extents_dynamic, 3>); -static_assert(all_extents_dynamic, 5>); +static_assert(all_extents_dynamic, 1>); +static_assert(all_extents_dynamic, 2>); +static_assert(all_extents_dynamic, 3>); +static_assert(all_extents_dynamic, 4>); +static_assert(all_extents_dynamic, 5>); +static_assert(all_extents_dynamic, 6>); +static_assert(all_extents_dynamic, 7>); +static_assert(all_extents_dynamic, 8>); +static_assert(all_extents_dynamic, 9>); int main() { static_assert(test()); From c34c10708e39f9ffe0d14cfc7deac640c5fa2013 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 12:19:11 +0200 Subject: [PATCH 03/13] Improve `std::layout_left` tests --- tests/std/include/test_mdspan_support.hpp | 80 ++++++++++ .../P0009R18_mdspan_layout_left/test.cpp | 140 ++++++++++++++++-- 2 files changed, 208 insertions(+), 12 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index 3163037be29..ff55ef3fe19 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -4,12 +4,15 @@ #pragma once #include +#include #include #include #include +#include #include #include #include +#include enum class IsExplicit : bool { no, yes }; enum class IsNothrow : bool { no, yes }; @@ -227,3 +230,80 @@ constexpr void check_members_with_various_extents(Fn&& fn) { details::check_members_with_various_extents_impl(std::forward(fn), std::make_index_sequence<16>{}); #endif // _PREFAST_ } + +namespace details { + static constexpr bool permissive() { + return false; + } + + template + struct PermissiveTestBase { + static constexpr bool permissive() { + return true; + } + }; + + template + struct PermissiveTest : PermissiveTestBase { + static constexpr bool test() { + return permissive(); + } + }; +} // namespace details + +inline constexpr bool is_permissive = details::PermissiveTest::test(); + +template +struct MappingProperties { + typename Mapping::index_type req_span_size; + bool uniqueness; + bool exhaustiveness; + bool strideness; +}; + +template + requires (!details::PermissiveTest::test()) +constexpr MappingProperties get_mapping_properties(const Mapping& mapping) { + constexpr typename Mapping::index_type zero = 0; + + auto make_cartesian_prod = [&](std::index_sequence) { + return std::views::cartesian_product(std::views::iota(zero, mapping.extents().extent(Indices))...); + }; + + auto indices = + make_cartesian_prod(std::make_index_sequence{}) + | std::views::transform([&](auto tpl) { return std::apply([&](auto... i) { return mapping(i...); }, tpl); }) + | std::ranges::to(); + std::ranges::sort(indices); + + MappingProperties props; + + { // Find required span size (N4950 [mdspan.layout.reqmts]/12) + auto exts = std::views::iota(0u, Mapping::extents_type::rank()) + | std::views::transform([&](auto i) { return mapping.extents().extent(i); }); + if (std::ranges::contains(exts, zero)) { + props.req_span_size = 0; + } else { + props.req_span_size = static_cast(1 + indices.back()); + } + } + + // Is mapping unique? (N4950 [mdspan.layout.reqmts]/14) + props.uniqueness = !std::ranges::contains(std::views::pairwise_transform(indices, std::minus{}), zero); + + { // Is mapping exhaustive? (N4950 [mdspan.layout.reqmts]/16) + const auto diffs = std::views::pairwise_transform(indices, [](auto x, auto y) { return y - x; }); + props.exhaustiveness = std::ranges::find_if_not(diffs, [](auto x) { return x == 1; }) == diffs.end(); + } + + // Is mapping strided? FIXME (N4950 [mdspan.layout.reqmts]/18) + props.strideness = true; + + return props; +} + +template + requires (details::PermissiveTest::test()) +constexpr MappingProperties get_mapping_properties(const Mapping&) { + return {}; // we cannot get properties in '/permissive' mode +} diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index d585c455b10..e8711c62f05 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -34,17 +34,26 @@ constexpr void check_members(const extents& ext, index_se static_assert(same_as); { // Check default and copy constructor - Mapping m; + const Mapping m; Mapping cpy = m; assert(cpy == m); static_assert(is_nothrow_default_constructible_v); static_assert(is_nothrow_copy_constructible_v); } + { // Check copy assignment operator + const Mapping m; + Mapping cpy; + cpy = m; + assert(cpy == m); + static_assert(is_nothrow_copy_assignable_v); + } + { // Check construction from extents_type Mapping m{ext}; assert(m.extents() == ext); static_assert(is_nothrow_constructible_v); + // Other tests are defined in 'check_construction_from_extents' function } using OtherIndexType = long long; @@ -75,6 +84,9 @@ constexpr void check_members(const extents& ext, index_se // Other tests are defined in 'check_construction_from_other_right_mapping' function } +#ifdef __clang__ + if (!is_constant_evaluated()) // FIXME clang hits contexpr limit here +#endif { // Check construction from layout_stride::mapping array strides{}; if constexpr (Ext::rank() > 0) { @@ -87,9 +99,9 @@ constexpr void check_members(const extents& ext, index_se } } - using StrideMapping = layout_stride::mapping; - StrideMapping stride_mapping{ext, strides}; - [[maybe_unused]] Mapping m{stride_mapping}; + layout_stride::mapping m1{ext, span{strides}}; + Mapping m2{m1}; + assert(m1.extents() == m2.extents()); // Other tests are defined in 'check_construction_from_other_stride_mapping' function } @@ -101,9 +113,10 @@ constexpr void check_members(const extents& ext, index_se } { // Check 'required_span_size' function - const IndexType expected_value = static_cast((ext.extent(Indices) * ... * 1)); - assert(m.required_span_size() == expected_value); + same_as decltype(auto) rss = m.required_span_size(); + assert(rss == static_cast((ext.extent(Indices) * ... * 1))); static_assert(noexcept(m.required_span_size())); + // Other tests are defined in 'check_mapping_properties' } { // Check operator() @@ -124,6 +137,7 @@ constexpr void check_members(const extents& ext, index_se static_assert(Mapping::is_unique()); static_assert(Mapping::is_exhaustive()); static_assert(Mapping::is_strided()); + // Other tests are defined in 'check_mapping_properties' } if constexpr (Ext::rank() > 0) { // Check 'stride' function @@ -133,6 +147,7 @@ constexpr void check_members(const extents& ext, index_se assert(m.stride(0) == 1); static_assert(noexcept(m.stride(Ext::rank() - 1))); static_assert(noexcept(m.stride(0))); + // Other tests are defined in 'check_stride_function' } else { static_assert(!CheckStrideMemberFunction); } @@ -144,6 +159,44 @@ constexpr void check_members(const extents& ext, index_se } } +constexpr void check_mapping_properties() { + auto check = [](const auto& mapping) { + const auto props = get_mapping_properties(mapping); + if constexpr (!is_permissive) { + assert(props.req_span_size == mapping.required_span_size()); + assert(props.uniqueness); + assert(props.exhaustiveness); + assert(props.strideness); + } + }; + + using M1 = layout_left::mapping>; + check(M1{}); + + using M2 = layout_left::mapping>; + check(M2{M2::extents_type{6}}); + + using M3 = layout_left::mapping>; + check(M3{M3::extents_type{3, 5, 4, 2}}); +} + +constexpr void check_construction_from_extents() { + using Ext = extents; + Ext ext; + + { // Check construction from 'extents_type' + layout_left::mapping mp(ext); + assert(mp.extents() == ext); + static_assert(is_nothrow_constructible_v); + } + + { // Check construction from other extents + layout_left::mapping> mp(ext); + assert(mp.extents() == ext); + static_assert(is_nothrow_constructible_v); + } +} + constexpr void check_construction_from_other_left_mapping() { { // Check invalid construction using Mapping = layout_left::mapping>; @@ -161,14 +214,23 @@ constexpr void check_construction_from_other_left_mapping() { static_assert(NotImplicitlyConstructibleFrom>, layout_left::mapping>>); } + + { // Check effects + layout_left::mapping> m1; + layout_left::mapping> m2{m1}; + assert(m2.extents().extent(0) == 5); + assert(m2.extents().extent(1) == 3); + assert(m2.extents().extent(2) == 5); + assert(m1.extents() == m2.extents()); + } } 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_nothrow_constructible_v>, + layout_right::mapping>>); + static_assert(is_nothrow_constructible_v>, + layout_right::mapping>>); static_assert( !is_constructible_v>, layout_right::mapping>>); static_assert( @@ -189,6 +251,12 @@ constexpr void check_construction_from_other_right_mapping() { static_assert(NotImplicitlyConstructibleFrom>, layout_right::mapping>>); } + + { // Check effects + layout_right::mapping> m1; + layout_left::mapping> m2{m1}; + assert(m2.extents().extent(0) == 8); + } } constexpr void check_construction_from_other_stride_mapping() { @@ -211,8 +279,13 @@ constexpr void check_construction_from_other_stride_mapping() { { // 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}; + layout_stride::mapping m1{Ext{}, array{1, 4, 12, 24, 72}}; + layout_left::mapping m2{m1}; + assert(m2.extents().extent(0) == 4); + assert(m2.extents().extent(1) == 3); + assert(m2.stride(2) == 12); + assert(m2.stride(3) == 24); + assert(m2.extents() == m1.extents()); } { // Check implicit conversions @@ -271,6 +344,35 @@ constexpr void check_call_operator() { } } +constexpr void check_stride_function() { + layout_left::mapping> prime_mapping; + + { // Check return type + same_as decltype(auto) s = prime_mapping.stride(0); + assert(s == 1); + } + + { // Check that argument is 'rank_type' + struct ConvertibleToRankType { + constexpr operator integral auto() const { + return 0; + } + + constexpr operator size_t() const { // NB: 'rank_type' is always 'size_t' + return 1; + } + }; + + assert(prime_mapping.stride(ConvertibleToRankType{}) == 2); // 1 * 2 + } + + { // Check other strides + assert(prime_mapping.stride(2) == 6); + assert(prime_mapping.stride(3) == 30); + assert(prime_mapping.stride(4) == 210); + } +} + constexpr void check_comparisons() { using StaticMapping = layout_left::mapping>; using DynamicMapping = layout_left::mapping>; @@ -291,6 +393,14 @@ constexpr void check_comparisons() { } } +constexpr void check_ctad() { + using Ext = extents; + layout_left::mapping m{Ext{}}; + static_assert(same_as>); + assert(m.extents().extent(0) == 3); + assert(m.stride(1) == 3); +} + constexpr void check_correctness() { { // empty extents const array values{}; @@ -385,11 +495,17 @@ constexpr bool test() { [](const extents& ext) { check_members(ext, make_index_sequence{}); }); + if (!is_constant_evaluated()) { // too heavy for compile time + check_mapping_properties(); + } + check_construction_from_extents(); check_construction_from_other_left_mapping(); check_construction_from_other_right_mapping(); check_construction_from_other_stride_mapping(); check_call_operator(); + check_stride_function(); check_comparisons(); + check_ctad(); check_correctness(); return true; From 8b5e4b03b237a6c09a013c6441623fa49415bf95 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 13:10:38 +0200 Subject: [PATCH 04/13] Improve `std::layout_right` tests --- stl/inc/mdspan | 3 +- .../P0009R18_mdspan_layout_right/test.cpp | 152 +++++++++++++++--- 2 files changed, 132 insertions(+), 23 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 2a0f9b289ab..bd7420639aa 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -549,7 +549,8 @@ public: template requires is_constructible_v - constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::template mapping<_OtherExtents>& _Other) + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::template mapping<_OtherExtents>& _Other) noexcept : _Exts(_Other.extents()) { if constexpr (extents_type::rank() > 0) { const bool _Verify = [&](index_sequence<_Indices...>) { diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp index dd67099a7a1..d94f05a0784 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -34,24 +34,35 @@ constexpr void check_members(const extents& ext, index_se static_assert(same_as); { // Check default and copy constructor - Mapping m; + const Mapping m; Mapping cpy = m; assert(cpy == m); static_assert(is_nothrow_default_constructible_v); static_assert(is_nothrow_copy_constructible_v); } + { // Check copy assignment operator + const Mapping m; + Mapping cpy; + cpy = m; + assert(cpy == m); + static_assert(is_nothrow_copy_assignable_v); + } + { // Check construction from extents_type Mapping m{ext}; assert(m.extents() == ext); static_assert(is_nothrow_constructible_v); + // Other tests are defined in 'check_construction_from_extents' function } using OtherIndexType = long long; using Ext2 = extents; using Mapping2 = layout_right::mapping; -#ifndef __clang__ // FIXME, Clang suddenly cannot digest this +#ifdef __clang__ + if (!is_constant_evaluated()) // FIXME clang hits contexpr limit here +#endif { // Check construction from other layout_right::mapping Mapping m1{ext}; Mapping2 m2{m1}; @@ -59,7 +70,6 @@ constexpr void check_members(const extents& ext, index_se static_assert(is_nothrow_constructible_v); // Other tests are defined in 'check_construction_from_other_right_mapping' function } -#endif // __clang__ { // Check construction from layout_left::mapping using LeftMapping = layout_left::mapping; @@ -89,9 +99,9 @@ constexpr void check_members(const extents& ext, index_se } } - using StrideMapping = layout_stride::mapping; - StrideMapping stride_mapping{ext, strides}; - [[maybe_unused]] Mapping m{stride_mapping}; + layout_stride::mapping m1{ext, strides}; + Mapping m2{m1}; + assert(m1.extents() == m2.extents()); // Other tests are defined in 'check_construction_from_other_stride_mapping' function } @@ -103,9 +113,10 @@ constexpr void check_members(const extents& ext, index_se } { // Check 'required_span_size' function - const IndexType expected_value = static_cast((ext.extent(Indices) * ... * 1)); - assert(m.required_span_size() == expected_value); + same_as decltype(auto) rss = m.required_span_size(); + assert(rss == static_cast((ext.extent(Indices) * ... * 1))); static_assert(noexcept(m.required_span_size())); + // Other tests are defined in 'check_mapping_properties' } { // Check operator() @@ -126,6 +137,7 @@ constexpr void check_members(const extents& ext, index_se static_assert(Mapping::is_unique()); static_assert(Mapping::is_exhaustive()); static_assert(Mapping::is_strided()); + // Other tests are defined in 'check_mapping_properties' } if constexpr (Ext::rank() > 0) { // Check 'stride' function @@ -134,6 +146,7 @@ constexpr void check_members(const extents& ext, index_se assert(m.stride(Ext::rank() - 1) == 1); static_assert(noexcept(m.stride(Ext::rank() - 1))); static_assert(noexcept(m.stride(0))); + // Other tests are defined in 'check_stride_function' } else { static_assert(!CheckStrideMemberFunction); } @@ -145,6 +158,44 @@ constexpr void check_members(const extents& ext, index_se } } +constexpr void check_mapping_properties() { + auto check = [](const auto& mapping) { + const auto props = get_mapping_properties(mapping); + if constexpr (!is_permissive) { + assert(props.req_span_size == mapping.required_span_size()); + assert(props.uniqueness); + assert(props.exhaustiveness); + assert(props.strideness); + } + }; + + using M1 = layout_right::mapping>; + check(M1{}); + + using M2 = layout_right::mapping>; + check(M2{M2::extents_type{2, 6}}); + + using M3 = layout_right::mapping>; + check(M3{M3::extents_type{4, 3, 5, 4}}); +} + +constexpr void check_construction_from_extents() { + using Ext = extents; + Ext ext; + + { // Check construction from 'extents_type' + layout_right::mapping mp(ext); + assert(mp.extents() == ext); + static_assert(is_nothrow_constructible_v); + } + + { // Check construction from other extents + layout_right::mapping> mp(ext); + assert(mp.extents() == ext); + static_assert(is_nothrow_constructible_v); + } +} + constexpr void check_construction_from_other_right_mapping() { { // Check invalid construction using Mapping = layout_right::mapping>; @@ -166,10 +217,10 @@ constexpr void check_construction_from_other_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_nothrow_constructible_v>, + layout_left::mapping>>); + static_assert(is_nothrow_constructible_v>, + layout_left::mapping>>); static_assert( !is_constructible_v>, layout_left::mapping>>); static_assert( @@ -188,18 +239,27 @@ constexpr void check_construction_from_other_left_mapping() { static_assert(NotImplicitlyConstructibleFrom>>); static_assert(NotImplicitlyConstructibleFrom>>); } + + { // Check effects + layout_right::mapping> m1; + layout_right::mapping> m2{m1}; + assert(m2.extents().extent(0) == 6); + assert(m2.extents().extent(1) == 2); + assert(m2.extents().extent(2) == 6); + assert(m1.extents() == m2.extents()); + } } 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>>); + static_assert(is_nothrow_constructible_v>, + layout_stride::mapping>>); + static_assert(is_nothrow_constructible_v>, + layout_stride::mapping>>); + static_assert(is_nothrow_constructible_v>, + layout_stride::mapping>>); + static_assert(is_nothrow_constructible_v>, + layout_stride::mapping>>); } { // Check construction from layout_stride::mapping when E is invalid @@ -210,8 +270,13 @@ constexpr void check_construction_from_other_stride_mapping() { { // 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}; + layout_stride::mapping m1{Ext{}, array{72, 24, 12, 4, 1}}; + layout_right::mapping m2{m1}; + assert(m2.extents().extent(0) == 4); + assert(m2.extents().extent(1) == 3); + assert(m2.stride(2) == 12); + assert(m2.stride(3) == 4); + assert(m2.extents() == m1.extents()); } { // Check implicit conversions @@ -272,6 +337,35 @@ constexpr void check_call_operator() { } } +constexpr void check_stride_function() { + layout_right::mapping> prime_mapping; + + { // Check return type + same_as decltype(auto) s = prime_mapping.stride(0); + assert(s == 1155); // 11 * 7 * 5 * 3 + } + + { // Check that argument is 'rank_type' + struct ConvertibleToRankType { + constexpr operator integral auto() const { + return 0; + } + + constexpr operator size_t() const { // NB: 'rank_type' is always 'size_t' + return 1; + } + }; + + assert(prime_mapping.stride(ConvertibleToRankType{}) == 385); // 11 * 7 * 5 + } + + { // Check other strides + assert(prime_mapping.stride(2) == 77); + assert(prime_mapping.stride(3) == 11); + assert(prime_mapping.stride(4) == 1); + } +} + constexpr void check_comparisons() { using StaticMapping = layout_right::mapping>; using DynamicMapping = layout_right::mapping>; @@ -292,6 +386,14 @@ constexpr void check_comparisons() { } } +constexpr void check_ctad() { + using Ext = extents; + layout_right::mapping m{Ext{}}; + static_assert(same_as>); + assert(m.extents().extent(0) == 5); + assert(m.stride(1) == 1); +} + constexpr void check_correctness() { { // empty extents const array vals{}; @@ -416,11 +518,17 @@ constexpr bool test() { [](const extents& ext) { check_members(ext, make_index_sequence{}); }); + if (!is_constant_evaluated()) { // too heavy for compile time + check_mapping_properties(); + } + check_construction_from_extents(); check_construction_from_other_right_mapping(); check_construction_from_other_left_mapping(); check_construction_from_other_stride_mapping(); check_call_operator(); + check_stride_function(); check_comparisons(); + check_ctad(); check_correctness(); return true; From 265440556cd1e0f5b037515c7e2753beb3551252 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 13:11:04 +0200 Subject: [PATCH 05/13] Drive-by: include `"test_mdspan_support.hpp"` instead of `` --- tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp | 2 +- tests/std/tests/P0009R18_mdspan_mdspan/test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp index 9036a910c75..f22101c0f7c 100644 --- a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include "test_mdspan_support.hpp" using namespace std; diff --git a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp index 44580c94dd0..b323b09621c 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include "test_mdspan_support.hpp" using namespace std; From 73e4fb08084281e1ef03ea8f529a0d5bb7a45dc5 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 14:13:29 +0200 Subject: [PATCH 06/13] Improve `std::layout_stride` tests --- .../P0009R18_mdspan_layout_stride/test.cpp | 248 +++++++++++++----- 1 file changed, 184 insertions(+), 64 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index ec4ea0711a9..13ab33b6139 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -44,7 +44,7 @@ constexpr void do_check_members(const extents& ext, static_assert(same_as); { // Check default and copy constructor - Mapping m; + const Mapping m; const Mapping cpy = m; const layout_right::mapping right_mapping; assert(m == right_mapping); @@ -53,12 +53,20 @@ constexpr void do_check_members(const extents& ext, static_assert(is_nothrow_copy_constructible_v); } + { // Check copy assignment operator + const Mapping m; + Mapping cpy; + cpy = m; + assert(cpy == m); + static_assert(is_nothrow_copy_assignable_v); + } + { // Check construction from extents_type and array Mapping m{ext, strs}; assert(m.extents() == ext); 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 + // Other tests are defined in 'check_construction_from_extents_and_array_or_span' function } { // Check construction from extents_type and span @@ -67,7 +75,7 @@ constexpr void do_check_members(const extents& ext, assert(m.extents() == ext); 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 + // Other tests are defined in 'check_construction_from_extents_and_array_or_span' function } using OtherIndexType = long long; @@ -94,6 +102,7 @@ constexpr void do_check_members(const extents& ext, same_as decltype(auto) strs2 = m.strides(); assert(ranges::equal(strs2, strs, CmpEqual{})); static_assert(noexcept(m.strides())); + // Other tests are defined in 'check_stride_function' } { // Check 'required_span_size' function @@ -105,7 +114,7 @@ constexpr void do_check_members(const extents& ext, assert(m.required_span_size() == expected_value); } static_assert(noexcept(m.required_span_size())); - // Other tests are defined in 'check_required_span_size' function + // Other tests are defined in 'check_required_span_size' and 'check_mapping_properties' functions } // Call operator() is tested in 'check_call_operator' function @@ -120,6 +129,7 @@ constexpr void do_check_members(const extents& ext, static_assert(Mapping::is_unique()); static_assert(Mapping::is_strided()); // Tests of 'is_exhaustive' are defined in 'check_is_exhaustive' function + // Other tests are defined in 'check_mapping_properties' } { // Check 'stride' function @@ -164,35 +174,99 @@ constexpr void check_members(extents ext, const array(ext, strides); } -constexpr void check_construction_from_extents_and_array() { - // Check invalid construction - using Mapping = layout_stride::mapping>; - static_assert(!is_constructible_v, array>); - static_assert(!is_constructible_v, array>); - static_assert(!is_constructible_v, array>); - static_assert(!is_constructible_v, array>); - static_assert(!is_constructible_v, span>); - static_assert(!is_constructible_v, span>); - static_assert(!is_constructible_v, span>); - static_assert(!is_constructible_v, span>); - static_assert(!is_constructible_v, array>); - static_assert(!is_constructible_v, span>); - static_assert(!is_constructible_v, array, 2>>); - static_assert(!is_constructible_v, span, 2>>); +constexpr void check_mapping_properties() { + auto check = [](const auto& mapping, [[maybe_unused]] const bool expected_exhaustiveness) { + const auto props = get_mapping_properties(mapping); + if constexpr (!is_permissive) { + assert(props.req_span_size == mapping.required_span_size()); + assert(props.uniqueness); + assert(props.exhaustiveness == expected_exhaustiveness); + assert(props.exhaustiveness == mapping.is_exhaustive()); + assert(props.strideness); + } + }; + + { // Check exhaustive mappings + using M1 = layout_stride::mapping>; + check(M1{M1::extents_type{}, array{6, 1, 2}}, true); + + using M2 = layout_stride::mapping>; + check(M2{M2::extents_type{6, 7}, array{1, 48, 6}}, true); + + using M3 = layout_stride::mapping>; + check(M3{M3::extents_type{3, 5, 2, 4}, array{20, 1, 60, 5}}, true); + } + + { // Check non-exhaustive mappings + using M1 = layout_stride::mapping>; + check(M1{M1::extents_type{}, array{9, 18, 1}}, false); + + using M2 = layout_stride::mapping>; + check(M2{M2::extents_type{4, 3}, array{12, 36, 1}}, false); + + using M3 = layout_stride::mapping>; + check(M3{M3::extents_type{4, 3, 2}, array{8, 32, 2}}, false); + } +} + +constexpr void check_construction_from_extents_and_array_or_span() { + { // Check invalid construction + using Mapping = layout_stride::mapping>; + static_assert(!is_constructible_v, array>); + static_assert(!is_constructible_v, span>); + static_assert(!is_constructible_v, array>); + static_assert(!is_constructible_v, span>); + static_assert(!is_constructible_v, array>); + static_assert(!is_constructible_v, span>); + static_assert(!is_constructible_v, array>); + static_assert(!is_constructible_v, span>); + static_assert(!is_constructible_v, array>); + static_assert(!is_constructible_v, span>); + static_assert(!is_constructible_v, array, 2>>); + static_assert(!is_constructible_v, span, 2>>); + } + + using Ext = extents; + Ext ext; + + { // Check construction from 'extents_type' + array strs{24, 1, 4}; + layout_stride::mapping m1(ext, strs); + assert(m1.extents() == ext); + static_assert(is_nothrow_constructible_v); + + span s{strs}; + layout_stride::mapping m2(ext, s); + assert(m2.extents() == ext); + static_assert(is_nothrow_constructible_v); + } + + { // Check construction from other extents + using Ext2 = extents; + + const array strs{1, 12, 2}; + layout_stride::mapping m1(ext, strs); + assert(m1.extents() == ext); + static_assert(is_nothrow_constructible_v); + + const span s{strs}; + layout_stride::mapping m2(ext, s); + static_assert(is_nothrow_constructible_v); + } } constexpr void check_construction_from_other_mappings() { - { // Check construction + { // Check valid construction using Mapping = layout_stride::mapping>; - static_assert(is_constructible_v>>); - static_assert(is_constructible_v>>); - static_assert(is_constructible_v>>); - static_assert(is_constructible_v>>); - static_assert(is_constructible_v>>); + static_assert(is_nothrow_constructible_v>>); + static_assert(is_nothrow_constructible_v>>); + static_assert(is_nothrow_constructible_v>>); + static_assert(is_nothrow_constructible_v>>); + static_assert(is_nothrow_constructible_v>>); } { // Check invalid construction - using Mapping = layout_stride::mapping>; + using Mapping = layout_stride::mapping>; static_assert(!is_constructible_v>>); static_assert(!is_constructible_v>>); static_assert(!is_constructible_v>>); @@ -328,6 +402,36 @@ constexpr void check_call_operator() { } } +constexpr void check_stride_function() { + using Ext = extents; + layout_stride::mapping even_mapping{Ext{}, array{80, 160, 640, 1, 8}}; + + { // Check return type + same_as decltype(auto) s = even_mapping.stride(0); + assert(s == 80); + } + + { // Check that argument is 'rank_type' + struct ConvertibleToRankType { + constexpr operator integral auto() const { + return 0; + } + + constexpr operator size_t() const { // NB: 'rank_type' is always 'size_t' + return 1; + } + }; + + assert(even_mapping.stride(ConvertibleToRankType{}) == 160); + } + + { // Check other strides + assert(even_mapping.stride(2) == 640); + assert(even_mapping.stride(3) == 1); + assert(even_mapping.stride(4) == 8); + } +} + constexpr void check_comparisons() { using E = extents; using StaticStrideMapping = layout_stride::mapping; @@ -351,7 +455,8 @@ constexpr void check_comparisons() { { // Check correctness: layout_stride::mapping with layout_stride::mapping StaticStrideMapping m1{E{}, array{3, 1}}; DynamicStrideMapping m2{dextents{2, 3}, array{3, 1}}; - assert(m1 == m2); // extents are equal, OFFSET(rhs) == 0, strides are equal + same_as decltype(auto) cond = m1 == m2; + assert(cond); // extents are equal, OFFSET(rhs) == 0, strides are equal DynamicStrideMapping m3{dextents{2, 3}, array{1, 2}}; assert(m1 != m3); // extents are equal, OFFSET(rhs) == 0, strides are not equal @@ -363,12 +468,16 @@ constexpr void check_comparisons() { assert(m3 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are not equal // NB: OFFSET(layout_stride::mapping) is always equal to 0 + + static_assert(noexcept(m1 == m2)); + static_assert(noexcept(m1 != m3)); } { // Check correctness: layout_stride::mapping with layout_left::mapping LeftMapping m1; StaticStrideMapping m2{E{}, array{1, 2}}; - assert(m1 == m2); // extents are equal, OFFSET(rhs) == 0, strides are equal + same_as decltype(auto) cond = m1 == m2; + assert(cond); // extents are equal, OFFSET(rhs) == 0, strides are equal DynamicStrideMapping m3{dextents{2, 3}, array{3, 1}}; assert(m1 != m3); // extents are equal, OFFSET(rhs) == 0, strides are not equal @@ -380,12 +489,16 @@ constexpr void check_comparisons() { assert(m3 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are not equal // NB: OFFSET(layout_left::mapping) is always equal to 0 + + static_assert(noexcept(m1 == m2)); + static_assert(noexcept(m1 != m3)); } { // Check correctness: layout_stride::mapping with layout_right::mapping RightMapping m1; StaticStrideMapping m2{E{}, array{3, 1}}; - assert(m1 == m2); // extents are equal, OFFSET(rhs) == 0, strides are equal + same_as decltype(auto) cond = m1 == m2; + assert(cond); // extents are equal, OFFSET(rhs) == 0, strides are equal DynamicStrideMapping m3{dextents{2, 3}, array{1, 2}}; assert(m1 != m3); // extents are equal, OFFSET(rhs) == 0, strides are not equal @@ -397,11 +510,47 @@ constexpr void check_comparisons() { assert(m3 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are not equal // NB: OFFSET(layout_right::mapping) is always equal to 0 + + static_assert(noexcept(m1 == m2)); + static_assert(noexcept(m1 != m3)); } // TRANSITION, Check comparisons with custom layout mapping } +constexpr void check_ctad() { + using E = extents; + E e; + + { // E::index_type and array::value_type are the same + array a{1, 2}; + layout_stride::mapping m1{e, a}; + static_assert(same_as>); + assert(m1.extents() == e); + assert(m1.strides() == a); + + span s{a}; + layout_stride::mapping m2{e, s}; + static_assert(same_as>); + assert(m2.extents() == e); + assert(m2.strides() == a); + } + + { // E::index_type and array::value_type are different + array a{1, 2}; + layout_stride::mapping m1{e, a}; + static_assert(same_as>); + assert(m1.extents() == e); + assert(ranges::equal(m1.strides(), a, CmpEqual{})); + + span s{a}; + layout_stride::mapping m2{e, s}; + static_assert(same_as>); + assert(m2.extents() == e); + assert(ranges::equal(m2.strides(), a, CmpEqual{})); + } +} + constexpr void check_correctness() { { // empty extents const array vals{}; @@ -535,39 +684,6 @@ constexpr void check_correctness() { } } -constexpr void check_ctad() { - using E = extents; - E e; - - { // E::index_type and array::value_type are the same - array a{1, 2}; - layout_stride::mapping m1{e, a}; - static_assert(same_as>); - assert(m1.extents() == e); - assert(m1.strides() == a); - - span s{a}; - layout_stride::mapping m2{e, s}; - static_assert(same_as>); - assert(m2.extents() == e); - assert(m2.strides() == a); - } - - { // E::index_type and array::value_type are different - array a{1, 2}; - layout_stride::mapping m1{e, a}; - static_assert(same_as>); - assert(m1.extents() == e); - assert(ranges::equal(m1.strides(), a, CmpEqual{})); - - span s{a}; - layout_stride::mapping m2{e, s}; - static_assert(same_as>); - assert(m2.extents() == e); - assert(ranges::equal(m2.strides(), a, CmpEqual{})); - } -} - constexpr bool test() { // Check signed integers check_members(extents{5}, array{1}); @@ -583,14 +699,18 @@ constexpr bool test() { check_members(extents{}, array{1}); check_members(extents{3}, array{1, 3, 6}); - check_construction_from_extents_and_array(); + if (!is_constant_evaluated()) { // too heavy for compile time + check_mapping_properties(); + } + check_construction_from_extents_and_array_or_span(); check_construction_from_other_mappings(); check_required_span_size(); check_is_exhaustive(); check_call_operator(); + check_stride_function(); check_comparisons(); - check_correctness(); check_ctad(); + check_correctness(); return true; } From 22270e79b824ae406f0b62e9309110c879b61ddf Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 14:13:55 +0200 Subject: [PATCH 07/13] Remove old tests --- tests/std/test.lst | 1 - tests/std/tests/P0009R18_mdspan/env.lst | 4 - tests/std/tests/P0009R18_mdspan/test.cpp | 1094 ---------------------- 3 files changed, 1099 deletions(-) delete mode 100644 tests/std/tests/P0009R18_mdspan/env.lst delete mode 100644 tests/std/tests/P0009R18_mdspan/test.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index 018e7f0a004..af17e49329e 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -233,7 +233,6 @@ tests\LWG3422_seed_seq_ctors tests\LWG3480_directory_iterator_range tests\LWG3545_pointer_traits_sfinae tests\LWG3610_iota_view_size_and_integer_class -tests\P0009R18_mdspan tests\P0009R18_mdspan_default_accessor tests\P0009R18_mdspan_extents tests\P0009R18_mdspan_extents_death diff --git a/tests/std/tests/P0009R18_mdspan/env.lst b/tests/std/tests/P0009R18_mdspan/env.lst deleted file mode 100644 index 18e2d7c71ec..00000000000 --- a/tests/std/tests/P0009R18_mdspan/env.lst +++ /dev/null @@ -1,4 +0,0 @@ -# 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/test.cpp b/tests/std/tests/P0009R18_mdspan/test.cpp deleted file mode 100644 index 28ea7b5acae..00000000000 --- a/tests/std/tests/P0009R18_mdspan/test.cpp +++ /dev/null @@ -1,1094 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include -#include -#include -#include -#include -#include - -using namespace std; - -// A type that's regular and trivially copyable, and also maximally nothrow. -template -using is_regular_trivial_nothrow = std::conjunction>, is_trivially_copyable, - is_nothrow_default_constructible, is_nothrow_copy_constructible, is_nothrow_move_constructible, - is_nothrow_copy_assignable, is_nothrow_move_assignable, is_nothrow_swappable>; - -template -inline constexpr bool is_regular_trivial_nothrow_v = is_regular_trivial_nothrow::value; - -struct Constructible { - // noexcept constructible for size_t, but not convertible - explicit operator size_t() noexcept; -}; - -struct Convertible { - // convertible, but not noexcept constructible - operator size_t(); -}; - -struct ConstructibleAndConvertible { - // convertible and noexcept constructible - constexpr operator size_t() noexcept { - return size_t{2}; - } -}; - -struct ConstructibleAndConvertibleConst { - // convertible and noexcept constructible - constexpr operator size_t() const noexcept { - return size_t{2}; - } -}; - - -void extent_tests_traits() { - static_assert(is_regular_trivial_nothrow_v>); - static_assert(is_regular_trivial_nothrow_v>); - static_assert(is_regular_trivial_nothrow_v>); - static_assert(is_regular_trivial_nothrow_v>); - static_assert(is_regular_trivial_nothrow_v>); - - static_assert(is_same_v, extents>); - static_assert(is_same_v, extents>); - static_assert(is_same_v, extents>); - static_assert(is_same_v, extents>); - - constexpr extents e(2, 3); - static_assert(is_same_v, dextents>); - static_assert(e.static_extent(0) == dynamic_extent); - static_assert(e.static_extent(1) == dynamic_extent); - static_assert(e.extent(0) == 2); - static_assert(e.extent(1) == 3); - - constexpr dextents ex0(1); - (void) ex0; - static_assert(!is_constructible_v, int*>); - - extents(); - extents(); - extents(); - extents(); - extents(); - extents(); - extents(); - extents(); - extents(); - extents(); -} - -void extent_tests_rank() { - static_assert(extents::rank() == 0); - static_assert(extents::rank_dynamic() == 0); - - static_assert(extents::rank() == 1); - static_assert(extents::rank_dynamic() == 0); - - static_assert(extents::rank() == 1); - static_assert(extents::rank_dynamic() == 1); - - static_assert(extents::rank() == 2); - static_assert(extents::rank_dynamic() == 0); - - static_assert(extents::rank() == 2); - static_assert(extents::rank_dynamic() == 1); - - static_assert(extents::rank() == 2); - static_assert(extents::rank_dynamic() == 1); - - static_assert(extents::rank() == 2); - static_assert(extents::rank_dynamic() == 2); -} - -void extent_tests_static_extent() { - static_assert(extents::static_extent(0) == 2); - static_assert(extents::static_extent(1) == 3); - - static_assert(extents::static_extent(0) == 2); - static_assert(extents::static_extent(1) == dynamic_extent); - - static_assert(extents::static_extent(0) == dynamic_extent); - static_assert(extents::static_extent(1) == 3); - - static_assert(extents::static_extent(0) == dynamic_extent); - static_assert(extents::static_extent(1) == dynamic_extent); -} - -void extent_tests_extent() { - constexpr extents e_23; - static_assert(e_23.extent(0) == 2); - static_assert(e_23.extent(1) == 3); - - constexpr extents e_2d{3}; - static_assert(e_2d.extent(0) == 2); - static_assert(e_2d.extent(1) == 3); - - constexpr extents e_dd{2, 3}; - static_assert(e_dd.extent(0) == 2); - static_assert(e_dd.extent(1) == 3); - - constexpr extents e_2dd{3, 5}; - static_assert(e_2dd.extent(0) == 2); - static_assert(e_2dd.extent(1) == 3); - static_assert(e_2dd.extent(2) == 5); -} - -void extent_tests_ctor_other_sizes() { - static_assert(!is_constructible_v, Constructible>); - static_assert(!is_constructible_v, Convertible>); - static_assert(is_constructible_v, ConstructibleAndConvertible>); - [[maybe_unused]] constexpr extents ex0{ConstructibleAndConvertible{}}; - static_assert(is_constructible_v, ConstructibleAndConvertibleConst>); - [[maybe_unused]] constexpr extents ex1{ConstructibleAndConvertibleConst{}}; - - static_assert(is_constructible_v, int>); - [[maybe_unused]] constexpr extents ex2(1); - static_assert(!is_constructible_v, int, int>); - static_assert(is_constructible_v, int, int, int>); - [[maybe_unused]] extents ex3(1, 2, 3); - - extents e0; - assert(e0.extent(0) == 2); - assert(e0.extent(1) == 3); - - extents e1(5); - assert(e1.extent(0) == 2); - assert(e1.extent(1) == 5); - - extents e2(5); - assert(e2.extent(0) == 5); - assert(e2.extent(1) == 3); - - extents e3(5, 7); - assert(e3.extent(0) == 5); - assert(e3.extent(1) == 7); -} - -void extent_tests_copy_ctor_other() { - // Rank and value of static extents must match. - static_assert(!is_constructible_v, extents>); - static_assert(!is_constructible_v, extents>); - static_assert(!is_constructible_v, extents>); - - // Static extents are constructible, but not convertible, from dynamic extents. - static_assert(is_constructible_v, extents>); - constexpr extents ex0{extents{3}}; - (void) ex0; - static_assert(!is_convertible_v, extents>); - - // Dynamic extents are constructible and convertible from static extents. - static_assert(is_constructible_v, extents>); - extents{extents{}}; - static_assert(is_convertible_v, extents>); - - // Can implicitly convert from narrower to wider size_type, but not vice-versa. - static_assert(is_convertible_v, extents>); - static_assert(!is_convertible_v, extents>); - - extents e_dyn(3); - extents e(e_dyn); - (void) e; - - using E = extents; - - extents e0{extents{}}; - E e1(extents(2u)); - extents e2{extents{3u}}; - extents e3{extents{2u, 3u}}; - - (void) e0; - (void) e1; - (void) e2; - (void) e3; -} - -template -struct is_array_cons_avail : std::false_type {}; - -template -struct is_array_cons_avail>()}), T>::value>> : std::true_type { -}; - -template -constexpr bool is_array_cons_avail_v = is_array_cons_avail::value; - -void extent_tests_ctor_array() { - static_assert(!is_constructible_v, array>); - static_assert(!is_constructible_v, array>); - static_assert(!is_constructible_v, array>); - static_assert(is_constructible_v, array>); - constexpr extents ex0{array{}}; - (void) ex0; - - static_assert(is_constructible_v, array>); - constexpr extents ex1{array{}}; - static_assert(!is_constructible_v, array>); - static_assert(is_constructible_v, array>); - constexpr extents ex2{array{1, 2, 2}}; - (void) ex1; - (void) ex2; - - static_assert(is_constructible_v, array>); - constexpr extents ex3{array{}}; - static_assert(is_constructible_v, array>); - constexpr extents ex4{array{10}}; - static_assert(!is_constructible_v, array>); - (void) ex3; - (void) ex4; - - extents e0; - assert(e0.extent(0) == 2u); - assert(e0.extent(1) == 3u); - - // native extent::size_type - extents e1(to_array({5})); - assert(e1.extent(0) == 2u); - assert(e1.extent(1) == 5u); - - extents e2(to_array({5})); - assert(e2.extent(0) == 5u); - assert(e2.extent(1) == 3u); - - extents e3(to_array({5, 7})); - assert(e3.extent(0) == 5u); - assert(e3.extent(1) == 7u); - - // convertible size type - extents e4(to_array({5})); - assert(e4.extent(0) == 2u); - assert(e4.extent(1) == 5u); - - extents e5(to_array({5})); - assert(e5.extent(0) == 5u); - assert(e5.extent(1) == 3u); - - extents e6(to_array({5, 7})); - assert(e6.extent(0) == 5u); - assert(e6.extent(1) == 7u); -} - -void extent_tests_ctor_span() { - static_assert(!is_constructible_v, span>); - static_assert(!is_constructible_v, span>); - static_assert(!is_constructible_v, span>); - static_assert(is_constructible_v, span>); - ConstructibleAndConvertibleConst arr0[1] = {{}}; - constexpr extents ex0{span{arr0}}; - (void) ex0; - - static_assert(is_constructible_v, span>); - constexpr int arr1[1] = {1}; - constexpr extents ex1{span{arr1}}; - static_assert(!is_constructible_v, span>); - static_assert(is_constructible_v, span>); - constexpr int arr2[3] = {3, 2, 2}; - constexpr extents ex2{span{arr2}}; - (void) ex1; - (void) ex2; - - - extents e0; - assert(e0.extent(0) == 2u); - assert(e0.extent(1) == 3u); - - // native extent::size_type - constexpr int one_int[] = {5}; - constexpr int two_int[] = {5, 7}; - extents e1(span{one_int}); - assert(e1.extent(0) == 2); - assert(e1.extent(1) == 5); - - extents e2(span{one_int}); - assert(e2.extent(0) == 5); - assert(e2.extent(1) == 3); - - extents e3(span{two_int}); - assert(e3.extent(0) == 5); - assert(e3.extent(1) == 7); - - // convertible size type - constexpr size_t one_sizet[] = {5}; - constexpr size_t two_sizet[] = {5, 7}; - extents e4(span{one_sizet}); - assert(e4.extent(0) == 2); - assert(e4.extent(1) == 5); - - extents e5(span{one_sizet}); - assert(e5.extent(0) == 5); - assert(e5.extent(1) == 3); - - extents e6(span{two_sizet}); - assert(e6.extent(0) == 5); - assert(e6.extent(1) == 7); -} - -void extent_tests_equality() { - static_assert(extents{} == extents{}); - static_assert(extents{} != extents{}); - static_assert(extents{} != extents{}); - - extents e_23; - extents e_2d{3}; - extents e_d3{2}; - extents e_dd{2, 3}; - - assert(e_23 == e_2d); - assert(e_23 == e_d3); - assert(e_23 == e_dd); - assert(e_2d == e_d3); -} - -template = 0> -void TestMapping(const Mapping& map) { - using IndexT = typename Mapping::index_type; - using RankT = typename Mapping::rank_type; - static_assert(is_same_v()(IndexT{0}, IndexT{0}))>); - static_assert(is_same_v().stride(RankT{0}))>); - - array s; - const auto& e = map.extents(); - size_t num_entries = 1; - for (size_t i = 0; i < Mapping::extents_type::rank(); ++i) { - num_entries *= e.extent(i); - s[i] = map.stride(i); - } - - vector indices; - indices.reserve(num_entries); - - for (IndexT i = 0; i < e.extent(0); ++i) { - for (IndexT j = 0; j < e.extent(1); ++j) { - const auto idx = i * s[0] + j * s[1]; - assert(map(i, j) == idx); - indices.push_back(idx); - } - } - - bool is_unique = true; - bool is_exhaust = true; - sort(indices.begin(), indices.end()); - for (size_t i = 1; i < indices.size(); ++i) { - const auto diff = indices[i] - indices[i - 1]; - if (diff == 0) { - is_unique = false; - } else if (diff != 1) { - is_exhaust = false; - } - } - - assert(map.is_unique() == is_unique); - assert(map.is_exhaustive() == is_exhaust); - assert(map.required_span_size() == indices.back() + 1); -} - -template = 0> -void TestMapping(const Mapping& map) { - using IndexT = typename Mapping::index_type; - using RankT = typename Mapping::rank_type; - static_assert(is_same_v()(IndexT{0}, IndexT{0}, IndexT{0}))>); - static_assert(is_same_v().stride(RankT{0}))>); - - array s; - const auto& e = map.extents(); - size_t num_entries = 1; - for (size_t i = 0; i < Mapping::extents_type::rank(); ++i) { - num_entries *= e.extent(i); - s[i] = map.stride(i); - } - - vector indices; - indices.reserve(num_entries); - - for (IndexT i = 0; i < e.extent(0); ++i) { - for (IndexT j = 0; j < e.extent(1); ++j) { - for (IndexT k = 0; k < e.extent(2); ++k) { - const auto idx = i * s[0] + j * s[1] + k * s[2]; - assert(map(i, j, k) == idx); - indices.push_back(idx); - } - } - } - - bool is_unique = true; - bool is_exhaust = true; - sort(indices.begin(), indices.end()); - for (size_t i = 1; i < indices.size(); ++i) { - const auto diff = indices[i] - indices[i - 1]; - if (diff == 0) { - is_unique = false; - } else if (diff != 1) { - is_exhaust = false; - } - } - - assert(map.is_unique() == is_unique); - assert(map.is_exhaustive() == is_exhaust); - assert(map.required_span_size() == indices.back() + 1); -} - -void layout_left_tests_traits() { - static_assert(is_regular_trivial_nothrow_v>>); - static_assert(is_regular_trivial_nothrow_v>>); - static_assert(is_regular_trivial_nothrow_v>>); - static_assert(is_regular_trivial_nothrow_v>>); - - using E = extents; - static_assert(is_same_v::extents_type, E>); - static_assert(is_same_v::index_type, E::index_type>); - static_assert(is_same_v::size_type, E::size_type>); - static_assert(is_same_v::rank_type, E::rank_type>); - static_assert(is_same_v::layout_type, layout_left>); -} - -void layout_right_tests_traits() { - static_assert(is_regular_trivial_nothrow_v>>); - static_assert(is_regular_trivial_nothrow_v>>); - static_assert(is_regular_trivial_nothrow_v>>); - static_assert(is_regular_trivial_nothrow_v>>); - - using E = extents; - static_assert(is_same_v::extents_type, E>); - static_assert(is_same_v::index_type, E::index_type>); - static_assert(is_same_v::size_type, E::size_type>); - static_assert(is_same_v::rank_type, E::rank_type>); - static_assert(is_same_v::layout_type, layout_right>); -} - -void layout_stride_tests_traits() { - static_assert(is_regular_trivial_nothrow_v>>); - static_assert(is_regular_trivial_nothrow_v>>); - static_assert(is_regular_trivial_nothrow_v>>); - static_assert( - is_regular_trivial_nothrow_v>>); - - using E = extents; - static_assert(is_same_v::extents_type, E>); - static_assert(is_same_v::index_type, E::index_type>); - static_assert(is_same_v::size_type, E::size_type>); - static_assert(is_same_v::rank_type, E::rank_type>); - static_assert(is_same_v::layout_type, layout_stride>); -} - -void layout_left_tests_properties() { - constexpr layout_left::mapping> map{}; - static_assert(map.is_unique() == true); - static_assert(map.is_exhaustive() == true); - static_assert(map.is_strided() == true); - - static_assert(decltype(map)::is_always_unique() == true); - static_assert(decltype(map)::is_always_exhaustive() == true); - static_assert(decltype(map)::is_always_strided() == true); -} - -void layout_right_tests_properties() { - constexpr layout_right::mapping> map{}; - static_assert(map.is_unique() == true); - static_assert(map.is_exhaustive() == true); - static_assert(map.is_strided() == true); - - static_assert(decltype(map)::is_always_unique() == true); - static_assert(decltype(map)::is_always_exhaustive() == true); - static_assert(decltype(map)::is_always_strided() == true); -} - -void layout_stride_tests_properties() { - constexpr layout_stride::mapping> map{}; - static_assert(map.is_unique() == true); - static_assert(map.is_strided() == true); - - static_assert(decltype(map)::is_always_unique() == true); - static_assert(decltype(map)::is_always_exhaustive() == false); - static_assert(decltype(map)::is_always_strided() == true); -} - -void layout_left_tests_extents_ctor() { - constexpr extents e1; - constexpr extents e2{7}; - constexpr extents e3{11}; - constexpr extents e4{17, 19}; - - constexpr layout_left::mapping m1{e1}; - static_assert(m1.extents() == e1); - - constexpr layout_left::mapping m2{e2}; - static_assert(m2.extents() == e2); - - constexpr layout_left::mapping m3{e3}; - static_assert(m3.extents() == e3); - - constexpr layout_left::mapping m4{e4}; - static_assert(m4.extents() == e4); -} - -void layout_right_tests_extents_ctor() { - constexpr extents e1; - constexpr extents e2{7}; - constexpr extents e3{11}; - constexpr extents e4{17, 19}; - - constexpr layout_right::mapping m1{e1}; - static_assert(m1.extents() == e1); - - constexpr layout_right::mapping m2{e2}; - static_assert(m2.extents() == e2); - - constexpr layout_right::mapping m3{e3}; - static_assert(m3.extents() == e3); - - constexpr layout_right::mapping m4{e4}; - static_assert(m4.extents() == e4); -} - -void layout_stride_tests_extents_ctor() { - constexpr extents e1; - constexpr array s1{1, 2}; - - constexpr layout_stride::mapping m1{e1, s1}; - static_assert(m1.extents() == e1); - static_assert(m1.strides() == s1); - - constexpr extents e2{7}; - constexpr array s2{7, 1}; - - constexpr layout_stride::mapping m2{e2, s2}; - static_assert(m2.extents() == e2); - static_assert(m2.strides() == s2); -} - -template -void copy_ctor_helper_left(const Extents& e) { - const layout_left::mapping m1{e}; - const layout_left::mapping m2{m1}; - assert(m1 == m2); -} - -template -void copy_ctor_helper_right(const Extents& e) { - const layout_right::mapping m1{e}; - const layout_right::mapping m2{m1}; - assert(m1 == m2); -} - -void layout_left_tests_copy_ctor() { - copy_ctor_helper_left(extents{}); - copy_ctor_helper_left(extents{7}); - copy_ctor_helper_left(extents{11}); - copy_ctor_helper_left(extents{17, 19}); -} - -void layout_right_tests_copy_ctor() { - copy_ctor_helper_right(extents{}); - copy_ctor_helper_right(extents{7}); - copy_ctor_helper_right(extents{11}); - copy_ctor_helper_right(extents{17, 19}); -} - -void layout_left_tests_copy_other_extent() { - using E1 = extents; - using E2 = extents; - constexpr E1 e1; - constexpr E2 e2{3}; - constexpr layout_left::mapping m1(static_cast(e2)); - constexpr layout_left::mapping m2(e1); - - static_assert(m1.extents() == e1); - static_assert(m2.extents() == e1); - static_assert(m1.extents() == e2); - static_assert(m2.extents() == e2); -} - -void layout_right_tests_copy_ctor_other() { - using E1 = extents; - using E2 = extents; - constexpr E1 e1; - constexpr E2 e2{3}; - constexpr layout_right::mapping m1(static_cast(e2)); - constexpr layout_right::mapping m2(e1); - - static_assert(m1.extents() == e1); - static_assert(m2.extents() == e1); - static_assert(m1.extents() == e2); - static_assert(m2.extents() == e2); -} - -template -void assign_helper_left(const Extents& e) { - const layout_left::mapping m1{e}; - layout_left::mapping m2; - m2 = m1; - assert(m1 == m2); -} - -template -void assign_helper_right(const Extents& e) { - const layout_right::mapping m1{e}; - layout_right::mapping m2; - m2 = m1; - assert(m1 == m2); -} - -void layout_left_tests_assign() { - assign_helper_left(extents{}); - assign_helper_left(extents{7}); - assign_helper_left(extents{11}); - assign_helper_left(extents{17, 19}); -} - -void layout_right_tests_assign() { - assign_helper_right(extents{}); - assign_helper_right(extents{7}); - assign_helper_right(extents{11}); - assign_helper_right(extents{17, 19}); -} - -void layout_left_tests_ctor_other_layout() { - using E = extents; - - // from layout_left - using OE1 = extents; - static_assert(is_nothrow_constructible_v, layout_right::mapping>); - static_assert(is_nothrow_convertible_v, layout_left::mapping>); - - using OE2 = extents; // not convertible - static_assert(is_nothrow_constructible_v, layout_right::mapping>); - static_assert(!is_convertible_v, layout_left::mapping>); - - using OE3 = extents; // not constructible, rank > 1 - static_assert(!is_constructible_v, layout_right::mapping>); - static_assert(!is_convertible_v, layout_left::mapping>); - - static_assert(!is_constructible_v, layout_right::mapping>); - static_assert(!is_convertible_v, layout_left::mapping>); - - // from layout_stride - static_assert(is_constructible_v>, layout_stride::mapping>>); - static_assert(is_convertible_v>, layout_left::mapping>>); - - static_assert(is_constructible_v, layout_stride::mapping>); - static_assert(!is_convertible_v, layout_left::mapping>); - - static_assert(!is_constructible_v, layout_stride::mapping>); - static_assert(!is_convertible_v, layout_left::mapping>); -} - -void layout_right_tests_ctor_other_layout() { - using E = extents; - - // from layout_left - using OE1 = extents; - static_assert(is_nothrow_constructible_v, layout_left::mapping>); - static_assert(is_nothrow_convertible_v, layout_right::mapping>); - - using OE2 = extents; // not convertible - static_assert(is_nothrow_constructible_v, layout_left::mapping>); - static_assert(!is_convertible_v, layout_right::mapping>); - - using OE3 = extents; // not constructible, rank > 1 - static_assert(!is_constructible_v, layout_left::mapping>); - static_assert(!is_convertible_v, layout_right::mapping>); - - static_assert(!is_constructible_v, layout_left::mapping>); - static_assert(!is_convertible_v, layout_right::mapping>); - - // from layout_stride - static_assert(is_constructible_v>, layout_stride::mapping>>); - static_assert(is_convertible_v>, layout_right::mapping>>); - - static_assert(is_constructible_v, layout_stride::mapping>); - static_assert(!is_convertible_v, layout_right::mapping>); - - static_assert(!is_constructible_v, layout_stride::mapping>); - static_assert(!is_convertible_v, layout_right::mapping>); -} - -void layout_left_tests_strides() { - using E = extents; - layout_left::mapping map; - static_assert(map.stride(0) == 1); - static_assert(map.stride(1) == 2); - static_assert(map.stride(2) == 2 * 3); - static_assert(map.stride(3) == 2 * 3 * 5); -} - -void layout_right_tests_strides() { - using E = extents; - layout_right::mapping map; - static_assert(map.stride(0) == 7 * 5 * 3); - static_assert(map.stride(1) == 7 * 5); - static_assert(map.stride(2) == 7); - static_assert(map.stride(3) == 1); -} - -void layout_stride_tests_strides() { - using E = extents; - constexpr array s{1, 3}; - constexpr layout_stride::mapping map{E{}, s}; - static_assert(map.stride(0) == s[0]); - static_assert(map.stride(1) == s[1]); - static_assert(map.strides() == s); -} - -void layout_left_tests_indexing() { - static_assert(layout_left::mapping>{}() == 0); - TestMapping(layout_left::mapping>{}); - TestMapping(layout_left::mapping>{}); -} - -void layout_right_tests_indexing() { - static_assert(layout_right::mapping>{}() == 0); - TestMapping(layout_right::mapping>{}); - TestMapping(layout_right::mapping>{}); -} - -template -void copy_ctor_helper_stride(const Extents& e) { - const layout_stride::mapping m1{layout_right::mapping{e}}; - const layout_stride::mapping m2{m1}; - assert(m1 == m2); -} - -void layout_stride_tests_copy_ctor() { - copy_ctor_helper_stride(extents{}); - copy_ctor_helper_stride(extents{7}); - copy_ctor_helper_stride(extents{11}); - copy_ctor_helper_stride(extents{17, 19}); -} - -void layout_stride_tests_ctor_other_extents() { - constexpr extents e1; - constexpr extents e2{3}; - constexpr array s{3, 1}; - - constexpr layout_stride::mapping> m1(e1, s); - constexpr layout_stride::mapping> m2(m1); - - static_assert(m2.extents() == e1); - static_assert(m2.strides() == s); -} - -template -void other_mapping_helper() { - constexpr LayoutMapping other; - constexpr layout_stride::mapping map{other}; - static_assert(map.extents() == other.extents()); - for (size_t i = 0; i < LayoutMapping::extents_type::rank(); ++i) { - assert(map.stride(i) == other.stride(i)); - } -} -void layout_stride_tests_ctor_other_mapping() { - using E = extents; - other_mapping_helper>(); - other_mapping_helper>(); -} - -template -void assign_helper_stride(const Extents& e) { - const layout_stride::mapping m1{layout_right::mapping{e}}; - layout_stride::mapping m2; - m2 = m1; - assert(m1 == m2); -} - -void layout_stride_tests_assign() { - assign_helper_stride(extents{}); - assign_helper_stride(extents{7}); - assign_helper_stride(extents{11}); - assign_helper_stride(extents{17, 19}); -} - -void layout_stride_tests_indexing_static() { - using E = extents; - TestMapping(layout_stride::mapping{E{}, array{1, 2}}); - TestMapping(layout_stride::mapping{E{}, array{3, 1}}); - - // non-exhaustive mappings - TestMapping(layout_stride::mapping{E{}, array{1, 3}}); - TestMapping(layout_stride::mapping{E{}, array{4, 1}}); - TestMapping(layout_stride::mapping{E{}, array{2, 3}}); - - // exhaustive mappings with singleton dimensions - using E1 = extents; - TestMapping(layout_stride::mapping{E1{}, array{3, 1, 1}}); - TestMapping(layout_stride::mapping{E1{}, array{3, 7, 1}}); - - using E2 = extents; - TestMapping(layout_stride::mapping{E2{}, array{3, 1, 1}}); - TestMapping(layout_stride::mapping{E2{}, array{3, 1, 11}}); - - using E3 = extents; - TestMapping(layout_stride::mapping{E3{}, array{1, 3, 1}}); - TestMapping(layout_stride::mapping{E3{}, array{1, 3, 13}}); -} - - -void layout_stride_tests_equality() { - using E = extents; - constexpr layout_stride::mapping map1(layout_right::mapping{}); - constexpr layout_stride::mapping map2(layout_right::mapping{}); - static_assert(map1 == map2); - - constexpr layout_stride::mapping map3{layout_left::mapping{}}; - static_assert(map1 != map3); - - using ED = extents; - constexpr layout_stride::mapping map4{ED{2, 3}, map1.strides()}; - static_assert(map1 == map4); -} - -void accessor_tests_general() { - default_accessor a; - double arr[4] = {}; - static_assert(a.offset(arr, 3) == &arr[3]); - - a.access(arr, 2) = 42; - assert(arr[2] == 42); - - static_assert(is_constructible_v, default_accessor>); - static_assert(!is_constructible_v, default_accessor>); -} - -namespace Pathological { - - struct Empty {}; - - struct Extents { - using index_type = int; - using size_type = std::make_unsigned_t; - using rank_type = size_t; - - explicit Extents(Empty) {} - - template - explicit Extents(const array&) {} - - static constexpr size_t rank() { - return 0; - } - - static constexpr size_t rank_dynamic() { - return 0; - } - }; - - struct Layout { - template - struct mapping { - using extents_type = E; - using layout_type = Layout; - mapping(Extents) {} - }; - }; - - struct Accessor { - using element_type = int; - using data_handle_type = int*; - using reference = int&; - Accessor(int) {} - }; -} // namespace Pathological - -void mdspan_tests_traits() { - using M = mdspan>; - static_assert(is_trivially_copyable_v /*&& is_default_constructible_v*/ - && is_copy_constructible_v && is_move_constructible_v && is_copy_assignable_v - && is_move_assignable_v); - - static_assert(is_same_v>); - static_assert(is_same_v); - static_assert(is_same_v>); - static_assert(is_same_v>>); - static_assert(is_same_v); - static_assert(is_same_v); - static_assert(is_same_v); - static_assert(is_same_v); - static_assert(is_same_v); -} - -void mdspan_tests_ctor_sizes() { - static constexpr int arr[6] = {}; - constexpr mdspan> mds1(arr, 2); - static_assert(mds1.data_handle() == arr); - static_assert((mds1.extents() == extents{})); - static_assert(mds1.is_exhaustive()); - - static_assert(!is_constructible_v, Pathological::Layout>, int*, - int>); // Pathological::Layout not constructible from extents - - static_assert( - !is_constructible_v, layout_right, Pathological::Accessor>, int*, - int>); // Pathological::Accessor not default constructible -} - -void mdspan_tests_ctor_array() { - static constexpr int arr[6] = {}; - constexpr mdspan> mds1(arr, array{2}); - static_assert(mds1.data_handle() == arr); - static_assert(mds1.extents() == extents{}); - - static_assert(!is_constructible_v, Pathological::Layout>, int*, - array>); // Pathological::Layout not constructible from extents - - static_assert( - !is_constructible_v, layout_right, Pathological::Accessor>, int*, - array>); // Pathological::Accessor not default constructible -} - -void mdspan_tests_ctor_extents() { - static constexpr int arr[6] = {}; - constexpr mdspan> mds1(arr, extents{2}); - static_assert(mds1.data_handle() == arr); - static_assert(mds1.extents() == extents{}); - - static_assert(!is_constructible_v, Pathological::Layout>, int*, - extents>); // Pathological::Layout not constructible from extents - - static_assert( - !is_constructible_v, layout_right, Pathological::Accessor>, int*, - extents>); // Pathological::Accessor not default constructible -} - -void mdspan_tests_ctor_mapping() { - static constexpr int arr[6] = {}; - using E = extents; - constexpr layout_left::mapping> map(extents{}); - - constexpr mdspan mds1(arr, map); - static_assert(mds1.data_handle() == arr); - static_assert(mds1.extents() == extents{}); - static_assert(mds1.mapping() == map); - - static_assert( - !is_constructible_v, layout_right, Pathological::Accessor>, int*, - extents>); // Pathological::Accessor not default constructible -} - -template -struct stateful_accessor { - using element_type = Type; - using data_handle_type = Type*; - using reference = Type&; - - constexpr stateful_accessor(int i_) : i(i_){}; - int i = 0; -}; - -void mdspan_tests_ctor_accessor() { - static constexpr int arr[6] = {}; - using E = extents; - constexpr layout_left::mapping> map(extents{}); - constexpr stateful_accessor acc(1); - - constexpr mdspan> mds1(arr, map, acc); - static_assert(mds1.data_handle() == arr); - static_assert(mds1.extents() == extents{}); - static_assert(mds1.mapping() == map); - static_assert(mds1.accessor().i == 1); - - static_assert( - !is_constructible_v, layout_right, Pathological::Accessor>, int*, - extents>); // Pathological::Accessor not default constructible -} - -void mdspan_tests_assign() { - using E2 = extents; - int arr[6] = {}; - mdspan> mds1(arr, 2); - mdspan> mds2(nullptr, 3); - mds2 = mds1; - assert(mds2.data_handle() == arr); - assert(mds2.extents() == E2{}); - assert(mds2.mapping() == mds1.mapping()); -} - -void mdspan_tests_observers() { - using E = extents; - static constexpr int arr[] = {0, 1, 2, 3, 4, 5, 6, 7}; - constexpr mdspan mds{arr, layout_stride::mapping{E{2}, array{1, 3}}}; - - static_assert(mds.rank() == 2); - static_assert(mds.rank_dynamic() == 1); - - static_assert(mds.static_extent(0) == dynamic_extent); - static_assert(mds.static_extent(1) == 3); - static_assert(mds.extent(0) == 2); - static_assert(mds.extent(1) == 3); - static_assert(mds.size() == 6); - - static_assert(mds.stride(0) == 1); - static_assert(mds.stride(1) == 3); - - static_assert(mds.is_always_unique()); - static_assert(!mds.is_always_exhaustive()); - static_assert(mds.is_always_strided()); - - static_assert(mds.is_unique()); - static_assert(!mds.is_exhaustive()); - static_assert(mds.is_strided()); - -#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 - static_assert(mds[1, 0] == 1); - static_assert(mds[1, 2] == 7); -#endif // __cpp_multidimensional_subscript - - static_assert(mds[array{0, 1}] == 3); - static_assert(mds[array{1, 1}] == 4); -} - -int main() { - extent_tests_rank(); - extent_tests_static_extent(); - extent_tests_extent(); - extent_tests_ctor_other_sizes(); - extent_tests_copy_ctor_other(); - extent_tests_ctor_array(); - extent_tests_ctor_span(); - extent_tests_equality(); - - layout_left_tests_traits(); - layout_left_tests_properties(); - layout_left_tests_extents_ctor(); - layout_left_tests_copy_ctor(); - layout_left_tests_copy_other_extent(); - layout_left_tests_assign(); - layout_left_tests_ctor_other_layout(); - layout_left_tests_strides(); - layout_left_tests_indexing(); - - layout_right_tests_traits(); - layout_right_tests_properties(); - layout_right_tests_extents_ctor(); - layout_right_tests_copy_ctor(); - layout_right_tests_copy_ctor_other(); - layout_right_tests_assign(); - layout_right_tests_ctor_other_layout(); - layout_right_tests_strides(); - layout_right_tests_indexing(); - - layout_stride_tests_traits(); - layout_stride_tests_properties(); - layout_stride_tests_extents_ctor(); - layout_stride_tests_strides(); - layout_stride_tests_copy_ctor(); - layout_stride_tests_ctor_other_extents(); - layout_stride_tests_ctor_other_mapping(); - layout_stride_tests_assign(); - layout_stride_tests_indexing_static(); - layout_stride_tests_equality(); - - accessor_tests_general(); - - mdspan_tests_traits(); - mdspan_tests_ctor_sizes(); - mdspan_tests_ctor_array(); - mdspan_tests_ctor_extents(); - mdspan_tests_ctor_mapping(); - mdspan_tests_ctor_accessor(); - mdspan_tests_assign(); - mdspan_tests_observers(); - - return 0; -} From 1f6f10cd8c9e1e85f0e35741ea40d063d81312cd Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 14:46:56 +0200 Subject: [PATCH 08/13] Change layouts' `check_mapping_properties` tests a little bit --- .../P0009R18_mdspan_layout_left/test.cpp | 24 +++++------ .../P0009R18_mdspan_layout_right/test.cpp | 24 +++++------ .../P0009R18_mdspan_layout_stride/test.cpp | 42 +++++++++---------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index e8711c62f05..146ca784d38 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -159,25 +159,25 @@ constexpr void check_members(const extents& ext, index_se } } -constexpr void check_mapping_properties() { - auto check = [](const auto& mapping) { - const auto props = get_mapping_properties(mapping); - if constexpr (!is_permissive) { +void check_mapping_properties() { + if constexpr (!is_permissive) { + auto check = []([[maybe_unused]] const auto& mapping) { + const auto props = get_mapping_properties(mapping); assert(props.req_span_size == mapping.required_span_size()); assert(props.uniqueness); assert(props.exhaustiveness); assert(props.strideness); - } - }; + }; - using M1 = layout_left::mapping>; - check(M1{}); + using M1 = layout_left::mapping>; + check(M1{}); - using M2 = layout_left::mapping>; - check(M2{M2::extents_type{6}}); + using M2 = layout_left::mapping>; + check(M2{M2::extents_type{6}}); - using M3 = layout_left::mapping>; - check(M3{M3::extents_type{3, 5, 4, 2}}); + using M3 = layout_left::mapping>; + check(M3{M3::extents_type{3, 5, 4, 2}}); + } } constexpr void check_construction_from_extents() { diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp index d94f05a0784..b0dd098f7fc 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -158,25 +158,25 @@ constexpr void check_members(const extents& ext, index_se } } -constexpr void check_mapping_properties() { - auto check = [](const auto& mapping) { - const auto props = get_mapping_properties(mapping); - if constexpr (!is_permissive) { +void check_mapping_properties() { + if constexpr (!is_permissive) { + auto check = []([[maybe_unused]] const auto& mapping) { + const auto props = get_mapping_properties(mapping); assert(props.req_span_size == mapping.required_span_size()); assert(props.uniqueness); assert(props.exhaustiveness); assert(props.strideness); - } - }; + }; - using M1 = layout_right::mapping>; - check(M1{}); + using M1 = layout_right::mapping>; + check(M1{}); - using M2 = layout_right::mapping>; - check(M2{M2::extents_type{2, 6}}); + using M2 = layout_right::mapping>; + check(M2{M2::extents_type{2, 6}}); - using M3 = layout_right::mapping>; - check(M3{M3::extents_type{4, 3, 5, 4}}); + using M3 = layout_right::mapping>; + check(M3{M3::extents_type{4, 3, 5, 4}}); + } } constexpr void check_construction_from_extents() { diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index 13ab33b6139..ee6fec0b4e5 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -174,38 +174,38 @@ constexpr void check_members(extents ext, const array(ext, strides); } -constexpr void check_mapping_properties() { - auto check = [](const auto& mapping, [[maybe_unused]] const bool expected_exhaustiveness) { - const auto props = get_mapping_properties(mapping); - if constexpr (!is_permissive) { +void check_mapping_properties() { + if constexpr (!is_permissive) { + auto check = [](const auto& mapping, const bool expected_exhaustiveness) { + const auto props = get_mapping_properties(mapping); assert(props.req_span_size == mapping.required_span_size()); assert(props.uniqueness); assert(props.exhaustiveness == expected_exhaustiveness); assert(props.exhaustiveness == mapping.is_exhaustive()); assert(props.strideness); - } - }; + }; - { // Check exhaustive mappings - using M1 = layout_stride::mapping>; - check(M1{M1::extents_type{}, array{6, 1, 2}}, true); + { // Check exhaustive mappings + using M1 = layout_stride::mapping>; + check(M1{M1::extents_type{}, array{6, 1, 2}}, true); - using M2 = layout_stride::mapping>; - check(M2{M2::extents_type{6, 7}, array{1, 48, 6}}, true); + using M2 = layout_stride::mapping>; + check(M2{M2::extents_type{6, 7}, array{1, 48, 6}}, true); - using M3 = layout_stride::mapping>; - check(M3{M3::extents_type{3, 5, 2, 4}, array{20, 1, 60, 5}}, true); - } + using M3 = layout_stride::mapping>; + check(M3{M3::extents_type{3, 5, 2, 4}, array{20, 1, 60, 5}}, true); + } - { // Check non-exhaustive mappings - using M1 = layout_stride::mapping>; - check(M1{M1::extents_type{}, array{9, 18, 1}}, false); + { // Check non-exhaustive mappings + using M1 = layout_stride::mapping>; + check(M1{M1::extents_type{}, array{9, 18, 1}}, false); - using M2 = layout_stride::mapping>; - check(M2{M2::extents_type{4, 3}, array{12, 36, 1}}, false); + using M2 = layout_stride::mapping>; + check(M2{M2::extents_type{4, 3}, array{12, 36, 1}}, false); - using M3 = layout_stride::mapping>; - check(M3{M3::extents_type{4, 3, 2}, array{8, 32, 2}}, false); + using M3 = layout_stride::mapping>; + check(M3{M3::extents_type{4, 3, 2}, array{8, 32, 2}}, false); + } } } From 96e1b3b6d955eab97c04a07acd614a114c8305c5 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 18:16:55 +0200 Subject: [PATCH 09/13] Implement `is_strided` check in `get_mapping_properties` --- tests/std/include/test_mdspan_support.hpp | 61 ++++++++++++++++------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index ff55ef3fe19..1690ada64c3 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -263,41 +264,65 @@ struct MappingProperties { template requires (!details::PermissiveTest::test()) -constexpr MappingProperties get_mapping_properties(const Mapping& mapping) { - constexpr typename Mapping::index_type zero = 0; +MappingProperties get_mapping_properties(const Mapping& mapping) { + using IndexType = typename Mapping::index_type; + constexpr IndexType zero = 0; + constexpr auto rank = Mapping::extents_type::rank(); + constexpr std::make_index_sequence rank_indices; - auto make_cartesian_prod = [&](std::index_sequence) { - return std::views::cartesian_product(std::views::iota(zero, mapping.extents().extent(Indices))...); - }; + auto get_extent = [&](size_t i) { return mapping.extents().extent(i); }; + auto multidim_indices = [&](std::index_sequence) { + return std::views::cartesian_product(std::views::iota(zero, get_extent(Indices))...); + }(rank_indices); - auto indices = - make_cartesian_prod(std::make_index_sequence{}) - | std::views::transform([&](auto tpl) { return std::apply([&](auto... i) { return mapping(i...); }, tpl); }) - | std::ranges::to(); - std::ranges::sort(indices); + auto map_index = [&](const auto& tpl) { return std::apply([&](auto... i) { return mapping(i...); }, tpl); }; + auto mapped_indices = multidim_indices | std::views::transform(map_index) | std::ranges::to(); + std::ranges::sort(mapped_indices); - MappingProperties props; + MappingProperties props{}; { // Find required span size (N4950 [mdspan.layout.reqmts]/12) - auto exts = std::views::iota(0u, Mapping::extents_type::rank()) - | std::views::transform([&](auto i) { return mapping.extents().extent(i); }); + auto exts = std::views::iota(0u, rank) | std::views::transform([&](auto i) { return get_extent(i); }); if (std::ranges::contains(exts, zero)) { props.req_span_size = 0; } else { - props.req_span_size = static_cast(1 + indices.back()); + props.req_span_size = static_cast(1 + mapped_indices.back()); } } // Is mapping unique? (N4950 [mdspan.layout.reqmts]/14) - props.uniqueness = !std::ranges::contains(std::views::pairwise_transform(indices, std::minus{}), zero); + props.uniqueness = !std::ranges::contains(std::views::pairwise_transform(mapped_indices, std::minus{}), zero); { // Is mapping exhaustive? (N4950 [mdspan.layout.reqmts]/16) - const auto diffs = std::views::pairwise_transform(indices, [](auto x, auto y) { return y - x; }); + const auto diffs = std::views::pairwise_transform(mapped_indices, [](auto x, auto y) { return y - x; }); props.exhaustiveness = std::ranges::find_if_not(diffs, [](auto x) { return x == 1; }) == diffs.end(); } - // Is mapping strided? FIXME (N4950 [mdspan.layout.reqmts]/18) - props.strideness = true; + { // Is mapping strided? (N4950 [mdspan.layout.reqmts]/18) + props.strideness = true; // assumption + for (auto r : std::views::iota(0u, rank)) { + std::optional sr; + for (auto i : multidim_indices) { + const auto i_plus_dr = [&](std::index_sequence) { + return std::array{static_cast(std::get(i) + (Indices == r ? 1 : 0))...}; + }(rank_indices); + + if (i_plus_dr[r] < get_extent(r)) { + const auto diff = static_cast(map_index(i_plus_dr) - map_index(i)); + if (!sr.has_value()) { + sr = diff; + } else if (*sr != diff) { + props.strideness = false; + break; + } + } + } + + if (!props.strideness) { + break; + } + } + } return props; } From a8150283d2a2d407ebbf4632b725c7c4b0f0f38e Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 19:34:27 +0200 Subject: [PATCH 10/13] Poke CI From 0e8ab84515fe7e857e913de0d931cdd54057a533 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 13 Jun 2023 21:27:14 +0200 Subject: [PATCH 11/13] Revert "Drive-by: include `"test_mdspan_support.hpp"` instead of ``" And use `` instead of `"test_mdspan_support.hpp"` This reverts commit 265440556cd1e0f5b037515c7e2753beb3551252. --- tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp | 2 +- tests/std/tests/P0009R18_mdspan_extents/test.cpp | 2 +- tests/std/tests/P0009R18_mdspan_layout_left/test.cpp | 2 +- tests/std/tests/P0009R18_mdspan_layout_right/test.cpp | 2 +- tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp | 2 +- tests/std/tests/P0009R18_mdspan_mdspan/test.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp index f22101c0f7c..9036a910c75 100644 --- a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp @@ -9,7 +9,7 @@ #include #include -#include "test_mdspan_support.hpp" +#include using namespace std; diff --git a/tests/std/tests/P0009R18_mdspan_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp index 1ed2d2f5848..3ff5424078e 100644 --- a/tests/std/tests/P0009R18_mdspan_extents/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -10,7 +10,7 @@ #include #include -#include "test_mdspan_support.hpp" +#include using namespace std; diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index 146ca784d38..ab353018523 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -9,7 +9,7 @@ #include #include -#include "test_mdspan_support.hpp" +#include using namespace std; diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp index b0dd098f7fc..e733fd63286 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -9,7 +9,7 @@ #include #include -#include "test_mdspan_support.hpp" +#include using namespace std; diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index ee6fec0b4e5..385b25dd44d 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -10,7 +10,7 @@ #include #include -#include "test_mdspan_support.hpp" +#include using namespace std; diff --git a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp index b323b09621c..44580c94dd0 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp @@ -13,7 +13,7 @@ #include #include -#include "test_mdspan_support.hpp" +#include using namespace std; From b8cb9a6df3e24ab338591b94030eb9f09aea12f5 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 14 Jun 2023 14:35:55 +0200 Subject: [PATCH 12/13] ``: remove `exts` variable from `get_mapping_properties` --- tests/std/include/test_mdspan_support.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index 1690ada64c3..6763f021fc5 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -281,13 +281,11 @@ MappingProperties get_mapping_properties(const Mapping& mapping) { MappingProperties props{}; - { // Find required span size (N4950 [mdspan.layout.reqmts]/12) - auto exts = std::views::iota(0u, rank) | std::views::transform([&](auto i) { return get_extent(i); }); - if (std::ranges::contains(exts, zero)) { - props.req_span_size = 0; - } else { - props.req_span_size = static_cast(1 + mapped_indices.back()); - } + // Find required span size (N4950 [mdspan.layout.reqmts]/12) + if (std::ranges::contains(std::views::iota(0u, rank) | std::views::transform(get_extent), zero)) { + props.req_span_size = 0; + } else { + props.req_span_size = static_cast(1 + mapped_indices.back()); } // Is mapping unique? (N4950 [mdspan.layout.reqmts]/14) From cfbc99ddd0948e96fcbcc3c58ea2e05bf0eeedfb Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 16 Jun 2023 14:39:23 -0700 Subject: [PATCH 13/13] Code review feedback. --- tests/std/include/test_mdspan_support.hpp | 2 ++ tests/std/tests/P0009R18_mdspan_layout_left/test.cpp | 4 ++-- tests/std/tests/P0009R18_mdspan_layout_right/test.cpp | 4 ++-- tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index 6763f021fc5..b653d74268e 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -7,10 +7,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index ab353018523..9946cf40f8e 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -46,7 +46,7 @@ constexpr void check_members(const extents& ext, index_se Mapping cpy; cpy = m; assert(cpy == m); - static_assert(is_nothrow_copy_assignable_v); + static_assert(is_nothrow_copy_assignable_v); } { // Check construction from extents_type @@ -85,7 +85,7 @@ constexpr void check_members(const extents& ext, index_se } #ifdef __clang__ - if (!is_constant_evaluated()) // FIXME clang hits contexpr limit here + if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here #endif { // Check construction from layout_stride::mapping array strides{}; diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp index e733fd63286..a5e58742cbe 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -46,7 +46,7 @@ constexpr void check_members(const extents& ext, index_se Mapping cpy; cpy = m; assert(cpy == m); - static_assert(is_nothrow_copy_assignable_v); + static_assert(is_nothrow_copy_assignable_v); } { // Check construction from extents_type @@ -61,7 +61,7 @@ constexpr void check_members(const extents& ext, index_se using Mapping2 = layout_right::mapping; #ifdef __clang__ - if (!is_constant_evaluated()) // FIXME clang hits contexpr limit here + if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here #endif { // Check construction from other layout_right::mapping Mapping m1{ext}; diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index 385b25dd44d..4c39707b548 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -58,7 +58,7 @@ constexpr void do_check_members(const extents& ext, Mapping cpy; cpy = m; assert(cpy == m); - static_assert(is_nothrow_copy_assignable_v); + static_assert(is_nothrow_copy_assignable_v); } { // Check construction from extents_type and array