[llvm-branch-commits] [libcxx] ab863b3 - [libc++][mdspan] Implement std::mdspan class
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jul 26 10:30:51 PDT 2023
Author: Christian Trott
Date: 2023-07-26T19:30:43+02:00
New Revision: ab863b3e73372e983ff5fb658b4bcb6577c87471
URL: https://github.com/llvm/llvm-project/commit/ab863b3e73372e983ff5fb658b4bcb6577c87471
DIFF: https://github.com/llvm/llvm-project/commit/ab863b3e73372e983ff5fb658b4bcb6577c87471.diff
LOG: [libc++][mdspan] Implement std::mdspan class
This implements P0009 std::mdspan ((https://wg21.link/p0009)),
a multidimensional span with customization points for
layouts and data access.
Co-authored-by: Damien L-G <dalg24 at gmail.com>
Differential Revision: https://reviews.llvm.org/154367
Added:
libcxx/include/__mdspan/mdspan.h
libcxx/test/std/containers/views/mdspan/mdspan/CustomTestAccessors.h
libcxx/test/std/containers/views/mdspan/mdspan/CustomTestLayouts.h
libcxx/test/std/containers/views/mdspan/mdspan/assert.conversion.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/assert.index_operator.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/assert.size.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/assign.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/ctor.move.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/element_type.verify.cpp
libcxx/test/std/containers/views/mdspan/mdspan/extents.verify.cpp
libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/mapping.verify.cpp
libcxx/test/std/containers/views/mdspan/mdspan/move.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/swap.pass.cpp
libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp
Modified:
libcxx/docs/ReleaseNotes/17.rst
libcxx/include/CMakeLists.txt
libcxx/include/__mdspan/extents.h
libcxx/include/__mdspan/layout_left.h
libcxx/include/__mdspan/layout_right.h
libcxx/include/mdspan
libcxx/include/module.modulemap.in
libcxx/modules/std/mdspan.cppm
libcxx/test/std/containers/views/mdspan/ConvertibleToIntegral.h
libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp
libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp
libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp
libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp
libcxx/test/std/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp
libcxx/test/std/containers/views/mdspan/layout_left/assert.stride.pass.cpp
libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp
libcxx/test/std/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp
libcxx/test/std/containers/views/mdspan/layout_right/assert.stride.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/ReleaseNotes/17.rst b/libcxx/docs/ReleaseNotes/17.rst
index ba17911b045a30..5aae64f1e2814f 100644
--- a/libcxx/docs/ReleaseNotes/17.rst
+++ b/libcxx/docs/ReleaseNotes/17.rst
@@ -69,6 +69,7 @@ Implemented Papers
- P2585R0 - Improving default container formatting
- P0408R7 - Efficient Access to ``basic_stringbuf``'s Buffer
- P2474R2 - ``views::repeat``
+- P0009R18 - ``mdspan`` (``layout_stride`` is not done yet)
Improvements and New Features
-----------------------------
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 8d03e1b8f43c30..af873fe0ea45ba 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -484,6 +484,7 @@ set(files
__mdspan/extents.h
__mdspan/layout_left.h
__mdspan/layout_right.h
+ __mdspan/mdspan.h
__memory/addressof.h
__memory/align.h
__memory/aligned_alloc.h
diff --git a/libcxx/include/__mdspan/extents.h b/libcxx/include/__mdspan/extents.h
index 42355678d60ccc..969204f6b55046 100644
--- a/libcxx/include/__mdspan/extents.h
+++ b/libcxx/include/__mdspan/extents.h
@@ -315,7 +315,8 @@ class extents {
}
template <class _OtherIndexType, size_t _Size>
- requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType> &&
+ requires(is_convertible_v<const _OtherIndexType&, index_type> &&
+ is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
(_Size == __rank_ || _Size == __rank_dynamic_))
explicit(_Size != __rank_dynamic_)
_LIBCPP_HIDE_FROM_ABI constexpr extents(const array<_OtherIndexType, _Size>& __exts) noexcept
@@ -325,7 +326,8 @@ class extents {
}
template <class _OtherIndexType, size_t _Size>
- requires(is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType> &&
+ requires(is_convertible_v<const _OtherIndexType&, index_type> &&
+ is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
(_Size == __rank_ || _Size == __rank_dynamic_))
explicit(_Size != __rank_dynamic_)
_LIBCPP_HIDE_FROM_ABI constexpr extents(const span<_OtherIndexType, _Size>& __exts) noexcept
diff --git a/libcxx/include/__mdspan/layout_left.h b/libcxx/include/__mdspan/layout_left.h
index e81e0d10b595a7..d2930904834af8 100644
--- a/libcxx/include/__mdspan/layout_left.h
+++ b/libcxx/include/__mdspan/layout_left.h
@@ -75,8 +75,9 @@ class layout_left::mapping {
_LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default;
_LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
_LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) {
- _LIBCPP_ASSERT(__required_span_size_is_representable(__ext),
- "layout_left::mapping extents ctor: product of extents must be representable as index_type.");
+ _LIBCPP_ASSERT_UNCATEGORIZED(
+ __required_span_size_is_representable(__ext),
+ "layout_left::mapping extents ctor: product of extents must be representable as index_type.");
}
template <class _OtherExtents>
@@ -84,7 +85,7 @@ class layout_left::mapping {
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>)
mapping(const mapping<_OtherExtents>& __other) noexcept
: __extents_(__other.extents()) {
- _LIBCPP_ASSERT(
+ _LIBCPP_ASSERT_UNCATEGORIZED(
__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type.");
}
@@ -94,7 +95,7 @@ class layout_left::mapping {
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>)
mapping(const layout_right::mapping<_OtherExtents>& __other) noexcept
: __extents_(__other.extents()) {
- _LIBCPP_ASSERT(
+ _LIBCPP_ASSERT_UNCATEGORIZED(
__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type.");
}
@@ -122,8 +123,8 @@ class layout_left::mapping {
requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) &&
(is_nothrow_constructible_v<index_type, _Indices> && ...))
_LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept {
- _LIBCPP_ASSERT(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...),
- "layout_left::mapping: out of bounds indexing");
+ _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...),
+ "layout_left::mapping: out of bounds indexing");
array<index_type, extents_type::rank()> __idx_a{static_cast<index_type>(__idx)...};
return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
index_type __res = 0;
@@ -144,7 +145,7 @@ class layout_left::mapping {
_LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept
requires(extents_type::rank() > 0)
{
- _LIBCPP_ASSERT(__r < extents_type::rank(), "layout_left::mapping::stride(): invalid rank index");
+ _LIBCPP_ASSERT_UNCATEGORIZED(__r < extents_type::rank(), "layout_left::mapping::stride(): invalid rank index");
index_type __s = 1;
for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--)
__s *= __extents_.extent(__i);
@@ -159,7 +160,7 @@ class layout_left::mapping {
}
private:
- extents_type __extents_{}; // exposition only
+ _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{};
};
#endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/include/__mdspan/layout_right.h b/libcxx/include/__mdspan/layout_right.h
index a8a91b86c71421..6d144294789cb5 100644
--- a/libcxx/include/__mdspan/layout_right.h
+++ b/libcxx/include/__mdspan/layout_right.h
@@ -74,8 +74,9 @@ class layout_right::mapping {
_LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept = default;
_LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
_LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) noexcept : __extents_(__ext) {
- _LIBCPP_ASSERT(__required_span_size_is_representable(__ext),
- "layout_right::mapping extents ctor: product of extents must be representable as index_type.");
+ _LIBCPP_ASSERT_UNCATEGORIZED(
+ __required_span_size_is_representable(__ext),
+ "layout_right::mapping extents ctor: product of extents must be representable as index_type.");
}
template <class _OtherExtents>
@@ -83,7 +84,7 @@ class layout_right::mapping {
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>)
mapping(const mapping<_OtherExtents>& __other) noexcept
: __extents_(__other.extents()) {
- _LIBCPP_ASSERT(
+ _LIBCPP_ASSERT_UNCATEGORIZED(
__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type.");
}
@@ -93,7 +94,7 @@ class layout_right::mapping {
_LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>)
mapping(const layout_left::mapping<_OtherExtents>& __other) noexcept
: __extents_(__other.extents()) {
- _LIBCPP_ASSERT(
+ _LIBCPP_ASSERT_UNCATEGORIZED(
__mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
"layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type.");
}
@@ -121,8 +122,8 @@ class layout_right::mapping {
requires((sizeof...(_Indices) == extents_type::rank()) && (is_convertible_v<_Indices, index_type> && ...) &&
(is_nothrow_constructible_v<index_type, _Indices> && ...))
_LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept {
- _LIBCPP_ASSERT(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...),
- "layout_right::mapping: out of bounds indexing");
+ _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...),
+ "layout_right::mapping: out of bounds indexing");
return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
index_type __res = 0;
((__res = static_cast<index_type>(__idx) + __extents_.extent(_Pos) * __res), ...);
@@ -141,7 +142,7 @@ class layout_right::mapping {
_LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept
requires(extents_type::rank() > 0)
{
- _LIBCPP_ASSERT(__r < extents_type::rank(), "layout_right::mapping::stride(): invalid rank index");
+ _LIBCPP_ASSERT_UNCATEGORIZED(__r < extents_type::rank(), "layout_right::mapping::stride(): invalid rank index");
index_type __s = 1;
for (rank_type __i = extents_type::rank() - 1; __i > __r; __i--)
__s *= __extents_.extent(__i);
@@ -156,7 +157,7 @@ class layout_right::mapping {
}
private:
- extents_type __extents_{}; // exposition only
+ _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{};
};
#endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/include/__mdspan/mdspan.h b/libcxx/include/__mdspan/mdspan.h
new file mode 100644
index 00000000000000..47351f113cfa8b
--- /dev/null
+++ b/libcxx/include/__mdspan/mdspan.h
@@ -0,0 +1,301 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// Kokkos v. 4.0
+// Copyright (2022) National Technology & Engineering
+// Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___MDSPAN_MDSPAN_H
+#define _LIBCPP___MDSPAN_MDSPAN_H
+
+#include <__assert>
+#include <__config>
+#include <__fwd/mdspan.h>
+#include <__mdspan/default_accessor.h>
+#include <__mdspan/extents.h>
+#include <__type_traits/extent.h>
+#include <__type_traits/is_abstract.h>
+#include <__type_traits/is_array.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/is_default_constructible.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/is_pointer.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/rank.h>
+#include <__type_traits/remove_all_extents.h>
+#include <__type_traits/remove_cv.h>
+#include <__type_traits/remove_pointer.h>
+#include <__type_traits/remove_reference.h>
+#include <__utility/integer_sequence.h>
+#include <array>
+#include <cinttypes>
+#include <cstddef>
+#include <limits>
+#include <span>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+// Helper for lightweight test checking that one did pass a layout policy as LayoutPolicy template argument
+namespace __mdspan_detail {
+template <class _Layout, class _Extents>
+concept __has_invalid_mapping = !requires { typename _Layout::template mapping<_Extents>; };
+} // namespace __mdspan_detail
+
+template <class _ElementType,
+ class _Extents,
+ class _LayoutPolicy = layout_right,
+ class _AccessorPolicy = default_accessor<_ElementType> >
+class mdspan {
+private:
+ static_assert(__mdspan_detail::__is_extents_v<_Extents>,
+ "mdspan: Extents template parameter must be a specialization of extents.");
+ static_assert(!is_array_v<_ElementType>, "mdspan: ElementType template parameter may not be an array type");
+ static_assert(!is_abstract_v<_ElementType>, "mdspan: ElementType template parameter may not be an abstract class");
+ static_assert(is_same_v<_ElementType, typename _AccessorPolicy::element_type>,
+ "mdspan: ElementType template parameter must match AccessorPolicy::element_type");
+ static_assert(!__mdspan_detail::__has_invalid_mapping<_LayoutPolicy, _Extents>,
+ "mdspan: LayoutPolicy template parameter is invalid. A common mistake is to pass a layout mapping "
+ "instead of a layout policy");
+
+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;
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank() noexcept { return extents_type::rank(); }
+ _LIBCPP_HIDE_FROM_ABI static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
+ _LIBCPP_HIDE_FROM_ABI static constexpr size_t static_extent(rank_type __r) noexcept {
+ return extents_type::static_extent(__r);
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type extent(rank_type __r) const noexcept {
+ return __map_.extents().extent(__r);
+ };
+
+public:
+ //--------------------------------------------------------------------------------
+ // [mdspan.mdspan.cons], mdspan constructors, assignment, and destructor
+
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan()
+ requires((extents_type::rank_dynamic() > 0) && is_default_constructible_v<data_handle_type> &&
+ is_default_constructible_v<mapping_type> && is_default_constructible_v<accessor_type>)
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan(const mdspan&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan(mdspan&&) = default;
+
+ template <class... _OtherIndexTypes>
+ requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) &&
+ (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
+ ((sizeof...(_OtherIndexTypes) == rank()) || (sizeof...(_OtherIndexTypes) == rank_dynamic())) &&
+ is_constructible_v<mapping_type, extents_type> && is_default_constructible_v<accessor_type>)
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr mdspan(data_handle_type __p, _OtherIndexTypes... __exts)
+ : __ptr_(std::move(__p)), __map_(extents_type(static_cast<index_type>(std::move(__exts))...)), __acc_{} {}
+
+ template <class _OtherIndexType, size_t _Size>
+ requires(is_convertible_v<const _OtherIndexType&, index_type> &&
+ is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
+ ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v<mapping_type, extents_type> &&
+ is_default_constructible_v<accessor_type>)
+ explicit(_Size != rank_dynamic())
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const array<_OtherIndexType, _Size>& __exts)
+ : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {}
+
+ template <class _OtherIndexType, size_t _Size>
+ requires(is_convertible_v<const _OtherIndexType&, index_type> &&
+ is_nothrow_constructible_v<index_type, const _OtherIndexType&> &&
+ ((_Size == rank()) || (_Size == rank_dynamic())) && is_constructible_v<mapping_type, extents_type> &&
+ is_default_constructible_v<accessor_type>)
+ explicit(_Size != rank_dynamic())
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, span<_OtherIndexType, _Size> __exts)
+ : __ptr_(std::move(__p)), __map_(extents_type(__exts)), __acc_{} {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const extents_type& __exts)
+ requires(is_default_constructible_v<accessor_type> && is_constructible_v<mapping_type, const extents_type&>)
+ : __ptr_(std::move(__p)), __map_(__exts), __acc_{} {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m)
+ requires(is_default_constructible_v<accessor_type>)
+ : __ptr_(std::move(__p)), __map_(__m), __acc_{} {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan(data_handle_type __p, const mapping_type& __m, const accessor_type& __a)
+ : __ptr_(std::move(__p)), __map_(__m), __acc_(__a) {}
+
+ template <class _OtherElementType, class _OtherExtents, class _OtherLayoutPolicy, class _OtherAccessor>
+ requires(is_constructible_v<mapping_type, const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&> &&
+ is_constructible_v<accessor_type, const _OtherAccessor&>)
+ explicit(!is_convertible_v<const typename _OtherLayoutPolicy::template mapping<_OtherExtents>&, mapping_type> ||
+ !is_convertible_v<const _OtherAccessor&, accessor_type>)
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan(
+ const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& __other)
+ : __ptr_(__other.__ptr_), __map_(__other.__map_), __acc_(__other.__acc_) {
+ static_assert(is_constructible_v<data_handle_type, const typename _OtherAccessor::data_handle_type&>,
+ "mdspan: incompatible data_handle_type for mdspan construction");
+ static_assert(
+ is_constructible_v<extents_type, _OtherExtents>, "mdspan: incompatible extents for mdspan construction");
+
+ // The following precondition is part of the standard, but is unlikely to be triggered.
+ // The extents constructor checks this and the mapping must be storing the extents, since
+ // its extents() function returns a const reference to extents_type.
+ // The only way this can be triggered is if the mapping conversion constructor would for example
+ // always construct its extents() only from the dynamic extents, instead of from the other extents.
+ if constexpr (rank() > 0) {
+ for (size_t __r = 0; __r < rank(); __r++) {
+ _LIBCPP_ASSERT_UNCATEGORIZED(
+ (static_extent(__r) == dynamic_extent) ||
+ (static_cast<index_type>(__other.extent(__r)) == static_cast<index_type>(static_extent(__r))),
+ "mdspan: conversion mismatch of source dynamic extents with static extents");
+ }
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(const mdspan&) = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr mdspan& operator=(mdspan&&) = default;
+
+ //--------------------------------------------------------------------------------
+ // [mdspan.mdspan.members], members
+
+ template <class... _OtherIndexTypes>
+ requires((is_convertible_v<_OtherIndexTypes, index_type> && ...) &&
+ (is_nothrow_constructible_v<index_type, _OtherIndexTypes> && ...) &&
+ (sizeof...(_OtherIndexTypes) == rank()))
+ _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](_OtherIndexTypes... __indices) const {
+ _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(extents(), __indices...),
+ "mdspan: operator[] out of bounds access");
+ return __acc_.access(__ptr_, __map_(static_cast<index_type>(std::move(__indices))...));
+ }
+
+ template <class _OtherIndexType>
+ requires(is_convertible_v<const _OtherIndexType&, index_type> &&
+ is_nothrow_constructible_v<index_type, const _OtherIndexType&>)
+ _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](const array< _OtherIndexType, rank()>& __indices) const {
+ return __acc_.access(__ptr_, [&]<size_t... _Idxs>(index_sequence<_Idxs...>) {
+ return __map_(__indices[_Idxs]...);
+ }(make_index_sequence<rank()>()));
+ }
+
+ template <class _OtherIndexType>
+ requires(is_convertible_v<const _OtherIndexType&, index_type> &&
+ is_nothrow_constructible_v<index_type, const _OtherIndexType&>)
+ _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](span<_OtherIndexType, rank()> __indices) const {
+ return __acc_.access(__ptr_, [&]<size_t... _Idxs>(index_sequence<_Idxs...>) {
+ return __map_(__indices[_Idxs]...);
+ }(make_index_sequence<rank()>()));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr size_type size() const noexcept {
+ _LIBCPP_ASSERT_UNCATEGORIZED(
+ false == ([&]<size_t... _Idxs>(index_sequence<_Idxs...>) {
+ size_type __prod = 1;
+ return (__builtin_mul_overflow(__prod, extent(_Idxs), &__prod) || ... || false);
+ }(make_index_sequence<rank()>())),
+ "mdspan: size() is not representable as size_type");
+ return [&]<size_t... _Idxs>(index_sequence<_Idxs...>) {
+ return ((static_cast<size_type>(__map_.extents().extent(_Idxs))) * ... * size_type(1));
+ }(make_index_sequence<rank()>());
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept {
+ return [&]<size_t... _Idxs>(index_sequence<_Idxs...>) {
+ return (rank() > 0) && ((__map_.extents().extent(_Idxs) == index_type(0)) || ... || false);
+ }(make_index_sequence<rank()>());
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr void swap(mdspan& __x, mdspan& __y) noexcept {
+ swap(__x.__ptr_, __y.__ptr_);
+ swap(__x.__map_, __y.__map_);
+ swap(__x.__acc_, __y.__acc_);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __map_.extents(); };
+ _LIBCPP_HIDE_FROM_ABI constexpr const data_handle_type& data_handle() const noexcept { return __ptr_; };
+ _LIBCPP_HIDE_FROM_ABI constexpr const mapping_type& mapping() const noexcept { return __map_; };
+ _LIBCPP_HIDE_FROM_ABI constexpr const accessor_type& accessor() const noexcept { return __acc_; };
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() { return mapping_type::is_always_unique(); };
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() { return mapping_type::is_always_exhaustive(); };
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() { return mapping_type::is_always_strided(); };
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool is_unique() const { return __map_.is_unique(); };
+ _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const { return __map_.is_exhaustive(); };
+ _LIBCPP_HIDE_FROM_ABI constexpr bool is_strided() const { return __map_.is_strided(); };
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const { return __map_.stride(__r); };
+
+private:
+ _LIBCPP_NO_UNIQUE_ADDRESS data_handle_type __ptr_{};
+ _LIBCPP_NO_UNIQUE_ADDRESS mapping_type __map_{};
+ _LIBCPP_NO_UNIQUE_ADDRESS accessor_type __acc_{};
+
+ template <class, class, class, class>
+ friend class mdspan;
+};
+
+template <class _ElementType, class... _OtherIndexTypes>
+ requires((is_convertible_v<_OtherIndexTypes, size_t> && ...) && (sizeof...(_OtherIndexTypes) > 0))
+explicit mdspan(_ElementType*, _OtherIndexTypes...)
+ -> mdspan<_ElementType, dextents<size_t, sizeof...(_OtherIndexTypes)>>;
+
+template <class Pointer>
+ requires(is_pointer_v<remove_reference_t<Pointer>>)
+mdspan(Pointer&&) -> mdspan<remove_pointer_t<remove_reference_t<Pointer>>, extents<size_t>>;
+
+template <class 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 <class _ElementType, class _OtherIndexType, size_t _Size>
+mdspan(_ElementType*, const array<_OtherIndexType, _Size>&) -> mdspan<_ElementType, dextents<size_t, _Size>>;
+
+template <class _ElementType, class _OtherIndexType, size_t _Size>
+mdspan(_ElementType*, span<_OtherIndexType, _Size>) -> mdspan<_ElementType, dextents<size_t, _Size>>;
+
+// This one is necessary because all the constructors take `data_handle_type`s, not
+// `_ElementType*`s, and `data_handle_type` is taken from `accessor_type::data_handle_type`, which
+// seems to throw off automatic deduction guides.
+template <class _ElementType, class _OtherIndexType, size_t... _ExtentsPack>
+mdspan(_ElementType*, const extents<_OtherIndexType, _ExtentsPack...>&)
+ -> mdspan<_ElementType, extents<_OtherIndexType, _ExtentsPack...>>;
+
+template <class _ElementType, class MappingType>
+mdspan(_ElementType*, const MappingType&)
+ -> mdspan<_ElementType, typename MappingType::extents_type, typename MappingType::layout_type>;
+
+template <class MappingType, class 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>;
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MDSPAN_MDSPAN_H
diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan
index 701def50b40a4d..9082eb8bdb5518 100644
--- a/libcxx/include/mdspan
+++ b/libcxx/include/mdspan
@@ -208,6 +208,135 @@ namespace std {
};
}
+// mdspan synopsis
+
+namespace std {
+ template<class ElementType, class Extents, class LayoutPolicy = layout_right,
+ class AccessorPolicy = default_accessor<ElementType>>
+ class mdspan {
+ 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); }
+
+ // [mdspan.mdspan.cons], constructors
+ constexpr mdspan();
+ constexpr mdspan(const mdspan& rhs) = default;
+ constexpr mdspan(mdspan&& rhs) = default;
+
+ template<class... OtherIndexTypes>
+ constexpr explicit mdspan(data_handle_type ptr, OtherIndexTypes... exts);
+ template<class OtherIndexType, size_t N>
+ constexpr explicit(N != rank_dynamic())
+ mdspan(data_handle_type p, span<OtherIndexType, N> exts);
+ template<class OtherIndexType, size_t N>
+ constexpr explicit(N != rank_dynamic())
+ mdspan(data_handle_type p, const array<OtherIndexType, N>& exts);
+ constexpr mdspan(data_handle_type p, const extents_type& ext);
+ constexpr mdspan(data_handle_type p, const mapping_type& m);
+ constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a);
+
+ template<class OtherElementType, class OtherExtents,
+ class OtherLayoutPolicy, class OtherAccessorPolicy>
+ constexpr explicit(see below)
+ mdspan(const mdspan<OtherElementType, OtherExtents,
+ OtherLayoutPolicy, OtherAccessorPolicy>& other);
+
+ constexpr mdspan& operator=(const mdspan& rhs) = default;
+ constexpr mdspan& operator=(mdspan&& rhs) = default;
+
+ // [mdspan.mdspan.members], members
+ template<class... OtherIndexTypes>
+ constexpr reference operator[](OtherIndexTypes... indices) const;
+ template<class OtherIndexType>
+ constexpr reference operator[](span<OtherIndexType, rank()> indices) const;
+ template<class OtherIndexType>
+ constexpr reference operator[](const array<OtherIndexType, rank()>& indices) const;
+
+ constexpr size_type size() const noexcept;
+ [[nodiscard]] constexpr bool empty() const noexcept;
+
+ friend constexpr void swap(mdspan& x, mdspan& y) noexcept;
+
+ constexpr const extents_type& extents() const noexcept { return map_.extents(); }
+ constexpr const data_handle_type& data_handle() const noexcept { return ptr_; }
+ constexpr const mapping_type& mapping() const noexcept { return map_; }
+ constexpr const accessor_type& accessor() const noexcept { return acc_; }
+
+ 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 map_.is_unique(); }
+ constexpr bool is_exhaustive() const
+ { return map_.is_exhaustive(); }
+ constexpr bool is_strided() const
+ { return map_.is_strided(); }
+ constexpr index_type stride(rank_type r) const
+ { return map_.stride(r); }
+
+ private:
+ accessor_type acc_; // exposition only
+ mapping_type map_; // exposition only
+ data_handle_type ptr_; // exposition only
+ };
+
+ template<class 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<class Pointer>
+ requires(is_pointer_v<remove_reference_t<Pointer>>)
+ mdspan(Pointer&&)
+ -> mdspan<remove_pointer_t<remove_reference_t<Pointer>>, extents<size_t>>;
+
+ template<class ElementType, class... Integrals>
+ requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0)
+ explicit mdspan(ElementType*, Integrals...)
+ -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>;
+
+ template<class ElementType, class OtherIndexType, size_t N>
+ mdspan(ElementType*, span<OtherIndexType, N>)
+ -> mdspan<ElementType, dextents<size_t, N>>;
+
+ template<class ElementType, class OtherIndexType, size_t N>
+ mdspan(ElementType*, const array<OtherIndexType, N>&)
+ -> mdspan<ElementType, dextents<size_t, N>>;
+
+ template<class ElementType, class IndexType, size_t... ExtentsPack>
+ mdspan(ElementType*, const extents<IndexType, ExtentsPack...>&)
+ -> mdspan<ElementType, extents<IndexType, ExtentsPack...>>;
+
+ template<class ElementType, class MappingType>
+ mdspan(ElementType*, const MappingType&)
+ -> mdspan<ElementType, typename MappingType::extents_type,
+ typename MappingType::layout_type>;
+
+ template<class MappingType, class 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>;
+}
*/
#ifndef _LIBCPP_MDSPAN
@@ -219,6 +348,7 @@ namespace std {
#include <__mdspan/extents.h>
#include <__mdspan/layout_left.h>
#include <__mdspan/layout_right.h>
+#include <__mdspan/mdspan.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 9ff8b67a6a20fd..0b418d2b78974e 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1516,6 +1516,7 @@ module std_private_mdspan_extents [system] {
}
module std_private_mdspan_layout_left [system] { header "__mdspan/layout_left.h" }
module std_private_mdspan_layout_right [system] { header "__mdspan/layout_right.h" }
+module std_private_mdspan_mdspan [system] { header "__mdspan/mdspan.h" }
module std_private_mdspan_mdspan_fwd [system] { header "__fwd/mdspan.h" }
module std_private_memory_addressof [system] { header "__memory/addressof.h" }
diff --git a/libcxx/modules/std/mdspan.cppm b/libcxx/modules/std/mdspan.cppm
index 5023dfb925ea11..d92024d9a77a3d 100644
--- a/libcxx/modules/std/mdspan.cppm
+++ b/libcxx/modules/std/mdspan.cppm
@@ -27,5 +27,5 @@ export namespace std {
using std::default_accessor;
// [mdspan.mdspan], class template mdspan
- // using std::mdspan;
+ using std::mdspan;
} // namespace std
diff --git a/libcxx/test/std/containers/views/mdspan/ConvertibleToIntegral.h b/libcxx/test/std/containers/views/mdspan/ConvertibleToIntegral.h
index df67c2050d4bea..d6540d8adb6a08 100644
--- a/libcxx/test/std/containers/views/mdspan/ConvertibleToIntegral.h
+++ b/libcxx/test/std/containers/views/mdspan/ConvertibleToIntegral.h
@@ -20,4 +20,25 @@ struct IntType {
constexpr operator char() const noexcept { return val; }
};
+// only non-const convertible
+struct IntTypeNC {
+ int val;
+ constexpr IntTypeNC() = default;
+ constexpr IntTypeNC(int v) noexcept : val(v){};
+
+ constexpr bool operator==(const IntType& rhs) const { return val == rhs.val; }
+ constexpr operator int() noexcept { return val; }
+ constexpr operator unsigned() { return val; }
+ constexpr operator char() noexcept { return val; }
+};
+
+// weird configurability of convertibility to int
+template<bool conv_c, bool conv_nc, bool ctor_nt_c, bool ctor_nt_nc>
+struct IntConfig {
+ int val;
+ constexpr explicit IntConfig(int val_):val(val_){}
+ constexpr operator int() noexcept(ctor_nt_nc) requires(conv_nc) { return val; }
+ constexpr operator int() const noexcept(ctor_nt_c) requires(conv_c) { return val; }
+};
+
#endif // TEST_STD_CONTAINERS_VIEWS_MDSPAN_CONVERTIBLE_TO_INTEGRAL_H
diff --git a/libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp
index e20146f9ea5181..078d41358d8661 100644
--- a/libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/extents/assert.obs.pass.cpp
@@ -6,7 +6,7 @@
//===----------------------------------------------------------------------===//
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// UNSUPPORTED: !libcpp-has-debug-mode
// XFAIL: availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp
index 733f2a6038ff56..ec4009e850c56b 100644
--- a/libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_array.pass.cpp
@@ -82,5 +82,17 @@ int main(int, char**) {
static_assert(std::is_convertible_v<IntType, int>, "Test helper IntType unexpectedly not convertible to int");
static_assert(!std::is_constructible_v< std::extents<unsigned long, D>, std::array<IntType, 1>>,
"extents constructible from illegal arguments");
+
+ // index_type is not nothrow constructible
+ static_assert(std::is_convertible_v<IntType, unsigned char>);
+ static_assert(std::is_convertible_v<const IntType&, unsigned char>);
+ static_assert(!std::is_nothrow_constructible_v<unsigned char, const IntType&>);
+ static_assert(!std::is_constructible_v<std::dextents<unsigned char, 2>, std::array<IntType, 2>>);
+
+ // convertible from non-const to index_type but not from const
+ static_assert(std::is_convertible_v<IntTypeNC, int>);
+ static_assert(!std::is_convertible_v<const IntTypeNC&, int>);
+ static_assert(std::is_nothrow_constructible_v<int, IntTypeNC>);
+ static_assert(!std::is_constructible_v<std::dextents<int, 2>, std::array<IntTypeNC, 2>>);
return 0;
}
diff --git a/libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp
index b327aa4de7afec..ea9c5be48357fa 100644
--- a/libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/extents/ctor_from_span.pass.cpp
@@ -84,5 +84,17 @@ int main(int, char**) {
static_assert(std::is_convertible_v<IntType, int>, "Test helper IntType unexpectedly not convertible to int");
static_assert(!std::is_constructible_v< std::extents<unsigned long, D>, std::span<IntType, 1>>,
"extents constructible from illegal arguments");
+
+ // index_type is not nothrow constructible
+ static_assert(std::is_convertible_v<IntType, unsigned char>);
+ static_assert(std::is_convertible_v<const IntType&, unsigned char>);
+ static_assert(!std::is_nothrow_constructible_v<unsigned char, const IntType&>);
+ static_assert(!std::is_constructible_v<std::dextents<unsigned char, 2>, std::span<IntType, 2>>);
+
+ // convertible from non-const to index_type but not from const
+ static_assert(std::is_convertible_v<IntTypeNC, int>);
+ static_assert(!std::is_convertible_v<const IntTypeNC&, int>);
+ static_assert(std::is_nothrow_constructible_v<int, IntTypeNC>);
+ static_assert(!std::is_constructible_v<std::dextents<int, 2>, std::span<IntTypeNC, 2>>);
return 0;
}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp
index 4a122e09040849..34b91c38185d30 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left/assert.ctor.extents.pass.cpp
@@ -8,7 +8,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// UNSUPPORTED: !libcpp-has-debug-mode
// XFAIL: availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp
index 1d10310f42e164..47fb858b1b4e07 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left/assert.index_operator.pass.cpp
@@ -8,7 +8,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// UNSUPPORTED: !libcpp-has-debug-mode
// XFAIL: availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left/assert.stride.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left/assert.stride.pass.cpp
index 6fe792d5170fd4..822104a9f341c6 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left/assert.stride.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left/assert.stride.pass.cpp
@@ -8,7 +8,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// UNSUPPORTED: !libcpp-has-debug-mode
// XFAIL: availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp
index a460a3a27b943a..0e523de847a7cc 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right/assert.ctor.extents.pass.cpp
@@ -8,7 +8,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// UNSUPPORTED: !libcpp-has-debug-mode
// XFAIL: availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp
index 4a9c4ee780d658..f45d4b72ede4d5 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right/assert.index_operator.pass.cpp
@@ -8,7 +8,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// UNSUPPORTED: !libcpp-has-debug-mode
// XFAIL: availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right/assert.stride.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right/assert.stride.pass.cpp
index 01b2891d93d770..7ba3f4e34c53bf 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right/assert.stride.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right/assert.stride.pass.cpp
@@ -8,7 +8,7 @@
// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
-// UNSUPPORTED: !libcpp-has-hardened-mode && !libcpp-has-debug-mode
+// UNSUPPORTED: !libcpp-has-debug-mode
// XFAIL: availability-verbose_abort-missing
// <mdspan>
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/CustomTestAccessors.h b/libcxx/test/std/containers/views/mdspan/mdspan/CustomTestAccessors.h
new file mode 100644
index 00000000000000..346f4977ca142e
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/CustomTestAccessors.h
@@ -0,0 +1,314 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// Kokkos v. 4.0
+// Copyright (2022) National Technology & Engineering
+// Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_ACCESSORS_H
+#define TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_ACCESSORS_H
+
+#include <mdspan>
+#include <type_traits>
+#include <cassert>
+
+// This contains a bunch of accessors and handles which have
diff erent properties
+// regarding constructibility and convertibility in order to test mdspan constraints
+
+// non default constructible data handle
+template <class T>
+struct no_default_ctor_handle {
+ T* ptr;
+ no_default_ctor_handle() = delete;
+ constexpr no_default_ctor_handle(T* ptr_) : ptr(ptr_) {}
+};
+
+// handle that can't convert from T to const T
+template <class T>
+struct not_const_convertible_handle {
+ T* ptr;
+ constexpr not_const_convertible_handle() : ptr(nullptr) {}
+ constexpr not_const_convertible_handle(T* ptr_) : ptr(ptr_) {}
+
+ constexpr T& operator[](size_t i) const { return ptr[i]; }
+};
+
+// handle where move has side effects
+template <class T>
+struct move_counted_handle {
+ T* ptr;
+ constexpr move_counted_handle() = default;
+ constexpr move_counted_handle(const move_counted_handle&) = default;
+ template <class OtherT>
+ requires(std::is_constructible_v<T*, OtherT*>)
+ constexpr move_counted_handle(const move_counted_handle<OtherT>& other) : ptr(other.ptr){};
+ constexpr move_counted_handle(move_counted_handle&& other) {
+ ptr = other.ptr;
+ if !consteval {
+ move_counter()++;
+ }
+ }
+ constexpr move_counted_handle(T* ptr_) : ptr(ptr_) {}
+
+ constexpr move_counted_handle& operator=(const move_counted_handle&) = default;
+
+ constexpr T& operator[](size_t i) const { return ptr[i]; }
+
+ static int& move_counter() {
+ static int c = 0;
+ return c;
+ }
+};
+
+// non-default constructible accessor with a bunch of
diff erent data handles
+template <class ElementType>
+struct checked_accessor {
+ size_t N;
+ using offset_policy = std::default_accessor<ElementType>;
+ using element_type = ElementType;
+ using reference = ElementType&;
+ using data_handle_type = move_counted_handle<ElementType>;
+
+ constexpr checked_accessor(size_t N_) : N(N_) {}
+ template <class OtherElementType>
+ requires(std::is_convertible_v<OtherElementType (*)[], element_type (*)[]>)
+ explicit constexpr checked_accessor(const checked_accessor<OtherElementType>& other) noexcept {
+ N = other.N;
+ }
+
+ constexpr reference access(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p[i];
+ }
+ constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return data_handle_type(p.ptr + i);
+ }
+};
+
+static_assert(std::is_constructible_v<checked_accessor<const int>, const checked_accessor<int>&>);
+static_assert(!std::is_convertible_v<const checked_accessor<int>&, checked_accessor<const int>>);
+
+template <>
+struct checked_accessor<double> {
+ size_t N;
+ using offset_policy = std::default_accessor<double>;
+ using element_type = double;
+ using reference = double&;
+ using data_handle_type = no_default_ctor_handle<double>;
+
+ constexpr checked_accessor(size_t N_) : N(N_) {}
+
+ template <class OtherElementType>
+ requires(std::is_convertible_v<OtherElementType (*)[], element_type (*)[]>)
+ constexpr checked_accessor(checked_accessor<OtherElementType>&& other) noexcept {
+ N = other.N;
+ }
+
+ constexpr reference access(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p.ptr[i];
+ }
+ constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p.ptr + i;
+ }
+};
+
+template <>
+struct checked_accessor<unsigned> {
+ size_t N;
+ using offset_policy = std::default_accessor<unsigned>;
+ using element_type = unsigned;
+ using reference = unsigned;
+ using data_handle_type = not_const_convertible_handle<unsigned>;
+
+ constexpr checked_accessor() : N(0) {}
+ constexpr checked_accessor(size_t N_) : N(N_) {}
+ constexpr checked_accessor(const checked_accessor& acc) : N(acc.N) {}
+
+ constexpr reference access(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p[i];
+ }
+ constexpr auto offset(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p.ptr + i;
+ }
+};
+template <>
+struct checked_accessor<const unsigned> {
+ size_t N;
+ using offset_policy = std::default_accessor<const unsigned>;
+ using element_type = const unsigned;
+ using reference = unsigned;
+ using data_handle_type = not_const_convertible_handle<const unsigned>;
+
+ constexpr checked_accessor() : N(0) {}
+ constexpr checked_accessor(size_t N_) : N(N_) {}
+ constexpr checked_accessor(const checked_accessor& acc) : N(acc.N) {}
+
+ template <class OtherACC>
+ constexpr explicit(std::is_const_v<OtherACC>) checked_accessor(OtherACC&& acc) : N(acc.N) {}
+
+ constexpr reference access(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p[i];
+ }
+ constexpr auto offset(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p.ptr + i;
+ }
+};
+
+template <>
+struct checked_accessor<const float> {
+ size_t N;
+ using offset_policy = std::default_accessor<const float>;
+ using element_type = const float;
+ using reference = const float&;
+ using data_handle_type = move_counted_handle<const float>;
+
+ constexpr checked_accessor() : N(0) {}
+ constexpr checked_accessor(size_t N_) : N(N_) {}
+ constexpr checked_accessor(const checked_accessor& acc) : N(acc.N) {}
+
+ constexpr checked_accessor(checked_accessor<float>&& acc) : N(acc.N) {}
+
+ constexpr reference access(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p[i];
+ }
+ constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return data_handle_type(p.ptr + i);
+ }
+};
+
+template <>
+struct checked_accessor<const double> {
+ size_t N;
+ using offset_policy = std::default_accessor<const double>;
+ using element_type = const double;
+ using reference = const double&;
+ using data_handle_type = move_counted_handle<const double>;
+
+ constexpr checked_accessor() : N(0) {}
+ constexpr checked_accessor(size_t N_) : N(N_) {}
+ constexpr checked_accessor(const checked_accessor& acc) : N(acc.N) {}
+
+ constexpr reference access(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p[i];
+ }
+ constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return data_handle_type(p.ptr + i);
+ }
+};
+
+// Data handle pair which has configurable conversion properties
+// bool template parameters are used to enable/disable ctors and assignment
+// the c is the one for const T the nc for non-const (so we can convert mdspan)
+// Note both take non-const T as template parameter though
+template <class T, bool, bool, bool, bool>
+struct conv_test_accessor_c;
+
+template <class T, bool conv_c, bool conv_nc>
+struct conv_test_accessor_nc {
+ using offset_policy = std::default_accessor<T>;
+ using element_type = T;
+ using reference = T&;
+ using data_handle_type = T*;
+
+ constexpr conv_test_accessor_nc() = default;
+ constexpr conv_test_accessor_nc(const conv_test_accessor_nc&) = default;
+
+ template <bool b1, bool b2, bool b3, bool b4>
+ constexpr operator conv_test_accessor_c<T, b1, b2, b3, b4>()
+ requires(conv_nc)
+ {
+ return conv_test_accessor_c<T, b1, b2, b3, b4>{};
+ }
+ template <bool b1, bool b2, bool b3, bool b4>
+ constexpr operator conv_test_accessor_c<T, b1, b2, b3, b4>() const
+ requires(conv_c)
+ {
+ return conv_test_accessor_c<T, b1, b2, b3, b4>{};
+ }
+
+ 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; }
+};
+
+template <class T, bool ctor_c, bool ctor_mv, bool assign_c, bool assign_mv>
+struct conv_test_accessor_c {
+ using offset_policy = std::default_accessor<const T>;
+ using element_type = const T;
+ using reference = const T&;
+ using data_handle_type = const T*;
+
+ constexpr conv_test_accessor_c() = default;
+ constexpr conv_test_accessor_c(const conv_test_accessor_c&) = default;
+
+ template <bool b1, bool b2>
+ constexpr conv_test_accessor_c(const conv_test_accessor_nc<T, b1, b2>&)
+ requires(ctor_c)
+ {}
+ template <bool b1, bool b2>
+ constexpr conv_test_accessor_c(conv_test_accessor_nc<T, b1, b2>&&)
+ requires(ctor_mv)
+ {}
+ template <bool b1, bool b2>
+ constexpr conv_test_accessor_c& operator=(const conv_test_accessor_nc<T, b1, b2>&)
+ requires(assign_c)
+ {
+ return {};
+ }
+ template <bool b1, bool b2>
+ constexpr conv_test_accessor_c& operator=(conv_test_accessor_nc<T, b1, b2>&&)
+ requires(assign_mv)
+ {
+ return {};
+ }
+
+ 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; }
+};
+
+template <class ElementType>
+struct convertible_accessor_but_not_handle {
+ size_t N;
+ using offset_policy = std::default_accessor<ElementType>;
+ using element_type = ElementType;
+ using reference = ElementType&;
+ using data_handle_type = not_const_convertible_handle<element_type>;
+
+ constexpr convertible_accessor_but_not_handle() = default;
+ template <class OtherElementType>
+ requires(std::is_convertible_v<OtherElementType (*)[], element_type (*)[]>)
+ explicit constexpr convertible_accessor_but_not_handle(
+ const convertible_accessor_but_not_handle<OtherElementType>& other) noexcept {
+ N = other.N;
+ }
+
+ constexpr reference access(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return p[i];
+ }
+ constexpr data_handle_type offset(data_handle_type p, size_t i) const noexcept {
+ assert(i < N);
+ return data_handle_type(p.ptr + i);
+ }
+};
+
+#endif // TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_ACCESSORS_H
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/CustomTestLayouts.h b/libcxx/test/std/containers/views/mdspan/mdspan/CustomTestLayouts.h
new file mode 100644
index 00000000000000..e1d6e80afbd84c
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/CustomTestLayouts.h
@@ -0,0 +1,325 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// Kokkos v. 4.0
+// Copyright (2022) National Technology & Engineering
+// Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H
+#define TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cinttypes>
+#include <concepts>
+#include <cstddef>
+#include <limits>
+#include <mdspan>
+#include <type_traits>
+#include <utility>
+
+// Layout that wraps indices to test some idiosyncratic behavior
+// - basically it is a layout_left where indicies are first wrapped i.e. i%Wrap
+// - only accepts integers as indices
+// - is_always_strided and is_always_unique are false
+// - is_strided and is_unique are true if all extents are smaller than Wrap
+// - not default constructible
+// - not extents constructible
+// - not trivally copyable
+// - does not check dynamic to static extent conversion in converting ctor
+// - check via side-effects that mdspan::swap calls mappings swap via ADL
+
+struct not_extents_constructible_tag {};
+
+template <size_t Wrap>
+class layout_wrapping_integral {
+public:
+ template <class Extents>
+ class mapping;
+};
+
+template <size_t WrapArg>
+template <class Extents>
+class layout_wrapping_integral<WrapArg>::mapping {
+ static constexpr typename Extents::index_type Wrap = static_cast<typename Extents::index_type>(WrapArg);
+
+public:
+ using extents_type = Extents;
+ 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 layout_type = layout_wrapping_integral<Wrap>;
+
+private:
+ static constexpr bool required_span_size_is_representable(const extents_type& ext) {
+ if constexpr (extents_type::rank() == 0)
+ return true;
+
+ index_type prod = ext.extent(0);
+ for (rank_type r = 1; r < extents_type::rank(); r++) {
+ bool overflowed = __builtin_mul_overflow(prod, std::min(ext.extent(r), Wrap), &prod);
+ if (overflowed)
+ return false;
+ }
+ return true;
+ }
+
+public:
+ constexpr mapping() noexcept = delete;
+ constexpr mapping(const mapping& other) noexcept : extents_(other.extents()){};
+ constexpr mapping(extents_type&& ext) noexcept
+ requires(Wrap == 8)
+ : extents_(ext) {}
+ constexpr mapping(const extents_type& ext, not_extents_constructible_tag) noexcept : extents_(ext) {}
+
+ template <class OtherExtents>
+ requires(std::is_constructible_v<extents_type, OtherExtents> && (Wrap != 8))
+ constexpr explicit(!std::is_convertible_v<OtherExtents, extents_type>)
+ mapping(const mapping<OtherExtents>& other) noexcept {
+ std::array<index_type, extents_type::rank_dynamic()> dyn_extents;
+ rank_type count = 0;
+ for (rank_type r = 0; r < extents_type::rank(); r++) {
+ if (extents_type::static_extent(r) == std::dynamic_extent) {
+ dyn_extents[count++] = other.extents().extent(r);
+ }
+ }
+ extents_ = extents_type(dyn_extents);
+ }
+ template <class OtherExtents>
+ requires(std::is_constructible_v<extents_type, OtherExtents> && (Wrap == 8))
+ constexpr explicit(!std::is_convertible_v<OtherExtents, extents_type>)
+ mapping(mapping<OtherExtents>&& other) noexcept {
+ std::array<index_type, extents_type::rank_dynamic()> dyn_extents;
+ rank_type count = 0;
+ for (rank_type r = 0; r < extents_type::rank(); r++) {
+ if (extents_type::static_extent(r) == std::dynamic_extent) {
+ dyn_extents[count++] = other.extents().extent(r);
+ }
+ }
+ extents_ = extents_type(dyn_extents);
+ }
+
+ constexpr mapping& operator=(const mapping& other) noexcept {
+ extents_ = other.extents_;
+ return *this;
+ };
+
+ constexpr const extents_type& extents() const noexcept { return extents_; }
+
+ constexpr index_type required_span_size() const noexcept {
+ index_type size = 1;
+ for (size_t r = 0; r < extents_type::rank(); r++)
+ size *= extents_.extent(r) < Wrap ? extents_.extent(r) : Wrap;
+ return size;
+ }
+
+ template <std::integral... Indices>
+ requires((sizeof...(Indices) == extents_type::rank()) && (std::is_convertible_v<Indices, index_type> && ...) &&
+ (std::is_nothrow_constructible_v<index_type, Indices> && ...))
+ constexpr index_type operator()(Indices... idx) const noexcept {
+ std::array<index_type, extents_type::rank()> idx_a{static_cast<index_type>(static_cast<index_type>(idx) % Wrap)...};
+ return [&]<size_t... Pos>(std::index_sequence<Pos...>) {
+ index_type res = 0;
+ ((res = idx_a[extents_type::rank() - 1 - Pos] +
+ (extents_.extent(extents_type::rank() - 1 - Pos) < Wrap ? extents_.extent(extents_type::rank() - 1 - Pos)
+ : Wrap) *
+ res),
+ ...);
+ return res;
+ }(std::make_index_sequence<sizeof...(Indices)>());
+ }
+
+ static constexpr bool is_always_unique() noexcept { return false; }
+ static constexpr bool is_always_exhaustive() noexcept { return true; }
+ static constexpr bool is_always_strided() noexcept { return false; }
+
+ constexpr bool is_unique() const noexcept {
+ for (rank_type r = 0; r < extents_type::rank(); r++) {
+ if (extents_.extent(r) > Wrap)
+ return false;
+ }
+ return true;
+ }
+ static constexpr bool is_exhaustive() noexcept { return true; }
+ constexpr bool is_strided() const noexcept {
+ for (rank_type r = 0; r < extents_type::rank(); r++) {
+ if (extents_.extent(r) > Wrap)
+ return false;
+ }
+ return true;
+ }
+
+ constexpr index_type stride(rank_type r) const noexcept
+ requires(extents_type::rank() > 0)
+ {
+ index_type s = 1;
+ for (rank_type i = extents_type::rank() - 1; i > r; i--)
+ s *= extents_.extent(i);
+ return s;
+ }
+
+ template <class OtherExtents>
+ requires(OtherExtents::rank() == extents_type::rank())
+ friend constexpr bool operator==(const mapping& lhs, const mapping<OtherExtents>& rhs) noexcept {
+ return lhs.extents() == rhs.extents();
+ }
+
+ friend constexpr void swap(mapping& x, mapping& y) noexcept {
+ swap(x.extents_, y.extents_);
+ if !consteval {
+ swap_counter()++;
+ }
+ }
+
+ static int& swap_counter() {
+ static int value = 0;
+ return value;
+ }
+
+private:
+ extents_type extents_{};
+};
+
+template <class Extents>
+constexpr auto construct_mapping(std::layout_left, Extents exts) {
+ return std::layout_left::mapping<Extents>(exts);
+}
+
+template <class Extents>
+constexpr auto construct_mapping(std::layout_right, Extents exts) {
+ return std::layout_right::mapping<Extents>(exts);
+}
+
+template <size_t Wraps, class Extents>
+constexpr auto construct_mapping(layout_wrapping_integral<Wraps>, Extents exts) {
+ return typename layout_wrapping_integral<Wraps>::template mapping<Extents>(exts, not_extents_constructible_tag{});
+}
+
+
+// This layout does not check convertibility of extents for its conversion ctor
+// Allows triggering mdspan's ctor static assertion on convertibility of extents
+class always_convertible_layout {
+public:
+ template <class Extents>
+ class mapping;
+};
+
+template <class Extents>
+class always_convertible_layout::mapping {
+public:
+ using extents_type = Extents;
+ 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 layout_type = always_convertible_layout;
+
+private:
+ static constexpr bool required_span_size_is_representable(const extents_type& ext) {
+ if constexpr (extents_type::rank() == 0)
+ return true;
+
+ index_type prod = ext.extent(0);
+ for (rank_type r = 1; r < extents_type::rank(); r++) {
+ bool overflowed = __builtin_mul_overflow(prod, ext.extent(r), &prod);
+ if (overflowed)
+ return false;
+ }
+ return true;
+ }
+
+public:
+ constexpr mapping() noexcept = delete;
+ constexpr mapping(const mapping& other) noexcept : extents_(other.extents()){};
+ constexpr mapping(const extents_type& ext) noexcept : extents_(ext){};
+
+ template <class OtherExtents>
+ constexpr mapping(const mapping<OtherExtents>& other) noexcept {
+ if constexpr (extents_type::rank() == OtherExtents::rank()) {
+ std::array<index_type, extents_type::rank_dynamic()> dyn_extents;
+ rank_type count = 0;
+ for (rank_type r = 0; r < extents_type::rank(); r++) {
+ if (extents_type::static_extent(r) == std::dynamic_extent) {
+ dyn_extents[count++] = other.extents().extent(r);
+ }
+ }
+ extents_ = extents_type(dyn_extents);
+ } else {
+ extents_ = extents_type();
+ }
+ }
+
+ constexpr mapping& operator=(const mapping& other) noexcept {
+ extents_ = other.extents_;
+ return *this;
+ };
+
+ constexpr const extents_type& extents() const noexcept { return extents_; }
+
+ constexpr index_type required_span_size() const noexcept {
+ index_type size = 1;
+ for (size_t r = 0; r < extents_type::rank(); r++)
+ size *= extents_.extent(r);
+ return size;
+ }
+
+ template <std::integral... Indices>
+ requires((sizeof...(Indices) == extents_type::rank()) && (std::is_convertible_v<Indices, index_type> && ...) &&
+ (std::is_nothrow_constructible_v<index_type, Indices> && ...))
+ constexpr index_type operator()(Indices... idx) const noexcept {
+ std::array<index_type, extents_type::rank()> idx_a{static_cast<index_type>(static_cast<index_type>(idx))...};
+ return [&]<size_t... Pos>(std::index_sequence<Pos...>) {
+ index_type res = 0;
+ ((res = idx_a[extents_type::rank() - 1 - Pos] + extents_.extent(extents_type::rank() - 1 - Pos) * res), ...);
+ return res;
+ }(std::make_index_sequence<sizeof...(Indices)>());
+ }
+
+ static constexpr bool is_always_unique() noexcept { return false; }
+ static constexpr bool is_always_exhaustive() noexcept { return true; }
+ static constexpr bool is_always_strided() noexcept { return false; }
+
+ static constexpr bool is_unique() noexcept { return true; }
+ static constexpr bool is_exhaustive() noexcept { return true; }
+ static constexpr bool is_strided() noexcept { return true; }
+
+ constexpr index_type stride(rank_type r) const noexcept
+ requires(extents_type::rank() > 0)
+ {
+ index_type s = 1;
+ for (rank_type i = extents_type::rank() - 1; i > r; i--)
+ s *= extents_.extent(i);
+ return s;
+ }
+
+ template <class OtherExtents>
+ requires(OtherExtents::rank() == extents_type::rank())
+ friend constexpr bool operator==(const mapping& lhs, const mapping<OtherExtents>& rhs) noexcept {
+ return lhs.extents() == rhs.extents();
+ }
+
+ friend constexpr void swap(mapping& x, mapping& y) noexcept {
+ swap(x.extents_, y.extents_);
+ if !consteval {
+ swap_counter()++;
+ }
+ }
+
+ static int& swap_counter() {
+ static int value = 0;
+ return value;
+ }
+
+private:
+ extents_type extents_{};
+};
+#endif // TEST_STD_CONTAINERS_VIEWS_MDSPAN_MDSPAN_CUSTOM_TEST_LAYOUTS_H
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/assert.conversion.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/assert.conversion.pass.cpp
new file mode 100644
index 00000000000000..a8ea360a9f59ae
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/assert.conversion.pass.cpp
@@ -0,0 +1,66 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: !libcpp-has-debug-mode
+// XFAIL: availability-verbose_abort-missing
+
+// <mdspan>
+
+// template<class OtherElementType, class OtherExtents,
+// class OtherLayoutPolicy, class OtherAccessor>
+// constexpr explicit(see below)
+// mdspan(const mdspan<OtherElementType, OtherExtents,
+// OtherLayoutPolicy, OtherAccessor>& other);
+//
+// Constraints:
+// - is_constructible_v<mapping_type, const OtherLayoutPolicy::template mapping<OtherExtents>&> is true, and
+// - is_constructible_v<accessor_type, const OtherAccessor&> is true.
+// Mandates:
+// - is_constructible_v<data_handle_type, const OtherAccessor::data_handle_type&> is
+// - is_constructible_v<extents_type, OtherExtents> is true.
+//
+// Preconditions:
+// - For each rank index r of extents_type, static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r) is true.
+// - [0, map_.required_span_size()) is an accessible range of ptr_ and acc_ for values of ptr_, map_, and acc_ after the invocation of this constructor.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with other.ptr_,
+// - direct-non-list-initializes map_ with other.map_, and
+// - direct-non-list-initializes acc_ with other.acc_.
+//
+// Remarks: The expression inside explicit is equivalent to:
+// !is_convertible_v<const OtherLayoutPolicy::template mapping<OtherExtents>&, mapping_type>
+// || !is_convertible_v<const OtherAccessor&, accessor_type>
+
+#include <array>
+#include <cassert>
+#include <mdspan>
+
+#include "check_assertion.h"
+#include "CustomTestLayouts.h"
+
+// We use a funky mapping in this test that doesn't check the dynamic/static extents mismatch itself
+int main(int, char**) {
+ constexpr size_t D = std::dynamic_extent;
+ std::array<float, 10> data;
+ typename layout_wrapping_integral<4>::template mapping<std::dextents<int, 2>> src_map(
+ std::dextents<int, 2>(5, 2), not_extents_constructible_tag());
+ std::mdspan<float, std::dextents<int, 2>, layout_wrapping_integral<4>> arg(data.data(), src_map);
+
+ // working case
+ {
+ [[maybe_unused]] std::mdspan<float, std::extents<size_t, D, 2>, layout_wrapping_integral<4>> m(arg); // should work
+ }
+ // mismatch of static extent
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(
+ ([=] { std::mdspan<float, std::extents<size_t, D, 3>, layout_wrapping_integral<4>> m(arg); }()),
+ "mdspan: conversion mismatch of source dynamic extents with static extents");
+ }
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/assert.index_operator.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/assert.index_operator.pass.cpp
new file mode 100644
index 00000000000000..11d013e18e93b8
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/assert.index_operator.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: !libcpp-has-debug-mode
+// XFAIL: availability-verbose_abort-missing
+
+// <mdspan>
+
+// template<class... OtherIndexTypes>
+// constexpr reference operator[](OtherIndexTypes... indices) const;
+// Constraints:
+// - (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
+// - (is_nothrow_constructible_v<index_type, OtherIndexTypes> && ...) is true, and
+// - sizeof...(OtherIndexTypes) == rank() is true.
+//
+// Let I be extents_type::index-cast(std::move(indices)).
+//
+// Preconditions: I is a multidimensional index in extents().
+// Note 1: This implies that map_(I) < map_.required_span_size() is true.
+//
+// Effects: Equivalent to:
+// return acc_.access(ptr_, map_(static_cast<index_type>(std::move(indices))...));
+
+#include <mdspan>
+#include <cassert>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ float data[1024];
+ // value out of range
+ {
+ std::mdspan m(data, std::extents<unsigned char, 5>());
+ TEST_LIBCPP_ASSERT_FAILURE(m[-1], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[-130], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[5], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[1000], "mdspan: operator[] out of bounds access");
+ }
+ {
+ std::mdspan m(data, std::extents<signed char, 5>());
+ TEST_LIBCPP_ASSERT_FAILURE(m[-1], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[-130], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[5], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[1000], "mdspan: operator[] out of bounds access");
+ }
+ {
+ std::mdspan m(data, std::dextents<unsigned char, 1>(5));
+ TEST_LIBCPP_ASSERT_FAILURE(m[-1], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[-130], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[5], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[1000], "mdspan: operator[] out of bounds access");
+ }
+ {
+ std::mdspan m(data, std::dextents<signed char, 1>(5));
+ TEST_LIBCPP_ASSERT_FAILURE(m[-1], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[-130], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[5], "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE(m[1000], "mdspan: operator[] out of bounds access");
+ }
+ {
+ std::mdspan m(data, std::dextents<int, 3>(5, 7, 9));
+ TEST_LIBCPP_ASSERT_FAILURE((m[-1, -1, -1]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[-1, 0, 0]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[0, -1, 0]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[0, 0, -1]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[5, 3, 3]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[3, 7, 3]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[3, 3, 9]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[5, 7, 9]), "mdspan: operator[] out of bounds access");
+ }
+ {
+ std::mdspan m(data, std::dextents<unsigned, 3>(5, 7, 9));
+ TEST_LIBCPP_ASSERT_FAILURE((m[-1, -1, -1]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[-1, 0, 0]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[0, -1, 0]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[0, 0, -1]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[5, 3, 3]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[3, 7, 3]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[3, 3, 9]), "mdspan: operator[] out of bounds access");
+ TEST_LIBCPP_ASSERT_FAILURE((m[5, 7, 9]), "mdspan: operator[] out of bounds access");
+ }
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/assert.size.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/assert.size.pass.cpp
new file mode 100644
index 00000000000000..0266ec11c21f5f
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/assert.size.pass.cpp
@@ -0,0 +1,50 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// UNSUPPORTED: !libcpp-has-debug-mode
+// XFAIL: availability-verbose_abort-missing
+
+// <mdspan>
+
+// constexpr size_type size() const noexcept;
+//
+// Preconditions: The size of the multidimensional index space extents() is representable as a value of type size_type ([basic.fundamental]).
+//
+// Returns: extents().fwd-prod-of-extents(rank()).
+
+#include <array>
+#include <cassert>
+#include <mdspan>
+
+#include "check_assertion.h"
+#include "CustomTestLayouts.h"
+
+// We use a funky mapping in this test where required_span_size is much smaller than the size of the index space
+int main(int, char**) {
+ std::array<float, 10> data;
+ // make sure we are not failing because of using index_type instead of size_type
+ {
+ typename layout_wrapping_integral<4>::template mapping<std::dextents<char, 2>> map(
+ std::dextents<char, 2>(100, 2), not_extents_constructible_tag());
+ std::mdspan<float, std::dextents<char, 2>, layout_wrapping_integral<4>> mds(data.data(), map);
+ assert(map.required_span_size() == char(8));
+ assert((static_cast<unsigned char>(200) == mds.size()));
+ }
+ {
+ typename layout_wrapping_integral<4>::template mapping<std::dextents<char, 2>> map(
+ std::dextents<char, 2>(100, 3), not_extents_constructible_tag());
+ std::mdspan<float, std::dextents<char, 2>, layout_wrapping_integral<4>> mds(data.data(), map);
+ // sanity check
+ assert(map.required_span_size() == char(12));
+ // 100 x 3 exceeds 256
+ {
+ TEST_LIBCPP_ASSERT_FAILURE(([=] { mds.size(); }()), "mdspan: size() is not representable as size_type");
+ }
+ }
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/assign.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/assign.pass.cpp
new file mode 100644
index 00000000000000..a6f436fd44880c
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/assign.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// constexpr mdspan& operator=(const mdspan& rhs) = default;
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ MDS m_org(handle, map, acc);
+ MDS m(handle, map, acc);
+
+ // The defaulted assignment operator seems to be deprecated because:
+ // error: definition of implicit copy assignment operator for 'checked_accessor<const double>' is deprecated
+ // because it has a user-provided copy constructor [-Werror,-Wdeprecated-copy-with-user-provided-copy]
+ if constexpr (!std::is_same_v<A, checked_accessor<const double>>)
+ m = m_org;
+ // even though the following checks out:
+ static_assert(std::copyable<checked_accessor<const double>>);
+ static_assert(std::is_assignable_v<checked_accessor<const double>, checked_accessor<const double>>);
+
+ static_assert(noexcept(m = m_org));
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == acc);
+
+ static_assert(std::is_trivially_assignable_v<MDS, const MDS&> ==
+ ((!std::is_class_v<H> ||
+ std::is_trivially_assignable_v<H, const H&>)&&std::is_trivially_assignable_v<M, const M&> &&
+ std::is_trivially_assignable_v<A, const A&>));
+}
+
+template <class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ // make sure we test a trivially assignable mapping
+ static_assert(std::is_trivially_assignable_v<typename std::layout_left::template mapping<std::extents<int>>,
+ const typename std::layout_left::template mapping<std::extents<int>>&>);
+ mixin_extents(handle, std::layout_left(), acc);
+ mixin_extents(handle, std::layout_right(), acc);
+ // make sure we test a not trivially assignable mapping
+ static_assert(!std::is_trivially_assignable_v<
+ typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ const typename layout_wrapping_integral<4>::template mapping<std::extents<int>>&>);
+ mixin_extents(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ // make sure we test trivially constructible accessor and data_handle
+ static_assert(std::is_trivially_copyable_v<std::default_accessor<T>>);
+ static_assert(std::is_trivially_copyable_v<typename std::default_accessor<T>::data_handle_type>);
+ mixin_layout(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is noexcept copy constructible except for const double
+ checked_accessor<T> acc(1024);
+ static_assert(noexcept(checked_accessor<T>(acc)) != std::is_same_v<T, const double>);
+ mixin_layout(typename checked_accessor<T>::data_handle_type(elements.get_ptr()), acc);
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp
new file mode 100644
index 00000000000000..bb592763335032
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp
@@ -0,0 +1,281 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class OtherElementType, class OtherExtents,
+// class OtherLayoutPolicy, class OtherAccessor>
+// constexpr explicit(see below)
+// mdspan(const mdspan<OtherElementType, OtherExtents,
+// OtherLayoutPolicy, OtherAccessor>& other);
+//
+// Constraints:
+// - is_constructible_v<mapping_type, const OtherLayoutPolicy::template mapping<OtherExtents>&> is true, and
+// - is_constructible_v<accessor_type, const OtherAccessor&> is true.
+// Mandates:
+// - is_constructible_v<data_handle_type, const OtherAccessor::data_handle_type&> is
+// - is_constructible_v<extents_type, OtherExtents> is true.
+//
+// Preconditions:
+// - For each rank index r of extents_type, static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r) is true.
+// - [0, map_.required_span_size()) is an accessible range of ptr_ and acc_ for values of ptr_, map_, and acc_ after the invocation of this constructor.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with other.ptr_,
+// - direct-non-list-initializes map_ with other.map_, and
+// - direct-non-list-initializes acc_ with other.acc_.
+//
+// Remarks: The expression inside explicit is equivalent to:
+// !is_convertible_v<const OtherLayoutPolicy::template mapping<OtherExtents>&, mapping_type>
+// || !is_convertible_v<const OtherAccessor&, accessor_type>
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class ToMDS, class FromMDS>
+constexpr void test_implicit_conversion(ToMDS to_mds, FromMDS from_mds) {
+ assert(to_mds.extents() == from_mds.extents());
+ if constexpr (std::equality_comparable_with<typename ToMDS::data_handle_type, typename FromMDS::data_handle_type>)
+ assert(to_mds.data_handle() == from_mds.data_handle());
+ if constexpr (std::equality_comparable_with<typename ToMDS::mapping_type, typename FromMDS::mapping_type>)
+ assert(to_mds.mapping() == from_mds.mapping());
+ if constexpr (std::equality_comparable_with<typename ToMDS::accessor_type, typename FromMDS::accessor_type>)
+ assert(to_mds.accessor() == from_mds.accessor());
+}
+
+template <class M>
+concept mapping_requirements = requires() {
+ requires(std::copyable<M> && std::equality_comparable<M>) && std::is_nothrow_move_constructible_v<M> &&
+ std::is_nothrow_move_assignable_v<M> && std::is_nothrow_swappable_v<M>;
+};
+
+template <class ToMDS, class FromMDS>
+constexpr void test_conversion(FromMDS from_mds) {
+ // check some requirements, to see we didn't screw up our test layouts/accessors
+ static_assert(mapping_requirements<typename ToMDS::mapping_type>);
+ static_assert(mapping_requirements<typename FromMDS::mapping_type>);
+
+ constexpr bool constructible =
+ std::is_constructible_v<typename ToMDS::mapping_type, const typename FromMDS::mapping_type&> &&
+ std::is_constructible_v<typename ToMDS::accessor_type, const typename FromMDS::accessor_type&>;
+ constexpr bool convertible =
+ std::is_convertible_v<const typename FromMDS::mapping_type&, typename ToMDS::mapping_type> &&
+ std::is_convertible_v<const typename FromMDS::accessor_type&, typename ToMDS::accessor_type>;
+ constexpr bool passes_mandates =
+ std::is_constructible_v<typename ToMDS::data_handle_type, const typename FromMDS::data_handle_type&> &&
+ std::is_constructible_v<typename ToMDS::extents_type, typename FromMDS::extents_type>;
+
+ if constexpr (constructible) {
+ if constexpr (passes_mandates) {
+ ToMDS to_mds(from_mds);
+ assert(to_mds.extents() == from_mds.extents());
+ if constexpr (std::equality_comparable_with<typename ToMDS::data_handle_type, typename FromMDS::data_handle_type>)
+ assert(to_mds.data_handle() == from_mds.data_handle());
+ if constexpr (std::equality_comparable_with<typename ToMDS::mapping_type, typename FromMDS::mapping_type>)
+ assert(to_mds.mapping() == from_mds.mapping());
+ if constexpr (std::equality_comparable_with<typename ToMDS::accessor_type, typename FromMDS::accessor_type>)
+ assert(to_mds.accessor() == from_mds.accessor());
+ if constexpr (convertible) {
+ test_implicit_conversion(from_mds, from_mds);
+ } else {
+ static_assert(!std::is_convertible_v<FromMDS, ToMDS>);
+ }
+ }
+ } else {
+ static_assert(!std::is_constructible_v<ToMDS, FromMDS>);
+ }
+}
+
+template <class ToL, class ToE, class ToA, class FromH, class FromL, class FromE, class FromA>
+constexpr void construct_from_mds(const FromH& handle, const FromL& layout, const FromE& exts, const FromA& acc) {
+ using ToMDS = std::mdspan<typename ToA::element_type, ToE, ToL, ToA>;
+ using FromMDS = std::mdspan<typename FromA::element_type, FromE, FromL, FromA>;
+ test_conversion<ToMDS>(FromMDS(handle, construct_mapping(layout, exts), acc));
+}
+
+template <class ToL, class ToA, class FromH, class FromL, class FromA>
+constexpr void mixin_extents(const FromH& handle, const FromL& layout, const FromA& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ // constructible and convertible
+ construct_from_mds<ToL, std::dextents<int, 0>, ToA>(handle, layout, std::dextents<int, 0>(), acc);
+ construct_from_mds<ToL, std::dextents<int, 1>, ToA>(handle, layout, std::dextents<int, 1>(4), acc);
+ construct_from_mds<ToL, std::dextents<int, 1>, ToA>(handle, layout, std::extents<int, 4>(), acc);
+ construct_from_mds<ToL, std::dextents<int, 2>, ToA>(handle, layout, std::dextents<int, 2>(4, 5), acc);
+ construct_from_mds<ToL, std::dextents<unsigned, 2>, ToA>(handle, layout, std::dextents<int, 2>(4, 5), acc);
+ construct_from_mds<ToL, std::dextents<unsigned, 2>, ToA>(handle, layout, std::extents<int, D, 5>(4), acc);
+ construct_from_mds<ToL, std::extents<int, D, 5>, ToA>(handle, layout, std::extents<int, D, 5>(4), acc);
+ construct_from_mds<ToL, std::extents<int, D, 5>, ToA>(handle, layout, std::extents<int, D, 5>(4), acc);
+ construct_from_mds<ToL, std::extents<int, D, 5, D, 7>, ToA>(handle, layout, std::extents<int, D, 5, D, 7>(4, 6), acc);
+
+ // not convertible
+ construct_from_mds<ToL, std::dextents<int, 1>, ToA>(handle, layout, std::dextents<unsigned, 1>(4), acc);
+ construct_from_mds<ToL, std::extents<int, D, 5, D, 7>, ToA>(
+ handle, layout, std::extents<int, D, 5, D, D>(4, 6, 7), acc);
+
+ // not constructible
+ construct_from_mds<ToL, std::dextents<int, 1>, ToA>(handle, layout, std::dextents<int, 2>(4, 5), acc);
+ construct_from_mds<ToL, std::extents<int, D, 5, D, 8>, ToA>(handle, layout, std::extents<int, D, 5, D, 7>(4, 6), acc);
+}
+
+template <class ToA, class FromH, class FromA>
+constexpr void mixin_layout(const FromH& handle, const FromA& acc) {
+ mixin_extents<std::layout_left, ToA>(handle, std::layout_left(), acc);
+ mixin_extents<std::layout_right, ToA>(handle, std::layout_right(), acc);
+ // Check layout policy conversion
+ //
diff erent layout policies, but constructible and convertible
+ static_assert(std::is_constructible_v<std::layout_left::mapping<std::dextents<int, 1>>,
+ const std::layout_right::mapping<std::dextents<int, 1>>&>);
+ static_assert(std::is_convertible_v<const std::layout_right::mapping<std::dextents<int, 1>>&,
+ std::layout_left::mapping<std::dextents<int, 1>>>);
+ //
diff erent layout policies, not constructible
+ static_assert(!std::is_constructible_v<std::layout_left::mapping<std::dextents<int, 2>>,
+ const std::layout_right::mapping<std::dextents<int, 2>>&>);
+ //
diff erent layout policies, constructible and not convertible
+ static_assert(std::is_constructible_v<std::layout_left::mapping<std::dextents<int, 1>>,
+ const std::layout_right::mapping<std::dextents<size_t, 1>>&>);
+ static_assert(!std::is_convertible_v<const std::layout_right::mapping<std::dextents<size_t, 1>>&,
+ std::layout_left::mapping<std::dextents<int, 1>>>);
+
+ mixin_extents<std::layout_left, ToA>(handle, std::layout_right(), acc);
+ mixin_extents<layout_wrapping_integral<4>, ToA>(handle, layout_wrapping_integral<4>(), acc);
+ //
diff erent layout policies, constructible and not convertible
+ static_assert(!std::is_constructible_v<layout_wrapping_integral<8>::mapping<std::dextents<unsigned, 2>>,
+ const layout_wrapping_integral<8>::mapping<std::dextents<int, 2>>&>);
+ static_assert(std::is_constructible_v<layout_wrapping_integral<8>::mapping<std::dextents<unsigned, 2>>,
+ layout_wrapping_integral<8>::mapping<std::dextents<int, 2>>>);
+ mixin_extents<layout_wrapping_integral<8>, ToA>(handle, layout_wrapping_integral<8>(), acc);
+}
+
+// check that we cover all corners with respect to constructibility and convertibility
+template <bool constructible_constref_acc,
+ bool convertible_constref_acc,
+ bool constructible_nonconst_acc,
+ bool convertible_nonconst_acc,
+ bool constructible_constref_handle,
+ bool convertible_constref_handle,
+ bool constructible_nonconst_handle,
+ bool convertible_nonconst_handle,
+ class ToA,
+ class FromA>
+constexpr bool test(FromA from_acc) {
+ static_assert(std::copyable<ToA>);
+ static_assert(std::copyable<FromA>);
+ static_assert(std::is_constructible_v<ToA, const FromA&> == constructible_constref_acc);
+ static_assert(std::is_constructible_v<ToA, FromA> == constructible_nonconst_acc);
+ static_assert(std::is_constructible_v<typename ToA::data_handle_type, const typename FromA::data_handle_type&> ==
+ constructible_constref_handle);
+ static_assert(std::is_constructible_v<typename ToA::data_handle_type, typename FromA::data_handle_type> ==
+ constructible_nonconst_handle);
+ static_assert(std::is_convertible_v<const FromA&, ToA> == convertible_constref_acc);
+ static_assert(std::is_convertible_v<FromA, ToA> == convertible_nonconst_acc);
+ static_assert(std::is_convertible_v<const typename FromA::data_handle_type&, typename ToA::data_handle_type> ==
+ convertible_constref_handle);
+ static_assert(std::is_convertible_v<typename FromA::data_handle_type, typename ToA::data_handle_type> ==
+ convertible_nonconst_handle);
+
+ ElementPool<typename FromA::element_type, 1024> elements;
+ mixin_layout<ToA>(typename FromA::data_handle_type(elements.get_ptr()), from_acc);
+ return true;
+}
+
+int main(int, char**) {
+ // using shorthands here: t and o for better visual distinguishability
+ constexpr bool t = true;
+ constexpr bool o = false;
+
+ // possibility matrix for constructibility and convertibility https://godbolt.org/z/98KGo8Wbc
+ // you can't have convertibility without constructibility
+ // and if you take const T& then you also can take T
+ // this leaves 7 combinations
+ // const_ref_ctor, const_ref_conv, nonconst_ctor, nonconst_conv, tested
+ // o o o o X
+ // o o t o X
+ // o o t t X
+ // t o t o X
+ // t o t t X
+ // t t t o X
+ // t t t t X
+
+ // checked_accessor has various weird data handles and some weird conversion properties
+ // conv_test_accessor_c/nc is an accessor pair which has configurable conversion properties, but plain ptr as data handle
+ // accessor constructible
+ test<t, t, t, t, t, t, t, t, std::default_accessor<float>>(std::default_accessor<float>());
+ test<t, t, t, t, t, t, t, t, std::default_accessor<const float>>(std::default_accessor<float>());
+ test<t, t, t, t, t, t, t, t, std::default_accessor<MinimalElementType>>(std::default_accessor<MinimalElementType>());
+ test<t, t, t, t, t, t, t, t, std::default_accessor<const MinimalElementType>>(
+ std::default_accessor<MinimalElementType>());
+ test<t, t, t, t, t, t, t, t, checked_accessor<int>>(checked_accessor<int>(1024));
+ test<t, o, t, o, t, t, t, t, checked_accessor<const int>>(checked_accessor<int>(1024));
+ test<t, t, t, t, o, o, o, o, checked_accessor<const unsigned>>(checked_accessor<unsigned>(1024));
+ test<t, t, t, t, t, t, t, t, checked_accessor<float>>(checked_accessor<float>(1024));
+ test<t, t, t, t, t, t, t, t, checked_accessor<double>>(checked_accessor<double>(1024));
+ test<t, t, t, t, t, t, t, t, checked_accessor<MinimalElementType>>(checked_accessor<MinimalElementType>(1024));
+ test<t, o, t, o, t, t, t, t, checked_accessor<const MinimalElementType>>(checked_accessor<MinimalElementType>(1024));
+ test<t, o, t, o, t, t, t, t, conv_test_accessor_c<int, t, t, t, t>>(conv_test_accessor_nc<int, t, t>());
+ test<t, o, t, t, t, t, t, t, conv_test_accessor_c<int, t, t, o, o>>(conv_test_accessor_nc<int, t, o>());
+ // FIXME: these tests trigger what appears to be a compiler bug on MINGW32 with --target=x86_64-w64-windows-gnu
+ // https://godbolt.org/z/KK8aj5bs7
+ // Bug report: https://github.com/llvm/llvm-project/issues/64077
+ #ifndef __MINGW32__
+ test<t, t, t, o, t, t, t, t, conv_test_accessor_c<int, o, t, t, t>>(conv_test_accessor_nc<int, t, t>());
+ test<t, t, t, t, t, t, t, t, conv_test_accessor_c<int, o, o, o, o>>(conv_test_accessor_nc<int, t, o>());
+ #endif
+
+ // ElementType convertible, but accessor not constructible
+ test<o, o, o, o, o, o, o, o, std::default_accessor<float>>(std::default_accessor<int>());
+ test<o, o, o, o, o, o, o, o, checked_accessor<const double>>(checked_accessor<double>(1024));
+ test<o, o, t, t, t, t, t, t, checked_accessor<const float>>(checked_accessor<float>(1024));
+ test<o, o, o, o, t, t, t, t, conv_test_accessor_c<int, o, o, t, t>>(conv_test_accessor_nc<int, o, o>());
+ test<o, o, t, o, t, t, t, t, conv_test_accessor_c<int, o, t, o, o>>(conv_test_accessor_nc<int, o, t>());
+ test<o, o, t, t, t, t, t, t, conv_test_accessor_c<int, o, o, t, t>>(conv_test_accessor_nc<int, o, t>());
+
+ // Ran into trouble with doing it all in one static_assert: exceeding step limit for consteval
+ static_assert(test<t, t, t, t, t, t, t, t, std::default_accessor<float>>(std::default_accessor<float>()));
+ static_assert(test<t, t, t, t, t, t, t, t, std::default_accessor<const float>>(std::default_accessor<float>()));
+ static_assert(test<t, t, t, t, t, t, t, t, std::default_accessor<MinimalElementType>>(
+ std::default_accessor<MinimalElementType>()));
+ static_assert(test<t, t, t, t, t, t, t, t, std::default_accessor<const MinimalElementType>>(
+ std::default_accessor<MinimalElementType>()));
+ static_assert(test<t, t, t, t, t, t, t, t, checked_accessor<int>>(checked_accessor<int>(1024)));
+ static_assert(test<t, o, t, o, t, t, t, t, checked_accessor<const int>>(checked_accessor<int>(1024)));
+ static_assert(test<t, t, t, t, o, o, o, o, checked_accessor<const unsigned>>(checked_accessor<unsigned>(1024)));
+ static_assert(test<t, t, t, t, t, t, t, t, checked_accessor<float>>(checked_accessor<float>(1024)));
+ static_assert(test<t, t, t, t, t, t, t, t, checked_accessor<double>>(checked_accessor<double>(1024)));
+ static_assert(
+ test<t, t, t, t, t, t, t, t, checked_accessor<MinimalElementType>>(checked_accessor<MinimalElementType>(1024)));
+ static_assert(test<t, o, t, o, t, t, t, t, checked_accessor<const MinimalElementType>>(
+ checked_accessor<MinimalElementType>(1024)));
+ static_assert(
+ test<t, o, t, o, t, t, t, t, conv_test_accessor_c<int, t, t, t, t>>(conv_test_accessor_nc<int, t, t>()));
+ static_assert(
+ test<t, o, t, t, t, t, t, t, conv_test_accessor_c<int, t, t, o, o>>(conv_test_accessor_nc<int, t, o>()));
+ static_assert(
+ test<t, t, t, o, t, t, t, t, conv_test_accessor_c<int, o, t, t, t>>(conv_test_accessor_nc<int, t, t>()));
+ static_assert(
+ test<t, t, t, t, t, t, t, t, conv_test_accessor_c<int, o, o, o, o>>(conv_test_accessor_nc<int, t, o>()));
+ static_assert(test<o, o, o, o, o, o, o, o, std::default_accessor<float>>(std::default_accessor<int>()));
+ static_assert(test<o, o, o, o, o, o, o, o, checked_accessor<const double>>(checked_accessor<double>(1024)));
+ static_assert(test<o, o, t, t, t, t, t, t, checked_accessor<const float>>(checked_accessor<float>(1024)));
+ static_assert(
+ test<o, o, o, o, t, t, t, t, conv_test_accessor_c<int, o, o, t, t>>(conv_test_accessor_nc<int, o, o>()));
+ static_assert(
+ test<o, o, t, o, t, t, t, t, conv_test_accessor_c<int, o, t, o, o>>(conv_test_accessor_nc<int, o, t>()));
+ static_assert(
+ test<o, o, t, t, t, t, t, t, conv_test_accessor_c<int, o, o, t, t>>(conv_test_accessor_nc<int, o, t>()));
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp
new file mode 100644
index 00000000000000..5a0ece29a9b84c
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp
@@ -0,0 +1,57 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class OtherElementType, class OtherExtents,
+// class OtherLayoutPolicy, class OtherAccessor>
+// constexpr explicit(see below)
+// mdspan(const mdspan<OtherElementType, OtherExtents,
+// OtherLayoutPolicy, OtherAccessor>& other);
+//
+// Constraints:
+// - is_constructible_v<mapping_type, const OtherLayoutPolicy::template mapping<OtherExtents>&> is true, and
+// - is_constructible_v<accessor_type, const OtherAccessor&> is true.
+// Mandates:
+// - is_constructible_v<data_handle_type, const OtherAccessor::data_handle_type&> is
+// - is_constructible_v<extents_type, OtherExtents> is true.
+//
+// Preconditions:
+// - For each rank index r of extents_type, static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r) is true.
+// - [0, map_.required_span_size()) is an accessible range of ptr_ and acc_ for values of ptr_, map_, and acc_ after the invocation of this constructor.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with other.ptr_,
+// - direct-non-list-initializes map_ with other.map_, and
+// - direct-non-list-initializes acc_ with other.acc_.
+//
+// Remarks: The expression inside explicit is equivalent to:
+// !is_convertible_v<const OtherLayoutPolicy::template mapping<OtherExtents>&, mapping_type>
+// || !is_convertible_v<const OtherAccessor&, accessor_type>
+
+#include <mdspan>
+#include "CustomTestAccessors.h"
+#include "CustomTestLayouts.h"
+
+void cant_construct_data_handle_type() {
+ int data;
+ std::mdspan<int, std::extents<int>, std::layout_right, convertible_accessor_but_not_handle<int>> m_nc(&data);
+ // expected-error-re@*:* {{{{.*}}no matching constructor for initialization of {{.*}} (aka 'not_const_convertible_handle<const int>')}}
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: incompatible data_handle_type for mdspan construction}}
+ [[maybe_unused]] std::
+ mdspan<const int, std::extents<int>, std::layout_right, convertible_accessor_but_not_handle<const int>>
+ m_c(m_nc);
+}
+
+void mapping_constructible_despite_extents_compatibility() {
+ int data;
+ std::mdspan<int, std::extents<int>, always_convertible_layout> m(&data);
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: incompatible extents for mdspan construction}}
+ [[maybe_unused]] std::mdspan<int, std::extents<int, 5>, always_convertible_layout> m2(m);
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp
new file mode 100644
index 00000000000000..813250d8cefff5
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp
@@ -0,0 +1,98 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// constexpr mdspan(const mdspan&) = default;
+//
+// A specialization of mdspan is a trivially copyable type if its accessor_type, mapping_type, and data_handle_type are trivially copyable types.
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ MDS m_org(handle, map, acc);
+ MDS m(m_org);
+ static_assert(noexcept(MDS(m_org)) == (noexcept(H(handle))&& noexcept(M(map))&& noexcept(A(acc))));
+ static_assert(
+ std::is_trivially_copyable_v<MDS> ==
+ (std::is_trivially_copyable_v<H> && std::is_trivially_copyable_v<M> && std::is_trivially_copyable_v<A>));
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == acc);
+}
+
+template <class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ // make sure we test a trivially copyable mapping
+ static_assert(std::is_trivially_copyable_v<typename std::layout_left::template mapping<std::extents<int>>>);
+ mixin_extents(handle, std::layout_left(), acc);
+ mixin_extents(handle, std::layout_right(), acc);
+ // make sure we test a not trivially copyable mapping
+ static_assert(
+ !std::is_trivially_copyable_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>>);
+ mixin_extents(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ // make sure we test trivially constructible accessor and data_handle
+ static_assert(std::is_trivially_copyable_v<std::default_accessor<T>>);
+ static_assert(std::is_trivially_copyable_v<typename std::default_accessor<T>::data_handle_type>);
+ mixin_layout(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is noexcept copy constructible except for const double
+ checked_accessor<T> acc(1024);
+ static_assert(noexcept(checked_accessor<T>(acc)) != std::is_same_v<T, const double>);
+ mixin_layout(typename checked_accessor<T>::data_handle_type(elements.get_ptr()), acc);
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp
new file mode 100644
index 00000000000000..f42a4dbf1bf2c0
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// constexpr mdspan();
+// Constraints:
+// - rank_dynamic() > 0 is true.
+// - is_default_constructible_v<data_handle_type> is true.
+// - is_default_constructible_v<mapping_type> is true.
+// - is_default_constructible_v<accessor_type> is true.
+//
+// Preconditions: [0, map_.required_span_size()) is an accessible range of ptr_
+// and acc_ for the values of map_ and acc_ after the invocation of this constructor.
+//
+// Effects: Value-initializes ptr_, map_, and acc_.
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <bool hc, bool mc, bool ac, class H, class M, class A>
+constexpr void test_mdspan_types(const H&, const M&, const A&) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ static_assert(hc == std::is_default_constructible_v<H>);
+ static_assert(mc == std::is_default_constructible_v<M>);
+ static_assert(ac == std::is_default_constructible_v<A>);
+
+ if constexpr (MDS::rank_dynamic() > 0 && hc && mc && ac) {
+ MDS m;
+ static_assert(noexcept(MDS()) == (noexcept(H())&& noexcept(M())&& noexcept(A())));
+ assert(m.extents() == typename MDS::extents_type());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == H());
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == M());
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == A());
+ } else {
+ static_assert(!std::is_default_constructible_v<MDS>);
+ }
+}
+
+template <bool hc, bool mc, bool ac, class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types<hc, mc, ac>(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types<hc, mc, ac>(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types<hc, mc, ac>(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types<hc, mc, ac>(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types<hc, mc, ac>(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types<hc, mc, ac>(
+ handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <bool hc, bool ac, class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents<hc, true, ac>(handle, std::layout_left(), acc);
+ mixin_extents<hc, true, ac>(handle, std::layout_right(), acc);
+
+ // Use weird layout, make sure it has the properties we want to test
+ constexpr size_t D = std::dynamic_extent;
+ static_assert(
+ !std::is_default_constructible_v< typename layout_wrapping_integral<4>::template mapping<std::extents<char, D>>>);
+ mixin_extents<hc, false, ac>(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout<true, true>(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is not default constructible except for const double, where it is not noexcept
+ static_assert(std::is_default_constructible_v<checked_accessor<T>> == std::is_same_v<T, const double>);
+ // checked_accessor's data handle type is not default constructible for double
+ static_assert(
+ std::is_default_constructible_v<typename checked_accessor<T>::data_handle_type> != std::is_same_v<T, double>);
+ mixin_layout<!std::is_same_v<T, double>, std::is_same_v<T, const double>>(
+ typename checked_accessor<T>::data_handle_type(elements.get_ptr()), checked_accessor<T>(1024));
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp
new file mode 100644
index 00000000000000..e7fd81b3ab4e93
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp
@@ -0,0 +1,197 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class OtherIndexType, size_t N>
+// constexpr explicit(N != rank_dynamic())
+// mdspan(data_handle_type p, const array<OtherIndexType, N>& exts);
+//
+// Constraints:
+// - is_convertible_v<const OtherIndexType&, index_type> is true,
+// - (is_nothrow_constructible<index_type, const OtherIndexType&> && ...) is true,
+// - N == rank() || N == rank_dynamic() is true,
+// - is_constructible_v<mapping_type, extents_type> is true, and
+// - is_default_constructible_v<accessor_type> is true.
+//
+// Preconditions: [0, map_.required_span_size()) is an accessible range of p and acc_
+// for the values of map_ and acc_ after the invocation of this constructor.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with std::move(p),
+// - direct-non-list-initializes map_ with extents_type(exts), and
+// - value-initializes acc_.
+
+#include <array>
+#include <concepts>
+#include <cassert>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../ConvertibleToIntegral.h"
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class Extents, size_t... Idxs>
+constexpr auto array_from_extents(const Extents& exts, std::index_sequence<Idxs...>) {
+ return std::array<typename Extents::index_type, Extents::rank()>{exts.extent(Idxs)...};
+}
+
+template <class MDS, class Exts>
+concept check_mdspan_ctor_implicit = requires(MDS m, typename MDS::data_handle_type h, const Exts& exts) {
+ m = {h, exts};
+};
+
+template <class H, class M, class A, size_t N>
+constexpr void
+test_mdspan_ctor_array(const H& handle, const M& map, const A&, std::array<typename M::index_type, N> exts) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+ if !consteval {
+ move_counted_handle<typename MDS::element_type>::move_counter() = 0;
+ }
+ MDS m(handle, exts);
+ if !consteval {
+ if constexpr (std::is_same_v<H, move_counted_handle<typename MDS::element_type>>) {
+ assert((H::move_counter() == 1));
+ }
+ }
+
+ static_assert(!noexcept(MDS(handle, exts)));
+
+ static_assert(check_mdspan_ctor_implicit<MDS, decltype(exts)> == (N == MDS::rank_dynamic()));
+
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == A());
+}
+
+template <bool mec, bool ac, class H, class M, class A>
+constexpr void test_mdspan_ctor(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+ static_assert(mec == std::is_constructible_v<M, typename M::extents_type>);
+ static_assert(ac == std::is_default_constructible_v<A>);
+ if constexpr (mec && ac) {
+ // test from all extents
+ auto exts = array_from_extents(map.extents(), std::make_index_sequence<MDS::rank()>());
+ test_mdspan_ctor_array(handle, map, acc, exts);
+
+ // test from dynamic extents
+ std::array<typename MDS::index_type, MDS::rank_dynamic()> exts_dynamic{};
+ size_t r_dyn = 0;
+ for (size_t r = 0; r < MDS::rank(); r++) {
+ if (MDS::static_extent(r) == std::dynamic_extent)
+ exts_dynamic[r_dyn++] = exts[r];
+ }
+ test_mdspan_ctor_array(handle, map, acc, exts_dynamic);
+ } else {
+ static_assert(!std::is_constructible_v<MDS, const H&, const std::array<typename MDS::index_type, MDS::rank()>&>);
+ }
+}
+
+template <bool mec, bool ac, class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_ctor<mec, ac>(
+ handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <bool ac, class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents<true, ac>(handle, std::layout_left(), acc);
+ mixin_extents<true, ac>(handle, std::layout_right(), acc);
+
+ // Sanity check that this layouts mapping is constructible from extents (via its move constructor)
+ static_assert(std::is_constructible_v<typename layout_wrapping_integral<8>::template mapping<std::extents<int>>,
+ std::extents<int>>);
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<8>::template mapping<std::extents<int>>,
+ const std::extents<int>&>);
+ mixin_extents<true, ac>(handle, layout_wrapping_integral<8>(), acc);
+ // Sanity check that this layouts mapping is not constructible from extents
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ std::extents<int>>);
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ const std::extents<int>&>);
+ mixin_extents<false, ac>(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout<true>(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is not default constructible except for const double, where it is not noexcept
+ static_assert(std::is_default_constructible_v<checked_accessor<T>> == std::is_same_v<T, const double>);
+ mixin_layout<std::is_same_v<T, const double>>(
+ typename checked_accessor<T>::data_handle_type(elements.get_ptr()), checked_accessor<T>(1024));
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+
+ // test non-constructibility from wrong array type
+ constexpr size_t D = std::dynamic_extent;
+ using mds_t = std::mdspan<float, std::extents<unsigned, 3, D, D>>;
+ // sanity check
+ static_assert(std::is_constructible_v<mds_t, float*, std::array<int, 3>>);
+ static_assert(std::is_constructible_v<mds_t, float*, std::array<int, 2>>);
+ // wrong size
+ static_assert(!std::is_constructible_v<mds_t, float*, std::array<int, 1>>);
+ static_assert(!std::is_constructible_v<mds_t, float*, std::array<int, 4>>);
+ // not convertible to index_type
+ static_assert(std::is_convertible_v<const IntType&, int>);
+ static_assert(!std::is_convertible_v<const IntType&, unsigned>);
+ static_assert(!std::is_constructible_v<mds_t, float*, std::array<IntType, 2>>);
+
+ // index_type is not nothrow constructible
+ using mds_uchar_t = std::mdspan<float, std::extents<unsigned char, 3, D, D>>;
+ static_assert(std::is_convertible_v<IntType, unsigned char>);
+ static_assert(std::is_convertible_v<const IntType&, unsigned char>);
+ static_assert(!std::is_nothrow_constructible_v<unsigned char, const IntType&>);
+ static_assert(!std::is_constructible_v<mds_uchar_t, float*, std::array<IntType, 2>>);
+
+ // convertible from non-const to index_type but not from const
+ using mds_int_t = std::mdspan<float, std::extents<int, 3, D, D>>;
+ static_assert(std::is_convertible_v<IntTypeNC, int>);
+ static_assert(!std::is_convertible_v<const IntTypeNC&, int>);
+ static_assert(std::is_nothrow_constructible_v<int, IntTypeNC>);
+ static_assert(!std::is_constructible_v<mds_int_t, float*, std::array<IntTypeNC, 2>>);
+
+ // can't test a combo where std::is_nothrow_constructible_v<int, const IntTypeNC&> is true,
+ // but std::is_convertible_v<const IntType&, int> is false
+
+ // test non-constructibility from wrong handle_type
+ static_assert(!std::is_constructible_v<mds_t, const float*, std::array<int, 2>>);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp
new file mode 100644
index 00000000000000..c194fdaeffd138
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp
@@ -0,0 +1,141 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// constexpr mdspan(data_handle_type p, const extents_type& ext);
+//
+// Constraints:
+// - is_constructible_v<mapping_type, const extents_type&> is true, and
+// - is_default_constructible_v<accessor_type> is true.
+//
+// Preconditions: [0, map_.required_span_size()) is an accessible range of p and acc_
+// for the values of map_ and acc_ after the invocation of this constructor.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with std::move(p),
+// - direct-non-list-initializes map_ with ext, and
+// - value-initializes acc_.
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <bool mec, bool ac, class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A&) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ static_assert(mec == std::is_constructible_v<M, const typename M::extents_type&>);
+ static_assert(ac == std::is_default_constructible_v<A>);
+ if constexpr (mec && ac) {
+ if !consteval {
+ move_counted_handle<typename MDS::element_type>::move_counter() = 0;
+ }
+ // use formulation of constructor which tests that its not explicit
+ MDS m = {handle, map.extents()};
+ if !consteval {
+ if constexpr (std::is_same_v<H, move_counted_handle<typename MDS::element_type>>) {
+ assert((H::move_counter() == 1));
+ }
+ }
+ static_assert(!noexcept(MDS(handle, map.extents())));
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == A());
+ } else {
+ static_assert(!std::is_constructible_v<MDS, const H&, const typename M::extents_type&>);
+ }
+}
+
+template <bool mec, bool ac, class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types<mec, ac>(
+ handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <bool ac, class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents<true, ac>(handle, std::layout_left(), acc);
+ mixin_extents<true, ac>(handle, std::layout_right(), acc);
+
+ // Use weird layout, make sure it has the properties we want to test
+ // Sanity check that this layouts mapping is constructible from extents (via its move constructor)
+ static_assert(std::is_constructible_v<typename layout_wrapping_integral<8>::template mapping<std::extents<int>>,
+ std::extents<int>>);
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<8>::template mapping<std::extents<int>>,
+ const std::extents<int>&>);
+ mixin_extents<false, ac>(handle, layout_wrapping_integral<8>(), acc);
+ // Sanity check that this layouts mapping is not constructible from extents
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ std::extents<int>>);
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ const std::extents<int>&>);
+ mixin_extents<false, ac>(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout<true>(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is not default constructible except for const double, where it is not noexcept
+ static_assert(std::is_default_constructible_v<checked_accessor<T>> == std::is_same_v<T, const double>);
+ mixin_layout<std::is_same_v<T, const double>>(
+ typename checked_accessor<T>::data_handle_type(elements.get_ptr()), checked_accessor<T>(1024));
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+
+ // test non-constructibility from wrong extents type
+ constexpr size_t D = std::dynamic_extent;
+ using mds_t = std::mdspan<float, std::extents<int, 3, D, D>>;
+ // sanity check
+ static_assert(std::is_constructible_v<mds_t, float*, std::extents<int, 3, D, D>>);
+ // wrong size
+ static_assert(!std::is_constructible_v<mds_t, float*, std::extents<int, D, D>>);
+ static_assert(!std::is_constructible_v<mds_t, float*, std::extents<int, D, D, D, D>>);
+ // wrong type in general: note the extents constructor does NOT convert, since it takes by const&
+ static_assert(!std::is_constructible_v<mds_t, float*, std::extents<int, D, D, D>>);
+ static_assert(!std::is_constructible_v<mds_t, float*, std::extents<unsigned, 3, D, D>>);
+
+ // test non-constructibility from wrong handle_type
+ static_assert(!std::is_constructible_v<mds_t, const float*, std::extents<int, 3, D, D>>);
+
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp
new file mode 100644
index 00000000000000..1bd9e488ad0d41
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp
@@ -0,0 +1,165 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class... OtherIndexTypes>
+// constexpr explicit mdspan(data_handle_type p, OtherIndexTypes... exts);
+//
+// Let N be sizeof...(OtherIndexTypes).
+//
+// Constraints:
+// - (is_convertible_v<OtherIndexTypes, index_type> && ...) is true,
+// - (is_nothrow_constructible<index_type, OtherIndexTypes> && ...) is true,
+// - N == rank() || N == rank_dynamic() is true,
+// - is_constructible_v<mapping_type, extents_type> is true, and
+// - is_default_constructible_v<accessor_type> is true.
+//
+// Preconditions: [0, map_.required_span_size()) is an accessible range of p and acc_
+// for the values of map_ and acc_ after the invocation of this constructor.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with std::move(p),
+// - direct-non-list-initializes map_ with extents_type(static_cast<index_type>(std::move(exts))...), and
+// - value-initializes acc_.
+
+#include <array>
+#include <concepts>
+#include <cassert>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class MDS, class... Args>
+concept check_mdspan_ctor_implicit = requires(MDS m, Args... args) { m = {args...}; };
+
+template <bool mec, bool ac, class H, class M, class A, class... Idxs>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A&, Idxs... idxs) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ static_assert(mec == std::is_constructible_v<M, typename M::extents_type>);
+ static_assert(ac == std::is_default_constructible_v<A>);
+
+ if constexpr (mec && ac) {
+ if !consteval {
+ move_counted_handle<typename MDS::element_type>::move_counter() = 0;
+ }
+ MDS m(handle, idxs...);
+ if !consteval {
+ if constexpr (std::is_same_v<H, move_counted_handle<typename MDS::element_type>>) {
+ assert((H::move_counter() == 1));
+ }
+ }
+
+ // sanity check that concept works
+ static_assert(check_mdspan_ctor_implicit<MDS, H, std::array<typename MDS::index_type, MDS::rank_dynamic()>>);
+ // check that the constructor from integral is explicit
+ static_assert(!check_mdspan_ctor_implicit<MDS, H, Idxs...>);
+
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == A());
+ } else {
+ static_assert(!std::is_constructible_v<MDS, const H&, Idxs... >);
+ }
+}
+
+template <bool mec, bool ac, class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ // construct from just dynamic extents
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<char, D>(7)), acc, 7);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc, 2, 3);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc, 0, 3);
+ test_mdspan_types<mec, ac>(
+ handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc, 1, 2, 3, 2);
+
+ // construct from all extents
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc, 7);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc, 2, 4, 3);
+ test_mdspan_types<mec, ac>(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc, 0, 7, 3);
+ test_mdspan_types<mec, ac>(
+ handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc, 1, 7, 2, 4, 3, 2);
+}
+
+template <bool ac, class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents<true, ac>(handle, std::layout_left(), acc);
+ mixin_extents<true, ac>(handle, std::layout_right(), acc);
+
+ // Use weird layout, make sure it has the properties we want to test
+ // Sanity check that this layouts mapping is constructible from extents (via its move constructor)
+ static_assert(std::is_constructible_v<typename layout_wrapping_integral<8>::template mapping<std::extents<int>>,
+ std::extents<int>>);
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<8>::template mapping<std::extents<int>>,
+ const std::extents<int>&>);
+ mixin_extents<true, ac>(handle, layout_wrapping_integral<8>(), acc);
+ // Sanity check that this layouts mapping is not constructible from extents
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ std::extents<int>>);
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ const std::extents<int>&>);
+ mixin_extents<false, ac>(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout<true>(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is not default constructible except for const double, where it is not noexcept
+ static_assert(std::is_default_constructible_v<checked_accessor<T>> == std::is_same_v<T, const double>);
+ mixin_layout<std::is_same_v<T, const double>>(
+ typename checked_accessor<T>::data_handle_type(elements.get_ptr()), checked_accessor<T>(1024));
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+
+ // test non-constructibility from wrong integer types
+ constexpr size_t D = std::dynamic_extent;
+ using mds_t = std::mdspan<float, std::extents<int, 3, D, D>>;
+ // sanity check
+ static_assert(std::is_constructible_v<mds_t, float*, int, int, int>);
+ static_assert(std::is_constructible_v<mds_t, float*, int, int>);
+ // wrong number of arguments
+ static_assert(!std::is_constructible_v<mds_t, float*, int>);
+ static_assert(!std::is_constructible_v<mds_t, float*, int, int, int, int>);
+ // not convertible to int
+ static_assert(!std::is_constructible_v<mds_t, float*, int, int, std::dextents<int, 1>>);
+
+ // test non-constructibility from wrong handle_type
+ static_assert(!std::is_constructible_v<mds_t, const float*, int, int>);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp
new file mode 100644
index 00000000000000..9b1c6bd0668af9
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp
@@ -0,0 +1,129 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// constexpr mdspan(data_handle_type p, const mapping_type& m);
+//
+// Constraints: is_default_constructible_v<accessor_type> is true.
+//
+// Preconditions: [0, m.required_span_size()) is an accessible range of p and acc_
+// for the value of acc_ after the invocation of this constructor.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with std::move(p),
+// - direct-non-list-initializes map_ with m, and
+// - value-initializes acc_.
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <bool ac, class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A&) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ static_assert(ac == std::is_default_constructible_v<A>);
+ if constexpr (ac) {
+ if !consteval {
+ move_counted_handle<typename MDS::element_type>::move_counter() = 0;
+ }
+ // use formulation of constructor which tests that it is not explicit
+ MDS m = {handle, map};
+ if !consteval {
+ if constexpr (std::is_same_v<H, move_counted_handle<typename MDS::element_type>>) {
+ assert((H::move_counter() == 1));
+ }
+ }
+ static_assert(!noexcept(MDS(handle, map)));
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == A());
+ } else {
+ static_assert(!std::is_constructible_v<MDS, const H&, const M&>);
+ }
+}
+
+template <bool ac, class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types<ac>(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types<ac>(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types<ac>(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types<ac>(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types<ac>(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types<ac>(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <bool ac, class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents<ac>(handle, std::layout_left(), acc);
+ mixin_extents<ac>(handle, std::layout_right(), acc);
+ mixin_extents<ac>(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout<true>(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is not default constructible except for const double, where it is not noexcept
+ static_assert(std::is_default_constructible_v<checked_accessor<T>> == std::is_same_v<T, const double>);
+ mixin_layout<std::is_same_v<T, const double>>(
+ typename checked_accessor<T>::data_handle_type(elements.get_ptr()), checked_accessor<T>(1024));
+}
+
+template <class E>
+using mapping_t = typename std::layout_right::template mapping<E>;
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+
+ constexpr size_t D = std::dynamic_extent;
+ using mds_t = std::mdspan<float, std::extents<int, 3, D, D>>;
+
+ // sanity check
+ static_assert(std::is_constructible_v<mds_t, float*, mapping_t<std::extents<int, 3, D, D>>>);
+
+ // test non-constructibility from wrong mapping type
+ // wrong rank
+ static_assert(!std::is_constructible_v<mds_t, float*, mapping_t<std::extents<int, D, D>>>);
+ static_assert(!std::is_constructible_v<mds_t, float*, mapping_t<std::extents<int, D, D, D, D>>>);
+ // wrong type in general: note the map constructor does NOT convert, since it takes by const&
+ static_assert(!std::is_constructible_v<mds_t, float*, mapping_t<std::extents<int, D, D, D>>>);
+ static_assert(!std::is_constructible_v<mds_t, float*, mapping_t<std::extents<unsigned, 3, D, D>>>);
+
+ // test non-constructibility from wrong handle_type
+ static_assert(!std::is_constructible_v<mds_t, const float*, mapping_t<std::extents<int, 3, D, D>>>);
+
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp
new file mode 100644
index 00000000000000..7a94e8b0403269
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp
@@ -0,0 +1,130 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// constexpr mdspan(data_handle_type p, const mapping_type& m, const accessor_type& a);
+//
+// Preconditions: [0, m.required_span_size()) is an accessible range of p and a.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with std::move(p),
+// - direct-non-list-initializes map_ with m, and
+// - direct-non-list-initializes acc_ with a.
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ if !consteval {
+ move_counted_handle<typename MDS::element_type>::move_counter() = 0;
+ }
+ // use formulation of constructor which tests that it is not explicit
+ MDS m = {handle, map, acc};
+ if !consteval {
+ if constexpr (std::is_same_v<H, move_counted_handle<typename MDS::element_type>>) {
+ assert((H::move_counter() == 1));
+ }
+ }
+ static_assert(!noexcept(MDS(handle, map, acc)));
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == acc);
+}
+
+template <class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents(handle, std::layout_left(), acc);
+ mixin_extents(handle, std::layout_right(), acc);
+ mixin_extents(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is not default constructible except for const double, where it is not noexcept
+ static_assert(std::is_default_constructible_v<checked_accessor<T>> == std::is_same_v<T, const double>);
+ // checked_accessor's data handle type is not default constructible for double
+ static_assert(
+ std::is_default_constructible_v<typename checked_accessor<T>::data_handle_type> != std::is_same_v<T, double>);
+ mixin_layout(typename checked_accessor<T>::data_handle_type(elements.get_ptr()), checked_accessor<T>(1024));
+}
+
+template <class E>
+using mapping_t = typename std::layout_right::template mapping<E>;
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+
+ // test non-constructibility from wrong args
+ constexpr size_t D = std::dynamic_extent;
+ using mds_t = std::mdspan<float, std::extents<int, 3, D, D>>;
+ using acc_t = std::default_accessor<float>;
+
+ // sanity check
+ static_assert(std::is_constructible_v<mds_t, float*, mapping_t<std::extents<int, 3, D, D>>, acc_t>);
+
+ // test non-constructibility from wrong accessor
+ static_assert(
+ !std::
+ is_constructible_v<mds_t, float*, mapping_t<std::extents<int, 3, D, D>>, std::default_accessor<const float>>);
+
+ // test non-constructibility from wrong mapping type
+ // wrong rank
+ static_assert(!std::is_constructible_v<mds_t, float*, mapping_t<std::extents<int, D, D>>, acc_t>);
+ static_assert(!std::is_constructible_v<mds_t, float*, mapping_t<std::extents<int, D, D, D, D>>, acc_t>);
+ // wrong type in general: note the map constructor does NOT convert, since it takes by const&
+ static_assert(!std::is_constructible_v<mds_t, float*, mapping_t<std::extents<int, D, D, D>>, acc_t>);
+ static_assert(!std::is_constructible_v<mds_t, float*, mapping_t<std::extents<unsigned, 3, D, D>>, acc_t>);
+
+ // test non-constructibility from wrong handle_type
+ static_assert(!std::is_constructible_v<mds_t, const float*, mapping_t<std::extents<int, 3, D, D>>, acc_t>);
+
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp
new file mode 100644
index 00000000000000..f76c909783344f
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp
@@ -0,0 +1,197 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class OtherIndexType, size_t N>
+// constexpr explicit(N != rank_dynamic())
+// mdspan(data_handle_type p, span<OtherIndexType, N> exts);
+//
+// Constraints:
+// - is_convertible_v<const OtherIndexType&, index_type> is true,
+// - (is_nothrow_constructible<index_type, const OtherIndexType&> && ...) is true,
+// - N == rank() || N == rank_dynamic() is true,
+// - is_constructible_v<mapping_type, extents_type> is true, and
+// - is_default_constructible_v<accessor_type> is true.
+//
+// Preconditions: [0, map_.required_span_size()) is an accessible range of p and acc_
+// for the values of map_ and acc_ after the invocation of this constructor.
+//
+// Effects:
+// - Direct-non-list-initializes ptr_ with std::move(p),
+// - direct-non-list-initializes map_ with extents_type(exts), and
+// - value-initializes acc_.
+
+#include <array>
+#include <concepts>
+#include <cassert>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../ConvertibleToIntegral.h"
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class Extents, size_t... Idxs>
+constexpr auto array_from_extents(const Extents& exts, std::index_sequence<Idxs...>) {
+ return std::array<typename Extents::index_type, Extents::rank()>{exts.extent(Idxs)...};
+}
+
+template <class MDS, class Exts>
+concept check_mdspan_ctor_implicit = requires(MDS m, typename MDS::data_handle_type h, const Exts& exts) {
+ m = {h, exts};
+};
+
+template <class H, class M, class A, size_t N>
+constexpr void
+test_mdspan_ctor_span(const H& handle, const M& map, const A&, std::span<typename M::index_type, N> exts) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+ if !consteval {
+ move_counted_handle<typename MDS::element_type>::move_counter() = 0;
+ }
+ MDS m(handle, exts);
+ if !consteval {
+ if constexpr (std::is_same_v<H, move_counted_handle<typename MDS::element_type>>) {
+ assert((H::move_counter() == 1));
+ }
+ }
+
+ static_assert(!noexcept(MDS(handle, exts)));
+
+ static_assert(check_mdspan_ctor_implicit<MDS, decltype(exts)> == (N == MDS::rank_dynamic()));
+
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == A());
+}
+
+template <bool mec, bool ac, class H, class M, class A>
+constexpr void test_mdspan_ctor(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+ static_assert(mec == std::is_constructible_v<M, typename M::extents_type>);
+ static_assert(ac == std::is_default_constructible_v<A>);
+ if constexpr (mec && ac) {
+ // test from all extents
+ auto exts = array_from_extents(map.extents(), std::make_index_sequence<MDS::rank()>());
+ test_mdspan_ctor_span(handle, map, acc, std::span(exts));
+
+ // test from dynamic extents
+ std::array<typename MDS::index_type, MDS::rank_dynamic()> exts_dynamic{};
+ size_t r_dyn = 0;
+ for (size_t r = 0; r < MDS::rank(); r++) {
+ if (MDS::static_extent(r) == std::dynamic_extent)
+ exts_dynamic[r_dyn++] = exts[r];
+ }
+ test_mdspan_ctor_span(handle, map, acc, std::span(exts_dynamic));
+ } else {
+ static_assert(!std::is_constructible_v<MDS, const H&, std::span<typename MDS::index_type, MDS::rank()>>);
+ }
+}
+
+template <bool mec, bool ac, class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_ctor<mec, ac>(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_ctor<mec, ac>(
+ handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <bool ac, class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents<true, ac>(handle, std::layout_left(), acc);
+ mixin_extents<true, ac>(handle, std::layout_right(), acc);
+
+ // Sanity check that this layouts mapping is constructible from extents (via its move constructor)
+ static_assert(std::is_constructible_v<typename layout_wrapping_integral<8>::template mapping<std::extents<int>>,
+ std::extents<int>>);
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<8>::template mapping<std::extents<int>>,
+ const std::extents<int>&>);
+ mixin_extents<true, ac>(handle, layout_wrapping_integral<8>(), acc);
+ // Sanity check that this layouts mapping is not constructible from extents
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ std::extents<int>>);
+ static_assert(!std::is_constructible_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>,
+ const std::extents<int>&>);
+ mixin_extents<false, ac>(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout<true>(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is not default constructible except for const double, where it is not noexcept
+ static_assert(std::is_default_constructible_v<checked_accessor<T>> == std::is_same_v<T, const double>);
+ mixin_layout<std::is_same_v<T, const double>>(
+ typename checked_accessor<T>::data_handle_type(elements.get_ptr()), checked_accessor<T>(1024));
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+
+ // test non-constructibility from wrong span type
+ constexpr size_t D = std::dynamic_extent;
+ using mds_t = std::mdspan<float, std::extents<unsigned, 3, D, D>>;
+ // sanity check
+ static_assert(std::is_constructible_v<mds_t, float*, std::span<int, 3>>);
+ static_assert(std::is_constructible_v<mds_t, float*, std::span<int, 2>>);
+ // wrong size
+ static_assert(!std::is_constructible_v<mds_t, float*, std::span<int, 1>>);
+ static_assert(!std::is_constructible_v<mds_t, float*, std::span<int, 4>>);
+ // not convertible to index_type
+ static_assert(std::is_convertible_v<const IntType&, int>);
+ static_assert(!std::is_convertible_v<const IntType&, unsigned>);
+ static_assert(!std::is_constructible_v<mds_t, float*, std::span<IntType, 2>>);
+
+ // index_type is not nothrow constructible
+ using mds_uchar_t = std::mdspan<float, std::extents<unsigned char, 3, D, D>>;
+ static_assert(std::is_convertible_v<IntType, unsigned char>);
+ static_assert(std::is_convertible_v<const IntType&, unsigned char>);
+ static_assert(!std::is_nothrow_constructible_v<unsigned char, const IntType&>);
+ static_assert(!std::is_constructible_v<mds_uchar_t, float*, std::span<IntType, 2>>);
+
+ // convertible from non-const to index_type but not from const
+ using mds_int_t = std::mdspan<float, std::extents<int, 3, D, D>>;
+ static_assert(std::is_convertible_v<IntTypeNC, int>);
+ static_assert(!std::is_convertible_v<const IntTypeNC&, int>);
+ static_assert(std::is_nothrow_constructible_v<int, IntTypeNC>);
+ static_assert(!std::is_constructible_v<mds_int_t, float*, std::span<IntTypeNC, 2>>);
+
+ // can't test a combo where std::is_nothrow_constructible_v<int, const IntTypeNC&> is true,
+ // but std::is_convertible_v<const IntType&, int> is false
+
+ // test non-constructibility from wrong handle_type
+ static_assert(!std::is_constructible_v<mds_t, const float*, std::span<int, 2>>);
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/ctor.move.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.move.pass.cpp
new file mode 100644
index 00000000000000..aaaa4bc85709c2
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/ctor.move.pass.cpp
@@ -0,0 +1,98 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// constexpr mdspan(mdspan&&) = default;
+//
+// A specialization of mdspan is a trivially copyable type if its accessor_type, mapping_type, and data_handle_type are trivially copyable types.
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ MDS m_org(handle, map, acc);
+ MDS m(std::move(m_org));
+ static_assert(std::is_trivially_move_constructible_v<MDS> ==
+ (std::is_trivially_move_constructible_v<H> && std::is_trivially_move_constructible_v<M> &&
+ std::is_trivially_move_constructible_v<A>));
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == acc);
+}
+
+template <class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ // make sure we test a trivially copyable mapping
+ static_assert(std::is_trivially_move_constructible_v<typename std::layout_left::template mapping<std::extents<int>>>);
+ mixin_extents(handle, std::layout_left(), acc);
+ mixin_extents(handle, std::layout_right(), acc);
+ // make sure we test a not trivially copyable mapping
+ static_assert(!std::is_trivially_move_constructible_v<
+ typename layout_wrapping_integral<4>::template mapping<std::extents<int>>>);
+ mixin_extents(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ // make sure we test trivially constructible accessor and data_handle
+ static_assert(std::is_trivially_move_constructible_v<std::default_accessor<T>>);
+ static_assert(std::is_trivially_move_constructible_v<typename std::default_accessor<T>::data_handle_type>);
+ mixin_layout(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is noexcept copy constructible except for const double
+ checked_accessor<T> acc(1024);
+ static_assert(std::is_trivially_move_constructible_v<typename checked_accessor<T>::data_handle_type> ==
+ std::is_same_v<T, double>);
+ mixin_layout(typename checked_accessor<T>::data_handle_type(elements.get_ptr()), acc);
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp
new file mode 100644
index 00000000000000..69b2f7e39831af
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp
@@ -0,0 +1,159 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class 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<class Pointer>
+// requires(is_pointer_v<remove_reference_t<Pointer>>)
+// mdspan(Pointer&&)
+// -> mdspan<remove_pointer_t<remove_reference_t<Pointer>>, extents<size_t>>;
+//
+// template<class ElementType, class... Integrals>
+// requires((is_convertible_v<Integrals, size_t> && ...) && sizeof...(Integrals) > 0)
+// explicit mdspan(ElementType*, Integrals...)
+// -> mdspan<ElementType, dextents<size_t, sizeof...(Integrals)>>;
+//
+// template<class ElementType, class OtherIndexType, size_t N>
+// mdspan(ElementType*, span<OtherIndexType, N>)
+// -> mdspan<ElementType, dextents<size_t, N>>;
+//
+// template<class ElementType, class OtherIndexType, size_t N>
+// mdspan(ElementType*, const array<OtherIndexType, N>&)
+// -> mdspan<ElementType, dextents<size_t, N>>;
+//
+// template<class ElementType, class IndexType, size_t... ExtentsPack>
+// mdspan(ElementType*, const extents<IndexType, ExtentsPack...>&)
+// -> mdspan<ElementType, extents<IndexType, ExtentsPack...>>;
+//
+// template<class ElementType, class MappingType>
+// mdspan(ElementType*, const MappingType&)
+// -> mdspan<ElementType, typename MappingType::extents_type,
+// typename MappingType::layout_type>;
+//
+// template<class MappingType, class 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>;
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ // deduction from data_handle_type (including non-pointer), mapping and accessor
+ ASSERT_SAME_TYPE(decltype(std::mdspan(handle, map, acc)), MDS);
+
+ if constexpr (std::is_same_v<A, std::default_accessor<typename A::element_type>>) {
+ // deduction from pointer and mapping
+ // non-pointer data-handle-types have other accessor
+ ASSERT_SAME_TYPE(decltype(std::mdspan(handle, map)), MDS);
+ if constexpr (std::is_same_v<typename M::layout_type, std::layout_right>) {
+ // deduction from pointer and extents
+ ASSERT_SAME_TYPE(decltype(std::mdspan(handle, map.extents())), MDS);
+ }
+ }
+}
+
+template <class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+struct SizeTIntType {
+ size_t val;
+ constexpr SizeTIntType(size_t val_) : val(val_) {}
+ constexpr operator size_t() const noexcept { return size_t(val); }
+};
+
+template <class H, class A>
+ requires(sizeof(decltype(std::mdspan(std::declval<H>(), 10))) > 0)
+constexpr bool test_no_layout_deduction_guides(const H& handle, const A&) {
+ using T = typename A::element_type;
+ // deduction from pointer alone
+ ASSERT_SAME_TYPE(decltype(std::mdspan(handle)), std::mdspan<T, std::extents<size_t>>);
+ // deduction from pointer and integral like
+ ASSERT_SAME_TYPE(decltype(std::mdspan(handle, 5, SizeTIntType(6))), std::mdspan<T, std::dextents<size_t, 2>>);
+
+ std::array<char, 3> exts;
+ // deduction from pointer and array
+ ASSERT_SAME_TYPE(decltype(std::mdspan(handle, exts)), std::mdspan<T, std::dextents<size_t, 3>>);
+ // deduction from pointer and span
+ ASSERT_SAME_TYPE(decltype(std::mdspan(handle, std::span(exts))), std::mdspan<T, std::dextents<size_t, 3>>);
+ return true;
+}
+
+template <class H, class A>
+constexpr bool test_no_layout_deduction_guides(const H&, const A&) {
+ return false;
+}
+
+template <class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents(handle, std::layout_left(), acc);
+ mixin_extents(handle, std::layout_right(), acc);
+ mixin_extents(handle, layout_wrapping_integral<4>(), acc);
+
+ // checking that there is no deduction happen for non-pointer handle type
+ assert((test_no_layout_deduction_guides(handle, acc) == std::is_same_v<H, typename A::element_type*>));
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is noexcept copy constructible except for const double
+ checked_accessor<T> acc(1024);
+ static_assert(noexcept(checked_accessor<T>(acc)) != std::is_same_v<T, const double>);
+ mixin_layout(typename checked_accessor<T>::data_handle_type(elements.get_ptr()), acc);
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+
+ // deduction from array alone
+ float a[12];
+ ASSERT_SAME_TYPE(decltype(std::mdspan(a)), std::mdspan<float, std::extents<size_t, 12>>);
+
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/element_type.verify.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/element_type.verify.cpp
new file mode 100644
index 00000000000000..eca44cc7fe78f9
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/element_type.verify.cpp
@@ -0,0 +1,39 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class ElementType, class Extents, class LayoutPolicy = layout_right, class AccessorPolicy = default_accessor>
+// class mdspan;
+//
+// Mandates:
+// - ElementType is a complete object type that is neither an abstract class type nor an array type.
+// - is_same_v<ElementType, typename AccessorPolicy::element_type> is true.
+
+#include <mdspan>
+
+class AbstractClass {
+public:
+ virtual void method() = 0;
+};
+
+void not_abstract_class() {
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: ElementType template parameter may not be an abstract class}}
+ [[maybe_unused]] std::mdspan<AbstractClass, std::extents<int>> m;
+}
+
+void not_array_type() {
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: ElementType template parameter may not be an array type}}
+ [[maybe_unused]] std::mdspan<int[5], std::extents<int>> m;
+}
+
+void element_type_mismatch() {
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: ElementType template parameter must match AccessorPolicy::element_type}}
+ [[maybe_unused]] std::mdspan<int, std::extents<int>, std::layout_right, std::default_accessor<const int>> m;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/extents.verify.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/extents.verify.cpp
new file mode 100644
index 00000000000000..d6b6173c82b0e6
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/extents.verify.cpp
@@ -0,0 +1,23 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class ElementType, class Extents, class LayoutPolicy = layout_right, class AccessorPolicy = default_accessor>
+// class mdspan;
+//
+// Mandates:
+// - Extents is a specialization of extents
+
+#include <mdspan>
+
+void not_extents() {
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: Extents template parameter must be a specialization of extents.}}
+ [[maybe_unused]] std::mdspan<int, int> m;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp
new file mode 100644
index 00000000000000..5284194632d0f4
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp
@@ -0,0 +1,259 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// Test default iteration:
+//
+// template<class... Indices>
+// constexpr reference operator[](Indices...) const noexcept;
+//
+// Constraints:
+// * sizeof...(Indices) == extents_type::rank() is true,
+// * (is_convertible_v<Indices, index_type> && ...) is true, and
+// * (is_nothrow_constructible_v<index_type, Indices> && ...) is true.
+//
+// Preconditions:
+// * extents_type::index-cast(i) is a multidimensional index in extents_.
+
+// GCC warns about comma operator changing its meaning inside [] in C++23
+#if defined(__GNUC__) && !defined(__clang_major__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcomma-subscript"
+#endif
+
+#include <mdspan>
+#include <cassert>
+#include <cstdint>
+
+#include "test_macros.h"
+
+#include "../ConvertibleToIntegral.h"
+#include "CustomTestLayouts.h"
+
+// Clang 15 and 16 do not support argument packs as input to operator []
+#if defined(__clang_major__) && __clang_major__ < 17
+template <class MDS>
+constexpr auto& access(MDS mds) {
+ return mds[];
+}
+template <class MDS>
+constexpr auto& access(MDS mds, int64_t i0) {
+ return mds[i0];
+}
+template <class MDS>
+constexpr auto& access(MDS mds, int64_t i0, int64_t i1) {
+ return mds[i0, i1];
+}
+template <class MDS>
+constexpr auto& access(MDS mds, int64_t i0, int64_t i1, int64_t i2) {
+ return mds[i0, i1, i2];
+}
+template <class MDS>
+constexpr auto& access(MDS mds, int64_t i0, int64_t i1, int64_t i2, int64_t i3) {
+ return mds[i0, i1, i2, i3];
+}
+#endif
+
+template <class MDS, class... Indices>
+concept operator_constraints = requires(MDS m, Indices... idxs) {
+ { std::is_same_v<decltype(m[idxs...]), typename MDS::reference> };
+};
+
+template <class MDS, class... Indices>
+ requires(operator_constraints<MDS, Indices...>)
+constexpr bool check_operator_constraints(MDS m, Indices... idxs) {
+ (void)m[idxs...];
+ return true;
+}
+
+template <class MDS, class... Indices>
+constexpr bool check_operator_constraints(MDS, Indices...) {
+ return false;
+}
+
+template <class MDS, class... Args>
+constexpr void iterate(MDS mds, Args... args) {
+ constexpr int r = static_cast<int>(MDS::extents_type::rank()) - 1 - static_cast<int>(sizeof...(Args));
+ if constexpr (-1 == r) {
+#if defined(__clang_major__) && __clang_major__ < 17
+ int* ptr1 = &access(mds, args...);
+#else
+ int* ptr1 = &mds[args...];
+#endif
+ int* ptr2 = &(mds.accessor().access(mds.data_handle(), mds.mapping()(args...)));
+ assert(ptr1 == ptr2);
+
+ std::array<typename MDS::index_type, MDS::rank()> args_arr{static_cast<typename MDS::index_type>(args)...};
+ int* ptr3 = &mds[args_arr];
+ assert(ptr3 == ptr2);
+ int* ptr4 = &mds[std::span(args_arr)];
+ assert(ptr4 == ptr2);
+ } else {
+ for (typename MDS::index_type i = 0; i < mds.extents().extent(r); i++) {
+ iterate(mds, i, args...);
+ }
+ }
+}
+
+template <class Mapping>
+constexpr void test_iteration(Mapping m) {
+ std::array<int, 1024> data;
+ using MDS = std::mdspan<int, typename Mapping::extents_type, typename Mapping::layout_type>;
+ MDS mds(data.data(), m);
+
+ iterate(mds);
+}
+
+template <class Layout>
+constexpr void test_layout() {
+ constexpr size_t D = std::dynamic_extent;
+ test_iteration(construct_mapping(Layout(), std::extents<int>()));
+ test_iteration(construct_mapping(Layout(), std::extents<unsigned, D>(1)));
+ test_iteration(construct_mapping(Layout(), std::extents<unsigned, D>(7)));
+ test_iteration(construct_mapping(Layout(), std::extents<unsigned, 7>()));
+ test_iteration(construct_mapping(Layout(), std::extents<unsigned, 7, 8>()));
+ test_iteration(construct_mapping(Layout(), std::extents<char, D, D, D, D>(1, 1, 1, 1)));
+
+// TODO enable for GCC 13, when the CI pipeline is switched, doesn't work with GCC 12
+#if defined(__clang_major__) && __clang_major__ >= 17
+ int data[1];
+ // Check operator constraint for number of arguments
+ static_assert(check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), 0));
+ static_assert(
+ !check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), 0, 0));
+
+ // Check operator constraint for convertibility of arguments to index_type
+ static_assert(
+ check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), IntType(0)));
+ static_assert(!check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<unsigned, D>(1))), IntType(0)));
+
+ // Check operator constraint for no-throw-constructibility of index_type from arguments
+ static_assert(!check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<unsigned char, D>(1))), IntType(0)));
+
+ // Check that mixed integrals work: note the second one tests that mdspan casts: layout_wrapping_integral does not accept IntType
+ static_assert(check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<unsigned char, D, D>(1, 1))), int(0), size_t(0)));
+ static_assert(check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D, D>(1, 1))), unsigned(0), IntType(0)));
+
+ constexpr bool t = true;
+ constexpr bool o = false;
+ static_assert(!check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D, D>(1, 1))),
+ unsigned(0),
+ IntConfig<o, o, t, t>(0)));
+ static_assert(check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D, D>(1, 1))),
+ unsigned(0),
+ IntConfig<o, t, t, t>(0)));
+ static_assert(check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D, D>(1, 1))),
+ unsigned(0),
+ IntConfig<o, t, o, t>(0)));
+ static_assert(!check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D, D>(1, 1))),
+ unsigned(0),
+ IntConfig<t, o, o, t>(0)));
+ static_assert(check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D, D>(1, 1))),
+ unsigned(0),
+ IntConfig<t, o, t, o>(0)));
+
+ // layout_wrapped wouldn't quite work here the way we wrote the check
+ // IntConfig has configurable conversion properties: convert from const&, convert from non-const, no-throw-ctor from const&, no-throw-ctor from non-const
+ if constexpr (std::is_same_v<Layout, std::layout_left>) {
+ static_assert(!check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), std::array{IntConfig<o, o, t, t>(0)}));
+ static_assert(!check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), std::array{IntConfig<o, t, t, t>(0)}));
+ static_assert(!check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), std::array{IntConfig<t, o, o, t>(0)}));
+ static_assert(!check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), std::array{IntConfig<t, t, o, t>(0)}));
+ static_assert(check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), std::array{IntConfig<t, o, t, o>(0)}));
+ static_assert(check_operator_constraints(
+ std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), std::array{IntConfig<t, t, t, t>(0)}));
+
+ {
+ std::array idx{IntConfig<o, o, t, t>(0)};
+ std::span s(idx);
+ assert(!check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), s));
+ }
+ {
+ std::array idx{IntConfig<o, o, t, t>(0)};
+ std::span s(idx);
+ assert(!check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), s));
+ }
+ {
+ std::array idx{IntConfig<o, o, t, t>(0)};
+ std::span s(idx);
+ assert(!check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), s));
+ }
+ {
+ std::array idx{IntConfig<o, o, t, t>(0)};
+ std::span s(idx);
+ assert(!check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), s));
+ }
+ {
+ std::array idx{IntConfig<o, o, t, t>(0)};
+ std::span s(idx);
+ assert(!check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), s));
+ }
+ {
+ std::array idx{IntConfig<o, o, t, t>(0)};
+ std::span s(idx);
+ assert(!check_operator_constraints(std::mdspan(data, construct_mapping(Layout(), std::extents<int, D>(1))), s));
+ }
+ }
+#endif
+}
+
+template <class Layout>
+constexpr void test_layout_large() {
+ constexpr size_t D = std::dynamic_extent;
+ test_iteration(construct_mapping(Layout(), std::extents<int64_t, D, 4, D, D>(3, 5, 6)));
+ test_iteration(construct_mapping(Layout(), std::extents<int64_t, D, 4, 1, D>(3, 6)));
+}
+
+// mdspan::operator[] casts to index_type before calling mapping
+// mapping requirements only require the index operator to mixed integer types not anything convertible to index_type
+constexpr void test_index_cast_happens() {}
+
+constexpr bool test() {
+ test_layout<std::layout_left>();
+ test_layout<std::layout_right>();
+ test_layout<layout_wrapping_integral<4>>();
+ return true;
+}
+
+constexpr bool test_large() {
+ test_layout_large<std::layout_left>();
+ test_layout_large<std::layout_right>();
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ // The large test iterates over ~10k loop indices.
+ // With assertions enabled this triggered the maximum default limit
+ // for steps in consteval expressions. Assertions roughly double the
+ // total number of instructions, so this was already close to the maximum.
+ test_large();
+ return 0;
+}
+#if defined(__GNUC__) && !defined(__clang_major__)
+# pragma GCC diagnostic pop
+#endif
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/mapping.verify.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/mapping.verify.cpp
new file mode 100644
index 00000000000000..51d8864ff9b72e
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/mapping.verify.cpp
@@ -0,0 +1,23 @@
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class ElementType, class Extents, class LayoutPolicy = layout_right, class AccessorPolicy = default_accessor>
+// class mdspan;
+//
+// Mandates:
+// - LayoutPolicy shall meet the layout mapping policy requirements ([mdspan.layout.policy.reqmts])
+
+#include <mdspan>
+
+void not_layout_policy() {
+ // expected-error-re@*:* {{{{(static_assert|static assertion)}} failed {{.*}}mdspan: LayoutPolicy template parameter is invalid. A common mistake is to pass a layout mapping instead of a layout policy}}
+ [[maybe_unused]] std::mdspan<int, std::extents<int>, std::layout_left::template mapping<std::extents<int>>> m;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/move.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/move.pass.cpp
new file mode 100644
index 00000000000000..544a5b8aa1ede4
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/move.pass.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// constexpr mdspan& operator=(mdspan&&) = default;
+//
+// A specialization of mdspan is a trivially copyable type if its accessor_type, mapping_type, and data_handle_type are trivially copyable types.
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+#include "CustomTestAccessors.h"
+
+template <class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+
+ MDS m_org(handle, map, acc);
+ MDS m_copy(m_org);
+ MDS m(std::move(m_copy));
+
+ assert(m.extents() == map.extents());
+ if constexpr (std::equality_comparable<H>)
+ assert(m.data_handle() == handle);
+ if constexpr (std::equality_comparable<M>)
+ assert(m.mapping() == map);
+ if constexpr (std::equality_comparable<A>)
+ assert(m.accessor() == acc);
+
+ static_assert(std::is_trivially_move_assignable_v<MDS> ==
+ (std::is_trivially_move_assignable_v<H> && std::is_trivially_move_assignable_v<M> &&
+ std::is_trivially_move_assignable_v<A>));
+}
+
+template <class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ // make sure we test a trivially copyable mapping
+ static_assert(std::is_trivially_move_assignable_v<typename std::layout_left::template mapping<std::extents<int>>>);
+ mixin_extents(handle, std::layout_left(), acc);
+ mixin_extents(handle, std::layout_right(), acc);
+ // make sure we test a not trivially copyable mapping
+ static_assert(
+ !std::is_trivially_move_assignable_v<typename layout_wrapping_integral<4>::template mapping<std::extents<int>>>);
+ mixin_extents(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ // make sure we test trivially constructible accessor and data_handle
+ static_assert(std::is_trivially_copyable_v<std::default_accessor<T>>);
+ static_assert(std::is_trivially_copyable_v<typename std::default_accessor<T>::data_handle_type>);
+ mixin_layout(elements.get_ptr(), std::default_accessor<T>());
+
+ // Using weird accessor/data_handle
+ // Make sure they actually got the properties we want to test
+ // checked_accessor is noexcept copy constructible except for const double
+ checked_accessor<T> acc(1024);
+ static_assert(noexcept(checked_accessor<T>(acc)) != std::is_same_v<T, const double>);
+ mixin_layout(typename checked_accessor<T>::data_handle_type(elements.get_ptr()), acc);
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp
new file mode 100644
index 00000000000000..c822c3ad9c24f0
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp
@@ -0,0 +1,214 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+
+// template<class ElementType, class Extents, class LayoutPolicy = layout_right,
+// class AccessorPolicy = default_accessor<ElementType>>
+// class mdspan {
+// public:
+// 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 size_type size() const noexcept;
+// [[nodiscard]] constexpr bool empty() const noexcept;
+//
+//
+// constexpr const extents_type& extents() const noexcept { return map_.extents(); }
+// constexpr const data_handle_type& data_handle() const noexcept { return ptr_; }
+// constexpr const mapping_type& mapping() const noexcept { return map_; }
+// constexpr const accessor_type& accessor() const noexcept { return acc_; }
+// 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 map_.is_unique(); }
+// constexpr bool is_exhaustive() const
+// { return map_.is_exhaustive(); }
+// constexpr bool is_strided() const
+// { return map_.is_strided(); }
+// constexpr index_type stride(rank_type r) const
+// { return map_.stride(r); }
+// };
+//
+// Each specialization MDS of mdspan models copyable and
+// - is_nothrow_move_constructible_v<MDS> is true,
+// - is_nothrow_move_assignable_v<MDS> is true, and
+// - is_nothrow_swappable_v<MDS> is true.
+// A specialization of mdspan is a trivially copyable type if its accessor_type, mapping_type, and data_handle_type are trivially copyable types.
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+
+template <class H, class M, class A>
+constexpr void test_mdspan_types(const H& handle, const M& map, const A& acc) {
+ using MDS = std::mdspan<typename A::element_type, typename M::extents_type, typename M::layout_type, A>;
+ MDS m(handle, map, acc);
+
+ // =====================================
+ // Traits for every mdspan
+ // =====================================
+ static_assert(std::copyable<MDS>);
+ static_assert(std::is_nothrow_move_constructible_v<MDS>);
+ static_assert(std::is_nothrow_move_assignable_v<MDS>);
+ static_assert(std::is_nothrow_swappable_v<MDS>);
+
+ // =====================================
+ // Invariants coming from data handle
+ // =====================================
+ // data_handle()
+ ASSERT_SAME_TYPE(decltype(m.data_handle()), const H&);
+ ASSERT_NOEXCEPT(m.data_handle());
+ if constexpr (std::equality_comparable<H>) {
+ assert(m.data_handle() == handle);
+ }
+
+ // =====================================
+ // Invariants coming from extents
+ // =====================================
+
+ // extents()
+ ASSERT_SAME_TYPE(decltype(m.extents()), const typename MDS::extents_type&);
+ ASSERT_NOEXCEPT(m.extents());
+ assert(m.extents() == map.extents());
+
+ // rank()
+ ASSERT_SAME_TYPE(decltype(m.rank()), typename MDS::rank_type);
+ ASSERT_NOEXCEPT(m.rank());
+ assert(MDS::rank() == MDS::extents_type::rank());
+
+ // rank_dynamic()
+ ASSERT_SAME_TYPE(decltype(m.rank_dynamic()), typename MDS::rank_type);
+ ASSERT_NOEXCEPT(m.rank_dynamic());
+ assert(MDS::rank_dynamic() == MDS::extents_type::rank_dynamic());
+
+ // extent(r), static_extent(r), size()
+ if constexpr (MDS::rank() > 0) {
+ typename MDS::size_type size = 1;
+ for (typename MDS::rank_type r = 0; r < MDS::rank(); r++) {
+ ASSERT_SAME_TYPE(decltype(MDS::static_extent(r)), size_t);
+ ASSERT_NOEXCEPT(MDS::static_extent(r));
+ assert(MDS::static_extent(r) == MDS::extents_type::static_extent(r));
+ ASSERT_SAME_TYPE(decltype(m.extent(r)), typename MDS::index_type);
+ ASSERT_NOEXCEPT(m.extent(r));
+ assert(m.extent(r) == m.extents().extent(r));
+ size *= m.extent(r);
+ }
+ assert(m.size() == size);
+ } else {
+ assert(m.size() == 1);
+ }
+ ASSERT_SAME_TYPE(decltype(m.size()), typename MDS::size_type);
+ ASSERT_NOEXCEPT(m.size());
+
+ // empty()
+ ASSERT_SAME_TYPE(decltype(m.empty()), bool);
+ ASSERT_NOEXCEPT(m.empty());
+ assert(m.empty() == (m.size() == 0));
+
+ // =====================================
+ // Invariants coming from mapping
+ // =====================================
+
+ // mapping()
+ ASSERT_SAME_TYPE(decltype(m.mapping()), const M&);
+ ASSERT_NOEXCEPT(m.mapping());
+
+ // is_[always_]unique/exhaustive/strided()
+ ASSERT_SAME_TYPE(decltype(MDS::is_always_unique()), bool);
+ ASSERT_SAME_TYPE(decltype(MDS::is_always_exhaustive()), bool);
+ ASSERT_SAME_TYPE(decltype(MDS::is_always_strided()), bool);
+ ASSERT_SAME_TYPE(decltype(m.is_unique()), bool);
+ ASSERT_SAME_TYPE(decltype(m.is_exhaustive()), bool);
+ ASSERT_SAME_TYPE(decltype(m.is_strided()), bool);
+ assert(!noexcept(MDS::is_always_unique()));
+ assert(!noexcept(MDS::is_always_exhaustive()));
+ assert(!noexcept(MDS::is_always_strided()));
+ assert(!noexcept(m.is_unique()));
+ assert(!noexcept(m.is_exhaustive()));
+ assert(!noexcept(m.is_strided()));
+ assert(MDS::is_always_unique() == M::is_always_unique());
+ assert(MDS::is_always_exhaustive() == M::is_always_exhaustive());
+ assert(MDS::is_always_strided() == M::is_always_strided());
+ assert(m.is_unique() == map.is_unique());
+ assert(m.is_exhaustive() == map.is_exhaustive());
+ assert(m.is_strided() == map.is_strided());
+
+ // stride(r)
+ if constexpr (MDS::rank() > 0) {
+ if (m.is_strided()) {
+ for (typename MDS::rank_type r = 0; r < MDS::rank(); r++) {
+ ASSERT_SAME_TYPE(decltype(m.stride(r)), typename MDS::index_type);
+ assert(!noexcept(m.stride(r)));
+ assert(m.stride(r) == map.stride(r));
+ }
+ }
+ }
+
+ // =====================================
+ // Invariants coming from accessor
+ // =====================================
+
+ // accessor()
+ ASSERT_SAME_TYPE(decltype(m.accessor()), const A&);
+ ASSERT_NOEXCEPT(m.accessor());
+}
+
+template <class H, class L, class A>
+constexpr void mixin_extents(const H& handle, const L& layout, const A& acc) {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D>(7)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<unsigned, 7>()), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<size_t, D, 4, D>(2, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<char, D, 7, D>(0, 3)), acc);
+ test_mdspan_types(handle, construct_mapping(layout, std::extents<int64_t, D, 7, D, 4, D, D>(1, 2, 3, 2)), acc);
+}
+
+template <class H, class A>
+constexpr void mixin_layout(const H& handle, const A& acc) {
+ mixin_extents(handle, std::layout_left(), acc);
+ mixin_extents(handle, std::layout_right(), acc);
+ mixin_extents(handle, layout_wrapping_integral<4>(), acc);
+}
+
+template <class T>
+constexpr void mixin_accessor() {
+ ElementPool<T, 1024> elements;
+ mixin_layout(elements.get_ptr(), std::default_accessor<T>());
+}
+
+constexpr bool test() {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+ return true;
+}
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/swap.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/swap.pass.cpp
new file mode 100644
index 00000000000000..dd1336c7af07e8
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/swap.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+//
+// friend constexpr void swap(mdspan& x, mdspan& y) noexcept;
+//
+// Effects: Equivalent to:
+// swap(x.ptr_, y.ptr_);
+// swap(x.map_, y.map_);
+// swap(x.acc_, y.acc_);
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestLayouts.h"
+
+template <class MDS>
+constexpr void test_swap(MDS a, MDS b) {
+ auto org_a = a;
+ auto org_b = b;
+ swap(a, b);
+ assert(a.extents() == org_b.extents());
+ assert(b.extents() == org_a.extents());
+ if constexpr (std::equality_comparable<typename MDS::mapping_type>) {
+ assert(a.mapping() == org_b.mapping());
+ assert(b.mapping() == org_a.mapping());
+ }
+ if constexpr (std::equality_comparable<typename MDS::data_handle_type>) {
+ assert(a.data_handle() == org_b.data_handle());
+ assert(b.data_handle() == org_a.data_handle());
+ }
+ // This check uses a side effect of layout_wrapping_integral::swap to make sure
+ // mdspan calls the underlying components' swap via ADL
+ if !consteval {
+ if constexpr (std::is_same_v<typename MDS::layout_type, layout_wrapping_integral<4>>) {
+ assert(MDS::mapping_type::swap_counter() > 0);
+ }
+ }
+}
+
+constexpr bool test() {
+ using extents_t = std::extents<int, 4, std::dynamic_extent>;
+ float data_a[1024];
+ float data_b[1024];
+ {
+ std::mdspan a(data_a, extents_t(12));
+ std::mdspan b(data_b, extents_t(5));
+ test_swap(a, b);
+ }
+ {
+ layout_wrapping_integral<4>::template mapping<extents_t> map_a(extents_t(12), not_extents_constructible_tag()),
+ map_b(extents_t(5), not_extents_constructible_tag());
+ std::mdspan a(data_a, map_a);
+ std::mdspan b(data_b, map_b);
+ test_swap(a, b);
+ }
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp b/libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp
new file mode 100644
index 00000000000000..5effea554c0d22
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp
@@ -0,0 +1,180 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <mdspan>
+//
+// template<class ElementType, class Extents, class LayoutPolicy = layout_right,
+// class AccessorPolicy = default_accessor<ElementType>>
+// class mdspan {
+// 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;
+// ...
+// };
+
+#include <mdspan>
+#include <type_traits>
+#include <concepts>
+#include <cassert>
+
+#include "test_macros.h"
+
+#include "../MinimalElementType.h"
+#include "CustomTestAccessors.h"
+#include "CustomTestLayouts.h"
+
+// Calculated expected size of an mdspan
+// Note this expectes that only default_accessor is empty
+template<class MDS>
+constexpr size_t expected_size() {
+ size_t sizeof_dht = sizeof(typename MDS::data_handle_type);
+ size_t result = sizeof_dht;
+ if(MDS::rank_dynamic() > 0) {
+ size_t alignof_idx = alignof(typename MDS::index_type);
+ size_t sizeof_idx = sizeof(typename MDS::index_type);
+ // add alignment if necessary
+ result += sizeof_dht%alignof_idx == 0?0:alignof_idx - (sizeof_dht%alignof_idx);
+ // add sizeof stored extents
+ result += MDS::rank_dynamic() * sizeof_idx;
+ }
+ using A = typename MDS::accessor_type;
+ if(!std::is_same_v<A, std::default_accessor<typename MDS::element_type>>) {
+ size_t alignof_acc = alignof(A);
+ size_t sizeof_acc = sizeof(A);
+ // add alignment if necessary
+ result += result%alignof_acc == 0?0:alignof_acc - (result%alignof_acc);
+ // add sizeof stored accessor
+ result += sizeof_acc;
+ }
+ // add alignment of the mdspan itself
+ result += result%alignof(MDS) == 0?0:alignof(MDS) - (result%alignof(MDS));
+ return result;
+}
+
+// check triviality
+template <class T>
+constexpr bool trv_df_ctor = std::is_trivially_default_constructible_v<T>;
+template <class T>
+constexpr bool trv_cp_ctor = std::is_trivially_copy_constructible_v<T>;
+template <class T>
+constexpr bool trv_mv_ctor = std::is_trivially_move_constructible_v<T>;
+template <class T>
+constexpr bool trv_dstruct = std::is_trivially_destructible_v<T>;
+template <class T>
+constexpr bool trv_cp_asgn = std::is_trivially_copy_assignable_v<T>;
+template <class T>
+constexpr bool trv_mv_asgn = std::is_trivially_move_assignable_v<T>;
+
+template <class MDS, bool default_ctor, bool copy_ctor, bool move_ctor, bool destr, bool copy_assign, bool move_assign>
+void check_triviality() {
+ static_assert(trv_df_ctor<MDS> == default_ctor);
+ static_assert(trv_cp_ctor<MDS> == copy_ctor);
+ static_assert(trv_mv_ctor<MDS> == move_ctor);
+ static_assert(trv_dstruct<MDS> == destr);
+ static_assert(trv_cp_asgn<MDS> == copy_assign);
+ static_assert(trv_mv_asgn<MDS> == move_assign);
+}
+
+template <class T, class E, class L, class A>
+void test_mdspan_types() {
+ using MDS = std::mdspan<T, E, L, A>;
+
+ ASSERT_SAME_TYPE(typename MDS::extents_type, E);
+ ASSERT_SAME_TYPE(typename MDS::layout_type, L);
+ ASSERT_SAME_TYPE(typename MDS::accessor_type, A);
+ ASSERT_SAME_TYPE(typename MDS::mapping_type, typename L::template mapping<E>);
+ ASSERT_SAME_TYPE(typename MDS::element_type, T);
+ ASSERT_SAME_TYPE(typename MDS::value_type, std::remove_cv_t<T>);
+ ASSERT_SAME_TYPE(typename MDS::index_type, typename E::index_type);
+ ASSERT_SAME_TYPE(typename MDS::size_type, typename E::size_type);
+ ASSERT_SAME_TYPE(typename MDS::rank_type, typename E::rank_type);
+ ASSERT_SAME_TYPE(typename MDS::data_handle_type, typename A::data_handle_type);
+ ASSERT_SAME_TYPE(typename MDS::reference, typename A::reference);
+
+// This miserably failed with clang-cl - likely because it doesn't honor/enable
+// no-unique-address fully by default
+#ifndef _WIN32
+ // check the size of mdspan
+ if constexpr (std::is_same_v<L, std::layout_left> || std::is_same_v<L, std::layout_right>) {
+ LIBCPP_STATIC_ASSERT(sizeof(MDS) == expected_size<MDS>());
+ }
+#endif
+
+ // check default template parameters:
+ ASSERT_SAME_TYPE(std::mdspan<T, E>, std::mdspan<T, E, std::layout_right, std::default_accessor<T>>);
+ ASSERT_SAME_TYPE(std::mdspan<T, E, L>, std::mdspan<T, E, L, std::default_accessor<T>>);
+
+ // check triviality
+ using DH = typename MDS::data_handle_type;
+ using MP = typename MDS::mapping_type;
+
+ check_triviality<MDS,
+ false, // mdspan is never trivially constructible right now
+ trv_cp_ctor<DH> && trv_cp_ctor<MP> && trv_cp_ctor<A>,
+ trv_mv_ctor<DH> && trv_mv_ctor<MP> && trv_mv_ctor<A>,
+ trv_dstruct<DH> && trv_dstruct<MP> && trv_dstruct<A>,
+ trv_cp_asgn<DH> && trv_cp_asgn<MP> && trv_cp_asgn<A>,
+ trv_mv_asgn<DH> && trv_mv_asgn<MP> && trv_mv_asgn<A>>();
+}
+
+template <class T, class L, class A>
+void mixin_extents() {
+ constexpr size_t D = std::dynamic_extent;
+ test_mdspan_types<T, std::extents<int>, L, A>();
+ test_mdspan_types<T, std::extents<char, D>, L, A>();
+ test_mdspan_types<T, std::dextents<char, 7>, L, A>();
+ test_mdspan_types<T, std::dextents<char, 9>, L, A>();
+ test_mdspan_types<T, std::extents<unsigned, 7>, L, A>();
+ test_mdspan_types<T, std::extents<unsigned, D, D, D>, L, A>();
+ test_mdspan_types<T, std::extents<size_t, D, 7, D>, L, A>();
+ test_mdspan_types<T, std::extents<int64_t, D, 7, D, 4, D, D>, L, A>();
+}
+
+template <class T, class A>
+void mixin_layout() {
+ mixin_extents<T, std::layout_left, A>();
+ mixin_extents<T, std::layout_right, A>();
+ mixin_extents<T, layout_wrapping_integral<4>, A>();
+}
+
+template <class T>
+void mixin_accessor() {
+ mixin_layout<T, std::default_accessor<T>>();
+ mixin_layout<T, checked_accessor<T>>();
+}
+
+int main(int, char**) {
+ mixin_accessor<int>();
+ mixin_accessor<const int>();
+ mixin_accessor<double>();
+ mixin_accessor<const double>();
+ mixin_accessor<MinimalElementType>();
+ mixin_accessor<const MinimalElementType>();
+
+ // sanity checks for triviality
+ check_triviality<std::mdspan<int, std::extents<int>>, false, true, true, true, true, true>();
+ check_triviality<std::mdspan<int, std::dextents<int, 1>>, false, true, true, true, true, true>();
+ check_triviality<std::mdspan<int, std::dextents<int, 1>, std::layout_right, checked_accessor<int>>,
+ false,
+ true,
+ false,
+ true,
+ true,
+ true>();
+ return 0;
+}
More information about the llvm-branch-commits
mailing list