[PATCH v5 7/8] libstdc++: Add tests for layout_stride.

Luc Grosheintz luc.grosheintz@gmail.com
Wed Jun 4 12:05:28 GMT 2025



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 the extents.
> As a consequence, other.required_span_size() is always greater than equal
> to 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 representable as
> index_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.

> 
> 
> On Wed, Jun 4, 2025 at 1:09 PM Luc Grosheintz <luc.grosheintz@gmail.com>
> wrote:
> 
>>
>>
>> On 6/3/25 15:24, Tomasz Kaminski wrote:
>>> On Fri, May 30, 2025 at 6:44 PM Luc Grosheintz <luc.grosheintz@gmail.com
>>>
>>> wrote:
>>>
>>>> Implements the tests for layout_stride and for the features of the other
>>>> two layouts that depend on layout_stride.
>>>>
>>>> libstdc++-v3/ChangeLog:
>>>>
>>>>           * testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc:
>> Add
>>>>           tests for layout_stride.
>>>>           * testsuite/23_containers/mdspan/layouts/ctors.cc: Add test for
>>>>           layout_stride and the interaction with other layouts.
>>>>           * testsuite/23_containers/mdspan/layouts/mapping.cc: Ditto.
>>>>           * testsuite/23_containers/mdspan/layouts/stride.cc: New test.
>>>>
>>>> Signed-off-by: Luc Grosheintz <luc.grosheintz@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 --git
>>>>
>> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
>>>>
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
>>>> index 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
>> "required
>>>> from" }
>>>>    A<std::layout_right> a_right;                    // { dg-error
>> "required
>>>> from" }
>>>> +A<std::layout_stride> a_stride;                  // { dg-error
>> "required
>>>> from" }
>>>>
>>>>    B<1, std::layout_left, std::layout_left> bll;    // { dg-error
>> "required
>>>> here" }
>>>> +B<2, std::layout_left, std::layout_stride> bls;  // { dg-error
>> "required
>>>> here" }
>>>>
>>> With the message that we added to static assert to layout_stride
>>> constructor:
>>>     >>  "other.required_span_size() must be representable as index_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 of OtherExtents
>>       must 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 as index_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 as index_type");
>>
>> We don't have tests that make __glibcxx_assert's fail. We could probably
>> do it with constexpr variables with "dynamic" extents.
>>
>>>
>>>>
>>>>    B<3, std::layout_right, std::layout_right> brr;  // { dg-error
>> "required
>>>> here" }
>>>> +B<4, std::layout_right, std::layout_stride> brs; // { dg-error
>> "required
>>>> here" }
>>>>
>>>>    // { dg-prune-output "must be representable as index_type" }
>>>> diff --git
>> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
>>>> b/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 --git
>> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
>>>> b/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<typename
>> M::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 --git
>> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/stride.cc
>>>> b/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, bool
>> Expected>
>>>> +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, bool expected)
>>>> +  {
>>>> +    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
>>>>
>>>>
>>>
>>
>>
> 



More information about the Libstdc++ mailing list