On 6/4/25 15:38, Tomasz Kaminski wrote:
On Wed, Jun 4, 2025 at 2:19 PM Tomasz Kaminski <tkami...@redhat.com> wrote:On Wed, Jun 4, 2025 at 2:05 PM Luc Grosheintz <luc.groshei...@gmail.com> wrote:On 6/4/25 13:19, Tomasz Kaminski wrote:Ah, sorry I got confused in the review suggestions, and latter when checking the code. What I meant is: Because the incoming strided_layout is required to be unique, that implies that for each of strides are greater or equal to theextents.As a consequence, other.required_span_size() is always greater thanequalto size of index_space, so we can have static assert like: static_assert(__mdspan::__representable_size<_OExtents, index_type>, "other.required_span_size() must be representable as index_type"); In here: if constexpr (cmp_greater( numeric_limits<typename_StridedMapping::index_type>::max(),numeric_limits<index_type>::max())) { static_assert(__mdspan::__representable_size<_OExtents, index_type>, "other.required_span_size() must be representableasindex_type")__glibcxx_assert(!cmp_less(numeric_limits<index_type>::max(),__other.required_span_size()));}I would lift the static assertion above the `if constexpr` because that way we have to trust the other mapping less.Sure, make sense.Maybe we should add a comment, explaning why !__representable_size && !is_unique implies __other.required_span_size() > index_type.
I just sent v6. Personally, I don't think that required_span_size >= extents size is a subtle statement. Maybe it's fine without?
On Wed, Jun 4, 2025 at 1:09 PM Luc Grosheintz <luc.groshei...@gmail.com wrote:On 6/3/25 15:24, Tomasz Kaminski wrote:On Fri, May 30, 2025 at 6:44 PM Luc Grosheintz <luc.groshei...@gmail.comwrote:Implements the tests for layout_stride and for the features of theothertwo layouts that depend on layout_stride. libstdc++-v3/ChangeLog: *testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc:Addtests for layout_stride. * testsuite/23_containers/mdspan/layouts/ctors.cc: Addtest forlayout_stride and the interaction with other layouts. * testsuite/23_containers/mdspan/layouts/mapping.cc: Ditto. * testsuite/23_containers/mdspan/layouts/stride.cc: Newtest.Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> ---LTGM. Only one comment regarding the tests that we could add..../mdspan/layouts/class_mandate_neg.cc | 3 + .../23_containers/mdspan/layouts/ctors.cc | 99 ++++ .../23_containers/mdspan/layouts/empty.cc | 1 + .../23_containers/mdspan/layouts/mapping.cc | 75 ++- .../23_containers/mdspan/layouts/stride.cc | 526++++++++++++++++++5 files changed, 703 insertions(+), 1 deletion(-) create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc diff --gita/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.ccb/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.ccindex 6469fa601e9..6862ed0c0ae 100644 ---a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc+++b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc@@ -31,9 +31,12 @@ template<size_t Count, typename Layout, typename OLayout> A<std::layout_left> a_left; // { dg-error"requiredfrom" } A<std::layout_right> a_right; // { dg-error"requiredfrom" } +A<std::layout_stride> a_stride; // { dg-error"requiredfrom" } B<1, std::layout_left, std::layout_left> bll; // { dg-error"requiredhere" } +B<2, std::layout_left, std::layout_stride> bls; // { dg-error"requiredhere" }With the message that we added to static assert to layout_stride constructor: >> "other.required_span_size() must be representable asindex_type"I believe you could add here: B<2, std::layout_stride, std::layout_left> And similarly for layout_right.I've tried (even before) and always failed miserably. Only good news is that the final // { dg-prune-output "must be representable as index_type" } isn't superfluous. I seem like the only string I can match against is the one associated with that line of code, in this case that's mdspan:773: error: static assertion failed: The size ofOtherExtentsmust be representable as index_type [ ... ] class_mandate_neg.cc:40: note: synthesized method 'constexpr B<4, std::layout_right, std::layout_stride>::B()' first required here I unsure why you're saying that we added the message: "other.required_span_size() must be representable as index_type" to a static_assert, we added it to a __glibcxx_assert. The tests here are designed to trigger different assertions. "A" triggers: template<typename _Extents> class layout_*::mapping { public: // ... static_assert(__mdspan::__representable_size<extents_type, index_type>, "The size of extents_type must be representable asindex_type");"B" triggers: template<typename _OExtents> constexpr explicit mapping(const _OExtents& __oexts, __mdspan::__internal_ctor)noexcept: _M_extents(__oexts) { static_assert(__mdspan::__representable_size<_OExtents,index_type>,"The size of OtherExtents must be representable asindex_type");We don't have tests that make __glibcxx_assert's fail. We couldprobablydo it with constexpr variables with "dynamic" extents.B<3, std::layout_right, std::layout_right> brr; // { dg-error"requiredhere" } +B<4, std::layout_right, std::layout_stride> brs; // { dg-error"requiredhere" } // { dg-prune-output "must be representable as index_type" } diff --gita/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.ccb/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc index b0e03161874..695e887ca87 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc @@ -323,6 +323,104 @@ namespace from_left_or_right } } +// ctor: mapping(layout_stride::mapping<OExtents>) +namespace from_stride +{ + template<typename Mapping> + constexpr auto + strides(Mapping m) + { + constexpr auto rank = Mapping::extents_type::rank(); + std::array<typename Mapping::index_type, rank> s; + + if constexpr (rank > 0) + for(size_t i = 0; i < rank; ++i) + s[i] = m.stride(i); + return s; + } + + template<typename Layout, typename Extents, typename OExtents> + constexpr void + verify_convertible(OExtents oexts) + { + using Mapping = typename Layout::mapping<Extents>; + using OMapping = std::layout_stride::mapping<OExtents>; + + constexpr auto other = OMapping(oexts, strides(Mapping(Extents(oexts)))); + if constexpr (std::is_same_v<Layout, std::layout_right>) + ::verify_nothrow_convertible<Mapping>(other); + else + ::verify_convertible<Mapping>(other); + } + + template<typename Layout, typename Extents, typename OExtents> + constexpr void + verify_constructible(OExtents oexts) + { + using Mapping = typename Layout::mapping<Extents>; + using OMapping = std::layout_stride::mapping<OExtents>; + + constexpr auto other = OMapping(oexts, strides(Mapping(Extents(oexts)))); + if constexpr (std::is_same_v<Layout, std::layout_right>) + ::verify_nothrow_constructible<Mapping>(other); + else + ::verify_constructible<Mapping>(other); + } + + template<typename Layout> + constexpr bool + test_ctor() + { + assert_not_constructible< + typename Layout::mapping<std::extents<int>>, + std::layout_stride::mapping<std::extents<int, 1>>>(); + + assert_not_constructible< + typename Layout::mapping<std::extents<int, 1>>, + std::layout_stride::mapping<std::extents<int>>>(); + + assert_not_constructible< + typename Layout::mapping<std::extents<int, 2>>, + std::layout_stride::mapping<std::extents<int, 1>>>(); + + verify_convertible<Layout,std::extents<int>>(std::extents<int>{});+ + verify_convertible<Layout, std::extents<unsigned int>>( + std::extents<int>{}); + + // Rank == 0 doesn't check IndexType for convertibility. + verify_convertible<Layout, std::extents<int>>( + std::extents<unsigned int>{}); + + verify_constructible<Layout, std::extents<int, 3>>( + std::extents<int, 3>{}); + + verify_constructible<Layout, std::extents<unsigned int, 3>>( + std::extents<int, 3>{}); + + verify_constructible<Layout, std::extents<int, 3>>( + std::extents<unsigned int, 3>{}); + + verify_constructible<Layout, std::extents<int, 3, 5>>( + std::extents<int, 3, 5>{}); + + verify_constructible<Layout, std::extents<unsigned int, 3,5>>(+ std::extents<int, 3, 5>{}); + + verify_constructible<Layout, std::extents<int, 3, 5>>( + std::extents<unsigned int, 3, 5>{}); + return true; + } + + template<typename Layout> + constexpr void + test_all() + { + test_ctor<Layout>(); + static_assert(test_ctor<Layout>()); + } +} + template<typename Layout> constexpr void test_all() @@ -330,6 +428,7 @@ template<typename Layout> default_ctor::test_all<Layout>(); from_extents::test_all<Layout>(); from_same_layout::test_all<Layout>(); + from_stride::test_all<Layout>(); } int diff --gita/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.ccb/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc index dc2a95ebbe6..d550c0a8e84 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc @@ -64,5 +64,6 @@ main() { static_assert(test_all<std::layout_left>()); static_assert(test_all<std::layout_right>()); + static_assert(test_all<std::layout_stride>()); return 0; } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc index 4dc0db66865..963c804a369 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc @@ -12,6 +12,7 @@ template<typename Layout, typename Extents> { using M = typename Layout::mapping<Extents>; static_assert(std::__mdspan::__is_extents<typenameM::extents_type>);+ static_assert(std::__mdspan::__mapping_alike<M>); static_assert(std::copyable<M>); static_assert(std::is_nothrow_move_constructible_v<M>); static_assert(std::is_nothrow_move_assignable_v<M>); @@ -30,6 +31,8 @@ template<typename Layout, typename Extents> static_assert(M::is_always_unique() && M::is_unique()); static_assert(M::is_always_strided() && M::is_strided()); + if constexpr (!std::is_same_v<Layout, std::layout_stride>) + static_assert(M::is_always_exhaustive() &&M::is_exhaustive());return true; } @@ -105,6 +108,39 @@ template<typename Layout> { return exts; } }; +template<> + struct MappingFactory<std::layout_stride> + { + template<typename Extents> + static constexpr std::layout_stride::mapping<Extents> + create(Extents exts) + { + if constexpr (Extents::rank() == 0) + { + auto strides = std::array<size_t, 0>{}; + return std::layout_stride::mapping(exts, strides); + } + else if constexpr (Extents::rank() == 1) + { + auto strides = std::array<size_t, 1>{2}; + return std::layout_stride::mapping(exts, strides); + } + else if constexpr (Extents::rank() == 2) + { + size_t m = exts.extent(1); + auto strides = std::array<size_t, 2>{3*m, 2}; + return std::layout_stride::mapping(exts, strides); + } + else if constexpr (Extents::rank() == 3) + { + size_t n = exts.extent(0); + size_t m = exts.extent(1); + auto strides = std::array<size_t, 3>{3*m, 2, 11*m*n}; + return std::layout_stride::mapping(exts, strides); + } + } + }; + template<typename Layout> constexpr void test_linear_index_3d() @@ -280,6 +316,16 @@ template<typename Layout> VERIFY(m.stride(0) == 1); } +template<> + constexpr void + test_stride_1d<std::layout_stride>() + { + std::array<int, 1> strides{13}; + std::layout_stride::mapping m(std::extents<int, 3>{}, strides); + VERIFY(m.stride(0) == strides[0]); + VERIFY(m.strides() == strides); + } + template<typename Layout> constexpr void test_stride_2d(); @@ -302,6 +348,17 @@ template<> VERIFY(m.stride(1) == 1); } +template<> + constexpr void + test_stride_2d<std::layout_stride>() + { + std::array<int, 2> strides{13, 2}; + std::layout_stride::mapping m(std::extents<int, 3, 5>{},strides);+ VERIFY(m.stride(0) == strides[0]); + VERIFY(m.stride(1) == strides[1]); + VERIFY(m.strides() == strides); + } + template<typename Layout> constexpr void test_stride_3d(); @@ -326,6 +383,19 @@ template<> VERIFY(m.stride(2) == 1); } +template<> + constexpr void + test_stride_3d<std::layout_stride>() + { + std::dextents<int, 3> exts(3, 5, 7); + std::array<int, 3> strides{11, 2, 41}; + std::layout_stride::mapping<std::dextents<int, 3>> m(exts,strides);+ VERIFY(m.stride(0) == strides[0]); + VERIFY(m.stride(1) == strides[1]); + VERIFY(m.stride(2) == strides[2]); + VERIFY(m.strides() == strides); + } + template<typename Layout> constexpr bool test_stride_all() @@ -347,7 +417,7 @@ template<typename Layout> test_has_stride_0d() { using Mapping = typename Layout::mapping<std::extents<int>>; - constexpr bool expected = false; + constexpr bool expected = std::is_same_v<Layout,std::layout_stride>;static_assert(has_stride<Mapping> == expected); } @@ -488,8 +558,11 @@ main() { test_all<std::layout_left>(); test_all<std::layout_right>(); + test_all<std::layout_stride>(); test_has_op_eq<std::layout_right, std::layout_left, false>(); + test_has_op_eq<std::layout_right, std::layout_stride, true>(); + test_has_op_eq<std::layout_left, std::layout_stride, true>(); test_has_op_eq_peculiar(); return 0; } diff --gita/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.ccb/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc new file mode 100644 index 00000000000..c8af5c61254 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc @@ -0,0 +1,526 @@ +// { dg-do run { target c++23 } } +#include <mdspan> + +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; + +template<typename MappingStride> + constexpr void + test_ctor_default_stride() + { + using Extents = typename MappingStride::extents_type; + MappingStride actual; + typename std::layout_right::mapping<Extents> expected; + + constexpr auto rank = MappingStride::extents_type::rank(); + if constexpr (rank > 0) + for(size_t i = 0; i < rank; ++i) + VERIFY(actual.stride(i) == expected.stride(i)); + } + +constexpr bool +test_ctor_default_stride_all() +{ + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, 3>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, 3, 5, 7>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::dextents<int, 3>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, 0, 5, 7>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, 3, dyn, dyn>>>(); + + test_ctor_default_stride< + std::layout_stride::mapping<std::extents<int, dyn, dyn, 3>>>(); + return true; +} + +struct IntLikeA +{ + operator int() + { return 0; } +}; + +struct IntLikeB +{ + operator int() noexcept + { return 0; } +}; + +struct NotIntLike +{ }; + +template<typename E, typename E_arg, typename T, size_t N, boolExpected>+constexpr void +test_stride_constructible() +{ + static_assert(std::is_nothrow_constructible_v< + std::layout_stride::mapping<E>, E_arg, std::span<T, N>> == Expected); + static_assert(std::is_nothrow_constructible_v< + std::layout_stride::mapping<E>, E_arg, std::array<T, N>> == Expected); +static_assert(!std::is_constructible_v<std::layout_stride::mapping<E>,+ E_arg>); +} + +constexpr void +test_stride_constructible_all() +{ + using E0 = std::extents<int>; + using E1 = std::extents<int, 2>; + using E2 = std::extents<int, dyn>; + + test_stride_constructible<E0, E0, int, 0, true>(); + test_stride_constructible<E0, E0, IntLikeA, 0, false>(); + test_stride_constructible<E0, E0, IntLikeB, 0, true>(); + test_stride_constructible<E0, E0, NotIntLike, 0, false>(); + test_stride_constructible<E1, E1, int, 1, true>(); + test_stride_constructible<E2, E1, int, 1, true>(); + test_stride_constructible<E1, E1, int, 2, false>(); + test_stride_constructible<E1, E0, int, 1, false>(); +} + +template<typename Extents, typename Shape> + constexpr void + test_ctor_shape_strides(Extents exts, Shape strides) + { + using M = std::layout_stride::mapping<Extents>; + M m(exts, strides); + + if constexpr (Extents::rank() > 0) + for(size_t i = 0; i < exts.rank(); ++i) + { + VERIFY(m.stride(i) == strides[i]); + VERIFY(m.extents().extent(i) == exts.extent(i)); + } + } + +constexpr bool +test_ctor_shape_stride_all() +{ + test_ctor_shape_strides(std::extents<int>{}, std::array<int,0>{});+ test_ctor_shape_strides(std::extents<int, 2>{}, std::array<int,1>{3});+ test_ctor_shape_strides(std::extents<int, 2, 4, 6>{}, + std::array<int, 3>{20, 5, 45}); + return true; +} + +template<typename Extents, std::array<bool, 2> Strided, + std::array<bool, 2> Unique, std::array<bool, 2> Exhautive, + typename Extents::index_type Offset = 0> + struct MappingLike + { + using extents_type = Extents; + using index_type = typename Extents::index_type; + + constexpr + MappingLike(extents_type extents, + std::array<index_type, Extents::rank()> strides) + : _extents(extents), _strides(strides) + { } + + static constexpr bool + is_always_strided() requires (Strided[0]) + { return Strided[1]; } + + static constexpr bool + is_always_unique() requires (Unique[0]) + { return Unique[1]; } + + static constexpr bool + is_always_exhaustive() requires (Exhautive[0]) + { return Exhautive[1]; } + + constexpr Extents + extents() const { return _extents; } + + constexpr index_type + stride(size_t i) const { return _strides[i]; } + + template<typename... Indices> + constexpr index_type + operator()(Indices... indices) const + { + if (empty()) + VERIFY(false); + + std::array<index_type, Extents::rank()> ind_arr{indices...}; + index_type ret = Offset; + for(size_t i = 0; i < Extents::rank(); ++i) + ret += ind_arr[i]*_strides[i]; + return ret; + } + + private: + constexpr bool + empty() const + { + for (size_t i = 0; i < extents_type::rank(); ++i) + if (_extents.extent(i) == 0) + return true; + return false; + } + + Extents _extents; + std::array<index_type, Extents::rank()> _strides; + }; + + +template<size_t Rank> +struct ExtentLike +{ + using index_type = int; + + static constexpr size_t + rank() { return Rank; } +}; + + +template<typename E1> +constexpr void +test_mapping_like_constructible() +{ + using M = std::layout_stride::mapping<E1>; + using E2 = std::dextents<typename E1::index_type, E1::rank()>; + using E3 = std::dextents<typename E1::index_type, E1::rank() + 1>; + using E4 = ExtentLike<E1::rank()>; + + constexpr auto TT = std::array{true, true}; + constexpr auto FT = std::array{false, true}; + constexpr auto TF = std::array{true, false}; + + static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT,TT>>);+ static_assert(std::is_constructible_v<M, MappingLike<E2, TT, TT,TT>>);+ static_assert(!std::is_constructible_v<M, MappingLike<E3, TT, TT,TT>>);+ static_assert(!std::is_constructible_v<M, MappingLike<E1, FT, TT,TT>>);+ static_assert(!std::is_constructible_v<M, MappingLike<E1, TF, TT,TT>>);+ static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, FT,TT>>);+ static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TF,TT>>);+ static_assert(!std::is_constructible_v<M, MappingLike<E1, TT, TT,FT>>);+ static_assert(std::is_constructible_v<M, MappingLike<E1, TT, TT,TF>>);+ static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT,TF>>);+ static_assert(!std::is_constructible_v<M, MappingLike<E4, TT, TT,TT>>);+} + +constexpr void +test_mapping_like_constructible_all() +{ + test_mapping_like_constructible<std::extents<int>>(); + test_mapping_like_constructible<std::extents<int, 2>>(); + test_mapping_like_constructible<std::extents<int, 2, 3>>(); +} + +template<typename E1, typename E2> +constexpr void +test_mapping_like_convertible() +{ + using M1 = std::layout_stride::mapping<E1>; + using M2 = std::layout_stride::mapping<E2>; + constexpr auto TT = std::array{true, true}; + + static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>,M1>);+ static_assert(!std::is_convertible_v<MappingLike<E2, TT, TT, TT>,M1>);+ static_assert(!std::is_convertible_v<MappingLike<E1, TT, TT, TT>,M2>);+ +static_assert(std::is_convertible_v<std::layout_stride::mapping<E2>,M1>); + static_assert(std::is_convertible_v<std::layout_left::mapping<E2>,M1>);+static_assert(std::is_convertible_v<std::layout_right::mapping<E2>,M1>); + +static_assert(!std::is_convertible_v<std::layout_stride::mapping<E1>,M2>); +static_assert(!std::is_convertible_v<std::layout_left::mapping<E1>,M2>); +static_assert(!std::is_convertible_v<std::layout_right::mapping<E1>,M2>); +} + +constexpr void +test_mapping_like_convertible_all() +{ + test_mapping_like_convertible<std::extents<unsigned int>, + std::extents<int>>(); + test_mapping_like_convertible<std::extents<unsigned int, 2>, + std::extents<int, 2>>(); + test_mapping_like_convertible<std::extents<int, dyn, 3>, + std::extents<int, 2, 3>>(); +} + +template<typename Extents> +constexpr void +test_ctor_stride_like(Extents exts, std::array<int, Extents::rank()> strides) +{ + auto other_right = std::layout_right::mapping(exts); + auto other_left = std::layout_left::mapping(exts); + auto other_stride = std::layout_stride::mapping(exts, strides); + + VERIFY(std::layout_stride::mapping<Extents>(other_right) == other_right); + VERIFY(std::layout_stride::mapping<Extents>(other_left) ==other_left);+ VERIFY(std::layout_stride::mapping<Extents>(other_stride) == other_stride); +} + +constexpr void +test_ctor_stride_like_all() +{ + using E1 = std::extents<int>; + auto s1 = std::array<int, 0>{}; + test_ctor_stride_like(E1{}, s1); + + using E2 = std::extents<int, 3>; + auto s2 = std::array<int, 1>{2}; + test_ctor_stride_like(E2{}, s2); + + using E3 = std::extents<int, 3, 5, 7>; + auto s3 = std::array<int, 3>{5, 1, 15}; + test_ctor_stride_like(E3{}, s3); +} + +constexpr bool +test_ctor_strides_all() +{ + test_ctor_default_stride_all(); + test_ctor_shape_stride_all(); + test_ctor_stride_like_all(); + return true; +} + +// Check is_exhaustive. +template<typename Extents, typename Strides> + constexpr void + test_is_exhaustive(Extents extents, Strides strides, boolexpected)+ { + std::layout_stride::mapping<Extents> m(extents, strides); + VERIFY(m.is_exhaustive() == expected); + + bool always_exhaustive = extents.rank() == 0 || m.required_span_size() == 0; + VERIFY(m.is_always_exhaustive() == always_exhaustive); + } + +constexpr void +test_is_exhaustive_zero_1d() +{ + std::extents<int, 0> extents; + test_is_exhaustive(extents, std::array{1}, true); + test_is_exhaustive(extents, std::array{2}, true); +} + +constexpr void +test_is_exhaustive_zero_3d() +{ + std::extents<int, 3, 0, 7> extents; + + test_is_exhaustive(extents, std::array{1, 1, 1}, true); + test_is_exhaustive(extents, std::array{1, 2*21, 2*3}, true); + test_is_exhaustive(extents, std::array{7, 2*21, 1}, true); + test_is_exhaustive(extents, std::array{1, 21, 3}, true); + test_is_exhaustive(extents, std::array{7, 21, 1}, true); +} + +constexpr void +test_is_exhaustive_0d() +{ + std::extents<int> extents; + test_is_exhaustive(extents, std::array<int, 0>{}, true); +} + +constexpr void +test_is_exhaustive_1d() +{ + std::extents<int, 3> extents; + test_is_exhaustive(extents, std::array{1}, true); + test_is_exhaustive(extents, std::array{3}, false); +} + + +constexpr void +test_is_exhaustive_3d() +{ + std::extents<int, 3, dyn, 7> extents(5); + + test_is_exhaustive(extents, std::array{1, 3, 3*5}, true); + test_is_exhaustive(extents, std::array{5*7, 1, 5}, true); + test_is_exhaustive(extents, std::array{7, 3*7, 1}, true); + + test_is_exhaustive(extents, std::array{1, 3, 2*3*5}, false); + test_is_exhaustive(extents, std::array{2*5*7, 1, 2*5}, false); + test_is_exhaustive(extents, std::array{2*7, 2*3*7, 2}, false); +} + +constexpr void +test_is_exhaustive_ones() +{ + std::extents<int, 1, 1, 3, 1> extents; + test_is_exhaustive(extents, std::array{1, 1, 1, 1}, true); + test_is_exhaustive(extents, std::array{1, 1, 1, 3}, true); + test_is_exhaustive(extents, std::array{3, 3, 1, 3}, true); + test_is_exhaustive(extents, std::array{3, 1, 1, 3}, true); +} + +constexpr bool +test_is_exhaustive_all() +{ + test_is_exhaustive_zero_1d(); + test_is_exhaustive_zero_3d(); + test_is_exhaustive_ones(); + test_is_exhaustive_0d(); + test_is_exhaustive_1d(); + test_is_exhaustive_3d(); + return true; +} + +template<typename Extents, int Offset> + using OffsetMapping = MappingLike<Extents, {true, true}, {true,true},+ {true, false}, Offset>; + +template<typename Extents> + constexpr void + test_eq(Extents exts, + std::array<typename Extents::index_type, Extents::rank()> left_strides, + std::array<typename Extents::index_type, Extents::rank()> right_strides, + std::array<typename Extents::index_type, Extents::rank()> padded_strides) + { + using DExtents = std::dextents<int, Extents::rank()>; + + std::layout_left::mapping<Extents> ml; + std::layout_right::mapping<DExtents> mr(exts); + + std::layout_stride::mapping<Extents> msd; + std::layout_stride::mapping<Extents> msl(exts, left_strides); + std::layout_stride::mapping<Extents> msr(exts, right_strides); + std::layout_stride::mapping<Extents> msp(exts, padded_strides); + + OffsetMapping<Extents, 0> mor{exts, right_strides}; + OffsetMapping<Extents, 0> mol{exts, left_strides}; + OffsetMapping<Extents, 0> mop{exts, padded_strides}; + OffsetMapping<Extents, 1> moo{exts, right_strides}; + + VERIFY(msd == mr); + VERIFY(msd == mor); + VERIFY(msd != msp); + VERIFY(msd != mop); + + VERIFY(msl == ml); + VERIFY(msl == mol); + VERIFY(msd != msp); + VERIFY(msl != mop); + + VERIFY(msp == mop); + VERIFY(msp != ml); + VERIFY(msp != mr); + + VERIFY(msd != moo); + } + +constexpr void +test_eq_0d() +{ + using Extents = std::extents<int>; + Extents exts; + std::layout_left::mapping<Extents> ml; + std::layout_right::mapping<Extents> mr; + std::layout_stride::mapping<Extents> ms; + OffsetMapping<Extents, 0> mor{exts, {}}; + OffsetMapping<Extents, 1> moo{exts, {}}; + + VERIFY(ms == ml); + VERIFY(ms == mr); + VERIFY(ms == mor); + VERIFY(ms != moo); +} + +constexpr void +test_eq_1d() +{ + using Extents = std::extents<int, 2>; + auto exhaustive_strides = std::array{1}; + auto padded_strides = std::array{2}; + + test_eq(Extents{}, exhaustive_strides, exhaustive_strides, padded_strides); +} + +constexpr void +test_eq_2d() +{ + using Extents = std::extents<int, 1, 2>; + auto left_strides = std::array{1, 1}; + auto right_strides = std::array{2, 1}; + auto padded_strides = std::array{2, 8}; + + test_eq(Extents{}, left_strides, right_strides, padded_strides); +} + +constexpr void +test_eq_zero() +{ + using Extents = std::extents<int, 0, 2>; + using Mapping = std::layout_stride::mapping<Extents>; + + Extents exts; + std::array<int, 2> sl{1, 5}; + std::array<int, 2> sr{5, 1}; + + Mapping m1(exts, sl); + Mapping m2(exts, sl); + Mapping m3(exts, sr); + OffsetMapping<Extents, 0> m4(exts, sl); + + VERIFY(m1 == m2); + VERIFY(m1 != m3); + VERIFY(m1 == m4); + +} + +constexpr bool +test_eq_all() +{ + test_eq_0d(); + test_eq_1d(); + test_eq_2d(); + test_eq_zero(); + return true; +} + +template<typename M1, typename M2> + concept has_op_eq = requires (M1 m1, M2 m2) + { + { m1 == m2 } -> std::same_as<bool>; + { m2 == m1 } -> std::same_as<bool>; + { m1 != m2 } -> std::same_as<bool>; + { m2 != m1 } -> std::same_as<bool>; + }; + +constexpr void +test_has_op_eq() +{ + using E1 = std::extents<int>; + using E2 = std::extents<int, 2>; + using E3 = std::extents<int, 1, 2>; + constexpr auto FT = std::array{false, true}; + + static_assert(!has_op_eq< + std::layout_stride::mapping<E1>, MappingLike<E1, FT, FT,FT>>);+ + static_assert(!has_op_eq< + std::layout_stride::mapping<E2>, MappingLike<E2, FT, FT,FT>>);+ + static_assert(!has_op_eq< + std::layout_stride::mapping<E3>, MappingLike<E3, FT, FT,FT>>);+} + +int +main() +{ + test_ctor_strides_all(); + static_assert(test_ctor_strides_all()); + test_mapping_like_convertible_all(); + test_mapping_like_constructible_all(); + test_stride_constructible_all(); + test_is_exhaustive_all(); + static_assert(test_is_exhaustive_all()); + test_eq_all(); + static_assert(test_eq_all()); + test_has_op_eq(); + return 0; +} -- 2.49.0