On Fri, Jul 25, 2025 at 10:37 AM Luc Grosheintz <luc.groshei...@gmail.com>
wrote:

>
>
> On 7/23/25 11:25, Luc Grosheintz wrote:
> > This commit completes the implementation of P2897R7 by implementing and
> > testing the template class aligned_accessor.
> >
> >       PR libstdc++/120994
> >
> > libstdc++-v3/ChangeLog:
> >
> >       * include/bits/version.def (aligned_accessor): Add.
> >       * include/bits/version.h: Regenerate.
> >       * include/std/mdspan (aligned_accessor): New class.
> >       * src/c++23/std.cc.in (aligned_accessor): Add.
> >       * testsuite/23_containers/mdspan/accessors/generic.cc: Add tests
> >       for aligned_accessor.
> >       * testsuite/23_containers/mdspan/accessors/aligned.cc: New test.
> >       * testsuite/23_containers/mdspan/accessors/aligned_neg.cc: New
> test.
> >       * testsuite/23_containers/mdspan/version.cc: Add test for
> >       __cpp_lib_aligned_accessor.
> >
> > Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
> > ---
> >   libstdc++-v3/include/bits/version.def         | 10 +++
> >   libstdc++-v3/include/bits/version.h           | 10 +++
> >   libstdc++-v3/include/std/mdspan               | 68 +++++++++++++++++++
> >   libstdc++-v3/src/c++23/std.cc.in              |  9 ++-
> >   .../23_containers/mdspan/accessors/aligned.cc | 43 ++++++++++++
> >   .../mdspan/accessors/aligned_neg.cc           | 33 +++++++++
> >   .../accessors/debug/aligned_access_neg.cc     | 23 +++++++
> >   .../accessors/debug/aligned_offset_neg.cc     | 23 +++++++
> >   .../23_containers/mdspan/accessors/generic.cc | 23 +++++++
> >   .../testsuite/23_containers/mdspan/version.cc |  8 +++
> >   10 files changed, 247 insertions(+), 3 deletions(-)
> >   create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned.cc
> >   create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc
> >   create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc
> >   create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc
> >
> > diff --git a/libstdc++-v3/include/bits/version.def
> b/libstdc++-v3/include/bits/version.def
> > index 56ad9ee9d4b..9d5122fed17 100644
> > --- a/libstdc++-v3/include/bits/version.def
> > +++ b/libstdc++-v3/include/bits/version.def
> > @@ -1025,6 +1025,16 @@ ftms = {
> >     };
> >   };
> >
> > +ftms = {
> > +  name = aligned_accessor;
> > +  values = {
> > +    v = 202411;
> > +    cxxmin = 26;
> > +    extra_cond = "__glibcxx_assume_aligned "
> > +    "&& __glibcxx_is_sufficiently_aligned";
> > +  };
> > +};
> > +
> >   ftms = {
> >     name = ssize;
> >     values = {
> > diff --git a/libstdc++-v3/include/bits/version.h
> b/libstdc++-v3/include/bits/version.h
> > index 51805d292f0..6feeaa4d15a 100644
> > --- a/libstdc++-v3/include/bits/version.h
> > +++ b/libstdc++-v3/include/bits/version.h
> > @@ -1149,6 +1149,16 @@
> >   #endif /* !defined(__cpp_lib_mdspan) && defined(__glibcxx_want_mdspan)
> */
> >   #undef __glibcxx_want_mdspan
> >
> > +#if !defined(__cpp_lib_aligned_accessor)
> > +# if (__cplusplus >  202302L) && (__glibcxx_assume_aligned &&
> __glibcxx_is_sufficiently_aligned)
> > +#  define __glibcxx_aligned_accessor 202411L
> > +#  if defined(__glibcxx_want_all) ||
> defined(__glibcxx_want_aligned_accessor)
> > +#   define __cpp_lib_aligned_accessor 202411L
> > +#  endif
> > +# endif
> > +#endif /* !defined(__cpp_lib_aligned_accessor) &&
> defined(__glibcxx_want_aligned_accessor) */
> > +#undef __glibcxx_want_aligned_accessor
> > +
> >   #if !defined(__cpp_lib_ssize)
> >   # if (__cplusplus >= 202002L)
> >   #  define __glibcxx_ssize 201902L
> > diff --git a/libstdc++-v3/include/std/mdspan
> b/libstdc++-v3/include/std/mdspan
> > index 7d17f32a836..4b2221bd070 100644
> > --- a/libstdc++-v3/include/std/mdspan
> > +++ b/libstdc++-v3/include/std/mdspan
> > @@ -39,7 +39,12 @@
> >   #include <limits>
> >   #include <utility>
> >
> > +#if __cplusplus > 202302L
> > +#include <bits/align.h>
> > +#endif
> > +
> >   #define __glibcxx_want_mdspan
> > +#define __glibcxx_want_aligned_accessor
> >   #include <bits/version.h>
> >
> >   #ifdef __glibcxx_mdspan
> > @@ -1062,6 +1067,69 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
> >         { return __p + __i; }
> >       };
> >
> > +#ifdef __glibcxx_aligned_accessor
> > +  template<typename _ElementType, size_t _ByteAlignment>
> > +    struct aligned_accessor
> > +    {
> > +      static_assert(has_single_bit(_ByteAlignment),
> > +     "ByteAlignment must be a power of two");
> > +      static_assert(_ByteAlignment >= alignof(_ElementType),
> > +     "ByteAlignment is too small for ElementType");
> > +
> > +      using offset_policy = default_accessor<_ElementType>;
> > +      using element_type = _ElementType;
> > +      using reference = element_type&;
> > +      using data_handle_type = element_type*;
> > +
> > +      static constexpr size_t byte_alignment = _ByteAlignment;
> > +
> > +      constexpr
> > +      aligned_accessor() noexcept = default;
> > +
> > +      template<typename _OElementType, size_t _OByteAlignment>
> > +     requires (is_convertible_v<_OElementType(*)[], element_type(*)[]>
> > +         && _OByteAlignment >= byte_alignment)
> > +     constexpr
> > +     aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>)
> > +     noexcept
> > +     { }
> > +
> > +      template<typename _OElementType>
> > +     requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
> > +     constexpr explicit
> > +     aligned_accessor(default_accessor<_OElementType>) noexcept
> > +     { }
> > +
> > +      template<typename _OElementType>
> > +     requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
>
> Should be:
>
>    requires is_convertible_v<element_type(*)[], _OElementType(*)[]>
>
> I'll generalize the test_ctor in generic.cc to accept two Accessors,
> then we can test this with the same rigour.
>
Good catch.
I am not sure about the generalization at this point, as:
* conversion between different accessor categories will be that common
* if the explicitness will match between accessors.
So I am just fine having a single test in aligned accessor now, but if you
find
it easier to express this in test_ctor, then no object to doing that.

Regards,
Tomasz

>
> > +     constexpr
> > +     operator default_accessor<_OElementType>() const noexcept
> > +     { return {}; }
> > +
> > +      constexpr reference
> > +      access(data_handle_type __p, size_t __i) const noexcept
> > +      {
> > +     if !consteval
> > +       {
> > +         _GLIBCXX_DEBUG_ASSERT(
> > +           std::is_sufficiently_aligned<_ByteAlignment>(__p));
> > +       }
> > +     return std::assume_aligned<byte_alignment>(__p)[__i];
> > +      }
> > +
> > +      constexpr typename offset_policy::data_handle_type
> > +      offset(data_handle_type __p, size_t __i) const noexcept
> > +      {
> > +     if !consteval
> > +       {
> > +         _GLIBCXX_DEBUG_ASSERT(
> > +           std::is_sufficiently_aligned<_ByteAlignment>(__p));
> > +       }
> > +     return std::assume_aligned<byte_alignment>(__p) + __i;
> > +      }
> > +    };
> > +#endif
> > +
> >     namespace __mdspan
> >     {
> >       template<typename _Extents, typename _IndexType, size_t _Nm>
> > diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/
> std.cc.in
> > index 24411476ba0..40d2fa03c5a 100644
> > --- a/libstdc++-v3/src/c++23/std.cc.in
> > +++ b/libstdc++-v3/src/c++23/std.cc.in
> > @@ -1858,10 +1858,13 @@ export namespace std
> >     using std::layout_right;
> >     using std::layout_stride;
> >     using std::default_accessor;
> > +#if __glibcxx_aligned_accessor
> > +  using std::aligned_accessor;
> > +#endif
> >     using std::mdspan;
> > -  // FIXME layout_left_padded, layout_right_padded, aligned_accessor,
> > -  // strided_slice, submdspan_mapping_result, full_extent_t,
> full_extent,
> > -  // submdspan_extents, mdsubspan
> > +  // FIXME layout_left_padded, layout_right_padded, strided_slice,
> > +  // submdspan_mapping_result, full_extent_t, full_extent,
> submdspan_extents,
> > +  // mdsubspan
> >   }
> >   #endif
> >
> > diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned.cc
> > new file mode 100644
> > index 00000000000..f84092f6d89
> > --- /dev/null
> > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned.cc
> > @@ -0,0 +1,43 @@
> > +// { dg-do compile { target c++26 } }
> > +#include <mdspan>
> > +
> > +#include <testsuite_hooks.h>
> > +
> > +constexpr bool
> > +test_from_other()
> > +{
> > +  std::aligned_accessor<double, 4*sizeof(double)> a4;
> > +  [[maybe_unused]] std::aligned_accessor<double, 2*sizeof(double)>
> a2(a4);
> > +
> static_assert(std::is_nothrow_convertible_v<std::aligned_accessor<char, 4>,
> > +                                           std::aligned_accessor<char,
> 2>>);
> > +  static_assert(!std::is_constructible_v<std::aligned_accessor<char, 4>,
> > +                                      std::aligned_accessor<char, 2>>);
> > +  return true;
> > +}
> > +static_assert(test_from_other());
> > +
> > +constexpr bool
> > +test_from_default()
> > +{
> > +  std::default_accessor<double> ad;
> > +  [[maybe_unused]] std::aligned_accessor<double, 4*sizeof(double)>
> a4(ad);
> > +  static_assert(!std::is_convertible_v<std::default_accessor<char>,
> > +                                    std::aligned_accessor<char, 1>>);
> > +  static_assert(!std::is_convertible_v<std::default_accessor<char>,
> > +                                    std::aligned_accessor<char, 2>>);
> > +  static_assert(std::is_nothrow_constructible_v<
> > +      std::aligned_accessor<char, 4>, std::default_accessor<char>>);
> > +  return true;
> > +}
> > +static_assert(test_from_default());
> > +
> > +constexpr bool
> > +test_to_default()
> > +{
> > +  std::aligned_accessor<double, 4*sizeof(double)> a4;
> > +  [[maybe_unused]] std::default_accessor<double> ad = a4;
> > +
> static_assert(std::is_nothrow_convertible_v<std::aligned_accessor<char, 2>,
> > +
>  std::default_accessor<char>>);
> > +  return true;
> > +}
> > +static_assert(test_to_default());
> > diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc
> > new file mode 100644
> > index 00000000000..46d80bf4083
> > --- /dev/null
> > +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc
> > @@ -0,0 +1,33 @@
> > +// { dg-do compile { target c++26 } }
> > +#include<mdspan>
> > +
> > +#include <cstdint>
> > +
> > +std::aligned_accessor<uint32_t, 0> a;          // { dg-error "required
> from here" }
> > +std::aligned_accessor<uint32_t, 7> b;          // { dg-error "required
> from here" }
> > +std::aligned_accessor<uint32_t, size_t(-1)> c; // { dg-error "required
> from here" }
> > +
> > +std::aligned_accessor<uint32_t, 2> d;          // { dg-error "required
> from here" }
> > +
> > +std::aligned_accessor<int[2], 32> e;           // { dg-error "required
> from here" }
> > +
> > +class Abstract
> > +{
> > +  virtual void
> > +  foo() const = 0;
> > +};
> > +
> > +class Derived : public Abstract
> > +{
> > +  void
> > +  foo() const override
> > +  { }
> > +};
> > +
> > +std::aligned_accessor<Derived, alignof(int)> f_ok;
> > +std::aligned_accessor<Abstract, alignof(int)> f_err; // { dg-error
> "required from here" }
> > +
> > +// { dg-prune-output "ByteAlignment must be a power of two" }
> > +// { dg-prune-output "ByteAlignment is too small for ElementType" }
> > +// { dg-prune-output "ElementType must not be an array type" }
> > +// { dg-prune-output "ElementType must not be an abstract" }
> > diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc
> > new file mode 100644
> > index 00000000000..3511cef1c3a
> > --- /dev/null
> > +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc
> > @@ -0,0 +1,23 @@
> > +// { dg-do run { target c++26 xfail *-*-* } }
> > +// { dg-require-debug-mode "" }
> > +
> > +#include <mdspan>
> > +#include <array>
> > +
> > +void
> > +test_unaligned_access()
> > +{
> > +  constexpr size_t N = 4;
> > +  alignas(N) std::array<char, 128> buffer{};
> > +  auto* unaligned = buffer.data() + 1;
> > +  auto a = std::aligned_accessor<char, N>{};
> > +
> > +  [[maybe_unused]] char x = a.access(unaligned, 0);
> > +}
> > +
> > +int
> > +main()
> > +{
> > +  test_unaligned_access();
> > +  return 0;
> > +};
> > diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc
> > new file mode 100644
> > index 00000000000..319da5ffef3
> > --- /dev/null
> > +++
> b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc
> > @@ -0,0 +1,23 @@
> > +// { dg-do run { target c++26 xfail *-*-* } }
> > +// { dg-require-debug-mode "" }
> > +
> > +#include <mdspan>
> > +#include <array>
> > +
> > +void
> > +test_unaligned_offset()
> > +{
> > +  constexpr size_t N = 4;
> > +  alignas(N) std::array<char, 128> buffer{};
> > +  auto* unaligned = buffer.data() + 1;
> > +  auto a = std::aligned_accessor<char, N>{};
> > +
> > +  [[maybe_unused]] char* x = a.offset(unaligned, 0);
> > +}
> > +
> > +int
> > +main()
> > +{
> > +  test_unaligned_offset();
> > +  return 0;
> > +};
> > diff --git
> a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
> > index c3350353aae..d420fe885aa 100644
> > --- a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
> > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
> > @@ -82,10 +82,28 @@ template<template<typename T> typename Accessor>
> >
> >   static_assert(test_properties<std::default_accessor>());
> >
> > +#ifdef __glibcxx_aligned_accessor
> > +template<size_t Mult>
> > +struct OverAlignedAccessorTrait
> > +{
> > +  template<typename T>
> > +    using type = std::aligned_accessor<T, Mult*alignof(T)>;
> > +};
> > +
> > +static_assert(test_properties<OverAlignedAccessorTrait<1>::type>());
> > +static_assert(test_properties<OverAlignedAccessorTrait<2>::type>());
> > +#endif
> > +
> >   template<typename A>
> >     constexpr size_t
> >     accessor_alignment = alignof(typename A::element_type);
> >
> > +#ifdef __glibcxx_aligned_accessor
> > +template<typename T, size_t N>
> > +  constexpr size_t
> > +  accessor_alignment<std::aligned_accessor<T, N>> = N;
> > +#endif
> > +
> >   template<typename Accessor>
> >     constexpr void
> >     test_access(Accessor accessor)
> > @@ -121,5 +139,10 @@ main()
> >   {
> >     test_all<std::default_accessor<double>>();
> >     static_assert(test_all<std::default_accessor<double>>());
> > +
> > +#ifdef __glibcxx_aligned_accessor
> > +  test_all<typename OverAlignedAccessorTrait<4>::type<double>>();
> > +  static_assert(test_all<typename
> OverAlignedAccessorTrait<4>::type<double>>());
> > +#endif
> >     return 0;
> >   }
> > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/version.cc
> b/libstdc++-v3/testsuite/23_containers/mdspan/version.cc
> > index 752060262a0..18826005971 100644
> > --- a/libstdc++-v3/testsuite/23_containers/mdspan/version.cc
> > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/version.cc
> > @@ -10,3 +10,11 @@
> >   #elif __cplusplus > 202302L && __cpp_lib_mdspan != 202406L
> >   #error "Feature test macro __cpp_lib_mdspan has the wrong value for
> C++26"
> >   #endif
> > +
> > +#if __cplusplus > 202302L
> > +#ifndef __cpp_lib_aligned_accessor
> > +#error "Feature test macro __cpp_lib_aligned_accessor is missing for
> <mdspan>"
> > +#elif __cpp_lib_aligned_accessor != 202411L
> > +#error "Feature test macro __cpp_lib_aligned_accessor has the wrong
> value"
> > +#endif
> > +#endif
>
>

Reply via email to