From 9c600a7e6cc588d2ee79d764cbf69ad677b1bac5 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Tue, 8 Jul 2025 11:49:21 +0200 Subject: [PATCH] libstdc++: Better CTAD for span and mdspan [PR120914]. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This implements P3029R1. In P3029R1, the CTAD for span is refined to permit deducing the extent of the span from an integral constant, e.g. span((T*) ptr, integral_constant{}); is deduced as span. Similarly, in auto exts = extents(integral_constant); auto md = mdspan((T*) ptr, integral_constant); exts and md have types extents and mdspan>, respectively. PR libstdc++/120914 libstdc++-v3/ChangeLog: * include/std/span (span): Update CTAD to enable integral constants [P3029R1]. * include/std/mdspan (extents): ditto. (mdspan): ditto. * testsuite/23_containers/span/deduction.cc: Test deduction guide. * testsuite/23_containers/mdspan/extents/misc.cc: ditto. * testsuite/23_containers/mdspan/mdspan.cc: ditto. Reviewed-by: Jonathan Wakely Reviewed-by: Tomasz Kamiński Signed-off-by: Luc Grosheintz --- libstdc++-v3/include/std/mdspan | 8 ++---- libstdc++-v3/include/std/span | 20 ++++++++++++++- .../23_containers/mdspan/extents/misc.cc | 20 +++++++++++++++ .../testsuite/23_containers/mdspan/mdspan.cc | 25 +++++++++++++++++++ .../testsuite/23_containers/span/deduction.cc | 3 +++ 5 files changed, 69 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 5a42aead3ebb..5d16de5d9072 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -406,10 +406,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template auto __build_dextents_type(integer_sequence) -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>; - - template - consteval size_t - __dynamic_extent() { return dynamic_extent; } } template @@ -419,7 +415,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template requires (is_convertible_v<_Integrals, size_t> && ...) explicit extents(_Integrals...) -> - extents()...>; + extents...>; struct layout_left { @@ -1316,7 +1312,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && (sizeof...(_Integrals) > 0) explicit mdspan(_ElementType*, _Integrals...) -> mdspan<_ElementType, - extents()...>>; + extents...>>; template mdspan(_ElementType*, span<_OIndexType, _Nm>) diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 49ab9109d83e..5629a71b9bd2 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -476,6 +476,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; // deduction guides + namespace __detail + { + template + concept __integral_constant_like = is_integral_v + && !is_same_v> + && convertible_to<_Tp, decltype(_Tp::value)> + && equality_comparable_with<_Tp, decltype(_Tp::value)> + && bool_constant<_Tp() == _Tp::value>::value + && bool_constant(_Tp()) == _Tp::value> + ::value; + + template + constexpr size_t __maybe_static_ext = dynamic_extent; + + template<__integral_constant_like _Tp> + constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value}; + } template span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>; @@ -489,7 +506,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template span(_Iter, _End) - -> span>>; + -> span>, + __detail::__maybe_static_ext<_End>>; template span(_Range &&) diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc index e71fdc542305..bca8901685d0 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc @@ -97,6 +97,25 @@ test_deduction(Extents... exts) VERIFY(e == expected); } +constexpr bool +test_integral_constant_deduction() +{ + auto verify = [](auto actual, auto expected) + { + static_assert(std::same_as); + VERIFY(actual == expected); + }; + + constexpr auto c1 = std::integral_constant{}; + constexpr auto c2 = std::integral_constant{}; + + verify(std::extents(1), std::extents{1}); + verify(std::extents(c1), std::extents{}); + verify(std::extents(c2), std::extents{}); + verify(std::extents(c1, 2), std::extents{2}); + return true; +} + constexpr bool test_deduction_all() { @@ -104,6 +123,7 @@ test_deduction_all() test_deduction<1>(1); test_deduction<2>(1.0, 2.0f); test_deduction<3>(int(1), short(2), size_t(3)); + test_integral_constant_deduction(); return true; } diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc index 9252273bf669..a650fb19bdf0 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc @@ -245,6 +245,28 @@ test_from_pointer_and_shape() return true; } +constexpr bool +test_from_pointer_and_integral_constant() +{ + std::array buffer{}; + double * ptr = buffer.data(); + + auto verify = [ptr](auto actual, auto exts) + { + auto expected = std::mdspan(ptr, exts); + static_assert(std::same_as); + VERIFY(actual.extents() == expected.extents()); + }; + + auto c3 = std::integral_constant{}; + auto c6 = std::integral_constant{}; + + verify(std::mdspan(ptr, 6), std::extents(6)); + verify(std::mdspan(ptr, c6), std::extents(c6)); + verify(std::mdspan(ptr, 2, c3), std::extents(2, c3)); + return true; +} + constexpr bool test_from_extents() { @@ -616,6 +638,9 @@ main() test_from_pointer_and_shape(); static_assert(test_from_pointer_and_shape()); + test_from_pointer_and_integral_constant(); + static_assert(test_from_pointer_and_integral_constant()); + test_from_extents(); static_assert(test_from_extents()); diff --git a/libstdc++-v3/testsuite/23_containers/span/deduction.cc b/libstdc++-v3/testsuite/23_containers/span/deduction.cc index dce6cedf89bd..c66db90222e6 100644 --- a/libstdc++-v3/testsuite/23_containers/span/deduction.cc +++ b/libstdc++-v3/testsuite/23_containers/span/deduction.cc @@ -80,4 +80,7 @@ test01() std::span s12(const_cast&>(s5)); static_assert( is_dynamic_span(s12) ); + + std::span s13(a.data(), std::integral_constant{}); + static_assert( is_static_span(s13)); } -- 2.47.2