On Wed, 4 Jun 2025 at 16:15, Luc Grosheintz <[email protected]> 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 <[email protected]>
OK for trunk
> ---
> .../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
>