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 > >> > >> > > > >