aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuc Grosheintz <luc.grosheintz@gmail.com>2025-08-04 12:59:27 +0200
committerTomasz Kamiński <tkaminsk@redhat.com>2025-08-21 11:55:02 +0200
commitd147e7a20a1372d8ea0af3185737bd6f46585569 (patch)
treea23c49ad088797d336709c792d7da35c52a21e40
parent5227ec972a59417a3fb3417388ba119a025b5aa6 (diff)
downloadgcc-d147e7a20a1372d8ea0af3185737bd6f46585569.zip
gcc-d147e7a20a1372d8ea0af3185737bd6f46585569.tar.gz
gcc-d147e7a20a1372d8ea0af3185737bd6f46585569.tar.bz2
libstdc++: Implement aligned_accessor from mdspan [PR120994]
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. Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com> Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
-rw-r--r--libstdc++-v3/include/bits/version.def10
-rw-r--r--libstdc++-v3/include/bits/version.h10
-rw-r--r--libstdc++-v3/include/std/mdspan53
-rw-r--r--libstdc++-v3/src/c++23/std.cc.in9
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/aligned_neg.cc33
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_access_neg.cc23
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/debug/aligned_offset_neg.cc23
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc31
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/version.cc8
9 files changed, 197 insertions, 3 deletions
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 56ad9ee..9d5122f 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1026,6 +1026,16 @@ ftms = {
};
ftms = {
+ name = aligned_accessor;
+ values = {
+ v = 202411;
+ cxxmin = 26;
+ extra_cond = "__glibcxx_assume_aligned "
+ "&& __glibcxx_is_sufficiently_aligned";
+ };
+};
+
+ftms = {
name = ssize;
values = {
v = 201902;
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 51805d2..6feeaa4 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 b7b4375..6c7469c 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -38,7 +38,12 @@
#include <type_traits>
#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
@@ -1184,6 +1189,54 @@ _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));
+
+ 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 (_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 1596459..4888b8b 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1865,10 +1865,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 0000000..f36ebb1
--- /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 "ElementType must not be an array type" }
+// { dg-prune-output "ElementType must not be an abstract" }
+// { dg-prune-output "static assertion failed" } // no message for alignment being too small
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 0000000..3511cef
--- /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 0000000..319da5f
--- /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 66009ad..31cb13e 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 7520602..1882600 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