Implements the class mdspan as described in N4950, i.e. without P3029.
It also adds tests for mdspan.

libstdc++-v3/ChangeLog:

        * include/std/mdspan (mdspan): New class.
        * src/c++23/std.cc.in: Add std::mdspan.
        * testsuite/23_containers/mdspan/class_mandate_neg.cc: New test.
        * testsuite/23_containers/mdspan/mdspan.cc: New test.

Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
---
 libstdc++-v3/include/std/mdspan               | 253 +++++++++++++
 libstdc++-v3/src/c++23/std.cc.in              |   3 +-
 .../23_containers/mdspan/class_mandate_neg.cc |  32 ++
 .../testsuite/23_containers/mdspan/mdspan.cc  | 348 ++++++++++++++++++
 4 files changed, 635 insertions(+), 1 deletion(-)
 create mode 100644 
libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc
 create mode 100644 libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc

diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 8c6b7f49155..6d7da858032 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -1030,6 +1030,259 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       { return __p + __i; }
     };
 
+  template<typename _ElementType, typename _Extents,
+          typename _LayoutPolicy = layout_right,
+          typename _AccessorPolicy = default_accessor<_ElementType>>
+    class mdspan {
+      static_assert(__mdspan::__is_extents<_Extents>,
+       "Extents must be a specialization of std::extents");
+      static_assert(is_same_v<_ElementType,
+                             typename _AccessorPolicy::element_type>);
+
+    public:
+      using extents_type = _Extents;
+      using layout_type = _LayoutPolicy;
+      using accessor_type = _AccessorPolicy;
+      using mapping_type = typename layout_type::template 
mapping<extents_type>;
+      using element_type = _ElementType;
+      using value_type = remove_cv_t<element_type>;
+      using index_type = typename extents_type::index_type;
+      using size_type = typename extents_type::size_type;
+      using rank_type = typename extents_type::rank_type;
+      using data_handle_type = typename accessor_type::data_handle_type;
+      using reference = typename accessor_type::reference;
+
+      static constexpr rank_type
+      rank() noexcept { return extents_type::rank(); }
+
+      static constexpr rank_type
+      rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
+
+      static constexpr size_t
+      static_extent(rank_type __r) noexcept
+      { return extents_type::static_extent(__r); }
+
+      constexpr index_type
+      extent(rank_type __r) const noexcept { return extents().extent(__r); }
+
+      constexpr
+      mdspan()
+      requires (rank_dynamic() > 0 &&
+         is_default_constructible_v<data_handle_type> &&
+         is_default_constructible_v<mapping_type> &&
+         is_default_constructible_v<accessor_type>)
+      : _M_accessor{}, _M_mapping{}, _M_handle{}
+      { }
+
+      constexpr
+      mdspan(const mdspan& __other) = default;
+
+      constexpr
+      mdspan(mdspan&& __other) = default;
+
+      template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
+       requires ((sizeof...(_OIndexTypes) == rank()
+                  || sizeof...(_OIndexTypes) == rank_dynamic())
+           && is_constructible_v<mapping_type, extents_type>
+           && is_default_constructible_v<accessor_type>)
+       constexpr explicit
+       mdspan(data_handle_type __handle, _OIndexTypes... __exts)
+       : _M_accessor{},
+         _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)),
+         _M_handle(std::move(__handle))
+       { }
+
+      template<__mdspan::__valid_index_type<index_type> _OIndexType,
+              size_t _Nm>
+       requires ((_Nm == rank() || _Nm == rank_dynamic())
+                  && is_constructible_v<mapping_type, extents_type>
+                  && is_default_constructible_v<accessor_type>)
+       constexpr explicit(_Nm != rank_dynamic())
+       mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts)
+       : _M_accessor{}, _M_mapping(extents_type(__exts)),
+         _M_handle(std::move(__handle))
+       { }
+
+      template<__mdspan::__valid_index_type<index_type> _OIndexType,
+              size_t _Nm>
+       requires ((_Nm == rank() || _Nm == rank_dynamic())
+                  && is_constructible_v<mapping_type, extents_type>
+                  && is_default_constructible_v<accessor_type>)
+       constexpr explicit(_Nm != rank_dynamic())
+       mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts)
+       : _M_accessor{}, _M_mapping(extents_type(__exts)),
+         _M_handle(std::move(__handle))
+       { }
+
+      constexpr
+      mdspan(data_handle_type __handle, const extents_type& __exts)
+      requires (is_constructible_v<mapping_type, const extents_type&>
+               && is_default_constructible_v<accessor_type>)
+      : _M_accessor{}, _M_mapping(__exts), _M_handle(std::move(__handle))
+      { }
+
+      constexpr
+      mdspan(data_handle_type __handle, const mapping_type& __mapping)
+      requires (is_default_constructible_v<accessor_type>)
+      : _M_accessor{}, _M_mapping(__mapping), _M_handle(std::move(__handle))
+      { }
+
+      constexpr
+      mdspan(data_handle_type __handle, const mapping_type& __mapping,
+            const accessor_type& __accessor)
+      : _M_accessor(__accessor), _M_mapping(__mapping),
+        _M_handle(std::move(__handle))
+      { }
+
+      template<typename _OElementType, typename _OExtents, typename _OLayout,
+              typename _OAccessor>
+       requires (is_constructible_v<mapping_type,
+             const typename _OLayout::mapping<_OExtents>&>
+         && is_constructible_v<accessor_type, const _OAccessor&>)
+       constexpr explicit(!(is_convertible_v<
+           const typename _OLayout::mapping<_OExtents>&, mapping_type>
+         && is_convertible_v<const _OAccessor&, accessor_type>))
+       mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>&
+                __other)
+       : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()),
+         _M_handle(__other.data_handle())
+       {
+         static_assert(is_constructible_v<data_handle_type,
+             const typename _OAccessor::data_handle_type&>);
+         static_assert(is_constructible_v<extents_type, _OExtents>);
+       }
+
+      constexpr mdspan&
+      operator=(const mdspan& __other) = default;
+
+      constexpr mdspan&
+      operator=(mdspan&& __other) = default;
+
+      template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
+       requires (sizeof...(_OIndexTypes) == rank())
+       constexpr reference
+       operator[](_OIndexTypes... __indices) const
+       {
+         auto __index = _M_mapping(
+           static_cast<index_type>(std::move(__indices))...);
+         __glibcxx_assert(__index < _M_mapping.required_span_size());
+         return _M_accessor.access(_M_handle, __index);
+       }
+
+      template<__mdspan::__valid_index_type<index_type> _OIndexType>
+       constexpr reference
+       operator[](span<_OIndexType, rank()> __indices) const
+       {
+         auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
+           -> reference
+           { return (*this)[as_const(__indices[_Counts])...]; };
+         return __call(make_index_sequence<rank()>());
+       }
+
+      template<__mdspan::__valid_index_type<index_type> _OIndexType>
+       constexpr reference
+       operator[](const array<_OIndexType, rank()>& __indices) const
+       { return (*this)[span<const _OIndexType, rank()>(__indices)]; }
+
+      constexpr size_type
+      size() const noexcept
+      { return size_type(__mdspan::__fwd_prod(extents(), rank())); }
+
+      [[nodiscard]] constexpr bool
+      empty() const noexcept
+      {
+       return __mdspan::__contains_zero(__mdspan::__static_extents<_Extents>())
+         || __mdspan::__contains_zero(__mdspan::__dynamic_extents(extents()));
+      }
+
+      friend constexpr void
+      swap(mdspan& __x, mdspan& __y) noexcept
+      {
+       std::swap(__x._M_mapping, __y._M_mapping);
+       std::swap(__x._M_accessor, __y._M_accessor);
+       std::swap(__x._M_handle, __y._M_handle);
+      }
+
+      constexpr const extents_type&
+      extents() const noexcept { return _M_mapping.extents(); }
+
+      constexpr const data_handle_type&
+      data_handle() const noexcept { return _M_handle; }
+
+      constexpr const mapping_type&
+      mapping() const noexcept { return _M_mapping; }
+
+      constexpr const accessor_type&
+      accessor() const noexcept { return _M_accessor; }
+
+      static constexpr bool
+      is_always_unique() { return mapping_type::is_always_unique(); }
+
+      static constexpr bool
+      is_always_exhaustive() { return mapping_type::is_always_exhaustive(); }
+
+      static constexpr bool
+      is_always_strided() { return mapping_type::is_always_strided(); }
+
+      constexpr bool
+      is_unique() const { return _M_mapping.is_unique(); }
+
+      constexpr bool
+      is_exhaustive() const { return _M_mapping.is_exhaustive(); }
+
+      constexpr bool
+      is_strided() const { return _M_mapping. is_strided(); }
+
+      constexpr index_type
+      stride(rank_type __r) const { return _M_mapping.stride(__r); }
+
+    private:
+      [[no_unique_address]] accessor_type _M_accessor;
+      [[no_unique_address]] mapping_type _M_mapping;
+      [[no_unique_address]] data_handle_type _M_handle;
+    };
+
+  template<typename _CArray>
+    requires(is_array_v<_CArray> && rank_v<_CArray> == 1)
+    mdspan(_CArray&)
+    -> mdspan<remove_all_extents_t<_CArray>,
+             extents<size_t, extent_v<_CArray, 0>>>;
+
+  template<typename _Pointer>
+    requires(is_pointer_v<remove_reference_t<_Pointer>>)
+    mdspan(_Pointer&&)
+    -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>;
+
+  template<typename _ElementType, typename... _Integrals>
+    requires((is_convertible_v<_Integrals, size_t> && ...)
+             && sizeof...(_Integrals) > 0)
+    explicit mdspan(_ElementType*, _Integrals...)
+    -> mdspan<_ElementType, dextents<size_t, sizeof...(_Integrals)>>;
+
+  template<typename _ElementType, typename _OIndexType, size_t _Nm>
+    mdspan(_ElementType*, span<_OIndexType, _Nm>)
+    -> mdspan<_ElementType, dextents<size_t, _Nm>>;
+
+  template<typename _ElementType, typename _OIndexType, size_t _Nm>
+    mdspan(_ElementType*, const array<_OIndexType, _Nm>&)
+    -> mdspan<_ElementType, dextents<size_t, _Nm>>;
+
+  template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack>
+    mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&)
+    -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>;
+
+  template<typename _ElementType, typename _MappingType>
+    mdspan(_ElementType*, const _MappingType&)
+    -> mdspan<_ElementType, typename _MappingType::extents_type,
+             typename _MappingType::layout_type>;
+
+  template<typename _MappingType, typename _AccessorType>
+    mdspan(const typename _AccessorType::data_handle_type&, const 
_MappingType&,
+          const _AccessorType&)
+    -> mdspan<typename _AccessorType::element_type,
+             typename _MappingType::extents_type,
+             typename _MappingType::layout_type, _AccessorType>;
+
 _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 51111627d7d..bad935cc045 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1848,7 +1848,8 @@ export namespace std
   using std::layout_right;
   using std::layout_stride;
   using std::default_accessor;
-  // FIXME layout_left_padded, layout_right_padded and mdspan
+  using std::mdspan;
+  // FIXME layout_left_padded, layout_right_padded, mdsubspan
 }
 #endif
 
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc
new file mode 100644
index 00000000000..55c49fa7018
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/class_mandate_neg.cc
@@ -0,0 +1,32 @@
+// { dg-do compile { target c++23 } }
+#include<mdspan>
+
+#include <cstdint>
+
+struct ExtentsLike
+{
+  using index_type = int;
+  using size_type = unsigned int;
+  using rank_type = size_t;
+
+  static constexpr size_t rank() { return 1; }
+  static constexpr size_t rank_dynamic() { return 0; }
+};
+
+struct A
+{
+  std::mdspan<double, ExtentsLike> md1; // { dg-error "required from here" }
+};
+
+struct B
+{
+  using E = std::extents<int, 1>;
+  using L = std::layout_right;
+  using A = std::default_accessor<double>;
+
+  std::mdspan<float, E, L, A> md2; // { dg-error "required from here" }
+};
+
+// { dg-prune-output "no type named '_S_storage'" }
+// { dg-prune-output "non-constant condition" }
+// { dg-prune-output "static assertion failed" }
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc 
b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
new file mode 100644
index 00000000000..7fcc50d7cb7
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
@@ -0,0 +1,348 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+constexpr auto dyn = std::dynamic_extent;
+
+template<typename T, typename E, typename L, typename A>
+  constexpr void
+  test_typedefs()
+  {
+    using MDSpan = std::mdspan<T, E, L, A>;
+    using MDConstSpan = std::mdspan<const T, E, L>;
+    static_assert(std::same_as<typename MDSpan::extents_type, E>);
+    static_assert(std::same_as<typename MDSpan::layout_type, L>);
+    static_assert(std::same_as<typename MDSpan::accessor_type, A>);
+    static_assert(std::same_as<typename MDSpan::mapping_type, typename 
L::mapping<E>>);
+    static_assert(std::same_as<typename MDSpan::element_type, T>);
+    static_assert(std::same_as<typename MDSpan::value_type, T>);
+    static_assert(std::same_as<typename MDConstSpan::element_type, const T>);
+    static_assert(std::same_as<typename MDConstSpan::value_type, T>);
+    static_assert(std::same_as<typename MDSpan::index_type, typename 
E::index_type>);
+    static_assert(std::same_as<typename MDSpan::size_type, typename 
E::size_type>);
+    static_assert(std::same_as<typename MDSpan::rank_type, typename 
E::rank_type>);
+    static_assert(std::same_as<typename MDSpan::data_handle_type, typename 
A::data_handle_type>);
+    static_assert(std::same_as<typename MDSpan::reference, typename 
A::reference>);
+  }
+
+constexpr void
+  test_typedefs_all()
+{
+  test_typedefs<double, std::extents<int, 1, 2>, std::layout_left, 
std::default_accessor<double>>();
+}
+
+template<typename MDSpan>
+  constexpr void
+  test_rank()
+  {
+    using Extents = typename MDSpan::extents_type;
+    static_assert(MDSpan::rank() == Extents::rank());
+    static_assert(MDSpan::rank_dynamic() == Extents::rank_dynamic());
+  }
+
+constexpr bool
+test_rank_all()
+{
+  test_rank<std::mdspan<double, std::extents<int>>>();
+  test_rank<std::mdspan<double, std::extents<int, 1>>>();
+  test_rank<std::mdspan<double, std::extents<int, dyn>>>();
+  return true;
+}
+
+template<typename MDSpan>
+  constexpr void
+  test_static_extent()
+  {
+    using Extents = typename MDSpan::extents_type;
+    for(size_t i = 0; i < MDSpan::rank(); ++i)
+      VERIFY(MDSpan::static_extent(i) == Extents::static_extent(i));
+  }
+
+constexpr bool
+test_static_extent_all()
+{
+  test_static_extent<std::mdspan<double, std::extents<int>>>();
+  test_static_extent<std::mdspan<double, std::extents<int, 1>>>();
+  test_static_extent<std::mdspan<double, std::extents<int, dyn>>>();
+  return true;
+}
+
+template<typename MDSpan>
+  constexpr void
+  test_class_properties()
+  {
+    static_assert(std::copyable<MDSpan>);
+    static_assert(std::is_nothrow_move_constructible_v<MDSpan>);
+    static_assert(std::is_nothrow_move_assignable_v<MDSpan>);
+    static_assert(std::is_nothrow_swappable_v<MDSpan>);
+    constexpr bool trivially_copyable =
+      std::is_trivially_copyable_v<typename MDSpan::accessor_type>
+      && std::is_trivially_copyable_v<typename MDSpan::mapping_type>
+      && std::is_trivially_copyable_v<typename MDSpan::data_handle_type>;
+    static_assert(std::is_trivially_copyable_v<MDSpan> == trivially_copyable);
+  }
+
+constexpr bool
+test_class_properties_all()
+{
+  test_class_properties<std::mdspan<double, std::extents<int>>>();
+  test_class_properties<std::mdspan<double, std::extents<int, 1>>>();
+  test_class_properties<std::mdspan<double, std::extents<int, dyn>>>();
+  return true;
+}
+
+constexpr bool
+test_default_ctor()
+{
+  static_assert(!std::is_default_constructible_v<std::mdspan<double, 
std::extents<int>>>);
+  static_assert(!std::is_default_constructible_v<std::mdspan<double, 
std::extents<int, 1>>>);
+  static_assert(std::is_default_constructible_v<std::mdspan<double, 
std::extents<int, dyn>>>);
+
+  std::mdspan<double, std::extents<int, dyn>> md;
+  VERIFY(md.data_handle() == nullptr);
+  VERIFY(md.extent(0) == 0);
+  return true;
+}
+
+constexpr bool
+test_from_other()
+{
+  using Extents = std::extents<int, 3, 5, 7>;
+  auto exts = Extents{};
+
+  auto mapping = std::layout_right::mapping(exts);
+  constexpr size_t n = mapping.required_span_size();
+  std::array<double, n> storage{};
+
+  auto md1 = std::mdspan(storage.data(), exts);
+  auto md2 = std::mdspan<double, std::dextents<int, 3>>(md1);
+
+  VERIFY(md1.data_handle() == md2.data_handle());
+  VERIFY(md1.size() == md2.size());
+  return true;
+}
+
+template<typename T, typename E, typename L = std::layout_right,
+        typename A = std::default_accessor<T>>
+constexpr void
+assert_deduced_typedefs(auto md)
+{
+    using MDSpan = decltype(md);
+    static_assert(std::same_as<typename MDSpan::element_type, T>);
+    static_assert(std::same_as<typename MDSpan::extents_type, E>);
+    static_assert(std::same_as<typename MDSpan::layout_type, L>);
+    static_assert(std::same_as<typename MDSpan::accessor_type, 
std::default_accessor<T>>);
+}
+
+constexpr bool
+test_from_carray()
+{
+  constexpr size_t n = 5;
+  double data[n] = {1.1, 2.2, 3.3, 4.4, 5.5};
+
+  auto md = std::mdspan(data);
+  assert_deduced_typedefs<double, std::extents<size_t, n>>(md);
+  VERIFY(md.rank() == 1);
+  VERIFY(md.rank_dynamic() == 0);
+  VERIFY(md[2] == data[2]);
+  return true;
+}
+
+constexpr bool
+test_from_pointer()
+{
+  double value = 12.3;
+  auto md = std::mdspan(&value);
+
+  assert_deduced_typedefs<double, std::extents<size_t>>(md);
+  VERIFY(md.rank() == 0);
+  VERIFY(md.rank_dynamic() == 0);
+  VERIFY(md[] == value);
+  return true;
+}
+
+constexpr bool
+test_from_pointer_and_shape()
+{
+  constexpr size_t n = 6;
+  std::array<double, n> data{1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
+  std::array<int, 2> shape{2, 3};
+
+  auto verify = [&data](auto md)
+  {
+    assert_deduced_typedefs<double, std::dextents<size_t, 2>>(md);
+    VERIFY(md.rank() == 2);
+    VERIFY(md.rank_dynamic() == 2);
+    VERIFY((md[0, 0]) == data[0]);
+    VERIFY((md[0, 1]) == data[1]);
+    VERIFY((md[1, 0]) == data[3]);
+  };
+
+  verify(std::mdspan(data.data(), shape[0], shape[1]));
+  verify(std::mdspan(data.data(), shape));
+  verify(std::mdspan(data.data(), std::span<const int, 2>(shape)));
+
+  static_assert(std::is_constructible_v<
+      std::mdspan<float, std::dextents<int, 2>>, float *, std::span<int, 2>>);
+  static_assert(!std::is_constructible_v<
+      std::mdspan<float, std::dextents<int, 2>>, float *, std::span<int, 
dyn>>);
+  return true;
+}
+
+constexpr bool
+test_from_extents()
+{
+  constexpr size_t n = 3*5*7;
+  std::array<double, n> storage{};
+  using Extents = std::extents<int, 3, 5, 7>;
+  auto exts = Extents{};
+  auto md = std::mdspan(storage.data(), exts);
+
+  assert_deduced_typedefs<double, Extents>(md);
+  VERIFY(md.data_handle() == storage.data());
+  VERIFY(md.extents() == exts);
+  return true;
+}
+
+constexpr bool
+test_from_mapping()
+{
+  constexpr size_t n = 3*5*7;
+  std::array<double, n> storage{};
+  using Extents = std::extents<int, 3, 5, 7>;
+
+  auto exts = Extents{};
+  auto m = std::layout_left::mapping(exts);
+  auto md = std::mdspan(storage.data(), m);
+
+  assert_deduced_typedefs<double, Extents, std::layout_left>(md);
+  VERIFY(md.data_handle() == storage.data());
+  VERIFY(md.mapping() == m);
+  return true;
+}
+
+constexpr bool
+test_from_accessor()
+{
+  constexpr size_t n = 3*5*7;
+  std::array<double, n> storage{};
+  using Extents = std::extents<int, 3, 5, 7>;
+
+  auto exts = Extents{};
+  auto m = std::layout_left::mapping(exts);
+  auto a = std::default_accessor<double>{};
+  auto md = std::mdspan(storage.data(), m, a);
+
+  assert_deduced_typedefs<double, Extents, std::layout_left>(md);
+  VERIFY(md.data_handle() == storage.data());
+  VERIFY(md.mapping() == m);
+  return true;
+}
+
+template<typename MDSpan>
+  constexpr void
+  test_empty(MDSpan md)
+  {
+    VERIFY(md.empty() == (md.size() == 0));
+  }
+
+constexpr bool
+test_empty_all()
+{
+  test_empty(std::mdspan<double, std::extents<int, dyn>>{});
+  return true;
+}
+
+constexpr bool
+test_access()
+{
+  using Extents = std::extents<int, 3, 5, 7>;
+  auto exts = Extents{};
+
+  auto mapping = std::layout_left::mapping(exts);
+  constexpr size_t n = mapping.required_span_size();
+  std::array<double, n> storage{};
+
+  auto md = std::mdspan(storage.data(), mapping);
+
+  for(int i = 0; i < exts.extent(0); ++i)
+    for(int j = 0; j < exts.extent(1); ++j)
+      for(int k = 0; k < exts.extent(2); ++k)
+       {
+         std::array<int, 3> ijk{i, j, k};
+         storage[mapping(i, j, k)] = 1.0;
+         VERIFY((md[i, j, k]) == 1.0);
+         VERIFY((md[ijk]) == 1.0);
+         VERIFY((md[std::span(ijk)]) == 1.0);
+         storage[mapping(i, j, k)] = 0.0;
+       }
+  return true;
+}
+
+constexpr bool
+test_swap()
+{
+  using Extents = std::dextents<int, 2>;
+  auto e1 = Extents{3, 5};
+  auto e2 = Extents{7, 11};
+
+  std::array<double, 3*5> s1{};
+  std::array<double, 7*11> s2{};
+
+  auto md1 = std::mdspan(s1.data(), e1);
+  auto md2 = std::mdspan(s2.data(), e2);
+
+  std::swap(md1, md2);
+
+  VERIFY(md1.data_handle() == s2.data());
+  VERIFY(md2.data_handle() == s1.data());
+
+  VERIFY(md1.size() == s2.size());
+  VERIFY(md2.size() == s1.size());
+  return true;
+}
+
+int
+main()
+{
+  test_typedefs_all();
+
+  test_default_ctor();
+  static_assert(test_default_ctor());
+
+  test_rank_all();
+  test_static_extent_all();
+  static_assert(test_static_extent_all());
+
+  test_class_properties_all();
+  static_assert(test_class_properties_all());
+
+  test_empty_all();
+  static_assert(test_empty_all());
+
+  test_from_other();
+  static_assert(test_from_other());
+
+  test_from_carray();
+  static_assert(test_from_carray());
+
+  test_from_pointer_and_shape();
+  static_assert(test_from_pointer_and_shape());
+
+  test_from_extents();
+  static_assert(test_from_extents());
+
+  test_from_mapping();
+  static_assert(test_from_mapping());
+
+  test_from_accessor();
+  static_assert(test_from_accessor());
+
+  test_access();
+  static_assert(test_access());
+
+  test_swap();
+  static_assert(test_swap());
+  return 0;
+}
-- 
2.49.0

Reply via email to