On 04/08/25 12:59 +0200, 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_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               | 54 +++++++++++++++++++
libstdc++-v3/src/c++23/std.cc.in              |  9 ++--
.../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 | 31 +++++++++++
.../testsuite/23_containers/mdspan/version.cc |  8 +++
9 files changed, 198 insertions(+), 3 deletions(-)
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 691d4836262..9ac283347ce 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
@@ -1055,6 +1060,55 @@ _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)

I think the opening '(' could be after the && but it doesn't really
matter, since evaluating that second operand is very cheap.

But it might help to reorder the two expressions, so that we check the
cheap one first and don't check is_convertible_v unless we really need
to?

      template<typename _OElementType, size_t _OByteAlignment>
        requires (_OByteAlignment >= byte_alignment)
            &&  is_convertible_v<_OElementType(*)[], element_type(*)[]>

+       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<element_type(*)[], _OElementType(*)[]>
+       constexpr
+       operator default_accessor<_OElementType>() const noexcept
+       { return {}; }
+
+      constexpr reference
+      access(data_handle_type __p, size_t __i) const noexcept
+      { 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
+      { 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_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 66009ad89c0..31cb13ed431 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
@@ -97,10 +97,36 @@ 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>());
+static_assert(test_ctor<OverAlignedAccessorTrait<2>::type,
+                       std::default_accessor, false>());
+static_assert(test_ctor<OverAlignedAccessorTrait<2>::type,
+                       OverAlignedAccessorTrait<4>::type>());
+static_assert(test_ctor<std::default_accessor,
+                       OverAlignedAccessorTrait<2>::type>());
+static_assert(!std::is_constructible_v<std::aligned_accessor<char, 4>,
+                                      std::aligned_accessor<char, 2>>);
+#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)
@@ -136,5 +162,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
--
2.50.0



Reply via email to