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 | 6 +- .../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 | 27 ++++++++ .../testsuite/23_containers/mdspan/version.cc | 8 +++ 10 files changed, 249 insertions(+), 2 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 9afb9304fb5..a1991d55e7f 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(*)[]> + 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 26d4e7098eb..baf13d6f3b1 100644 --- a/libstdc++-v3/src/c++23/std.cc.in +++ b/libstdc++-v3/src/c++23/std.cc.in @@ -1858,8 +1858,10 @@ export namespace std using std::layout_right; using std::layout_stride; using std::default_accessor; - using std::mdspan; - // FIXME layout_left_padded, layout_right_padded, aligned_accessor, mdsubspan +#if __glibcxx_aligned_accessor + using std::aligned_accessor; +#endif + // FIXME layout_left_padded, layout_right_padded and submdspan } #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 600d152b690..f97946bd276 100644 --- a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc +++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc @@ -98,10 +98,32 @@ static_assert(test_class_properties<std::default_accessor<double>>()); static_assert(test_accessor_policy<std::default_accessor<double>>()); static_assert(test_ctor<DefaultAccessorTrait>()); +#ifdef __glibcxx_aligned_accessor +struct AlignedAccessorTrait +{ + template<typename T> + using type = std::aligned_accessor<T, alignof(T)>; +}; + +static_assert(test_class_properties<std::aligned_accessor<double, + sizeof(double)>>()); +static_assert(test_accessor_policy<std::aligned_accessor<double, + sizeof(double)>>()); +static_assert(test_accessor_policy<std::aligned_accessor<double, + 2*sizeof(double)>>()); +static_assert(test_ctor<AlignedAccessorTrait>()); +#endif + template<typename A> constexpr size_t accessor_alignment = sizeof(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) @@ -137,5 +159,10 @@ main() { test_all<std::default_accessor<double>>(); static_assert(test_all<std::default_accessor<double>>()); + +#ifdef __glibcxx_aligned_accessor + test_all<std::aligned_accessor<double, 4*sizeof(double)>>(); + static_assert(test_all<std::aligned_accessor<double, 4*sizeof(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