On 6/5/25 10:18, Tomasz Kaminski wrote:
On Wed, Jun 4, 2025 at 5:15 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/empty.cc: New test.
         * testsuite/23_containers/mdspan/layouts/mapping.cc: New test.

Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
---

Again LGTM. The new test for dynamic overflow in empty.cc are nice addition.
The testsuite you have created seem like something other implementation may
look checking
if they pass.

Thank you! We know for sure that both libc++ and MSVCs implementation
will not pass these tests. Especially the corner cases we figured out
surrounding empty extents, will uncover bugs in the two other major
implementations.

I reported some of the bugs on the CLang issue tracker, but haven't
heard anything yet.

At the end, i.e. when we have std::mdspan, I was thinking of running
their test suite, to see what we missed.


  .../mdspan/layouts/class_mandate_neg.cc       |  36 ++
  .../23_containers/mdspan/layouts/ctors.cc     | 278 +++++++++++
  .../23_containers/mdspan/layouts/empty.cc     | 112 +++++
  .../23_containers/mdspan/layouts/mapping.cc   | 437 ++++++++++++++++++
  4 files changed, 863 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..c6c55bdd4bc
--- /dev/null
+++
b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/class_mandate_neg.cc
@@ -0,0 +1,36 @@
+// { 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" }
+  };
+
+template<size_t Count, typename Layout, typename OLayout>
+  struct B
+  {
+    using Extents = std::extents<uint8_t, dyn, dyn, Count>;
+    using OExtents = std::extents<uint16_t, n, 4, Count>;
+
+    using Mapping = typename Layout::mapping<Extents>;
+    using OMapping = typename OLayout::mapping<OExtents>;
+
+    Mapping m{OMapping{}};
+  };
+
+A<std::layout_left> a_left;                      // { dg-error "required
from" }
+
+B<1, std::layout_left, std::layout_left> b0;     // { 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
new file mode 100644
index 00000000000..d634fa867cc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
@@ -0,0 +1,278 @@
+// { 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 Layout, typename Extents>
+    constexpr void
+    test_default_ctor()
+    {
+      using Mapping = typename Layout::mapping<Extents>;
+
+      Mapping m;
+      for(size_t i = 0; i < Extents::rank(); ++i)
+       if (Extents::static_extent(i) == std::dynamic_extent)
+         VERIFY(m.extents().extent(i) == 0);
+       else
+         VERIFY(m.extents().static_extent(i) ==
Extents::static_extent(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, 1, 2>>();
+      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>>();
+      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..9c2ae363da0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/empty.cc
@@ -0,0 +1,112 @@
+// { 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
+  invoke_stride(Mapping m)
+  {
+    // Only checking for UB, e.g. signed overflow.
+    for(size_t i = 0; i < Mapping::extents_type::rank(); ++i)
+      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);
+    invoke_stride(m);
+  }
+
+template<typename Layout, typename Int>
+constexpr void
+test_static_overflow()
+{
+  constexpr Int n1 = std::numeric_limits<Int>::max();
+  constexpr size_t n2 = std::dynamic_extent - 1;
+  constexpr size_t n = std::cmp_less(n1, n2) ? size_t(n1) : n2;
+
+  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, typename Extents>
+constexpr typename Layout::mapping<Extents>
+make_mapping(Extents exts)
+{
+  return typename Layout::mapping(exts);
+}
+
+template<typename Layout, typename Int>
+constexpr void
+test_dynamic_overflow()
+{
+  constexpr Int n1 = std::numeric_limits<Int>::max();
+  constexpr size_t n2 = std::dynamic_extent - 1;
+  constexpr Int n = std::cmp_less(n1, n2) ? n1 : Int(n2);
+
+  verify_all(make_mapping<Layout>(
+      std::extents<Int, dyn, dyn, 0, dyn, dyn>{n, n, n, n}));
+
+  verify_all(make_mapping<Layout>(
+      std::extents<Int, dyn, dyn, dyn, dyn, dyn>{n, n, 0, n, n}));
+
+  verify_all(make_mapping<Layout>(
+      std::extents<Int, dyn, dyn, dyn, 0>{n, n, n}));
+
+  verify_all(make_mapping<Layout>(
+      std::extents<Int, dyn, dyn, dyn, dyn>{n, n, n, 0}));
+
+  verify_all(make_mapping<Layout>(
+      std::extents<Int, 0, dyn, dyn, dyn>{n, n, n}));
+
+  verify_all(make_mapping<Layout>(
+      std::extents<Int, dyn, dyn, dyn, dyn>{0, n, n, n}));
+}
+
+template<typename Layout, typename Int>
+constexpr void
+test_overflow()
+{
+  test_static_overflow<Layout, Int>();
+  test_dynamic_overflow<Layout, Int>();
+}
+
+template<typename Layout>
+constexpr bool
+test_all()
+{
+  test_overflow<Layout, signed char>();
+  test_overflow<Layout, short int>();
+  test_overflow<Layout, int>();
+  test_overflow<Layout, long int>();
+  test_overflow<Layout, long long int>();
+
+  test_overflow<Layout, unsigned char>();
+  test_overflow<Layout, unsigned short int>();
+  test_overflow<Layout, unsigned int>();
+  test_overflow<Layout, unsigned long int>();
+  test_overflow<Layout, unsigned long long int>();
+  test_overflow<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()
+  {
+    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