[PATCH 1/1] libstdc++: Implement default_accessor from mdspan.

Luc Grosheintz luc.grosheintz@gmail.com
Mon Jun 30 07:29:06 GMT 2025


Re: [PATCH 1/1] libstdc++: Implement default_accessor from mdspan.

Despite the Subject line, this is v6 and future versions will
not number single patches as 1/1 (hopefully).

On 6/30/25 09:23, Luc Grosheintz wrote:
> libstdc++-v3/ChangeLog:
> 
> 	* include/std/mdspan (default_accessor): New class.
> 	* src/c++23/std.cc.in: Register default_accessor.
> 	* testsuite/23_containers/mdspan/accessors/default.cc: New test.
> 	* testsuite/23_containers/mdspan/accessors/default_neg.cc: New test.
> 
> Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>
> ---
> 
> Version of v5 with all local changes included.
> 
>   libstdc++-v3/include/std/mdspan               | 31 ++++++
>   libstdc++-v3/src/c++23/std.cc.in              |  3 +-
>   .../23_containers/mdspan/accessors/default.cc | 99 +++++++++++++++++++
>   .../mdspan/accessors/default_neg.cc           | 23 +++++
>   4 files changed, 155 insertions(+), 1 deletion(-)
>   create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc
>   create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc
> 
> diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
> index 6dc2441f80b..c72a64094b7 100644
> --- a/libstdc++-v3/include/std/mdspan
> +++ b/libstdc++-v3/include/std/mdspan
> @@ -1004,6 +1004,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>         [[no_unique_address]] _S_strides_t _M_strides;
>       };
>   
> +  template<typename _ElementType>
> +    struct default_accessor
> +    {
> +      static_assert(!is_array_v<_ElementType>,
> +	"ElementType must not be an array type");
> +      static_assert(!is_abstract_v<_ElementType>,
> +	"ElementType must not be an abstract class type");
> +
> +      using offset_policy = default_accessor;
> +      using element_type = _ElementType;
> +      using reference = element_type&;
> +      using data_handle_type = element_type*;
> +
> +      constexpr
> +      default_accessor() noexcept = default;
> +
> +      template<typename _OElementType>
> +	requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
> +	constexpr
> +	default_accessor(default_accessor<_OElementType>) noexcept
> +	{ }
> +
> +      constexpr reference
> +      access(data_handle_type __p, size_t __i) const noexcept
> +      { return __p[__i]; }
> +
> +      constexpr data_handle_type
> +      offset(data_handle_type __p, size_t __i) const noexcept
> +      { return __p + __i; }
> +    };
> +
>   _GLIBCXX_END_NAMESPACE_VERSION
>   }
>   #endif
> diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
> index 9336118f5d9..e692caaa5f9 100644
> --- a/libstdc++-v3/src/c++23/std.cc.in
> +++ b/libstdc++-v3/src/c++23/std.cc.in
> @@ -1850,7 +1850,8 @@ export namespace std
>     using std::layout_left;
>     using std::layout_right;
>     using std::layout_stride;
> -  // FIXME layout_left_padded, layout_right_padded, default_accessor and mdspan
> +  using std::default_accessor;
> +  // FIXME layout_left_padded, layout_right_padded, aligned_accessor and mdspan
>   }
>   #endif
>   
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc
> new file mode 100644
> index 00000000000..c036f8ad10f
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc
> @@ -0,0 +1,99 @@
> +// { dg-do run { target c++23 } }
> +#include <mdspan>
> +
> +#include <testsuite_hooks.h>
> +
> +constexpr size_t dyn = std::dynamic_extent;
> +
> +template<typename Accessor>
> +  constexpr void
> +  test_accessor_policy()
> +  {
> +    static_assert(std::copyable<Accessor>);
> +    static_assert(std::is_nothrow_move_constructible_v<Accessor>);
> +    static_assert(std::is_nothrow_move_assignable_v<Accessor>);
> +    static_assert(std::is_nothrow_swappable_v<Accessor>);
> +  }
> +
> +constexpr bool
> +test_access()
> +{
> +  std::default_accessor<double> accessor;
> +  std::array<double, 5> a{10, 11, 12, 13, 14};
> +  VERIFY(accessor.access(a.data(), 0) == 10);
> +  VERIFY(accessor.access(a.data(), 4) == 14);
> +  return true;
> +}
> +
> +constexpr bool
> +test_offset()
> +{
> +  std::default_accessor<double> accessor;
> +  std::array<double, 5> a{10, 11, 12, 13, 14};
> +  VERIFY(accessor.offset(a.data(), 0) == a.data());
> +  VERIFY(accessor.offset(a.data(), 4) == a.data() + 4);
> +  return true;
> +}
> +
> +class Base
> +{ };
> +
> +class Derived : public Base
> +{ };
> +
> +constexpr void
> +test_ctor()
> +{
> +  // T -> T
> +  static_assert(std::is_nothrow_constructible_v<std::default_accessor<double>,
> +						std::default_accessor<double>>);
> +  static_assert(std::is_convertible_v<std::default_accessor<double>,
> +				      std::default_accessor<double>>);
> +
> +  // T -> const T
> +  static_assert(std::is_convertible_v<std::default_accessor<double>,
> +				      std::default_accessor<const double>>);
> +  static_assert(std::is_convertible_v<std::default_accessor<Derived>,
> +				      std::default_accessor<const Derived>>);
> +
> +  // const T -> T
> +  static_assert(!std::is_constructible_v<std::default_accessor<double>,
> +					 std::default_accessor<const double>>);
> +  static_assert(!std::is_constructible_v<std::default_accessor<Derived>,
> +					 std::default_accessor<const Derived>>);
> +
> +  // T <-> volatile T
> +  static_assert(std::is_convertible_v<std::default_accessor<int>,
> +				      std::default_accessor<volatile int>>);
> +  static_assert(!std::is_constructible_v<std::default_accessor<int>,
> +					 std::default_accessor<volatile int>>);
> +
> +  // size difference
> +  static_assert(!std::is_constructible_v<std::default_accessor<char>,
> +					 std::default_accessor<int>>);
> +
> +  // signedness
> +  static_assert(!std::is_constructible_v<std::default_accessor<int>,
> +					 std::default_accessor<unsigned int>>);
> +  static_assert(!std::is_constructible_v<std::default_accessor<unsigned int>,
> +					 std::default_accessor<int>>);
> +
> +  // Derived <-> Base
> +  static_assert(!std::is_constructible_v<std::default_accessor<Base>,
> +					 std::default_accessor<Derived>>);
> +  static_assert(!std::is_constructible_v<std::default_accessor<Derived>,
> +					 std::default_accessor<Base>>);
> +
> +}
> +
> +int
> +main()
> +{
> +  test_accessor_policy<std::default_accessor<double>>();
> +  test_access();
> +  static_assert(test_access());
> +  test_offset();
> +  static_assert(test_offset());
> +  test_ctor();
> +  return 0;
> +}
> diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc
> new file mode 100644
> index 00000000000..f8da2b569ca
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default_neg.cc
> @@ -0,0 +1,23 @@
> +// { dg-do compile { target c++23 } }
> +#include<mdspan>
> +
> +std::default_accessor<int[3]> a; // { dg-error "required from here" }
> +
> +class AbstractBase
> +{
> +  virtual void
> +  foo() const = 0;
> +};
> +
> +class Derived : public AbstractBase
> +{
> +  void
> +  foo() const override
> +  { }
> +};
> +
> +std::default_accessor<Derived> b_ok;
> +std::default_accessor<AbstractBase> b_err; // { dg-error "required from here"}
> +
> +// { dg-prune-output "ElementType must not be an array type" }
> +// { dg-prune-output "ElementType must not be an abstract" }



More information about the Libstdc++ mailing list