<div dir="ltr"><div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Jul 3, 2025 at 12:38 PM Luc Grosheintz <<a href="mailto:luc.grosheintz@gmail.com" target="_blank">luc.grosheintz@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This commit completes the implementation of P2897R7 by implementing and<br>
testing the template class aligned_accessor.<br>
<br>
libstdc++-v3/ChangeLog:<br>
<br>
        * include/bits/version.def (aligned_accessor): Add.<br>
        * include/bits/version.h: Regenerate.<br>
        * include/std/mdspan (aligned_accessor): New class.<br>
        * src/c++23/<a href="http://std.cc.in" rel="noreferrer" target="_blank">std.cc.in</a> (aligned_accessor): Add.<br>
        * testsuite/23_containers/mdspan/accessors/generic.cc: Add tests<br>
        for aligned_accessor.<br>
        * testsuite/23_containers/mdspan/accessors/aligned.cc: New test.<br>
        * testsuite/23_containers/mdspan/accessors/aligned_ftm.cc: New test.<br>
        * testsuite/23_containers/mdspan/accessors/aligned_neg.cc: New test.<br>
---<br>
 libstdc++-v3/include/bits/version.def         | 10 +++<br>
 libstdc++-v3/include/bits/version.h           | 10 +++<br>
 libstdc++-v3/include/std/mdspan               | 72 +++++++++++++++++++<br>
 libstdc++-v3/src/c++23/<a href="http://std.cc.in" rel="noreferrer" target="_blank">std.cc.in</a>              |  3 +-<br>
 .../23_containers/mdspan/accessors/aligned.cc | 43 +++++++++++<br>
 .../mdspan/accessors/aligned_ftm.cc           |  6 ++<br>
 .../mdspan/accessors/aligned_neg.cc           | 33 +++++++++<br>
 .../accessors/debug/aligned_access_neg.cc     | 23 ++++++<br>
 .../accessors/debug/aligned_offset_neg.cc     | 23 ++++++<br>
 .../23_containers/mdspan/accessors/generic.cc | 27 +++++++<br>
 10 files changed, 249 insertions(+), 1 deletion(-)<br>
 create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned.cc<br>
 create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_ftm.cc<br>
 create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc<br>
 create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc<br>
 create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc<br>
<br>
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def<br>
index a2695e67716..42445165b91 100644<br>
--- a/libstdc++-v3/include/bits/version.def<br>
+++ b/libstdc++-v3/include/bits/version.def<br>
@@ -1022,6 +1022,16 @@ ftms = {<br>
   };<br>
 };<br>
<br>
+ftms = {<br>
+  name = aligned_accessor;<br>
+  values = {<br>
+    v = 202411;<br>
+    cxxmin = 26;<br>
+    extra_cond = "__glibcxx_assume_aligned "<br>
+    "&& __glibcxx_is_sufficiently_aligned";<br>
+  };<br>
+};<br>
+<br>
 ftms = {<br>
   name = ssize;<br>
   values = {<br>
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h<br>
index 1b17a965239..3efa7b1baae 100644<br>
--- a/libstdc++-v3/include/bits/version.h<br>
+++ b/libstdc++-v3/include/bits/version.h<br>
@@ -1143,6 +1143,16 @@<br>
 #endif /* !defined(__cpp_lib_mdspan) && defined(__glibcxx_want_mdspan) */<br>
 #undef __glibcxx_want_mdspan<br>
<br>
+#if !defined(__cpp_lib_aligned_accessor)<br>
+# if (__cplusplus >  202302L) && (__glibcxx_assume_aligned && __glibcxx_is_sufficiently_aligned)<br>
+#  define __glibcxx_aligned_accessor 202411L<br>
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_aligned_accessor)<br>
+#   define __cpp_lib_aligned_accessor 202411L<br>
+#  endif<br>
+# endif<br>
+#endif /* !defined(__cpp_lib_aligned_accessor) && defined(__glibcxx_want_aligned_accessor) */<br>
+#undef __glibcxx_want_aligned_accessor<br>
+<br>
 #if !defined(__cpp_lib_ssize)<br>
 # if (__cplusplus >= 202002L)<br>
 #  define __glibcxx_ssize 201902L<br>
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan<br>
index c72a64094b7..6eb804bf9a0 100644<br>
--- a/libstdc++-v3/include/std/mdspan<br>
+++ b/libstdc++-v3/include/std/mdspan<br>
@@ -39,7 +39,12 @@<br>
 #include <limits><br>
 #include <utility><br>
<br>
+#if __cplusplus > 202302L<br>
+#include <bits/align.h><br>
+#endif<br>
+<br>
 #define __glibcxx_want_mdspan<br>
+#define __glibcxx_want_aligned_accessor<br>
 #include <bits/version.h><br>
<br>
 #ifdef __glibcxx_mdspan<br>
@@ -1035,6 +1040,73 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION<br>
       { return __p + __i; }<br>
     };<br>
<br>
+#ifdef __glibcxx_aligned_accessor<br>
+  template<typename _ElementType, size_t _ByteAlignment><br>
+    struct aligned_accessor<br>
+    {<br>
+      static_assert(has_single_bit(_ByteAlignment),<br>
+       "ByteAlignment must be a power of two");<br>
+      static_assert(_ByteAlignment >= alignof(_ElementType),<br>
+       "ByteAlignment is too small for ElementType");<br>
+      static_assert(!is_array_v<_ElementType>,<br>
+       "ElementType must not be an array type");<br>
+      static_assert(!is_abstract_v<_ElementType>,<br>
+       "ElementType must not be an abstract class type");<br>
+<br>
+      using offset_policy = default_accessor<_ElementType>;<br>
+      using element_type = _ElementType;<br>
+      using reference = element_type&;<br>
+      using data_handle_type = element_type*;<br>
+<br>
+      static constexpr size_t byte_alignment = _ByteAlignment;<br>
+<br>
+      constexpr<br>
+      aligned_accessor() noexcept = default;<br>
+<br>
+      template<typename _OElementType, size_t _OByteAlignment><br>
+       requires (is_convertible_v<_OElementType(*)[], element_type(*)[]><br>
+           && _OByteAlignment >= byte_alignment)<br>
+       constexpr<br>
+       aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>)<br>
+       noexcept<br>
+       { }<br>
+<br>
+      template<typename _OElementType><br>
+       requires is_convertible_v<_OElementType(*)[], element_type(*)[]><br>
+       constexpr explicit<br>
+       aligned_accessor(default_accessor<_OElementType>) noexcept<br>
+       { }<br>
+<br>
+      template<typename _OElementType><br>
+       requires is_convertible_v<_OElementType(*)[], element_type(*)[]><br>
+       constexpr<br>
+       operator default_accessor<_OElementType>() const noexcept<br>
+       { return {}; }<br>
+<br>
+      constexpr reference<br>
+      access(data_handle_type __p, size_t __i) const noexcept<br>
+      {<br>
+       if !consteval<br>
+         {<br>
+           _GLIBCXX_DEBUG_ASSERT(<br>
+             std::is_sufficiently_aligned<_ByteAlignment>(__p));<br>
+         }<br></blockquote><div>I would not add this check, as the purpose of this accessor is to assume aligned,<br></div><div>and that should be checked during mdspan construction, however we do not currently have a</div><div>way to do so.<br></div><div>Such a check is currently performed anyway by assume_aligned, and in my opinion should stay there.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+       return std::assume_aligned<byte_alignment>(__p)[__i];<br>
+      }<br>
+<br>
+      constexpr typename offset_policy::data_handle_type<br>
+      offset(data_handle_type __p, size_t __i) const noexcept<br>
+      {<br>
+       if !consteval<br>
+         {<br>
+           _GLIBCXX_DEBUG_ASSERT(<br>
+             std::is_sufficiently_aligned<_ByteAlignment>(__p));<br>
+         }<br>
+       return std::assume_aligned<byte_alignment>(__p) + __i;<br>
+      }<br>
+    };<br>
+#endif<br>
+<br>
 _GLIBCXX_END_NAMESPACE_VERSION<br>
 }<br>
 #endif<br>
diff --git a/libstdc++-v3/src/c++23/<a href="http://std.cc.in" rel="noreferrer" target="_blank">std.cc.in</a> b/libstdc++-v3/src/c++23/<a href="http://std.cc.in" rel="noreferrer" target="_blank">std.cc.in</a><br>
index 6f4214ed3a7..02e1713bdc3 100644<br>
--- a/libstdc++-v3/src/c++23/<a href="http://std.cc.in" rel="noreferrer" target="_blank">std.cc.in</a><br>
+++ b/libstdc++-v3/src/c++23/<a href="http://std.cc.in" rel="noreferrer" target="_blank">std.cc.in</a><br>
@@ -1851,7 +1851,8 @@ export namespace std<br>
   using std::layout_right;<br>
   using std::layout_stride;<br>
   using std::default_accessor;<br>
-  // FIXME layout_left_padded, layout_right_padded, aligned_accessor and mdspan<br>
+  using std::aligned_accessor;<br>
+  // FIXME layout_left_padded, layout_right_padded and mdspan<br>
 }<br>
 #endif<br>
<br>
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned.cc<br>
new file mode 100644<br>
index 00000000000..75581d3eb70<br>
--- /dev/null<br>
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned.cc<br>
@@ -0,0 +1,43 @@<br>
+// { dg-do compile { target c++26 } }<br>
+#include <mdspan><br>
+<br>
+#include <testsuite_hooks.h><br>
+<br>
+constexpr bool<br>
+test_from_other()<br>
+{<br>
+  std::aligned_accessor<double, 4*sizeof(double)> a4;<br>
+  [[maybe_unused]] std::aligned_accessor<double, 2*sizeof(double)> a2(a4);<br>
+  static_assert(std::is_nothrow_convertible_v<std::aligned_accessor<char, 4>,<br>
+                                             std::aligned_accessor<char, 2>>);<br>
+  static_assert(!std::is_convertible_v<std::aligned_accessor<char, 2>,<br>
+                                      std::aligned_accessor<char, 4>>);<br></blockquote><div>I would check !is_cosntructible, to indicate that there is no explicit constructor. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  return true;<br>
+}<br>
+static_assert(test_from_other());<br>
+<br>
+constexpr bool<br>
+test_from_default()<br>
+{<br>
+  std::default_accessor<double> ad;<br>
+  [[maybe_unused]] std::aligned_accessor<double, 4*sizeof(double)> a4(ad);<br>
+  static_assert(!std::is_convertible_v<std::default_accessor<char>,<br>
+                                      std::aligned_accessor<char, 1>>);<br>
+  static_assert(!std::is_convertible_v<std::default_accessor<char>,<br>
+                                      std::aligned_accessor<char, 2>>);<br>
+  static_assert(std::is_nothrow_constructible_v<<br>
+      std::aligned_accessor<char, 4>, std::default_accessor<char>>);<br>
+  return true;<br>
+}<br>
+static_assert(test_from_default());<br>
+<br>
+constexpr bool<br>
+test_to_default()<br>
+{<br>
+  std::aligned_accessor<double, 4*sizeof(double)> a4;<br>
+  [[maybe_unused]] std::default_accessor<double> ad = a4;<br>
+  static_assert(std::is_nothrow_convertible_v<std::aligned_accessor<char, 2>,<br>
+                                             std::default_accessor<char>>);<br>
+  return true;<br>
+}<br>
+static_assert(test_to_default());<br>
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_ftm.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_ftm.cc<br>
new file mode 100644<br>
index 00000000000..361bf750c33<br>
--- /dev/null<br>
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_ftm.cc<br>
@@ -0,0 +1,6 @@<br>
+// { dg-do compile { target c++26 } }<br>
+#include <mdspan><br>
+<br>
+#ifndef __cpp_lib_aligned_accessor<br>
+#error "Missing FTM"<br></blockquote><div>Updated how this test is performed. And I would rename this file to version.</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+#endif<br>
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc<br>
new file mode 100644<br>
index 00000000000..46d80bf4083<br>
--- /dev/null<br>
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc<br>
@@ -0,0 +1,33 @@<br>
+// { dg-do compile { target c++26 } }<br>
+#include<mdspan><br>
+<br>
+#include <cstdint><br>
+<br>
+std::aligned_accessor<uint32_t, 0> a;          // { dg-error "required from here" }<br>
+std::aligned_accessor<uint32_t, 7> b;          // { dg-error "required from here" }<br>
+std::aligned_accessor<uint32_t, size_t(-1)> c; // { dg-error "required from here" }<br>
+<br>
+std::aligned_accessor<uint32_t, 2> d;          // { dg-error "required from here" }<br>
+<br>
+std::aligned_accessor<int[2], 32> e;           // { dg-error "required from here" }<br>
+<br>
+class Abstract<br>
+{<br>
+  virtual void<br>
+  foo() const = 0;<br>
+};<br>
+<br>
+class Derived : public Abstract<br>
+{<br>
+  void<br>
+  foo() const override<br>
+  { }<br>
+};<br>
+<br>
+std::aligned_accessor<Derived, alignof(int)> f_ok;<br>
+std::aligned_accessor<Abstract, alignof(int)> f_err; // { dg-error "required from here" }<br>
+<br>
+// { dg-prune-output "ByteAlignment must be a power of two" }<br>
+// { dg-prune-output "ByteAlignment is too small for ElementType" }<br>
+// { dg-prune-output "ElementType must not be an array type" }<br>
+// { dg-prune-output "ElementType must not be an abstract" }<br>
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<br>
new file mode 100644<br>
index 00000000000..3511cef1c3a<br>
--- /dev/null<br>
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc<br></blockquote><div>Again, I feel like these negative checks belong to assume_alinged. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
@@ -0,0 +1,23 @@<br>
+// { dg-do run { target c++26 xfail *-*-* } }<br>
+// { dg-require-debug-mode "" }<br>
+<br>
+#include <mdspan><br>
+#include <array><br>
+<br>
+void<br>
+test_unaligned_access()<br>
+{<br>
+  constexpr size_t N = 4;<br>
+  alignas(N) std::array<char, 128> buffer{};<br>
+  auto* unaligned = buffer.data() + 1;<br>
+  auto a = std::aligned_accessor<char, N>{};<br>
+<br>
+  [[maybe_unused]] char x = a.access(unaligned, 0);<br>
+}<br>
+<br>
+int<br>
+main()<br>
+{<br>
+  test_unaligned_access();<br>
+  return 0;<br>
+};<br>
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<br>
new file mode 100644<br>
index 00000000000..319da5ffef3<br>
--- /dev/null<br>
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc<br>
@@ -0,0 +1,23 @@<br>
+// { dg-do run { target c++26 xfail *-*-* } }<br>
+// { dg-require-debug-mode "" }<br>
+<br>
+#include <mdspan><br>
+#include <array><br>
+<br>
+void<br>
+test_unaligned_offset()<br>
+{<br>
+  constexpr size_t N = 4;<br>
+  alignas(N) std::array<char, 128> buffer{};<br>
+  auto* unaligned = buffer.data() + 1;<br>
+  auto a = std::aligned_accessor<char, N>{};<br>
+<br>
+  [[maybe_unused]] char* x = a.offset(unaligned, 0);<br>
+}<br>
+<br>
+int<br>
+main()<br>
+{<br>
+  test_unaligned_offset();<br>
+  return 0;<br>
+};<br>
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc<br>
index 600d152b690..f97946bd276 100644<br>
--- a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc<br>
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc<br>
@@ -98,10 +98,32 @@ static_assert(test_class_properties<std::default_accessor<double>>());<br>
 static_assert(test_accessor_policy<std::default_accessor<double>>());<br>
 static_assert(test_ctor<DefaultAccessorTrait>());<br>
<br>
+#ifdef __glibcxx_aligned_accessor<br>
+struct AlignedAccessorTrait<br>
+{<br>
+  template<typename T><br>
+    using type = std::aligned_accessor<T, alignof(T)>;<br>
+};<br>
+<br>
+static_assert(test_class_properties<std::aligned_accessor<double,<br>
+                                                         sizeof(double)>>());<br>
+static_assert(test_accessor_policy<std::aligned_accessor<double,<br>
+                                                        sizeof(double)>>());<br>
+static_assert(test_accessor_policy<std::aligned_accessor<double,<br>
+                                                        2*sizeof(double)>>());<br>
+static_assert(test_ctor<AlignedAccessorTrait>());<br>
+#endif<br>
+<br>
 template<typename A><br>
   constexpr size_t<br>
   accessor_alignment = sizeof(typename A::element_type);<br>
<br>
+#ifdef __glibcxx_aligned_accessor<br>
+template<typename T, size_t N><br>
+  constexpr size_t<br>
+  accessor_alignment<std::aligned_accessor<T, N>> = N;<br>
+#endif<br>
+<br>
 template<typename Accessor><br>
   constexpr void<br>
   test_access(Accessor accessor)<br>
@@ -137,5 +159,10 @@ main()<br>
 {<br>
   test_all<std::default_accessor<double>>();<br>
   static_assert(test_all<std::default_accessor<double>>());<br>
+<br>
+#ifdef __glibcxx_aligned_accessor<br>
+  test_all<std::aligned_accessor<double, 4*sizeof(double)>>();<br>
+  static_assert(test_all<std::aligned_accessor<double, 4*sizeof(double)>>());<br>
+#endif<br>
   return 0;<br>
 }<br>
-- <br>
2.49.0<br>
<br>
</blockquote></div></div>
</div>