Sorry, I'll continue working another day. This commit is
broken; please ignore.
On 6/27/25 13:15, 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.groshei...@gmail.com>
---
Changes since v4:
* Test types with different cv-qualifiers.
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..62ac791f0aa
--- /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<const double>,
+ std::default_accessor<double>>);
+ static_assert(!std::is_constructible_v<std::default_accessor<const Derived>,
+ std::default_accessor<Derived>>);
+
+ // T <-> volatile T
+ static_assert(std::is_convertible_v<std::default_accessor<double>,
+ std::default_accessor<volatile double>>);
+ static_assert(!std::is_constructible_v<std::default_accessor<volatile
double>,
+ std::default_accessor<double>>);
+
+ // 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" }