diff --git a/tests/std/include/test_mdspan_support.hpp b/tests/std/include/test_mdspan_support.hpp index c6c1f034fa..e4775be525 100644 --- a/tests/std/include/test_mdspan_support.hpp +++ b/tests/std/include/test_mdspan_support.hpp @@ -304,7 +304,8 @@ MappingProperties get_mapping_properties(const Mapping& mapping) { 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))...}; + return std::array{ + static_cast(std::get(i) + (Indices == r ? 1 : 0))...}; }(rank_indices); if (i_plus_dr[r] < get_extent(r)) { diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index 4c39707b54..ab20ad5c87 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -21,6 +22,82 @@ struct CmpEqual { } }; +struct NotLayoutMappingAlikeAtAll { + template + class mapping : public layout_right::mapping { + public: + using layout_type = NotLayoutMappingAlikeAtAll; + + private: + using layout_right::mapping::is_always_exhaustive; + }; +}; + +static_assert(!_Layout_mapping_alike>>); + +enum class AlwaysUnique { no, yes }; +enum class AlwaysStrided { no, yes }; + +template +struct LyingLayout { + template + class mapping : public layout_left::mapping { + public: + using layout_type = LyingLayout; + + constexpr bool is_unique() const { + return is_unique(); + } + + constexpr bool is_exhaustive() const { + return is_exhaustive(); + } + + constexpr bool is_strided() const { + return is_strided(); + } + + static constexpr bool is_always_unique() { + return to_underlying( + Unique); // might be a lie, allowed by the standard (N4950 [mdspan.layout.reqmts]/23 Note 5) + } + + static constexpr bool is_always_exhaustive() { + return layout_right::mapping::is_always_exhaustive(); + } + + static constexpr bool is_always_strided() { + return to_underlying( + Strided); // might be a lie, allowed by the standard (N4950 [mdspan.layout.reqmts]/27 Note 7) + } + }; +}; + +static_assert( + check_layout_mapping_policy_requirements, extents>()); +static_assert( + check_layout_mapping_policy_requirements, dextents>()); + +struct HollowLayout { + template + requires (Extents::rank() == 0) + class mapping : public layout_right::mapping { + public: + using index_type = Extents::index_type; + using layout_type = HollowLayout; + + constexpr index_type operator()() const noexcept { + return 1; // NB: used by 'check_comparisons' (OFFSET(*this) != 0) + } + + constexpr index_type required_span_size() const noexcept { + return 2; + } + }; +}; + +static_assert(check_layout_mapping_policy_requirements>()); + template constexpr void do_check_members(const extents& ext, const array& strs, index_sequence) { @@ -263,16 +340,24 @@ constexpr void check_construction_from_other_mappings() { static_assert(is_nothrow_constructible_v>>); static_assert(is_nothrow_constructible_v>>); static_assert(is_nothrow_constructible_v>>); + static_assert(is_nothrow_constructible_v::mapping>>); } { // 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>>); static_assert(!is_constructible_v>>); - // TRANSITION, Check other kinds of invalid construction (requires new helper types) + static_assert(!is_constructible_v::mapping>>); + static_assert(!is_constructible_v::mapping>>); + static_assert(!is_constructible_v::mapping>>); } { // Check construction from layout_left::mapping @@ -439,17 +524,29 @@ constexpr void check_comparisons() { using RightMapping = layout_right::mapping; using LeftMapping = layout_left::mapping; - { // Check equality_comparable_with concept + { // Check equality_comparable_with concept (correct comparisons) 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); + } + + { // Check equality_comparable_with concept (incorrect comparisons) + 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: N4950 [mdspan.layout.stride.obs]/6.1, 6.3 + static_assert(!equality_comparable_with::mapping>>); + static_assert(!equality_comparable_with::mapping>>); + static_assert(!equality_comparable_with::mapping>>); + static_assert(!equality_comparable_with::mapping>>); } { // Check correctness: layout_stride::mapping with layout_stride::mapping @@ -515,7 +612,47 @@ constexpr void check_comparisons() { static_assert(noexcept(m1 != m3)); } - // TRANSITION, Check comparisons with custom layout mapping + { // Check correctness: layout_stride::mapping with LyingLayout::mapping + using CustomMapping = LyingLayout::mapping; + CustomMapping m1; + StaticStrideMapping m2{E{}, array{1, 2}}; + 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 + assert(m2 != m3); // ditto + + DynamicStrideMapping m4{dextents{1, 3}, 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(CustomMapping) is always equal to 0 + + static_assert(noexcept(m1 == m2)); + static_assert(noexcept(m1 != m3)); + } + + { // Check correctness: layout_stride::mapping with HollowLayout::mapping + HollowLayout::mapping> m1; + if constexpr (!is_permissive) { + if (!is_constant_evaluated()) { // too heavy for compile time + const auto props = get_mapping_properties(m1); + assert(props.req_span_size == m1.required_span_size()); + assert(props.uniqueness); + assert(props.exhaustiveness); + assert(props.strideness); + } + } + + layout_stride::mapping> m2; + same_as decltype(auto) cond = m1 == m2; + assert(!cond); // extents are equal, OFFSET(rhs) != 0, strides are equal + + static_assert(noexcept(m1 == m2)); + static_assert(noexcept(m1 != m2)); + } } constexpr void check_ctad() {