On Tue, 8 Jul 2025 at 11:46, Tomasz Kaminski <tkami...@redhat.com> wrote:
>
>
>
> On Tue, Jul 8, 2025 at 12:08 PM Jonathan Wakely <jwak...@redhat.com> wrote:
>>
>> On Tue, 8 Jul 2025 at 10:54, Luc Grosheintz <luc.groshei...@gmail.com> wrote:
>> >
>> > 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.
>> >
>> >         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.
>> >
>> > Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
>> > ---
>> >  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 0fd78570b3e..152dcb3e92a 100644
>> > --- a/libstdc++-v3/include/std/mdspan
>> > +++ b/libstdc++-v3/include/std/mdspan
>> > @@ -406,10 +406,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> >      template<typename _IndexType, size_t... _Counts>
>> >        auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
>> >         -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
>> > -
>> > -    template<typename _Tp>
>> > -      consteval size_t
>> > -      __dynamic_extent() { return dynamic_extent; }
>> >    }
>> >
>> >    template<typename _IndexType, size_t _Rank>
>> > @@ -419,7 +415,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
>> >    {
>> > @@ -1316,7 +1312,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};
>>
>> Are the braces here to detect narrowing conversions?
>>
>> (The paper doesn't mention why they're used, as far as I can see)
>
> The information is in revision history (a bit hidden):
> Initialized the maybe-static-ext's specialization with {T::value} to prevent 
> conversions from negative values.

Thanks. OK for trunk then.


>>
>>
>>
>> > +  }
>> >
>> >    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/extents/misc.cc 
>> > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc
>> > index e71fdc54230..bca8901685d 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<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_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 9252273bf66..a650fb19bdf 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<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;
>> > +}
>> > +
>> >  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 dce6cedf89b..c66db90222e 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<const std::span<int>&>(s5));
>> >    static_assert( is_dynamic_span<int>(s12) );
>> > +
>> > +  std::span s13(a.data(), std::integral_constant<size_t, 3>{});
>> > +  static_assert( is_static_span<long, 3>(s13));
>> >  }
>> > --
>> > 2.49.0
>> >
>>

Reply via email to