[PATCH v4 3/8] libstdc++: Add tests for layout_left.

Luc Grosheintz luc.grosheintz@gmail.com
Fri May 30 12:40:17 GMT 2025



On 5/28/25 14:49, Tomasz Kaminski wrote:
> On Mon, May 26, 2025 at 4:21 PM Luc Grosheintz <luc.grosheintz@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.grosheintz@gmail.com>
>> ---
>>
> This looks very good for me, mostly some nitpick/stylistic comments.
> 
> 
>>   .../mdspan/layouts/class_mandate_neg.cc       |  22 +
>>   .../23_containers/mdspan/layouts/ctors.cc     | 286 ++++++++++++
>>   .../23_containers/mdspan/layouts/empty.cc     |  70 +++
>>   .../23_containers/mdspan/layouts/mapping.cc   | 437 ++++++++++++++++++
>>   4 files changed, 815 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/empty.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..b276fbd333e
>> --- /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 = std::numeric_limits<uint8_t>::max() / 2;
>> +
>> +template<typename Layout>
>> +  struct A
>> +  {
>> +    typename Layout::mapping<std::extents<uint8_t, n, 2>> 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..18d9743a57b
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
>> @@ -0,0 +1,286 @@
>> +// { dg-do run { target c++23 } }
>> +#include <mdspan>
>> +
>> +#include <cstdint>
>> +#include <testsuite_hooks.h>
>> +
>> +constexpr size_t dyn = std::dynamic_extent;
>> +
>> +template<typename Mapping, typename IndexType, size_t... Extents>
>> +  constexpr void
>> +  verify(std::extents<IndexType, Extents...> oexts)
>> +  {
>> +    auto m = Mapping(oexts);
>> +    VERIFY(m.extents() == oexts);
>> +  }
>> +
>> +template<typename Mapping, typename OMapping>
>> +  requires (requires { typename OMapping::layout_type; })
>> +  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)));
>> +  }
>> +
>> +
>> +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_nothrow_convertible(From from)
>> +  {
>> +    static_assert(std::is_nothrow_constructible_v<To, From>);
>> +    verify_convertible<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_constructible_v<To, From>);
>> +    verify<To>(from);
>> +  }
>> +
>> +template<typename To, typename From>
>> +  constexpr void
>> +  verify_nothrow_constructible(From from)
>> +  {
>> +    static_assert(std::is_nothrow_constructible_v<To, From>);
>> +    verify_constructible<To>(from);
>> +  }
>> +
>> +template<typename Mapping, typename OExtents>
>> +  constexpr void
>> +  assert_not_constructible()
>> +  {
>> +    static_assert(!std::is_constructible_v<Mapping, OExtents>);
>> +  }
>> +
>> +// ctor: mapping()
>> +namespace default_ctor
>> +{
>> +  template<typename Mapping>
>> +    constexpr void
>> +    verify_default_extent(Mapping m, size_t i)
>> +    {
>> +      using Extents = typename Mapping::extents_type;
>> +      if (Extents::static_extent(i) == std::dynamic_extent)
>> +       VERIFY(m.extents().extent(i) == 0);
>> +    }
>> +
>> +  template<typename Layout, typename Extents>
>> +    constexpr void
>> +    test_default_ctor()
>> +    {
>> +      using Mapping = typename Layout::mapping<Extents>;
>> +
>> +      Mapping m;
>> +      auto exts = m.extents();
>> +      for(size_t i = 0; i < Extents::rank(); ++i)
>> +       {
>>
> We do not need braces here.

Not yet, when we add layout_stride we'll also need to check
default strides.

However, we don't need to do so here, in fact we already do
it in stride.cc. Hence, I'll inline verify_default_extent.

> 
>> +         verify_default_extent(m, i);
>> +       }
>> +    }
>> +
>> +  template<typename Layout>
>> +    constexpr bool
>> +    test_default_ctor_all()
>> +    {
>> +      test_default_ctor<Layout, std::extents<int, dyn>>();
>> +      test_default_ctor<Layout, std::extents<int, dyn, 2>>();
>> +      test_default_ctor<Layout, std::extents<int, dyn, dyn>>();
>> +      test_default_ctor<Layout, std::extents<int, dyn, 2, dyn>>();
>> +      test_default_ctor<Layout, std::extents<int, dyn, dyn, dyn>>();
>>
> All tests also for all static. One would be sufficient.
> 
>> +      return true;
>> +    }
>> +
>> +  template<typename Layout>
>> +  constexpr void
>> +  test_all()
>> +  {
>> +    test_default_ctor_all<Layout>();
>> +    static_assert(test_default_ctor_all<Layout>());
>> +  }
>> +}
>> +
>> +// 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()
>> +  {
>> +    default_ctor::test_all<Layout>();
>> +    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/empty.cc
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
>> new file mode 100644
>> index 00000000000..8cca8171d12
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
>> @@ -0,0 +1,70 @@
>> +// { dg-do run { target c++23 } }
>> +#include <mdspan>
>> +
>> +#include <cstdint>
>> +#include <testsuite_hooks.h>
>> +
>> +constexpr size_t dyn = std::dynamic_extent;
>> +
>> +template<typename Mapping>
>> +  constexpr void
>> +  verify_stride(Mapping m)
>> +  {
>> +    using Layout = typename Mapping::layout_type;
>> +    constexpr size_t rank = Mapping::extents_type::rank();
>> +    for(size_t i = 0; i < rank; ++i)
>> +      {
>>
> Remove the braces, and could you add a comment that we are only validating,
> that this call didn't produce UB. Otherwise these are surprising.
> 
>> +       m.stride(i);
>> +      }
>> +  }
>> +
>> +template<typename Mapping>
>> +  constexpr void
>> +  verify_required_span_size(Mapping m)
>> +  { VERIFY(m.required_span_size() == 0); }
>> +
>> +template<typename Mapping>
>> +  constexpr void
>> +  verify_all(Mapping m)
>> +  {
>> +    verify_required_span_size(m);
>> +    verify_stride(m);
>> +  }
>> +
>> +template<typename Layout, typename Int>
>> +constexpr void
>> +test_default_constructed()
>> +{
>> +  constexpr auto n = std::numeric_limits<Int>::max();
>> +  verify_all(typename Layout::mapping<std::extents<Int, n, n, 0, n,
>> n>>{});
>> +  verify_all(typename Layout::mapping<std::extents<Int, 0, n, n, n>>{});
>> +  verify_all(typename Layout::mapping<std::extents<Int, dyn, n, n, n>>{});
>> +  verify_all(typename Layout::mapping<std::extents<Int, n, n, n, 0>>{});
>> +  verify_all(typename Layout::mapping<std::extents<Int, n, n, n, dyn>>{});
>> +}
>> +
>> +template<typename Layout>
>> +constexpr bool
>> +test_all()
>> +{
>> +  test_default_constructed<Layout, signed char>();
>> +  test_default_constructed<Layout, short int>();
>> +  test_default_constructed<Layout, int>();
>> +  test_default_constructed<Layout, long int>();
>> +  test_default_constructed<Layout, long long int>();
>> +
>> +  test_default_constructed<Layout, unsigned char>();
>> +  test_default_constructed<Layout, unsigned short int>();
>> +  test_default_constructed<Layout, unsigned int>();
>> +  test_default_constructed<Layout, unsigned long int>();
>> +  test_default_constructed<Layout, unsigned long long int>();
>> +  test_default_constructed<Layout, size_t>();
>> +  return true;
>> +}
>> +
>> +int
>> +main()
>> +{
>> +  static_assert(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..a5be1166617
>> --- /dev/null
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
>> @@ -0,0 +1,437 @@
>> +// { 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; }
>> +  };
>> +
>> +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>
>> +  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();
>> +
>> +    auto impl = [m]<index_type... Counts>(
>> +       std::integer_sequence<index_type, Counts...>) -> index_type
>> +      {
>> +       auto exts = m.extents();
>> +       if(((exts.extent(Counts) == 0) || ...))
>> +         return 0;
>> +       return m((exts.extent(Counts) - 1)...) + 1;
>> +      };
>> +
>> +    return impl(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()
>>
> Would raname it to test_no_stride_0d.

Unfortunately not, because layout_stride *does* have stride.

> 
>> +  {
>> +    using Mapping = typename Layout::mapping<std::extents<int>>;
>> +    constexpr bool expected = false;
>> +    static_assert(has_stride<Mapping> == expected);
>>
> I would prefer if this would say:
>    static_assert(!has_stride<Mapping>);
> Or:
>    static_assert(not has_stride<Mapping>);
> I got confused by the lack of negation at the front, so would find that
> more readable.
> 
>> +  }
>> +
>> +template<typename Layout>
>> +  constexpr void
>> +  test_has_stride_1d()
>> +  { static_assert(has_stride<typename Layout::mapping<std::extents<int,
>> 1>>>); }
>>
> I do not think this checks are necessary, after we successfully compiled
> calls to this function in
> test_stride_1d. So I will remove this.
> 

This looks like I also wanted to know that it returns an index_type; and
while hardening the tests for the hierarchical approach I made sure every
test came in all three flavours. Happy to remove this.

>> +
>> +template<typename Layout>
>> +  constexpr void
>> +  test_has_stride_2d()
>>
> And here.
> 
>> +  {
>> +    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
>>
>>
> 



More information about the Libstdc++ mailing list