From: Luc Grosheintz Date: Wed, 4 Jun 2025 14:58:48 +0000 (+0200) Subject: libstdc++: Add tests for layout_left. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a8672c957edf2a826a8aab048c8680cf266090b;p=thirdparty%2Fgcc.git libstdc++: Add tests for layout_left. 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 Reviewed-by: Tomasz KamiƄski --- 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 + +#include + +constexpr size_t dyn = std::dynamic_extent; +static constexpr size_t n = std::numeric_limits::max() / 2; + +template + struct A + { + typename Layout::mapping> m0; + typename Layout::mapping> m1; + typename Layout::mapping> m2; + + using extents_type = std::extents; + typename Layout::mapping m3; // { dg-error "required from" } + }; + +template + struct B + { + using Extents = std::extents; + using OExtents = std::extents; + + using Mapping = typename Layout::mapping; + using OMapping = typename OLayout::mapping; + + Mapping m{OMapping{}}; + }; + +A 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 + +#include +#include + +constexpr size_t dyn = std::dynamic_extent; + +template + constexpr void + verify(std::extents oexts) + { + auto m = Mapping(oexts); + VERIFY(m.extents() == oexts); + } + +template + 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 + constexpr void + verify_convertible(From from) + { + static_assert(std::is_convertible_v); + verify(from); + } + +template + constexpr void + verify_nothrow_convertible(From from) + { + static_assert(std::is_nothrow_constructible_v); + verify_convertible(from); + } + +template + constexpr void + verify_constructible(From from) + { + static_assert(!std::is_convertible_v); + static_assert(std::is_constructible_v); + verify(from); + } + +template + constexpr void + verify_nothrow_constructible(From from) + { + static_assert(std::is_nothrow_constructible_v); + verify_constructible(from); + } + +template + constexpr void + assert_not_constructible() + { + static_assert(!std::is_constructible_v); + } + +// ctor: mapping() +namespace default_ctor +{ + template + constexpr void + test_default_ctor() + { + using Mapping = typename Layout::mapping; + + 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 + constexpr bool + test_default_ctor_all() + { + test_default_ctor>(); + test_default_ctor>(); + test_default_ctor>(); + test_default_ctor>(); + test_default_ctor>(); + test_default_ctor>(); + return true; + } + + template + constexpr void + test_all() + { + test_default_ctor_all(); + static_assert(test_default_ctor_all()); + } +} + +// ctor: mapping(const extents&) +namespace from_extents +{ + template + constexpr void + verify_nothrow_convertible(OExtents oexts) + { + using Mapping = typename Layout::mapping; + ::verify_nothrow_convertible(oexts); + } + + template + constexpr void + verify_nothrow_constructible(OExtents oexts) + { + using Mapping = typename Layout::mapping; + ::verify_nothrow_constructible(oexts); + } + + template + constexpr void + assert_not_constructible() + { + using Mapping = typename Layout::mapping; + ::assert_not_constructible(); + } + + template + constexpr bool + test_ctor() + { + verify_nothrow_convertible>( + std::extents{}); + + verify_nothrow_convertible>( + std::extents{}); + + verify_nothrow_convertible>( + std::extents{2}); + + verify_nothrow_constructible>( + std::extents{}); + + verify_nothrow_constructible>( + std::extents{}); + + verify_nothrow_constructible>( + std::extents{}); + + assert_not_constructible, + std::extents>(); + assert_not_constructible, + std::extents>(); + assert_not_constructible, + std::extents>(); + return true; + } + + template + constexpr void + assert_deducible(Extents exts) + { + typename Layout::mapping m(exts); + static_assert(std::same_as>); + } + + template + constexpr void + test_deducible() + { + assert_deducible(std::extents()); + assert_deducible(std::extents()); + assert_deducible(std::extents(3)); + } + + template + constexpr void + test_all() + { + test_ctor(); + static_assert(test_ctor()); + test_deducible(); + } +} + +// ctor: mapping(mapping) +namespace from_same_layout +{ + template + constexpr void + verify_nothrow_convertible(OExtents exts) + { + using Mapping = typename Layout::mapping; + using OMapping = typename Layout::mapping; + + ::verify_nothrow_convertible(OMapping(exts)); + } + + template + constexpr void + verify_nothrow_constructible(OExtents exts) + { + using Mapping = typename Layout::mapping; + using OMapping = typename Layout::mapping; + + ::verify_nothrow_constructible(OMapping(exts)); + } + + template + constexpr bool + test_ctor() + { + verify_nothrow_convertible>( + std::extents{}); + + verify_nothrow_constructible>( + std::extents{}); + + assert_not_constructible< + typename Layout::mapping>, + typename Layout::mapping>>(); + + assert_not_constructible< + typename Layout::mapping>, + typename Layout::mapping>>(); + + verify_nothrow_constructible>( + std::extents{1}); + + verify_nothrow_convertible>( + std::extents{}); + + assert_not_constructible< + typename Layout::mapping>, + typename Layout::mapping>>(); + + verify_nothrow_constructible>( + std::extents{1}); + + verify_nothrow_convertible>( + std::extents{}); + return true; + } + + template + constexpr void + test_all() + { + test_ctor(); + static_assert(test_ctor()); + } +} + +template + constexpr void + test_all() + { + default_ctor::test_all(); + from_extents::test_all(); + from_same_layout::test_all(); + } + +int +main() +{ + test_all(); + 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 + +#include +#include + +constexpr size_t dyn = std::dynamic_extent; + +template + 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 + constexpr void + verify_required_span_size(Mapping m) + { VERIFY(m.required_span_size() == 0); } + +template + constexpr void + verify_all(Mapping m) + { + verify_required_span_size(m); + invoke_stride(m); + } + +template +constexpr void +test_static_overflow() +{ + constexpr Int n1 = std::numeric_limits::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>{}); + verify_all(typename Layout::mapping>{}); + verify_all(typename Layout::mapping>{}); + verify_all(typename Layout::mapping>{}); + verify_all(typename Layout::mapping>{}); +} + +template +constexpr typename Layout::mapping +make_mapping(Extents exts) +{ + return typename Layout::mapping(exts); +} + +template +constexpr void +test_dynamic_overflow() +{ + constexpr Int n1 = std::numeric_limits::max(); + constexpr size_t n2 = std::dynamic_extent - 1; + constexpr Int n = std::cmp_less(n1, n2) ? n1 : Int(n2); + + verify_all(make_mapping( + std::extents{n, n, n, n})); + + verify_all(make_mapping( + std::extents{n, n, 0, n, n})); + + verify_all(make_mapping( + std::extents{n, n, n})); + + verify_all(make_mapping( + std::extents{n, n, n, 0})); + + verify_all(make_mapping( + std::extents{n, n, n})); + + verify_all(make_mapping( + std::extents{0, n, n, n})); +} + +template +constexpr void +test_overflow() +{ + test_static_overflow(); + test_dynamic_overflow(); +} + +template +constexpr bool +test_all() +{ + test_overflow(); + test_overflow(); + test_overflow(); + test_overflow(); + test_overflow(); + + test_overflow(); + test_overflow(); + test_overflow(); + test_overflow(); + test_overflow(); + test_overflow(); + return true; +} + +int +main() +{ + static_assert(test_all()); + 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 + +#include +#include + +constexpr size_t dyn = std::dynamic_extent; + +template + constexpr bool + test_mapping_properties() + { + using M = typename Layout::mapping; + static_assert(std::__mdspan::__is_extents); + static_assert(std::copyable); + static_assert(std::is_nothrow_move_constructible_v); + static_assert(std::is_nothrow_move_assignable_v); + static_assert(std::is_nothrow_swappable_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + static_assert(std::is_same_v); + + static_assert(std::is_trivially_copyable_v); + static_assert(std::regular); + + static_assert(M::is_always_unique() && M::is_unique()); + static_assert(M::is_always_strided() && M::is_strided()); + return true; + } + +template + constexpr bool + test_mapping_properties_all() + { + test_mapping_properties>(); + test_mapping_properties>(); + test_mapping_properties>(); + test_mapping_properties>(); + return true; + } + +// Check operator()(Indices...) +template + constexpr typename Mapping::index_type + linear_index(const Mapping& mapping, + const std::array& 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 + 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 + constexpr void + test_linear_index_0d() + { + constexpr typename Layout::mapping> m; + VERIFY(m() == 0); + } + +template + constexpr void + test_linear_index_1d() + { + typename Layout::mapping> m; + test_linear_index(m, 0); + test_linear_index(m, 1); + test_linear_index(m, 4); + } + +template + constexpr void + test_linear_index_2d() + { + typename Layout::mapping> 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 + struct MappingFactory + { + template + static constexpr typename Layout::mapping + create(Extents exts) + { return exts; } + }; + +template + constexpr void + test_linear_index_3d() + { + auto m = MappingFactory::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 + constexpr void + test_has_linear_index_0d() + { + using Mapping = typename Layout::mapping>; + static_assert(std::invocable); + static_assert(!std::invocable); + static_assert(!std::invocable); + static_assert(!std::invocable); + static_assert(!std::invocable); + } + +template + constexpr void + test_has_linear_index_1d() + { + using Mapping = typename Layout::mapping>; + static_assert(std::invocable); + static_assert(!std::invocable); + static_assert(!std::invocable); + static_assert(std::invocable); + static_assert(!std::invocable); + static_assert(std::invocable); + } + +template + constexpr void + test_has_linear_index_2d() + { + using Mapping = typename Layout::mapping>; + static_assert(std::invocable); + static_assert(!std::invocable); + static_assert(!std::invocable); + static_assert(std::invocable); + static_assert(!std::invocable); + static_assert(std::invocable); + } + +template + constexpr bool + test_linear_index_all() + { + test_linear_index_0d(); + test_linear_index_1d(); + test_linear_index_2d(); + test_linear_index_3d(); + test_has_linear_index_0d(); + test_has_linear_index_1d(); + test_has_linear_index_2d(); + return true; + } + +template + 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]( + std::integer_sequence) -> 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()); + } + +// Check required_span_size +template + constexpr void + test_required_span_size(Mapping m) + { VERIFY(m.required_span_size() == linear_index_end(m)); } + +template + constexpr void + test_required_span_size_0d() + { + typename Layout::mapping> m; + test_required_span_size(m); + } + +template + constexpr void + test_required_span_size_1d() + { + auto m = MappingFactory::create(std::extents(3)); + test_required_span_size(m); + } + +template + constexpr void + test_required_span_size_2d() + { + auto m = MappingFactory::create(std::extents(3, 5)); + test_required_span_size(m); + } + +template + constexpr void + test_required_span_size_3d() + { + auto m = MappingFactory::create(std::extents(3, 5, 7)); + test_required_span_size(m); + } + +template + constexpr void + test_required_span_size_zero_1d() + { + auto m = MappingFactory::create(std::extents(3, 0)); + test_required_span_size(m); + } + +template + constexpr void + test_required_span_size_zero_3d() + { + auto m = MappingFactory::create(std::extents(3, 0, 7)); + test_required_span_size(m); + } + +template + constexpr bool + test_required_span_size_all() + { + test_required_span_size_0d(); + test_required_span_size_1d(); + test_required_span_size_2d(); + test_required_span_size_3d(); + test_required_span_size_zero_1d(); + test_required_span_size_zero_3d(); + return true; + } + +// Check stride +template + constexpr void + test_stride_1d() + { + std::layout_left::mapping> m; + VERIFY(m.stride(0) == 1); + } + +template + constexpr void + test_stride_2d(); + +template<> + constexpr void + test_stride_2d() + { + std::layout_left::mapping> m; + VERIFY(m.stride(0) == 1); + VERIFY(m.stride(1) == 3); + } + +template + constexpr void + test_stride_3d(); + +template<> + constexpr void + test_stride_3d() + { + std::layout_left::mapping m(std::dextents(3, 5, 7)); + VERIFY(m.stride(0) == 1); + VERIFY(m.stride(1) == 3); + VERIFY(m.stride(2) == 3*5); + } + +template + constexpr bool + test_stride_all() + { + test_stride_1d(); + test_stride_2d(); + test_stride_3d(); + return true; + } + +template + concept has_stride = requires (Mapping m) + { + { m.stride(0) } -> std::same_as; + }; + +template + constexpr void + test_has_stride_0d() + { + using Mapping = typename Layout::mapping>; + constexpr bool expected = false; + static_assert(has_stride == expected); + } + +template + constexpr void + test_has_stride_1d() + { static_assert(has_stride>>); } + +template + constexpr void + test_has_stride_2d() + { + using Extents = std::extents; + static_assert(has_stride>); + } + +// Check operator== +template + constexpr void + test_eq() + { + typename Layout::mapping> m1; + typename Layout::mapping> m2; + typename Layout::mapping> m3(m1); + + VERIFY(m1 == m1); + VERIFY(m1 != m2); + VERIFY(m1 == m3); + VERIFY(m2 != m3); + } + +template + constexpr void + test_eq_zero() + { + typename Layout::mapping> m1; + typename Layout::mapping> m2; + typename Layout::mapping> m3; + + VERIFY(m1 == m2); + VERIFY(m1 != m3); + } + +template + concept has_op_eq = requires (M1 m1, M2 m2) + { + { m1 == m2 } -> std::same_as; + { m2 == m1 } -> std::same_as; + { m1 != m2 } -> std::same_as; + { m2 != m1 } -> std::same_as; + }; + +template + constexpr bool + test_has_op_eq() + { + static_assert(!has_op_eq< + typename Layout::mapping>, + typename Layout::mapping>>); + + static_assert(has_op_eq< + typename Layout::mapping>, + typename Layout::mapping>>); + + static_assert(has_op_eq< + typename Layout::mapping>, + typename Layout::mapping>>); + return true; + } + +template + constexpr bool + test_mapping_all() + { + test_linear_index_all(); + test_required_span_size_all(); + test_stride_all(); + + test_eq(); + test_eq_zero(); + return true; + } + +template + constexpr void + test_all() + { + static_assert(std::is_trivially_default_constructible_v); + static_assert(std::is_trivially_copyable_v); + static_assert(test_mapping_properties_all()); + + test_mapping_all(); + static_assert(test_mapping_all()); + + test_has_stride_0d(); + test_has_stride_1d(); + test_has_stride_2d(); + test_has_op_eq(); + } + +int +main() +{ + test_all(); + return 0; +}