On Thu, 20 Nov 2025 at 13:56, Tomasz Kaminski <[email protected]> wrote:
>
>
>
> On Tue, Nov 18, 2025 at 3:25 PM Luc Grosheintz <[email protected]> 
> wrote:
>>
>> The changes needed for submdspan are:
>>
>>   * In submdspan related code the user-defined integer-like
>>     types need to be copy- and move-constructable.
>>
>>   * The traits for writing tests that work with both left- and right,
>>     possibly padded, layouts will also be useful for submdspan.
>>     Therefore, this code is moved up and generalized.
>>
>>   * Move __offset further up in <mdspan> and fix some formatting
>>     mistakes.
>>
>>         * include/std/mdspan: Improve formatting and placement.
>>         * testsuite/23_containers/mdspan/int_like.h: Optionally,
>>         add move- and copy-ctors.
>>         * testsuite/23_containers/mdspan/layouts/padded_traits.h: Move to...
>>         * testsuite/23_containers/mdspan/layout_traits.h: ...here.
>>         * testsuite/23_containers/mdspan/layouts/ctors.cc: Fix include.
>>         * testsuite/23_containers/mdspan/layouts/mapping.cc: Ditto.
>>         * testsuite/23_containers/mdspan/layouts/padded.cc: Ditto.
>>         * testsuite/23_containers/mdspan/layouts/padded_neg.cc: Ditto.
>>
>> Signed-off-by: Luc Grosheintz <[email protected]>
>> ---
>
> LGTM, one very minor comment, but the change is not required.
>>
>>  libstdc++-v3/include/std/mdspan               | 52 ++++++++-------
>>  .../testsuite/23_containers/mdspan/int_like.h | 25 ++++---
>>  .../padded_traits.h => layout_traits.h}       | 65 +++++++++++++++----
>>  .../23_containers/mdspan/layouts/ctors.cc     |  2 +-
>>  .../23_containers/mdspan/layouts/mapping.cc   |  2 +-
>>  .../23_containers/mdspan/layouts/padded.cc    |  2 +-
>>  .../mdspan/layouts/padded_neg.cc              |  2 +-
>>  7 files changed, 103 insertions(+), 47 deletions(-)
>>  rename libstdc++-v3/testsuite/23_containers/mdspan/{layouts/padded_traits.h 
>> => layout_traits.h} (70%)
>>
>> diff --git a/libstdc++-v3/include/std/mdspan 
>> b/libstdc++-v3/include/std/mdspan
>> index bd7a2a201a7..0a49f24fd3f 100644
>> --- a/libstdc++-v3/include/std/mdspan
>> +++ b/libstdc++-v3/include/std/mdspan
>> @@ -338,21 +338,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>
>>  #if __glibcxx_submdspan
>>    struct full_extent_t
>>    {
>>      explicit full_extent_t() = default;
>>    };
>>
>>    inline constexpr full_extent_t full_extent{};
>>
>>    template<typename _OffsetType, typename _ExtentType, typename _StrideType>
>> -    struct strided_slice {
>> +    struct strided_slice
>> +    {
>>        static_assert(__is_standard_integer<_OffsetType>::value
>>         || __detail::__integral_constant_like<_OffsetType>);
>>        static_assert(__is_standard_integer<_ExtentType>::value
>>         || __detail::__integral_constant_like<_ExtentType>);
>>        static_assert(__is_standard_integer<_StrideType>::value
>>         || __detail::__integral_constant_like<_StrideType>);
>>
>>        using offset_type = _OffsetType;
>>        using extent_type = _ExtentType;
>>        using stride_type = _StrideType;
>> @@ -361,21 +362,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        [[no_unique_address]] extent_type extent{};
>>        [[no_unique_address]] stride_type stride{};
>>      };
>>
>>    template<typename _Mapping>
>>      struct submdspan_mapping_result
>>      {
>>        [[no_unique_address]] _Mapping mapping = _Mapping();
>>        size_t offset{};
>>      };
>> -#endif
>> +#endif // __glibcxx_submdspan
>>
>>    template<typename _IndexType, size_t... _Extents>
>>      class extents
>>      {
>>        static_assert(__is_standard_integer<_IndexType>::value,
>>                     "IndexType must be a signed or unsigned integer type");
>>        static_assert(
>>           (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
>>           "Extents must either be dynamic or representable as IndexType");
>>
>> @@ -546,21 +547,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>             __ret *= size_t(__factor);
>>         return static_cast<typename _Extents::index_type>(__ret);
>>        }
>>
>>      // Preconditions: _r < _Extents::rank()
>>      template<typename _Extents>
>>        constexpr typename _Extents::index_type
>>        __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) 
>> noexcept
>>        {
>>         size_t __sta_prod = [__begin, __end] {
>> -         span<const size_t> __sta_exts = 
>> __static_extents<_Extents>(__begin, __end);
>> +         span<const size_t> __sta_exts
>> +           = __static_extents<_Extents>(__begin, __end);
>>           size_t __ret = 1;
>>           for(auto __ext : __sta_exts)
>>             if (__ext != dynamic_extent)
>>               __ret *= __ext;
>>           return __ret;
>>         }();
>>         return __extents_prod(__exts, __sta_prod, __begin, __end);
>>        }
>>
>>      template<typename _Extents>
>> @@ -762,21 +764,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>           }
>>        }
>>
>>      template<typename _Extents, typename _IndexType>
>>        concept __representable_size = _Extents::rank_dynamic() != 0
>>         || __contains_zero(__static_extents<_Extents>())
>>         || (__static_quotient<_Extents, _IndexType>() != 0);
>>
>>      template<typename _Layout, typename _Mapping>
>>        concept __mapping_of =
>> -       is_same_v<typename _Layout::template mapping<typename 
>> _Mapping::extents_type>,
>> +       is_same_v<typename _Layout::template mapping<
>> +                   typename _Mapping::extents_type>,
>>                   _Mapping>;
>>
>>      template<template<size_t> typename _Layout, typename _Mapping>
>>        concept __padded_mapping_of = __mapping_of<
>>         _Layout<_Mapping::padding_value>, _Mapping>;
>>
>>  #ifdef __glibcxx_padded_layouts
>>      template<typename _Mapping>
>>        constexpr bool __is_left_padded_mapping = __padded_mapping_of<
>>         layout_left_padded, _Mapping>;
>> @@ -797,20 +800,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>                                        || __mapping_of<layout_stride, 
>> _Mapping>
>>  #ifdef __glibcxx_padded_layouts
>>                                        || __is_left_padded_mapping<_Mapping>
>>                                        || __is_right_padded_mapping<_Mapping>
>>  #endif
>>                                        ;
>>
>>      // A tag type to create internal ctors.
>>      class __internal_ctor
>>      { };
>> +
>> +    template<typename _Mapping>
>> +      constexpr typename _Mapping::index_type
>> +      __offset(const _Mapping& __m) noexcept
>> +      {
>> +       using _IndexType = typename _Mapping::index_type;
>> +       constexpr auto __rank = _Mapping::extents_type::rank();
>> +
>> +       if constexpr (__standardized_mapping<_Mapping>)
>> +         return 0;
>> +       else if (__empty(__m.extents()))
>> +         return 0;
>> +       else
>> +         {
>> +           auto __impl = [&__m]<size_t... 
>> _Counts>(index_sequence<_Counts...>)
>> +             { return __m(((void) _Counts, _IndexType(0))...); };
>> +           return __impl(make_index_sequence<__rank>());
>> +         }
>> +      }
>>    }
>>
>>    template<typename _Extents>
>>      class layout_left::mapping
>>      {
>>      public:
>>        using extents_type = _Extents;
>>        using index_type = typename extents_type::index_type;
>>        using size_type = typename extents_type::size_type;
>>        using rank_type = typename extents_type::rank_type;
>> @@ -1030,21 +1052,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>                                    extents_type>)
>>         mapping(const _RightPaddedMapping& __other) noexcept
>>         : mapping(__other.extents(), __mdspan::__internal_ctor{})
>>         {
>>           constexpr size_t __rank = extents_type::rank();
>>           constexpr size_t __ostride_sta
>>             = __mdspan::__get_static_stride<_RightPaddedMapping>();
>>
>>           if constexpr (__rank > 1)
>>             {
>> -             if constexpr (extents_type::static_extent(__rank - 1) != 
>> dynamic_extent
>> +             if constexpr (
>> +               extents_type::static_extent(__rank - 1) != dynamic_extent
>
> The 80 collumn limit is our soft limit, and 100 is the max, I think for here 
> I preffer going slightly
> over it than having condition in next line.

I agree. Feel free to make that change when pushing if you want to.

OK for trunk.

>>
>>                   && __ostride_sta != dynamic_extent)
>>                 static_assert(extents_type::static_extent(__rank - 1)
>>                     == __ostride_sta);
>>               else
>>                 __glibcxx_assert(__other.stride(__rank - 2)
>>                     == __other.extents().extent(__rank - 1));
>>             }
>>         }
>>  #endif
>>
>> @@ -1129,39 +1152,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>        {
>>         requires __is_extents<typename _Mp::extents_type>;
>>         { _Mp::is_always_strided() } -> same_as<bool>;
>>         { _Mp::is_always_exhaustive() } -> same_as<bool>;
>>         { _Mp::is_always_unique() } -> same_as<bool>;
>>         bool_constant<_Mp::is_always_strided()>::value;
>>         bool_constant<_Mp::is_always_exhaustive()>::value;
>>         bool_constant<_Mp::is_always_unique()>::value;
>>        };
>>
>> -    template<typename _Mapping>
>> -      constexpr typename _Mapping::index_type
>> -      __offset(const _Mapping& __m) noexcept
>> -      {
>> -       using _IndexType = typename _Mapping::index_type;
>> -       constexpr auto __rank = _Mapping::extents_type::rank();
>> -
>> -       if constexpr (__standardized_mapping<_Mapping>)
>> -         return 0;
>> -       else if (__empty(__m.extents()))
>> -         return 0;
>> -       else
>> -         {
>> -           auto __impl = [&__m]<size_t... 
>> _Counts>(index_sequence<_Counts...>)
>> -             { return __m(((void) _Counts, _IndexType(0))...); };
>> -           return __impl(make_index_sequence<__rank>());
>> -         }
>> -      }
>> -
>>      template<typename _Mapping, typename... _Indices>
>>        constexpr typename _Mapping::index_type
>>        __linear_index_strides(const _Mapping& __m, _Indices... __indices)
>>        noexcept
>>        {
>>         using _IndexType = typename _Mapping::index_type;
>>         _IndexType __res = 0;
>>         if constexpr (sizeof...(__indices) > 0)
>>           {
>>             auto __update = [&, __pos = 0u](_IndexType __idx) mutable
>> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h 
>> b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
>> index e9172c13455..2f79b9dd3b5 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/int_like.h
>> @@ -2,38 +2,47 @@
>>  #define TEST_MDSPAN_INT_LIKE_H
>>
>>  enum class CustomIndexKind
>>  {
>>    Const,
>>    Throwing,
>>    Mutating,
>>    RValue,
>>  };
>>
>> -template<CustomIndexKind Kind>
>> +template<CustomIndexKind Kind, bool Copyable = false>
>>    class CustomIndexType
>>    {
>>    public:
>>      explicit
>>      CustomIndexType(int i)
>>      : value(i)
>>      { }
>>
>> -    CustomIndexType() = delete;
>> -    CustomIndexType(const CustomIndexType&) = delete;
>> -    CustomIndexType(CustomIndexType&&) = delete;
>> +    CustomIndexType() requires(Copyable) = default;
>> +    CustomIndexType() requires(!Copyable) = delete;
>>
>> -    const CustomIndexType&
>> -    operator=(const CustomIndexType&) = delete;
>> +    CustomIndexType(const CustomIndexType&) requires(Copyable) = default;
>> +    CustomIndexType(const CustomIndexType&) requires(!Copyable) = delete;
>>
>> -    const CustomIndexType&
>> -    operator=(CustomIndexType&&) = delete;
>> +    CustomIndexType(CustomIndexType&&) requires(Copyable) = default;
>> +    CustomIndexType(CustomIndexType&&) requires(!Copyable) = delete;
>> +
>> +    CustomIndexType&
>> +    operator=(const CustomIndexType&) requires(Copyable) = default;
>> +    CustomIndexType&
>> +    operator=(const CustomIndexType&) requires(!Copyable) = delete;
>> +
>> +    CustomIndexType&
>> +    operator=(CustomIndexType&&) requires(Copyable) = default;
>> +    CustomIndexType&
>> +    operator=(CustomIndexType&&) requires(!Copyable) = delete;
>>
>>      constexpr
>>      operator int() const noexcept
>>      requires (Kind == CustomIndexKind::Const)
>>      { return value; }
>>
>>      constexpr
>>      operator int() const
>>      requires (Kind == CustomIndexKind::Throwing)
>>      { return value; }
>> diff --git 
>> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h 
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
>> similarity index 70%
>> rename from 
>> libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h
>> rename to libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
>> index 788ae82fcc4..619cab53b9e 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_traits.h
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layout_traits.h
>> @@ -1,15 +1,21 @@
>> -#ifndef TEST_MDSPAN_PADDED_TRAITS_H
>> -#define TEST_MDSPAN_PADDED_TRAITS_H
>> +#ifndef TEST_MDSPAN_LAYOUT_TRAITS_H
>> +#define TEST_MDSPAN_LAYOUT_TRAITS_H
>>
>>  #include <algorithm>
>>
>> +enum class PaddingSide
>> +{
>> +  Left,
>> +  Right
>> +};
>> +
>>  template<typename Layout>
>>    constexpr static bool is_left_padded = false;
>>
>>  #if __cplusplus > 202302L
>>  template<size_t PaddingValue>
>>    constexpr static bool 
>> is_left_padded<std::layout_left_padded<PaddingValue>>
>>      = true;
>>  #endif
>>
>>  template<typename Layout>
>> @@ -19,53 +25,61 @@ template<typename Layout>
>>  template<size_t PaddingValue>
>>    constexpr static bool 
>> is_right_padded<std::layout_right_padded<PaddingValue>>
>>      = true;
>>  #endif
>>
>>  template<typename Layout>
>>    constexpr bool
>>    is_padded_layout = is_left_padded<Layout> || is_right_padded<Layout>;
>>
>>  #if __cplusplus > 202302L
>> +template<PaddingSide Side, typename Layout>
>> +  constexpr bool
>> +  is_same_padded;
>> +
>> +template<typename Layout>
>> +  constexpr bool
>> +  is_same_padded<PaddingSide::Left, Layout> = is_left_padded<Layout>;
>> +
>> +template<typename Layout>
>> +  constexpr bool
>> +  is_same_padded<PaddingSide::Right, Layout> = is_right_padded<Layout>;
>> +
>>  template<typename Extents>
>>    constexpr auto
>>    dynamic_extents_array(const Extents& exts)
>>    {
>>      std::array<typename Extents::index_type, Extents::rank()> ret;
>>      for(size_t i = 0; i < Extents::rank(); ++i)
>>        ret[i] = exts.extent(i);
>>      return ret;
>>    }
>>
>> -enum class PaddingSide
>> -{
>> -  Left,
>> -  Right
>> -};
>> -
>>  struct DeducePaddingSide
>>  {
>>    template<template<size_t> typename Layout>
>>      constexpr static PaddingSide
>>      from_template()
>>      {
>>        if constexpr (std::same_as<Layout<0>, std::layout_left_padded<0>>)
>>         return PaddingSide::Left;
>>        else
>>         return PaddingSide::Right;
>>      }
>>
>>    template<typename Layout>
>>      constexpr static PaddingSide
>>      from_typename()
>>      {
>> -      if constexpr (is_left_padded<Layout>)
>> +      if constexpr (std::same_as<Layout, std::layout_left>)
>> +       return PaddingSide::Left;
>> +      else if constexpr (is_left_padded<Layout>)
>>         return PaddingSide::Left;
>>        else
>>         return PaddingSide::Right;
>>      }
>>  };
>>
>>  template<PaddingSide Side>
>>    struct LayoutTraits;
>>
>>  template<>
>> @@ -77,22 +91,32 @@ template<>
>>      template<typename Extents>
>>        using extents_type = Extents;
>>
>>      template<typename Extents>
>>        constexpr static extents_type<Extents>
>>        make_extents(const Extents& exts)
>>        { return exts; }
>>
>>      template<typename T, size_t N>
>>        constexpr static std::array<T, N>
>> -      make_array(const std::array<T, N>& expected)
>> -      { return expected; }
>> +      make_array(const std::array<T, N>& a)
>> +      { return a; }
>> +
>> +    template<typename... Indices>
>> +      constexpr static auto
>> +      make_indices(Indices... indices)
>> +      { return std::array{indices...}; }
>> +
>> +    template<typename... Ts>
>> +      constexpr static std::tuple<Ts...>
>> +      make_tuple(const std::tuple<Ts...>& tup)
>> +      { return tup; }
>>
>>      template<typename Mapping>
>>        constexpr static auto
>>        padded_stride(const Mapping& m)
>>        { return m.stride(1); }
>>
>>      template<typename Extents>
>>        constexpr static auto
>>        padded_extent(const Extents& exts)
>>        { return exts.extent(0); }
>> @@ -121,20 +145,39 @@ template<>
>>        using extents_type = decltype(make_extents(std::declval<Extents>()));
>>
>>      template<typename T, size_t N>
>>        constexpr static std::array<T, N>
>>        make_array(std::array<T, N> a)
>>        {
>>         std::ranges::reverse(a);
>>         return a;
>>        }
>>
>> +    template<typename... Indices>
>> +      constexpr static auto
>> +      make_indices(Indices... indices)
>> +      { return make_array(std::array{indices...}); }
>> +
>> +    template<typename... Ts>
>> +      constexpr static auto
>> +      make_tuple(const std::tuple<Ts...>& tup)
>> +      {
>> +       constexpr size_t rank = sizeof...(Ts);
>> +       auto impl = [&]<size_t... I>(std::index_sequence<I...>)
>> +       {
>> +         auto idx = [rank](size_t i) consteval
>> +         { return rank - 1 - i; };
>> +         return std::tuple<Ts...[idx(I)]...>{get<idx(I)>(tup)...};
>> +       };
>> +       return impl(std::make_index_sequence<rank>());
>> +      }
>> +
>>      template<typename Mapping>
>>        constexpr static auto
>>        padded_stride(const Mapping& m)
>>        {
>>         auto rank = Mapping::extents_type::rank();
>>         return m.stride(rank - 2);
>>        }
>>
>>      template<typename Extents>
>>        constexpr static auto
>> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc 
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
>> index 27065a0dfc6..80ae5d8d56a 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/ctors.cc
>> @@ -1,14 +1,14 @@
>>  // { dg-do run { target c++23 } }
>>  #include <mdspan>
>>
>> -#include "padded_traits.h"
>> +#include "../layout_traits.h"
>>  #include <cstdint>
>>  #include <testsuite_hooks.h>
>>
>>  constexpr size_t dyn = std::dynamic_extent;
>>
>>  template<typename Mapping, typename IndexType, size_t... Extents>
>>    constexpr void
>>    verify(std::extents<IndexType, Extents...> oexts)
>>    {
>>      auto m = Mapping(oexts);
>> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc 
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
>> index d1486e4e11c..17cfac54113 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/mapping.cc
>> @@ -1,15 +1,15 @@
>>  // { dg-do run { target c++23 } }
>>  #include <mdspan>
>>
>>  #include "../int_like.h"
>> -#include "padded_traits.h"
>> +#include "../layout_traits.h"
>>  #include <cstdint>
>>  #include <testsuite_hooks.h>
>>
>>  constexpr size_t dyn = std::dynamic_extent;
>>
>>  template<typename Mapping>
>>    concept has_static_is_exhaustive = requires
>>    {
>>      { Mapping::is_exhaustive() } -> std::same_as<bool>;
>>    };
>> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc 
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
>> index cf4821a3c74..19fdf93ce0d 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded.cc
>> @@ -1,16 +1,16 @@
>>  // { dg-do run { target c++26 } }
>>  #include <mdspan>
>>
>>  #include <cstdint>
>>  #include "../int_like.h"
>> -#include "padded_traits.h"
>> +#include "../layout_traits.h"
>>  #include <testsuite_hooks.h>
>>
>>  constexpr size_t dyn = std::dynamic_extent;
>>
>>  template<template<size_t> typename Layout>
>>    constexpr bool
>>    test_representable_padded_size()
>>    {
>>      using Traits = LayoutTraits<DeducePaddingSide::from_template<Layout>()>;
>>      {
>> diff --git 
>> a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc 
>> b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
>> index a758f74287f..4073f683822 100644
>> --- a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
>> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/padded_neg.cc
>> @@ -1,14 +1,14 @@
>>  // { dg-do compile { target c++26 } }
>>  #include <mdspan>
>>
>> -#include "padded_traits.h"
>> +#include "../layout_traits.h"
>>  #include <cstdint>
>>
>>  constexpr size_t dyn = std::dynamic_extent;
>>
>>  template<template<size_t> typename Layout>
>>    constexpr bool
>>    test_from_extens_representable_sta()
>>    {
>>      using E1 = std::extents<uint8_t, 8, 128>;
>>      auto m = typename Layout<dyn>::mapping(E1{}); // { dg-error "required 
>> from" }
>> --
>> 2.51.2
>>

Reply via email to