[PATCH v4 2/2] libstdc++: Implement aligned_accessor from mdspan [PR120994]
Tomasz Kaminski
tkaminsk@redhat.com
Thu Aug 14 12:13:16 GMT 2025
On Mon, Aug 4, 2025 at 1:03 PM Luc Grosheintz <luc.grosheintz@gmail.com>
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.grosheintz@gmail.com>
> ---
>
This is also LGTM, thanks for the update. I have added it to my local
branch,
and am running a test suite now. I will respond on PATCH 0 once the test
will be done.
> 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)
> + 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250814/7c5c799b/attachment-0001.htm>
More information about the Libstdc++
mailing list