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<size_t, 5>{}); is deduced as span<T, 5>. Similarly, in auto exts = extents(integral_constant<int, 2>); auto md = mdspan((T*) ptr, integral_constant<int, 2>); exts and md have types extents<size_t, 2> and mdspan<double, extents<size_t, 2>>, respectively. 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/p3029.cc: New test. * testsuite/23_containers/mdspan/p3029.cc: New test. Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> --- libstdc++-v3/include/std/mdspan | 4 +- libstdc++-v3/include/std/span | 20 ++++++- .../testsuite/23_containers/mdspan/p3029.cc | 58 +++++++++++++++++++ .../testsuite/23_containers/span/p3029.cc | 11 ++++ 4 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/p3029.cc create mode 100644 libstdc++-v3/testsuite/23_containers/span/p3029.cc diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index f64804e2a42..51abf9624e0 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -419,7 +419,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename... _Integrals> requires (is_convertible_v<_Integrals, size_t> && ...) explicit extents(_Integrals...) -> - extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>; + extents<size_t, __detail::__maybe_static_ext<_Integrals>...>; struct layout_left { @@ -1315,7 +1315,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION && (sizeof...(_Integrals) > 0) explicit mdspan(_ElementType*, _Integrals...) -> mdspan<_ElementType, - extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>>; + extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>; template<typename _ElementType, typename _OIndexType, size_t _Nm> mdspan(_ElementType*, span<_OIndexType, _Nm>) diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 49ab9109d83..5629a71b9bd 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<typename _Tp> + concept __integral_constant_like = is_integral_v<decltype(_Tp::value)> + && !is_same_v<bool, remove_const_t<decltype(_Tp::value)>> + && convertible_to<_Tp, decltype(_Tp::value)> + && equality_comparable_with<_Tp, decltype(_Tp::value)> + && bool_constant<_Tp() == _Tp::value>::value + && bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == _Tp::value> + ::value; + + template<typename _Tp> + constexpr size_t __maybe_static_ext = dynamic_extent; + + template<__integral_constant_like _Tp> + constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value}; + } template<typename _Type, size_t _ArrayExtent> span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>; @@ -489,7 +506,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template<contiguous_iterator _Iter, typename _End> span(_Iter, _End) - -> span<remove_reference_t<iter_reference_t<_Iter>>>; + -> span<remove_reference_t<iter_reference_t<_Iter>>, + __detail::__maybe_static_ext<_End>>; template<ranges::contiguous_range _Range> span(_Range &&) diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/p3029.cc b/libstdc++-v3/testsuite/23_containers/mdspan/p3029.cc new file mode 100644 index 00000000000..7c38dc00bf4 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/mdspan/p3029.cc @@ -0,0 +1,58 @@ +// { dg-do run { target c++23 } } + +#include <mdspan> + +#include <testsuite_hooks.h> + +constexpr size_t dyn = std::dynamic_extent; + +constexpr bool +test_extents() +{ + auto verify = [](auto actual, auto expected) + { + static_assert(std::same_as<decltype(actual), decltype(expected)>); + VERIFY(actual == expected); + }; + + constexpr auto c1 = std::integral_constant<size_t, 1>{}; + constexpr auto c2 = std::integral_constant<int, 2>{}; + + verify(std::extents(1), std::extents<size_t, dyn>{1}); + verify(std::extents(c1), std::extents<size_t, 1>{}); + verify(std::extents(c2), std::extents<size_t, 2>{}); + verify(std::extents(c1, 2), std::extents<size_t, 1, dyn>{2}); + return true; +} + +constexpr bool +test_mdspan() +{ + std::array<double, 6> buffer{}; + double * ptr = buffer.data(); + + auto verify = [ptr](auto actual, auto exts) + { + auto expected = std::mdspan<double, decltype(exts)>(ptr, exts); + static_assert(std::same_as<decltype(actual), decltype(expected)>); + VERIFY(actual.extents() == expected.extents()); + }; + + auto c3 = std::integral_constant<int, 3>{}; + auto c6 = std::integral_constant<int, 6>{}; + + 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; +} + +int +main() +{ + test_extents(); + static_assert(test_extents()); + + test_mdspan(); + static_assert(test_mdspan()); +} diff --git a/libstdc++-v3/testsuite/23_containers/span/p3029.cc b/libstdc++-v3/testsuite/23_containers/span/p3029.cc new file mode 100644 index 00000000000..e894255546f --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/span/p3029.cc @@ -0,0 +1,11 @@ +// { dg-do compile { target c++20 } } + +#include <span> + +constexpr void +test_ctad() +{ + std::array<double, 5> a{}; + std::span s(a.data(), std::integral_constant<size_t, 5>{}); + static_assert(std::same_as<decltype(s), std::span<double, 5>>); +} -- 2.49.0