From 72b131680ee55aa6af85508762559ccb7e0edb13 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sun, 14 May 2023 21:03:11 +0200 Subject: [PATCH] More tests --- .../P0009R18_mdspan_layout_stride/test.cpp | 381 +++++++++++++++++- 1 file changed, 368 insertions(+), 13 deletions(-) diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index e18d9186566..99dcce276d8 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, 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 [FIXME] + // Other tests are defined in 'check_construction_from_extents_and_array' function } { // Check construction from extents_type and span @@ -67,7 +67,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 [FIXME] + // Other tests are defined in 'check_construction_from_extents_and_array' function } using OtherIndexType = long long; @@ -79,7 +79,7 @@ constexpr void do_check_members(const extents& ext, Mapping2 m2{m1}; assert(m1 == m2); static_assert(is_nothrow_constructible_v); - // Other tests are defined in 'check_construction_from_other_mappings' function [FIXME] + // Other tests are defined in 'check_construction_from_other_mappings' function } Mapping m{ext, strs}; // For later use @@ -96,8 +96,7 @@ constexpr void do_check_members(const extents& ext, static_assert(noexcept(m.strides())); } - // Function 'required_span_size' is tested in 'check_required_span_size' function[FIXME] - { // Check 'required_span_size' function[FIXME] + { // Check 'required_span_size' function if (((ext.extent(Indices) == 0) || ...)) { assert(m.required_span_size() == 0); } else { @@ -106,6 +105,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 } // Call operator() is tested in 'check_call_operator' function @@ -119,7 +119,7 @@ constexpr void do_check_members(const extents& ext, { // Check 'is_[unique/strided]' functions static_assert(Mapping::is_unique()); static_assert(Mapping::is_strided()); - // Tests of 'is_exhaustive' are defined in 'check_is_exhaustive' function [FIXME] + // Tests of 'is_exhaustive' are defined in 'check_is_exhaustive' function } { // Check 'stride' function @@ -135,7 +135,7 @@ constexpr void do_check_members(const extents& ext, { // Check comparisons assert(m == m); assert(!(m != m)); - // Other tests are defined in 'check_comparisons' function [FIXME] + // Other tests are defined in 'check_comparisons' function } } @@ -164,12 +164,361 @@ 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_construction_from_other_mappings() { + { // Check 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>>); + } + + { // Check invalid 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>>); + // TRANSITION, Check other kinds of invalid construction (requires new helper types) + } + + { // Check construction from layout_left::mapping + layout_left::mapping> left_mapping{dextents{4, 3, 2}}; + layout_stride::mapping> strided_mapping{left_mapping}; + assert(ranges::equal(strided_mapping.strides(), array{1, 4, 12}, CmpEqual{})); + } + + { // Check construction from layout_right::mapping + layout_right::mapping> right_mapping{dextents{4, 3, 2}}; + layout_stride::mapping> strided_mapping{right_mapping}; + assert(ranges::equal(strided_mapping.strides(), array{6, 2, 1}, CmpEqual{})); + } +} + +constexpr void check_required_span_size() { + { // Check [mdspan.layout.stride.expo]/1.1: Ext::rank() == 0 + using M1 = layout_stride::mapping>; + static_assert(M1{}.required_span_size() == 1); + + layout_stride::mapping> m2; + assert(m2.required_span_size() == 1); + } + + { // Check [mdspan.layout.stride.expo]/1.2: size of the multidimensional index space e is 0 + using M1 = layout_stride::mapping>; + static_assert(M1{}.required_span_size() == 0); + + layout_stride::mapping> m2{dextents{3, 0, 3, 3}, array{1, 3, 1, 1}}; + assert(m2.required_span_size() == 0); + } + + { // Check [mdspan.layout.stride.expo]/1.3: final case + using M1 = layout_stride::mapping>; + static_assert(M1{}.required_span_size() == 36); + + layout_stride::mapping> m2{dextents{4, 3, 4}, array{1, 4, 12}}; + assert(m2.required_span_size() == 48); + } +} + +constexpr void check_is_exhaustive() { + { // Check exhaustive mappings (all possibilities) + using E = extents; + assert((layout_stride::mapping{E{}, array{1, 2, 6}}.is_exhaustive())); + assert((layout_stride::mapping{E{}, array{1, 10, 2}}.is_exhaustive())); + assert((layout_stride::mapping{E{}, array{3, 1, 6}}.is_exhaustive())); + assert((layout_stride::mapping{E{}, array{15, 1, 3}}.is_exhaustive())); + assert((layout_stride::mapping{E{}, array{5, 10, 1}}.is_exhaustive())); + assert((layout_stride::mapping{E{}, array{15, 5, 1}}.is_exhaustive())); + } + + { // Check non-exhaustive mappings + using E = extents; + assert((!layout_stride::mapping{E{}, array{1, 2, 12}}.is_exhaustive())); + assert((!layout_stride::mapping{E{}, array{8, 18, 1}}.is_exhaustive())); + assert((!layout_stride::mapping{E{}, array{5, 1, 12}}.is_exhaustive())); + } +} + +constexpr void check_call_operator() { + { // Check call with invalid amount of indices + using Mapping = layout_stride::mapping>; + static_assert(!CheckCallOperatorOfLayoutMapping); + static_assert(!CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(!CheckCallOperatorOfLayoutMapping); + } + + { // Check call with invalid types + using Mapping = layout_stride::mapping>; + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping); + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(!CheckCallOperatorOfLayoutMapping); + } + + { // Check call with types that might throw during conversion + using Mapping = layout_stride::mapping>; + static_assert(CheckCallOperatorOfLayoutMapping>); + static_assert(!CheckCallOperatorOfLayoutMapping>); + } + + { // Check various mappings + layout_stride::mapping> m1; + assert(m1() == 0); + + layout_stride::mapping> m2{dextents{4}, array{1}}; + assert(m2(0) == 0); + assert(m2(1) == 1); + assert(m2(2) == 2); + assert(m2(3) == 3); + + layout_stride::mapping> m3{{}, array{1, 5}}; // non-exhaustive mapping + assert(!m3.is_exhaustive()); + assert(m3(0, 0) == 0); + assert(m3(0, 1) == 5); + assert(m3(0, 2) == 10); + assert(m3(0, 3) == 15); + assert(m3(0, 4) == 20); + assert(m3(1, 0) == 1); + assert(m3(1, 1) == 6); + assert(m3(1, 2) == 11); + assert(m3(1, 3) == 16); + assert(m3(1, 4) == 21); + assert(m3(2, 0) == 2); + assert(m3(2, 1) == 7); + assert(m3(2, 2) == 12); + assert(m3(2, 3) == 17); + assert(m3(3, 0) == 3); + assert(m3(3, 1) == 8); + assert(m3(3, 2) == 13); + assert(m3(3, 4) == 23); + + layout_stride::mapping> m4{{}, array{15, 1, 3}}; // exhaustive mapping + assert(m4.is_exhaustive()); + assert(m4(0, 0, 0) == 0); + assert(m4(0, 0, 1) == 3); + assert(m4(0, 1, 0) == 1); + assert(m4(0, 1, 1) == 4); + assert(m4(1, 0, 0) == 15); + assert(m4(1, 0, 1) == 18); + assert(m4(1, 1, 0) == 16); + assert(m4(1, 1, 1) == 19); + assert(m4(1, 2, 4) == 29); + } +} + +constexpr void check_comparisons() { + using E = extents; + using StaticStrideMapping = layout_stride::mapping; + using DynamicStrideMapping = layout_stride::mapping>; + using RightMapping = layout_right::mapping; + using LeftMapping = layout_left::mapping; + + { // Check equality_comparable_with concept + static_assert(equality_comparable_with); + static_assert(equality_comparable_with); + static_assert(equality_comparable_with); + static_assert(equality_comparable_with); + static_assert(equality_comparable_with); + static_assert(!equality_comparable_with>>); + static_assert(!equality_comparable_with>>); + static_assert(!equality_comparable_with>>); + static_assert(!equality_comparable_with>>); + // TRANSITION, Check other constraints: [mdspan.layout.stride.obs]/6.1, 6.3 + } + + { // 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 + + DynamicStrideMapping m3{dextents{2, 3}, array{1, 2}}; + assert(m1 != m3); // extents are equal, OFFSET(rhs) == 0, strides are not equal + assert(m2 != m3); // ditto + + DynamicStrideMapping m4{dextents{1, 3}, array{3, 1}}; + assert(m1 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are equal + assert(m2 != m4); // ditto + assert(m3 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are not equal + + // NB: OFFSET(layout_stride::mapping) is always equal to 0 + } + + { // 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 + + DynamicStrideMapping m3{dextents{2, 3}, array{3, 1}}; + assert(m1 != m3); // extents are equal, OFFSET(rhs) == 0, strides are not equal + assert(m2 != m3); // ditto + + DynamicStrideMapping m4{dextents{2, 1}, array{1, 2}}; + assert(m1 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are equal + assert(m2 != m4); // ditto + assert(m3 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are not equal + + // NB: OFFSET(layout_left::mapping) is always equal to 0 + } + + { // 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 + + DynamicStrideMapping m3{dextents{2, 3}, array{1, 2}}; + assert(m1 != m3); // extents are equal, OFFSET(rhs) == 0, strides are not equal + assert(m2 != m3); // ditto + + DynamicStrideMapping m4{dextents{1, 3}, array{3, 1}}; + assert(m1 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are equal + assert(m2 != m4); // ditto + assert(m3 != m4); // extents are not equal, OFFSET(rhs) == 0, strides are not equal + + // NB: OFFSET(layout_right::mapping) is always equal to 0 + } + + // TRANSITION, Check comparisons with custom layout mapping +} + +constexpr void check_correctness() { + { // empty extents + const array vals{}; + mdspan, layout_stride> nothing{vals.data(), {}}; + assert(nothing.size() == 1); + } + + { // regular vector + using E = extents; + const array vals{1, 2, 3}; + layout_stride::mapping m{E{}, array{1}}; + mdspan, layout_stride> vec{vals.data(), m}; + + // TRANSITION, use operator[] + assert(vec(0) == 1); + assert(vec(1) == 2); + assert(vec(2) == 3); + } + + { // 2x3 matrix with row-major order + using E = extents; + const array vals{1, 2, 3, 4, 5, 6}; + layout_stride::mapping m{E{}, array{3, 1}}; + mdspan matrix{vals.data(), m}; + + // TRANSITION, use operator[] + assert(matrix(0, 0) == 1); + assert(matrix(0, 1) == 2); + assert(matrix(0, 2) == 3); + assert(matrix(1, 0) == 4); + assert(matrix(1, 1) == 5); + assert(matrix(1, 2) == 6); + } + + { // 3x2x2 tensor + using E = extents; + const array vals{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; + layout_stride::mapping m{E{}, array{8, 1, 6}}; // non-exhaustive mapping + assert(!m.is_exhaustive()); + mdspan tensor{vals.data(), m}; + + // TRANSITION, use operator[] + assert(tensor(0, 0, 0) == 0); + assert(tensor(0, 0, 1) == 6); + assert(tensor(0, 1, 0) == 1); + assert(tensor(0, 1, 1) == 7); + assert(tensor(1, 0, 0) == 8); + assert(tensor(1, 0, 1) == 14); + assert(tensor(1, 1, 0) == 9); + assert(tensor(1, 1, 1) == 15); + assert(tensor(2, 0, 0) == 16); + assert(tensor(2, 0, 1) == 22); + assert(tensor(2, 1, 0) == 17); + assert(tensor(2, 1, 1) == 23); + } + + { // 2x3x3x2 tensor + using E = extents; + const array vals{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35}; + layout_stride::mapping m{E{}, array{18, 1, 3, 9}}; // exhaustive mapping + assert(m.is_exhaustive()); + mdspan tensor{vals.data(), m}; + + // TRANSITION, use operator[] + assert(tensor(0, 0, 0, 0) == 0); + assert(tensor(0, 0, 0, 1) == 9); + assert(tensor(0, 0, 1, 0) == 3); + assert(tensor(0, 0, 1, 1) == 12); + assert(tensor(0, 1, 0, 0) == 1); + assert(tensor(0, 1, 0, 1) == 10); + assert(tensor(0, 1, 1, 0) == 4); + assert(tensor(0, 1, 1, 1) == 13); + assert(tensor(1, 0, 0, 0) == 18); + assert(tensor(1, 0, 0, 1) == 27); + assert(tensor(1, 0, 1, 0) == 21); + assert(tensor(1, 0, 1, 1) == 30); + assert(tensor(1, 1, 0, 0) == 19); + assert(tensor(1, 1, 0, 1) == 28); + assert(tensor(1, 1, 1, 0) == 22); + assert(tensor(1, 1, 1, 1) == 31); + assert(tensor(0, 2, 2, 0) == 8); + assert(tensor(1, 2, 2, 1) == 35); + } +} + constexpr void check_ctad() { - extents e; - array s{1, 2}; - layout_stride::mapping m{e, s}; - assert(m.extents() == e); - assert(m.strides() == s); + 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() { @@ -187,9 +536,15 @@ constexpr bool test() { check_members(extents{}, array{1}); check_members(extents{3}, array{1, 3, 6}); + check_construction_from_extents_and_array(); + check_construction_from_other_mappings(); + check_required_span_size(); + check_is_exhaustive(); + check_call_operator(); + check_comparisons(); + check_correctness(); check_ctad(); - // TRANSITION more tests return true; }