On Tue, May 20, 2025 at 10:24 AM Luc Grosheintz <luc.groshei...@gmail.com>
wrote:

>
>
> On 5/19/25 2:56 PM, Tomasz Kaminski wrote:
> > On Sun, May 18, 2025 at 10:14 PM Luc Grosheintz <
> luc.groshei...@gmail.com>
> > wrote:
> >
> >> Implements a suite of tests for the currently implemented parts of
> >> layout_left. The individual tests are templated over the layout type, to
> >> allow reuse as more layouts are added.
> >>
> >> libstdc++-v3/ChangeLog:
> >>
> >>          * testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc:
> New
> >> test.
> >>          * testsuite/23_containers/mdspan/layouts/ctors.cc: New test.
> >>          * testsuite/23_containers/mdspan/layouts/mapping.cc: New test.
> >>
> >> Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
> >> ---
> >>   .../mdspan/layouts/class_mandate_neg.cc       |  22 +
> >>   .../23_containers/mdspan/layouts/ctors.cc     | 258 ++++++++++
> >>   .../23_containers/mdspan/layouts/mapping.cc   | 445 ++++++++++++++++++
> >>   3 files changed, 725 insertions(+)
> >>   create mode 100644
> >> libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
> >>   create mode 100644
> >> libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
> >>   create mode 100644
> >> libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.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
> >> new file mode 100644
> >> index 00000000000..f122541b3e8
> >> --- /dev/null
> >> +++
> >>
> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
> >> @@ -0,0 +1,22 @@
> >> +// { dg-do compile { target c++23 } }
> >> +#include<mdspan>
> >> +
> >> +#include <cstdint>
> >> +
> >> +constexpr size_t dyn = std::dynamic_extent;
> >> +static constexpr size_t n = (size_t(1) << 7) - 1;
> >>
> > I would use numeric_limits_max<unit8_t> here.
> >
> >> +
> >> +template<typename Layout>
> >> +  struct A
> >> +  {
> >> +    typename Layout::mapping<std::extents<uint8_t>> m0;
> >> +    typename Layout::mapping<std::extents<uint8_t, n, 2, dyn>> m1;
> >> +    typename Layout::mapping<std::extents<uint8_t, n, 2, 0>> m2;
> >> +
> >> +    using extents_type = std::extents<uint8_t, n, 4>;
> >> +    typename Layout::mapping<extents_type> m3; // { dg-error "required
> >> from" }
> >> +  };
> >> +
> >> +A<std::layout_left> a_left;                     // { dg-error "required
> >> from" }
> >> +
> >> +// { 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
> >> new file mode 100644
> >> index 00000000000..4592a05dec8
> >> --- /dev/null
> >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
> >> @@ -0,0 +1,258 @@
> >> +// { dg-do run { target c++23 } }
> >> +#include <mdspan>
> >> +
> >> +#include <testsuite_hooks.h>
> >> +
> >> +constexpr size_t dyn = std::dynamic_extent;
> >> +
> >> +template<typename Mapping, typename OExtents>
> >> +  constexpr void
> >> +  verify_from_exts(OExtents exts)
> >> +  {
> >> +    auto m = Mapping(exts);
> >> +    VERIFY(m.extents() == exts);
> >> +  }
> >> +
> >> +
> >> +template<typename SMapping, typename OMapping>
> >> +  constexpr void
> >> +  verify_from_mapping(OMapping other)
> >> +  {
> >> +    auto m = SMapping(other);
> >> +    VERIFY(m.extents() == other.extents());
> >> +  }
> >> +
> >> +template<typename Mapping, typename OExtents>
> >> +  requires (std::__mdspan::__is_extents<OExtents>)
> >> +  constexpr void
> >> +  verify(OExtents oexts)
> >> +  {
> >
> > In general, wen possible we prefer to not use internal details in tests.
> > I would use if constexpr with requires { typename Other::layout_type; },
> ie.
> > template<typename Mapping, typename Source>
> > cosntexpr void
> > verify(Source const& src)
> > {
> >    if constexpr (requires { typename Other::layout_type; })
> >       verify_from_mapping(src)
> >    else
> >       verify_from_extents(src);
> > }
> >
> > +    auto m = Mapping(oexts);
> >> +    VERIFY(m.extents() == oexts);
> >> +  }
> >> +
> >> +template<typename Mapping, typename OMapping>
>
>> +  requires (std::__mdspan::__standardized_mapping<OMapping>)
> >> +  constexpr void
> >> +  verify(OMapping other)
> >> +  {
> >> +    constexpr auto rank = Mapping::extents_type::rank();
> >> +    auto m = Mapping(other);
> >> +    VERIFY(m.extents() == other.extents());
> >> +    if constexpr (rank > 0)
> >> +      for(size_t i = 0; i < rank; ++i)
> >> +       VERIFY(std::cmp_equal(m.stride(i), other.stride(i)));
> >>
> > Why is this not checked in verify_from_mapping?
> >
> >> +  }
> >> +
> >> +
> >> +template<typename To, typename From>
> >> +  constexpr void
> >> +  verify_nothrow_convertible(From from)
> >> +  {
> >> +    static_assert(std::is_nothrow_constructible_v<To, From>);
> >>
> > I would call  `verify_convertible` here, instead of these two lines.
> >
> >> +    static_assert(std::is_convertible_v<From, To>);
> >> +    verify<To>(from);
> >> +  }
> >> +
> >> +template<typename To, typename From>
> >> +  constexpr void
> >> +  verify_convertible(From from)
> >> +  {
> >> +    static_assert(std::is_convertible_v<From, To>);
> >> +    verify<To>(from);
> >> +  }
> >> +
> >> +template<typename To, typename From>
> >> +  constexpr void
> >> +  verify_constructible(From from)
> >> +  {
> >> +    static_assert(!std::is_convertible_v<From, To>);
> >> +    static_assert(!std::is_nothrow_constructible_v<To, From>);
> >>
> > Implementations are allowed to add noexcept on the functions, so I would
> > not perform this checks.
> > See: https://eel.is/c++draft/res.on.exception.handling#5
> >
> >> +    static_assert(std::is_constructible_v<To, From>);
> >> +    verify<To>(from);
> >> +  }
> >> +
> >> +template<typename To, typename From>
> >> +  constexpr void
> >> +  verify_nothrow_constructible(From from)
> >> +  {
> >> +    static_assert(!std::is_convertible_v<From, To>);
> >> +    static_assert(std::is_nothrow_constructible_v<To, From>);
> >>
> > With the change above, I would call verify  verify_constructible.
> >
> >> +    verify<To>(from);
> >> +  }
> >> +
> >> +template<typename Mapping, typename OExtents>
> >> +  constexpr void
> >> +  assert_not_constructible()
> >> +  {
> >> +    static_assert(!std::is_constructible_v<Mapping, OExtents>);
> >> +  }
> >> +
> >> +// ctor: mapping(const extents&)
> >> +namespace from_extents
> >> +{
> >> +  template<typename Layout, typename Extents, typename OExtents>
> >> +    constexpr void
> >> +    verify_nothrow_convertible(OExtents oexts)
> >> +    {
> >> +      using Mapping = typename Layout::mapping<Extents>;
> >> +      ::verify_nothrow_convertible<Mapping>(oexts);
> >> +    }
> >> +
> >> +  template<typename Layout, typename Extents, typename OExtents>
> >> +    constexpr void
> >> +    verify_nothrow_constructible(OExtents oexts)
> >> +    {
> >> +      using Mapping = typename Layout::mapping<Extents>;
> >> +      ::verify_nothrow_constructible<Mapping>(oexts);
> >> +    }
> >> +
> >> +  template<typename Layout, typename Extents, typename OExtents>
> >> +    constexpr void
> >> +    assert_not_constructible()
> >> +    {
> >> +      using Mapping = typename Layout::mapping<Extents>;
> >> +      ::assert_not_constructible<Mapping, OExtents>();
> >> +    }
> >> +
> >> +  template<typename Layout>
> >> +    constexpr bool
> >> +    test_ctor()
> >> +    {
> >> +      verify_nothrow_convertible<Layout, std::extents<int>>(
> >> +       std::extents<int>{});
> >> +
> >> +      verify_nothrow_convertible<Layout, std::extents<int, 2>>(
> >> +       std::extents<int, 2>{});
> >> +
> >> +      verify_nothrow_convertible<Layout, std::extents<int, dyn, 3>>(
> >> +       std::extents<int, dyn, 3>{2});
> >> +
> >> +      verify_nothrow_constructible<Layout, std::extents<unsigned int>>(
> >> +       std::extents<int>{});
> >> +
> >> +      verify_nothrow_constructible<Layout, std::extents<int, dyn>>(
> >> +       std::extents<int, 2>{});
> >> +
> >> +      verify_nothrow_constructible<Layout, std::extents<int, dyn, 3>>(
> >> +       std::extents<int, 2, 3>{});
> >> +
> >> +      assert_not_constructible<Layout, std::extents<int>,
> >> +                              std::extents<unsigned int>>();
> >> +      assert_not_constructible<Layout, std::extents<int, 2>,
> >> +                              std::extents<int, dyn>>();
> >> +      assert_not_constructible<Layout, std::extents<int, 2, 3>,
> >> +                              std::extents<int, dyn, 3>>();
> >> +      return true;
> >> +    }
> >> +
> >> +  template<typename Layout, typename Extents>
> >> +    constexpr void
> >> +    assert_deducible(Extents exts)
> >> +    {
> >> +      typename Layout::mapping m(exts);
> >> +      static_assert(std::same_as<decltype(m),
> >> +                   typename Layout::mapping<Extents>>);
> >> +    }
> >> +
> >> +  template<typename Layout>
> >> +    constexpr void
> >> +    test_deducible()
> >> +    {
> >> +      assert_deducible<Layout>(std::extents<int>());
> >> +      assert_deducible<Layout>(std::extents<int, 1>());
> >> +      assert_deducible<Layout>(std::extents<int, 1, 2, dyn>(3));
> >> +    }
> >> +
> >> +  template<typename Layout>
> >> +    constexpr void
> >> +    test_all()
> >> +    {
> >> +      test_ctor<Layout>();
> >> +      static_assert(test_ctor<Layout>());
> >> +      test_deducible<Layout>();
> >> +    }
> >> +}
> >> +
> >> +// ctor: mapping(mapping<OExtents>)
> >> +namespace from_same_layout
> >> +{
> >> +  template<typename Layout, typename Extents, typename OExtents>
> >> +    constexpr void
> >> +    verify_nothrow_convertible(OExtents exts)
> >> +    {
> >> +      using Mapping = typename Layout::mapping<Extents>;
> >> +      using OMapping = typename Layout::mapping<OExtents>;
> >> +
> >> +      ::verify_nothrow_convertible<Mapping>(OMapping(exts));
> >> +    }
> >> +
> >> +  template<typename Layout, typename Extents, typename OExtents>
> >> +    constexpr void
> >> +    verify_nothrow_constructible(OExtents exts)
> >> +    {
> >> +      using Mapping = typename Layout::mapping<Extents>;
> >> +      using OMapping = typename Layout::mapping<OExtents>;
> >> +
> >> +      ::verify_nothrow_constructible<Mapping>(OMapping(exts));
> >> +    }
> >> +
> >> +  template<typename Layout>
> >> +    constexpr bool
> >> +    test_ctor()
> >> +    {
> >> +      verify_nothrow_convertible<Layout, std::extents<unsigned int>>(
> >> +       std::extents<int>{});
> >> +
> >> +      verify_nothrow_constructible<Layout, std::extents<int>>(
> >> +       std::extents<unsigned int>{});
> >> +
> >> +      assert_not_constructible<
> >> +       typename Layout::mapping<std::extents<int>>,
> >> +       typename Layout::mapping<std::extents<int, 1>>>();
> >> +
> >> +      assert_not_constructible<
> >> +       typename Layout::mapping<std::extents<int, 1>>,
> >> +       typename Layout::mapping<std::extents<int>>>();
> >> +
> >> +      verify_nothrow_constructible<Layout, std::extents<int, 1>>(
> >> +       std::extents<int, dyn>{1});
> >> +
> >> +      verify_nothrow_convertible<Layout, std::extents<int, dyn>>(
> >> +       std::extents<int, 1>{});
> >> +
> >> +      assert_not_constructible<
> >> +       typename Layout::mapping<std::extents<int, 1, 2>>,
> >> +       typename Layout::mapping<std::extents<int, 1>>>();
> >> +
> >> +      verify_nothrow_constructible<Layout, std::extents<int, 1, 2>>(
> >> +       std::extents<int, dyn, 2>{1});
> >> +
> >> +      verify_nothrow_convertible<Layout, std::extents<int, dyn, 2>>(
> >> +       std::extents<int, 1, 2>{});
> >> +      return true;
> >> +    }
> >> +
> >> +  template<typename Layout>
> >> +    constexpr void
> >> +    test_all()
> >> +    {
> >> +      test_ctor<Layout>();
> >> +      static_assert(test_ctor<Layout>());
> >> +    }
> >> +}
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_all()
> >> +  {
> >> +    from_extents::test_all<Layout>();
> >> +    from_same_layout::test_all<Layout>();
> >> +  }
> >> +
> >> +int
> >> +main()
> >> +{
> >> +  test_all<std::layout_left>();
> >> +  return 0;
> >> +}
> >> diff --git
> >> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> >> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> >> new file mode 100644
> >> index 00000000000..18f3548df67
> >> --- /dev/null
> >> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
> >> @@ -0,0 +1,445 @@
> >> +// { dg-do run { target c++23 } }
> >> +#include <mdspan>
> >> +
> >> +#include <cstdint>
> >> +#include <testsuite_hooks.h>
> >> +
> >> +constexpr size_t dyn = std::dynamic_extent;
> >> +
> >> +template<typename Layout, typename Extents>
> >> +  constexpr bool
> >> +  test_mapping_properties()
> >> +  {
> >> +    using M = typename Layout::mapping<Extents>;
> >> +    static_assert(std::__mdspan::__is_extents<typename
> M::extents_type>);
> >> +    static_assert(std::copyable<M>);
> >> +    static_assert(std::is_nothrow_move_constructible_v<M>);
> >> +    static_assert(std::is_nothrow_move_assignable_v<M>);
> >> +    static_assert(std::is_nothrow_swappable_v<M>);
> >> +    static_assert(std::is_same_v<typename M::extents_type, Extents>);
> >> +    static_assert(std::is_same_v<typename M::index_type,
> >> +                                typename M::extents_type::index_type>);
> >> +    static_assert(std::is_same_v<typename M::size_type,
> >> +                                typename M::extents_type::size_type>);
> >> +    static_assert(std::is_same_v<typename M::rank_type,
> >> +                                typename M::extents_type::rank_type>);
> >> +    static_assert(std::is_same_v<typename M::layout_type, Layout>);
> >> +
> >> +    static_assert(std::is_trivially_copyable_v<M>);
> >> +    static_assert(std::regular<M>);
> >> +
> >> +    static_assert(M::is_always_unique() && M::is_unique());
> >> +    static_assert(M::is_always_strided() && M::is_strided());
> >> +    return true;
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr bool
> >> +  test_mapping_properties_all()
> >> +  {
> >> +    test_mapping_properties<Layout, std::extents<int>>();
> >> +    test_mapping_properties<Layout, std::extents<int, 1>>();
> >> +    test_mapping_properties<Layout, std::extents<int, dyn>>();
> >> +    test_mapping_properties<Layout, std::extents<int, dyn, dyn>>();
> >> +    return true;
> >> +  }
> >> +
> >> +// Check operator()(Indices...)
> >> +template<typename Mapping, size_t N>
> >> +  constexpr typename Mapping::index_type
> >> +  linear_index(const Mapping& mapping,
> >> +              const std::array<typename Mapping::index_type, N>&
> indices)
> >> +  {
> >> +    typename Mapping::index_type ret = 0;
> >> +    for(size_t r = 0; r < indices.size(); ++r)
> >> +      ret += indices[r] * mapping.stride(r);
> >> +    return ret;
> >> +  }
> >> +
> >> +template<typename Mapping, typename... Indices>
> >> +  constexpr void
> >> +  test_linear_index(const Mapping& m, Indices... i)
> >> +  {
> >> +    using index_type = typename Mapping::index_type;
> >> +    index_type expected = linear_index(m,
> std::array{index_type(i)...});
> >> +    VERIFY(m(i...) == expected);
> >> +    VERIFY(m(uint8_t(i)...) == expected);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_linear_index_0d()
> >> +  {
> >> +    constexpr typename Layout::mapping<std::extents<int>> m;
> >> +    VERIFY(m() == 0);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_linear_index_1d()
> >> +  {
> >> +    typename Layout::mapping<std::extents<int, 5>> m;
> >> +    test_linear_index(m, 0);
> >> +    test_linear_index(m, 1);
> >> +    test_linear_index(m, 4);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_linear_index_2d()
> >> +  {
> >> +    typename Layout::mapping<std::extents<int, 3, 256>> m;
> >> +    test_linear_index(m, 0, 0);
> >> +    test_linear_index(m, 1, 0);
> >> +    test_linear_index(m, 0, 1);
> >> +    test_linear_index(m, 1, 1);
> >> +    test_linear_index(m, 2, 4);
> >> +  }
> >> +
> >> +
> >> +template<typename Layout>
> >> +  struct MappingFactory
> >> +  {
> >> +    template<typename Extents>
> >> +      static constexpr typename Layout::mapping<Extents>
> >> +      create(Extents exts)
> >> +      { return exts; }
> >>
> > This call to this function be replaced with:
> > typename Layout::mapping<Extents> m(std::extents(3, 5, 7));
> > I think expressing this directly would help.
> >
>
> This prepares for `layout_stride`. In that case a) the ctor
> layout_stride(extents) doesn't exist; and b) we want to have
> non-default strides.
>
> The factory will be specialized and return some generic mapping
> for any of the three layouts and ranks 0, 1, 2, 3.
>
I just noticed it, yes it makes sense.

>
> >> +  };
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_linear_index_3d()
> >> +  {
> >> +    auto m = MappingFactory<Layout>::create(std::extents(3, 5, 7));
> >> +    test_linear_index(m, 0, 0, 0);
> >> +    test_linear_index(m, 1, 0, 0);
> >> +    test_linear_index(m, 0, 1, 0);
> >> +    test_linear_index(m, 0, 0, 1);
> >> +    test_linear_index(m, 1, 1, 0);
> >> +    test_linear_index(m, 2, 4, 6);
> >> +  }
> >> +
> >> +struct IntLikeA
> >> +{
> >> +  operator int()
> >> +  { return 0; }
> >> +};
> >> +
> >> +struct IntLikeB
> >> +{
> >> +  operator int() noexcept
> >> +  { return 0; }
> >> +};
> >> +
> >> +struct NotIntLike
> >> +{ };
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_has_linear_index_0d()
> >> +  {
> >> +    using Mapping = typename Layout::mapping<std::extents<int>>;
> >> +    static_assert(std::invocable<Mapping>);
> >> +    static_assert(!std::invocable<Mapping, int>);
> >> +    static_assert(!std::invocable<Mapping, IntLikeA>);
> >> +    static_assert(!std::invocable<Mapping, IntLikeB>);
> >> +    static_assert(!std::invocable<Mapping, NotIntLike>);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_has_linear_index_1d()
> >> +  {
> >> +    using Mapping = typename Layout::mapping<std::extents<int, 3>>;
> >> +    static_assert(std::invocable<Mapping, int>);
> >> +    static_assert(!std::invocable<Mapping>);
> >> +    static_assert(!std::invocable<Mapping, IntLikeA>);
> >> +    static_assert(std::invocable<Mapping, IntLikeB>);
> >> +    static_assert(!std::invocable<Mapping, NotIntLike>);
> >> +    static_assert(std::invocable<Mapping, double>);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_has_linear_index_2d()
> >> +  {
> >> +    using Mapping = typename Layout::mapping<std::extents<int, 3, 5>>;
> >> +    static_assert(std::invocable<Mapping, int, int>);
> >> +    static_assert(!std::invocable<Mapping, int>);
> >> +    static_assert(!std::invocable<Mapping, IntLikeA, int>);
> >> +    static_assert(std::invocable<Mapping, IntLikeB, int>);
> >> +    static_assert(!std::invocable<Mapping, NotIntLike, int>);
> >> +    static_assert(std::invocable<Mapping, double, double>);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr bool
> >> +  test_linear_index_all()
> >> +  {
> >> +    test_linear_index_0d<Layout>();
> >> +    test_linear_index_1d<Layout>();
> >> +    test_linear_index_2d<Layout>();
> >> +    test_linear_index_3d<Layout>();
> >> +    test_has_linear_index_0d<Layout>();
> >> +    test_has_linear_index_1d<Layout>();
> >> +    test_has_linear_index_2d<Layout>();
> >> +    return true;
> >> +  }
> >> +
> >> +template<typename Mapping, typename Mapping::index_type... Counts>
> >> +  constexpr typename Mapping::index_type
> >> +  linear_index_end_impl(Mapping m,
> >> +      std::integer_sequence<typename Mapping::index_type, Counts...>)
> >>
> > I would define this as local lambda inside linear_index_end:
> > auto __impl = [&m]<typename Mapping::index_type... Counts>
> > {
> >       // code you have here.
> > }
> > return _impl(make_index_sequence(...);
> >
> >> +  {
> >> +    if constexpr (sizeof...(Counts) == 0)
> >>
> > I do not think you need this special case, it fails from the
> specification
> > below.
> > as  m((exts.extent(Counts) - 1)...) + 1 becomes m() + 1.
> >
> >> +      return 1;
> >> +    else
> >> +      {
> >> +       auto exts = m.extents();
> >> +       if(((exts.extent(Counts) == 0) || ...))
> >> +         return 0;
> >> +       return m((exts.extent(Counts) - 1)...) + 1;
> >> +      }
> >> +  }
> >> +
> >> +template<typename Mapping>
> >> +  constexpr typename Mapping::index_type
> >> +  linear_index_end(Mapping m)
> >> +  {
> >> +    using index_type = typename Mapping::index_type;
> >> +    constexpr size_t rank = Mapping::extents_type::rank();
> >> +    return linear_index_end_impl(m,
> >> +      std::make_integer_sequence<index_type, rank>());
> >> +  }
> >> +
> >> +// Check required_span_size
> >> +template<typename Mapping>
> >> +  constexpr void
> >> +  test_required_span_size(Mapping m)
> >> +  { VERIFY(m.required_span_size() == linear_index_end(m)); }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_required_span_size_0d()
> >> +  {
> >> +    typename Layout::mapping<std::extents<int>> m;
> >> +    test_required_span_size(m);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_required_span_size_1d()
> >> +  {
> >> +    auto m = MappingFactory<Layout>::create(std::extents(3));
> >> +    test_required_span_size(m);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_required_span_size_2d()
> >> +  {
> >> +    auto m = MappingFactory<Layout>::create(std::extents(3, 5));
> >> +    test_required_span_size(m);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_required_span_size_3d()
> >> +  {
> >> +    auto m = MappingFactory<Layout>::create(std::extents(3, 5, 7));
> >> +    test_required_span_size(m);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_required_span_size_zero_1d()
> >> +  {
> >> +    auto m = MappingFactory<Layout>::create(std::extents(3, 0));
> >> +    test_required_span_size(m);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_required_span_size_zero_3d()
> >> +  {
> >> +    auto m = MappingFactory<Layout>::create(std::extents(3, 0, 7));
> >> +    test_required_span_size(m);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr bool
> >> +  test_required_span_size_all()
> >> +  {
> >> +    test_required_span_size_0d<Layout>();
> >> +    test_required_span_size_1d<Layout>();
> >> +    test_required_span_size_2d<Layout>();
> >> +    test_required_span_size_3d<Layout>();
> >> +    test_required_span_size_zero_1d<Layout>();
> >> +    test_required_span_size_zero_3d<Layout>();
> >> +    return true;
> >> +  }
> >> +
> >> +// Check stride
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_stride_1d()
> >> +  {
> >> +    std::layout_left::mapping<std::extents<int, 3>> m;
> >> +    VERIFY(m.stride(0) == 1);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_stride_2d();
> >> +
> >> +template<>
> >> +  constexpr void
> >> +  test_stride_2d<std::layout_left>()
> >> +  {
> >> +    std::layout_left::mapping<std::extents<int, 3, 5>> m;
> >> +    VERIFY(m.stride(0) == 1);
> >> +    VERIFY(m.stride(1) == 3);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_stride_3d();
> >> +
> >> +template<>
> >> +  constexpr void
> >> +  test_stride_3d<std::layout_left>()
> >> +  {
> >> +    std::layout_left::mapping m(std::dextents<int, 3>(3, 5, 7));
> >> +    VERIFY(m.stride(0) == 1);
> >> +    VERIFY(m.stride(1) == 3);
> >> +    VERIFY(m.stride(2) == 3*5);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr bool
> >> +  test_stride_all()
> >> +  {
> >> +    test_stride_1d<Layout>();
> >> +    test_stride_2d<Layout>();
> >> +    test_stride_3d<Layout>();
> >> +    return true;
> >> +  }
> >> +
> >> +template<typename Mapping>
> >> +  concept has_stride = requires (Mapping m)
> >> +  {
> >> +    { m.stride(0) } -> std::same_as<typename Mapping::index_type>;
> >> +  };
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_has_stride_0d()
> >> +  {
> >> +    using Mapping = typename Layout::mapping<std::extents<int>>;
> >> +    constexpr bool expected = false;
> >> +    static_assert(has_stride<Mapping> == expected);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_has_stride_1d()
> >> +  { static_assert(has_stride<typename Layout::mapping<std::extents<int,
> >> 1>>>); }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_has_stride_2d()
> >> +  {
> >> +    using Extents = std::extents<int, 1, 2>;
> >> +    static_assert(has_stride<typename Layout::mapping<Extents>>);
> >> +  }
> >> +
> >> +// Check operator==
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_eq()
> >> +  {
> >> +    typename Layout::mapping<std::extents<int, 1, 2>> m1;
> >> +    typename Layout::mapping<std::extents<int, 2, 2>> m2;
> >> +    typename Layout::mapping<std::dextents<int, 2>> m3(m1);
> >> +
> >> +    VERIFY(m1 == m1);
> >> +    VERIFY(m1 != m2);
> >> +    VERIFY(m1 == m3);
> >> +    VERIFY(m2 != m3);
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_eq_zero()
> >> +  {
> >> +    typename Layout::mapping<std::extents<int, 0, 2>> m1;
> >> +    typename Layout::mapping<std::extents<int, 0, 2>> m2;
> >> +    typename Layout::mapping<std::extents<int, 2, 0>> m3;
> >> +
> >> +    VERIFY(m1 == m2);
> >> +    VERIFY(m1 != m3);
> >> +  }
> >> +
> >> +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>;
> >> +  };
> >> +
> >> +template<typename Layout>
> >> +  constexpr bool
> >> +  test_has_op_eq()
> >> +  {
> >> +    static_assert(!has_op_eq<
> >> +       typename Layout::mapping<std::extents<int, 1, 2>>,
> >> +       typename Layout::mapping<std::extents<int, 1>>>);
> >> +
> >> +    static_assert(has_op_eq<
> >> +       typename Layout::mapping<std::extents<int, 1>>,
> >> +       typename Layout::mapping<std::extents<int, 1>>>);
> >> +
> >> +    static_assert(has_op_eq<
> >> +       typename Layout::mapping<std::extents<int, 1>>,
> >> +       typename Layout::mapping<std::extents<int, 2>>>);
> >> +    return true;
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr bool
> >> +  test_mapping_all()
> >> +  {
> >> +    test_linear_index_all<Layout>();
> >> +    test_required_span_size_all<Layout>();
> >> +    test_stride_all<Layout>();
> >> +
> >> +    test_eq<Layout>();
> >> +    test_eq_zero<Layout>();
> >> +    return true;
> >> +  }
> >> +
> >> +template<typename Layout>
> >> +  constexpr void
> >> +  test_all()
> >> +  {
> >> +    static_assert(std::is_trivially_default_constructible_v<Layout>);
> >> +    static_assert(std::is_trivially_copyable_v<Layout>);
> >> +    static_assert(test_mapping_properties_all<Layout>());
> >> +
> >> +    test_mapping_all<Layout>();
> >> +    static_assert(test_mapping_all<Layout>());
> >> +
> >> +    test_has_stride_0d<Layout>();
> >> +    test_has_stride_1d<Layout>();
> >> +    test_has_stride_2d<Layout>();
> >> +    test_has_op_eq<Layout>();
> >> +  }
> >> +
> >> +int
> >> +main()
> >> +{
> >> +  test_all<std::layout_left>();
> >> +  return 0;
> >> +}
> >> --
> >> 2.49.0
> >>
> >>
> >
>
>

Reply via email to