[libcxx-commits] [libcxx] [libc++] Partially implement P2642R6: Padded mdspan layouts (PR #187873)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Mar 23 21:07:40 PDT 2026
https://github.com/eiytoq updated https://github.com/llvm/llvm-project/pull/187873
>From c9113a65e8c10305aff10019538d368811e41e4e Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Fri, 20 Mar 2026 20:57:03 +0800
Subject: [PATCH 1/6] impl
---
libcxx/docs/Status/Cxx2cIssues.csv | 2 +-
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
libcxx/include/CMakeLists.txt | 4 +
libcxx/include/__fwd/mdspan.h | 16 +
libcxx/include/__mdspan/concepts.h | 46 ++
libcxx/include/__mdspan/layout_left_padded.h | 415 +++++++++++++++++
.../include/__mdspan/layout_padded_common.h | 98 ++++
libcxx/include/__mdspan/layout_right_padded.h | 428 ++++++++++++++++++
libcxx/include/__mdspan/layout_stride.h | 19 +-
libcxx/include/mdspan | 171 +++++++
libcxx/modules/std/mdspan.inc | 5 +
.../layout_left_padded/comparison.pass.cpp | 91 ++++
.../layout_left_padded/ctor.copy.pass.cpp | 55 +++
.../layout_left_padded/ctor.default.pass.cpp | 53 +++
.../layout_left_padded/ctor.extents.pass.cpp | 59 +++
.../ctor.layout_left.pass.cpp | 79 ++++
.../ctor.layout_right.pass.cpp | 74 +++
.../ctor.layout_right_padded.pass.cpp | 74 +++
.../ctor.layout_stride.pass.cpp | 78 ++++
.../ctor.mapping.assert.pass.cpp | 53 +++
.../layout_left_padded/ctor.mapping.pass.cpp | 86 ++++
.../layout_left_padded/ctor.padding.pass.cpp | 52 +++
.../layout_left_padded/extents.verify.cpp | 36 ++
.../index_operator.pass.cpp | 105 +++++
.../layout_left_padded/properties.pass.cpp | 88 ++++
.../required_span_size.pass.cpp | 53 +++
.../static_requirements.pass.cpp | 68 +++
.../mdspan/layout_left_padded/stride.pass.cpp | 61 +++
.../layout_right_padded/comparison.pass.cpp | 91 ++++
.../layout_right_padded/ctor.copy.pass.cpp | 59 +++
.../layout_right_padded/ctor.default.pass.cpp | 53 +++
.../layout_right_padded/ctor.extents.pass.cpp | 59 +++
.../ctor.layout_left.pass.cpp | 74 +++
.../ctor.layout_left_padded.pass.cpp | 74 +++
.../ctor.layout_right.pass.cpp | 79 ++++
.../ctor.layout_stride.pass.cpp | 78 ++++
.../ctor.mapping.assert.pass.cpp | 52 +++
.../layout_right_padded/ctor.mapping.pass.cpp | 86 ++++
.../layout_right_padded/ctor.padding.pass.cpp | 52 +++
.../layout_right_padded/extents.verify.cpp | 36 ++
.../index_operator.pass.cpp | 105 +++++
.../layout_right_padded/properties.pass.cpp | 87 ++++
.../required_span_size.pass.cpp | 53 +++
.../static_requirements.pass.cpp | 68 +++
.../layout_right_padded/stride.pass.cpp | 61 +++
45 files changed, 3518 insertions(+), 20 deletions(-)
create mode 100644 libcxx/include/__mdspan/concepts.h
create mode 100644 libcxx/include/__mdspan/layout_left_padded.h
create mode 100644 libcxx/include/__mdspan/layout_padded_common.h
create mode 100644 libcxx/include/__mdspan/layout_right_padded.h
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/comparison.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.copy.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.default.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.extents.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_left.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_right.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_right_padded.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_stride.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.mapping.assert.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.mapping.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.padding.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/extents.verify.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/index_operator.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/properties.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/required_span_size.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/static_requirements.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left_padded/stride.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/comparison.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.copy.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.default.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.extents.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_left.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_left_padded.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_right.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_stride.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.mapping.assert.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.mapping.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.padding.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/extents.verify.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/index_operator.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/properties.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/required_span_size.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/static_requirements.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right_padded/stride.pass.cpp
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index 60b1bd6ff70da..5036ebfb1691a 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -204,7 +204,7 @@
"`LWG4366 <https://wg21.link/LWG4366>`__","Heterogeneous comparison of ``expected`` may be ill-formed","2025-11 (Kona)","","","`#171362 <https://github.com/llvm/llvm-project/issues/171362>`__",""
"`LWG4369 <https://wg21.link/LWG4369>`__","``check-types`` function for ``upon_error`` and ``upon_stopped`` is wrong","2025-11 (Kona)","","","`#171363 <https://github.com/llvm/llvm-project/issues/171363>`__",""
"`LWG4370 <https://wg21.link/LWG4370>`__","Comparison of ``optional<T>`` to ``T`` may be ill-formed","2025-11 (Kona)","|Complete|","22","`#171364 <https://github.com/llvm/llvm-project/issues/171364>`__",""
-"`LWG4372 <https://wg21.link/LWG4372>`__","Weaken *Mandates:* for dynamic padding values in padded layouts","2025-11 (Kona)","","","`#171365 <https://github.com/llvm/llvm-project/issues/171365>`__",""
+"`LWG4372 <https://wg21.link/LWG4372>`__","Weaken *Mandates:* for dynamic padding values in padded layouts","2025-11 (Kona)","|Complete|","23","`#171365 <https://github.com/llvm/llvm-project/issues/171365>`__",""
"`LWG4375 <https://wg21.link/LWG4375>`__","``std::simd::bit_ceil`` should not be ``noexcept``","2025-11 (Kona)","","","`#171366 <https://github.com/llvm/llvm-project/issues/171366>`__",""
"`LWG4376 <https://wg21.link/LWG4376>`__","ABI tag in return type of [simd.mask.unary] is overconstrained","2025-11 (Kona)","","","`#171367 <https://github.com/llvm/llvm-project/issues/171367>`__",""
"`LWG4377 <https://wg21.link/LWG4377>`__","Misleading note about lock-free property of ``std::atomic_ref``","2025-11 (Kona)","","","`#171368 <https://github.com/llvm/llvm-project/issues/171368>`__",""
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 29642fc53cac6..3d84652940a3d 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -60,7 +60,7 @@
"`P2810R4 <https://wg21.link/P2810R4>`__","``is_debugger_present`` ``is_replaceable``","2024-03 (Tokyo)","","","`#105422 <https://github.com/llvm/llvm-project/issues/105422>`__",""
"`P1068R11 <https://wg21.link/P1068R11>`__","Vector API for random number generation","2024-03 (Tokyo)","","","`#105423 <https://github.com/llvm/llvm-project/issues/105423>`__",""
"`P2944R3 <https://wg21.link/P2944R3>`__","Comparisons for ``reference_wrapper``","2024-03 (Tokyo)","|Complete|","22","`#105424 <https://github.com/llvm/llvm-project/issues/105424>`__","The changes to ``tuple``'s equality overload from P2165R4 are not yet implemented."
-"`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","","","`#105425 <https://github.com/llvm/llvm-project/issues/105425>`__",""
+"`P2642R6 <https://wg21.link/P2642R6>`__","Padded ``mdspan`` layouts","2024-03 (Tokyo)","|Partial|","23","`#105425 <https://github.com/llvm/llvm-project/issues/105425>`__",""
"`P3029R1 <https://wg21.link/P3029R1>`__","Better ``mdspan``'s CTAD","2024-03 (Tokyo)","|Complete|","19","`#105426 <https://github.com/llvm/llvm-project/issues/105426>`__",""
"","","","","","",""
"`P2747R2 <https://wg21.link/P2747R2>`__","``constexpr`` placement new","2024-06 (St. Louis)","|Complete|","20","`#105427 <https://github.com/llvm/llvm-project/issues/105427>`__",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 53165f0336b2d..474f21bc4959d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -572,9 +572,13 @@ set(files
__math/trigonometric_functions.h
__mbstate_t.h
__mdspan/aligned_accessor.h
+ __mdspan/concepts.h
__mdspan/default_accessor.h
__mdspan/extents.h
__mdspan/layout_left.h
+ __mdspan/layout_left_padded.h
+ __mdspan/layout_padded_common.h
+ __mdspan/layout_right_padded.h
__mdspan/layout_right.h
__mdspan/layout_stride.h
__mdspan/mdspan.h
diff --git a/libcxx/include/__fwd/mdspan.h b/libcxx/include/__fwd/mdspan.h
index 8889567a047f6..8c069577ab2a9 100644
--- a/libcxx/include/__fwd/mdspan.h
+++ b/libcxx/include/__fwd/mdspan.h
@@ -18,6 +18,8 @@
#define _LIBCPP___MDSPAN_LAYOUTS_H
#include <__config>
+#include <cstddef>
+#include <span>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -48,6 +50,20 @@ struct layout_stride {
class mapping;
};
+# if _LIBCPP_STD_VER >= 26
+template <size_t _PaddingValue = dynamic_extent>
+struct layout_left_padded {
+ template <class _Extents>
+ class mapping;
+};
+
+template <size_t _PaddingValue = dynamic_extent>
+struct layout_right_padded {
+ template <class _Extents>
+ class mapping;
+};
+# endif
+
#endif // _LIBCPP_STD_VER >= 23
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__mdspan/concepts.h b/libcxx/include/__mdspan/concepts.h
new file mode 100644
index 0000000000000..9b5d321c79cdb
--- /dev/null
+++ b/libcxx/include/__mdspan/concepts.h
@@ -0,0 +1,46 @@
+#ifndef _LIBCPP___MDSPAN_CONCEPT_H
+#define _LIBCPP___MDSPAN_CONCEPT_H
+
+#include <__assert>
+#include <__concepts/same_as.h>
+#include <__config>
+#include <__mdspan/extents.h>
+
+#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
+
+namespace __mdspan_detail {
+
+template <class _Layout, class _Mapping>
+constexpr bool __is_mapping_of =
+ is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, _Mapping>;
+
+template <class _Mapping>
+concept __layout_mapping_alike = requires {
+ requires __is_mapping_of<typename _Mapping::layout_type, _Mapping>;
+ requires __is_extents_v<typename _Mapping::extents_type>;
+ { _Mapping::is_always_strided() } -> same_as<bool>;
+ { _Mapping::is_always_exhaustive() } -> same_as<bool>;
+ { _Mapping::is_always_unique() } -> same_as<bool>;
+ bool_constant<_Mapping::is_always_strided()>::value;
+ bool_constant<_Mapping::is_always_exhaustive()>::value;
+ bool_constant<_Mapping::is_always_unique()>::value;
+};
+
+} // namespace __mdspan_detail
+
+#endif // _LIBCPP_STD_VER >= 23
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MDSPAN_CONCEPT_H
diff --git a/libcxx/include/__mdspan/layout_left_padded.h b/libcxx/include/__mdspan/layout_left_padded.h
new file mode 100644
index 0000000000000..f2709975c49bf
--- /dev/null
+++ b/libcxx/include/__mdspan/layout_left_padded.h
@@ -0,0 +1,415 @@
+// -*- 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_LAYOUT_LEFT_PADDED_H
+#define _LIBCPP___MDSPAN_LAYOUT_LEFT_PADDED_H
+
+#include <__assert>
+#include <__config>
+#include <__fwd/mdspan.h>
+#include <__mdspan/concepts.h>
+#include <__mdspan/extents.h>
+#include <__mdspan/layout_left.h>
+#include <__mdspan/layout_padded_common.h>
+#include <__mdspan/layout_right.h>
+#include <__mdspan/layout_stride.h>
+#include <__memory/addressof.h>
+#include <__type_traits/common_type.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__utility/integer_sequence.h>
+#include <array>
+
+#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 >= 26
+
+template <size_t _PaddingValue>
+template <class _Extents>
+class layout_left_padded<_PaddingValue>::mapping {
+public:
+ static_assert(__mdspan_detail::__is_extents<_Extents>::value,
+ "layout_left_padded::mapping template argument must be a specialization of extents.");
+
+ static constexpr size_t padding_value = _PaddingValue;
+
+ using extents_type = _Extents;
+ using index_type = extents_type::index_type;
+ using size_type = extents_type::size_type;
+ using rank_type = extents_type::rank_type;
+ using layout_type = layout_left_padded;
+
+private:
+ static constexpr rank_type __rank_ = extents_type::rank();
+ static constexpr size_t __first_static_extent = __rank_ == 0 ? 0uz : extents_type::static_extent(0);
+
+ static constexpr size_t __static_padding_stride = [] {
+ if constexpr (__rank_ <= 1)
+ return 0uz;
+ if constexpr (padding_value == dynamic_extent || __first_static_extent == dynamic_extent)
+ return dynamic_extent;
+ return __mdspan_detail::__least_multiple_at_least(padding_value, __first_static_extent);
+ }();
+
+ // Do not store value if __static_padding_stride is not dynamic_extent.
+ using __stride_1_type = std::extents<index_type, __static_padding_stride>;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type __stride_1() const noexcept {
+ if constexpr (__rank_ <= 1)
+ return static_cast<index_type>(0);
+ if constexpr (__static_padding_stride != dynamic_extent)
+ return static_cast<index_type>(__static_padding_stride);
+ return __stride_1_.extent(0);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool __index_space_size_is_representable(const extents_type& __ext) {
+ for (rank_type __r = 0; __r < __rank_; ++__r) {
+ if (__ext.extent(__r) == static_cast<index_type>(0))
+ return true;
+ }
+
+ index_type __prod = static_cast<index_type>(1);
+
+ for (rank_type __r = 0; __r < __rank_; ++__r) {
+ bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod));
+ if (__overflowed)
+ return false;
+ }
+
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool
+ __padded_product_is_representable(const extents_type& __ext, index_type __stride_1) {
+ if (__stride_1 == static_cast<index_type>(0))
+ return true;
+ for (rank_type __r = 1; __r < __rank_; ++__r) {
+ if (__ext.extent(__r) == static_cast<index_type>(0))
+ return true;
+ }
+
+ index_type __prod = __stride_1;
+ for (rank_type __r = 1; __r < __rank_; ++__r) {
+ bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod));
+ if (__overflowed)
+ return false;
+ }
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static consteval bool __static_padded_product_is_representable() {
+ if constexpr (__rank_ <= 1 || padding_value == dynamic_extent || extents_type::rank_dynamic() > 0)
+ return true;
+ for (rank_type __r = 0; __r < __rank_; ++__r) {
+ if (extents_type::static_extent(__r) == 0)
+ return true;
+ }
+ if constexpr (__static_padding_stride == dynamic_extent ||
+ !__mdspan_detail::__is_representable_as<index_type>(__static_padding_stride))
+ return false;
+ size_t __prod = __static_padding_stride;
+ for (rank_type __r = 1; __r < __rank_; ++__r) {
+ bool __overflowed = __builtin_mul_overflow(__prod, extents_type::static_extent(__r), std::addressof(__prod));
+ if (__overflowed)
+ return false;
+ }
+ return __mdspan_detail::__is_representable_as<index_type>(__prod);
+ }
+
+ static_assert(extents_type::rank_dynamic() != 0 || __index_space_size_is_representable(extents_type{}),
+ "layout_left_padded::mapping index space for static extents must be representable as index_type.");
+
+ static_assert(padding_value == dynamic_extent || __mdspan_detail::__is_representable_as<index_type>(padding_value),
+ "layout_left_padded::mapping padding_value must be representable as index_type.");
+
+ static_assert(__rank_ <= 1 || padding_value == dynamic_extent || __first_static_extent == dynamic_extent ||
+ (__mdspan_detail::__least_multiple_at_least_is_representable_as<size_t>(
+ padding_value, __first_static_extent) &&
+ __mdspan_detail::__least_multiple_at_least_is_representable_as<index_type>(
+ padding_value, __first_static_extent)),
+ "layout_left_padded::mapping padded stride for the first static extent must be representable as "
+ "size_t and index_type.");
+
+ static_assert(__static_padded_product_is_representable(),
+ "layout_left_padded::mapping required span size for static extents must be representable as size_t "
+ "and index_type.");
+
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : mapping(extents_type{}) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) : __extents_(__ext) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __index_space_size_is_representable(__ext),
+ "layout_left_padded::mapping(extents): index space size must be representable as index_type.");
+
+ if constexpr (__rank_ > 1) {
+ index_type __stride_1 = 0;
+ if constexpr (padding_value == dynamic_extent) {
+ __stride_1 = __ext.extent(0);
+ } else {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__least_multiple_at_least_is_representable_as<index_type>(
+ static_cast<index_type>(padding_value), __ext.extent(0)),
+ "layout_left_padded::mapping(extents): padded stride must be representable as index_type.");
+ __stride_1 =
+ __mdspan_detail::__least_multiple_at_least(static_cast<index_type>(padding_value), __ext.extent(0));
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __padded_product_is_representable(__ext, __stride_1),
+ "layout_left_padded::mapping(extents): required span size must be representable as index_type.");
+ }
+ if constexpr (__static_padding_stride == dynamic_extent)
+ __stride_1_ = __stride_1_type(__stride_1);
+ }
+ }
+
+ template <class _OtherIndexType>
+ requires is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType>
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, _OtherIndexType __pad) : __extents_(__ext) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__pad),
+ "layout_left_padded::mapping(extents, pad): pad must be representable as index_type.");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ static_cast<index_type>(__pad) > 0, "layout_left_padded::mapping(extents, pad): pad must be greater than 0.");
+
+ if constexpr (padding_value != dynamic_extent)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(padding_value == static_cast<index_type>(__pad),
+ "layout_left_padded::mapping(extents, pad): pad must equal padding_value.");
+
+ if constexpr (__rank_ > 1) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__least_multiple_at_least_is_representable_as<index_type>(
+ static_cast<index_type>(__pad), __ext.extent(0)),
+ "layout_left_padded::mapping(extents, pad): padded stride must be representable as index_type.");
+
+ const index_type __stride_1 =
+ __mdspan_detail::__least_multiple_at_least(static_cast<index_type>(__pad), __ext.extent(0));
+
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __padded_product_is_representable(__ext, __stride_1),
+ "layout_left_padded::mapping(extents, pad): required span size must be representable as index_type.");
+
+ if constexpr (__static_padding_stride == dynamic_extent)
+ __stride_1_ = __stride_1_type(__stride_1);
+ }
+ }
+
+ template <class _OtherExtents>
+ requires is_constructible_v<extents_type, _OtherExtents>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>)
+ mapping(const layout_left::mapping<_OtherExtents>& __other)
+ : mapping(extents_type(__other.extents())) {
+ static_assert(_OtherExtents::rank() <= 1 || __static_padding_stride == dynamic_extent ||
+ _OtherExtents::static_extent(0) == dynamic_extent ||
+ __static_padding_stride == _OtherExtents::static_extent(0));
+
+ if constexpr (__rank_ > 1 && padding_value != dynamic_extent) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(1) ==
+ __mdspan_detail::__least_multiple_at_least(
+ static_cast<index_type>(padding_value), static_cast<index_type>(__other.extents().extent(0))),
+ "layout_left_padded::mapping from layout_left ctor: source stride must match the padded stride implied by "
+ "padding_value.");
+ }
+
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_left_padded::mapping from layout_left ctor: other.required_span_size() must be representable as "
+ "index_type.");
+ }
+
+ template <class _OtherExtents>
+ requires is_constructible_v<extents_type, _OtherExtents>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(!(__rank_ == 0 && is_convertible_v<_OtherExtents, extents_type>))
+ mapping(const layout_stride::mapping<_OtherExtents>& __other)
+ : __extents_(extents_type(__other.extents())) {
+ if constexpr (__rank_ > 1 && padding_value != dynamic_extent)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(1) ==
+ __mdspan_detail::__least_multiple_at_least(
+ static_cast<index_type>(padding_value), static_cast<index_type>(__other.extents().extent(0))),
+ "layout_left_padded::mapping from layout_stride ctor: source stride must match the padded stride implied by "
+ "padding_value.");
+
+ if constexpr (__rank_ > 0)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(0) == 1, "layout_left_padded::mapping from layout_stride ctor: stride(0) must equal 1.");
+
+ if constexpr (__rank_ > 2) {
+ using _Common = common_type_t<index_type, typename layout_stride::mapping<_OtherExtents>::index_type>;
+ _Common __expected = static_cast<_Common>(__other.stride(1));
+ for (rank_type __r = 2; __r < __rank_; ++__r) {
+ __expected *= static_cast<_Common>(__other.extents().extent(__r - 1));
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ static_cast<_Common>(__other.stride(__r)) == __expected,
+ "layout_left_padded::mapping from layout_stride ctor: strides are not compatible with layout_left_padded.");
+ }
+ }
+
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_left_padded::mapping from layout_stride ctor: other.required_span_size() must be representable as "
+ "index_type.");
+
+ if constexpr (__rank_ > 1 && __static_padding_stride == dynamic_extent) {
+# if 0 // TODO
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.stride(1)),
+ "layout_left_padded::mapping from layout_stride ctor: source padded stride must be representable as "
+ "index_type.");
+# endif
+ __stride_1_ = __stride_1_type(static_cast<index_type>(__other.stride(1)));
+ }
+ }
+
+ template <class _LayoutLeftPaddedMapping>
+ requires __mdspan_detail::__layout_left_padded_mapping_of<_LayoutLeftPaddedMapping> &&
+ is_constructible_v<extents_type, typename _LayoutLeftPaddedMapping::extents_type>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(
+ !is_convertible_v<typename _LayoutLeftPaddedMapping::extents_type, extents_type> ||
+ (__rank_ > 1 && (padding_value != dynamic_extent || _LayoutLeftPaddedMapping::padding_value == dynamic_extent)))
+ mapping(const _LayoutLeftPaddedMapping& __other)
+ : __extents_(extents_type(__other.extents())) {
+ static_assert(
+ __rank_ <= 1 || padding_value == dynamic_extent || _LayoutLeftPaddedMapping::padding_value == dynamic_extent ||
+ padding_value == _LayoutLeftPaddedMapping::padding_value,
+ "layout_left_padded::mapping converting ctor: incompatible static padding values.");
+
+ if constexpr (__rank_ > 1 && padding_value != dynamic_extent)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(1) ==
+ __mdspan_detail::__least_multiple_at_least(
+ static_cast<index_type>(padding_value), static_cast<index_type>(__other.extents().extent(0))),
+ "layout_left_padded::mapping from layout_left_padded ctor: source stride must match the padded stride "
+ "implied by padding_value.");
+
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_left_padded::mapping from layout_left_padded ctor: other.required_span_size() must be representable as "
+ "index_type.");
+
+ if constexpr (__rank_ > 1 && __static_padding_stride == dynamic_extent) {
+# if 0 // TODO
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.stride(1)),
+ "layout_left_padded::mapping from layout_left_padded ctor: source padded stride must be representable as "
+ "index_type.");
+# endif
+ __stride_1_ = __stride_1_type(static_cast<index_type>(__other.stride(1)));
+ }
+ }
+
+ template <class _LayoutRightPaddedMapping>
+ requires(__mdspan_detail::__layout_right_padded_mapping_of<_LayoutRightPaddedMapping> ||
+ __mdspan_detail::__layout_right_mapping_of<_LayoutRightPaddedMapping>) &&
+ (__rank_ <= 1) && is_constructible_v<extents_type, typename _LayoutRightPaddedMapping::extents_type>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(
+ !is_convertible_v<typename _LayoutRightPaddedMapping::extents_type, extents_type>)
+ mapping(const _LayoutRightPaddedMapping& __other) noexcept
+ : __extents_(extents_type(__other.extents())) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_left_padded::mapping converting ctor: other.required_span_size() must be representable as index_type.");
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr array<index_type, __rank_> strides() const noexcept {
+ return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ return array<index_type, __rank_>{stride(_Pos)...};
+ }(make_index_sequence<__rank_>());
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept {
+ return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ if (((__extents_.extent(_Pos) == static_cast<index_type>(0)) || ...))
+ return static_cast<index_type>(0);
+
+ return static_cast<index_type>(
+ (*this)(static_cast<index_type>(__extents_.extent(_Pos) - static_cast<index_type>(1))...) +
+ static_cast<index_type>(1));
+ }(make_index_sequence<__rank_>());
+ }
+
+ template <class... _Indices>
+ requires(sizeof...(_Indices) == __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_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...),
+ "layout_left_padded::mapping: out of bounds indexing.");
+ return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ return ((static_cast<index_type>(__idx) * stride(_Pos)) + ... + static_cast<index_type>(0));
+ }(make_index_sequence<sizeof...(_Indices)>());
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; }
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept {
+ if constexpr (__rank_ <= 1)
+ return true;
+ if constexpr (__first_static_extent == dynamic_extent || __static_padding_stride == dynamic_extent)
+ return false;
+ return __first_static_extent == __static_padding_stride;
+ }
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; }
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const noexcept {
+ if constexpr (__rank_ <= 1)
+ return true;
+ return extents().extent(0) == stride(1);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__r < __rank_, "layout_left_padded::mapping::stride(): invalid rank index.");
+
+ if (__r == 0)
+ return static_cast<index_type>(1);
+
+ index_type __stride = __stride_1();
+ for (rank_type __i = 1; __i < __r; ++__i)
+ __stride *= __extents_.extent(__i);
+ return __stride;
+ }
+
+ template <class _LayoutLeftPaddedMapping>
+ requires __mdspan_detail::__layout_left_padded_mapping_of<_LayoutLeftPaddedMapping> &&
+ (_LayoutLeftPaddedMapping::extents_type::rank() == __rank_)
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator==(const mapping& __x, const _LayoutLeftPaddedMapping& __y) noexcept {
+ return __x.extents() == __y.extents() && (__rank_ < 2 || __x.stride(1) == __y.stride(1));
+ }
+
+private:
+ _LIBCPP_NO_UNIQUE_ADDRESS __stride_1_type __stride_1_{};
+ _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{};
+};
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MDSPAN_LAYOUT_LEFT_PADDED_H
diff --git a/libcxx/include/__mdspan/layout_padded_common.h b/libcxx/include/__mdspan/layout_padded_common.h
new file mode 100644
index 0000000000000..aae860f6f8d87
--- /dev/null
+++ b/libcxx/include/__mdspan/layout_padded_common.h
@@ -0,0 +1,98 @@
+// -*- 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_LAYOUT_PADDED_COMMON_H
+#define _LIBCPP___MDSPAN_LAYOUT_PADDED_COMMON_H
+
+#include <__config>
+#include <__fwd/mdspan.h>
+#include <__mdspan/concepts.h>
+#include <__memory/addressof.h>
+
+#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 >= 26
+
+namespace __mdspan_detail {
+
+template <class _Integral>
+_LIBCPP_HIDE_FROM_ABI constexpr _Integral __least_multiple_at_least(_Integral __multiplier, _Integral __minimum) {
+ if (__multiplier == static_cast<_Integral>(0))
+ return __minimum;
+
+ _Integral __factor = __minimum / __multiplier;
+ if (__minimum % __multiplier != static_cast<_Integral>(0))
+ ++__factor;
+
+ return __factor * __multiplier;
+}
+
+template <class _To, class _Integral>
+_LIBCPP_HIDE_FROM_ABI constexpr bool
+__least_multiple_at_least_is_representable_as(_Integral __multiplier, _Integral __minimum) {
+ if (__multiplier == static_cast<_Integral>(0))
+ return __mdspan_detail::__is_representable_as<_To>(__minimum);
+
+ _Integral __factor = __minimum / __multiplier;
+ if (__minimum % __multiplier != static_cast<_Integral>(0)) {
+ bool __overflowed_add = __builtin_add_overflow(__factor, static_cast<_Integral>(1), std::addressof(__factor));
+ if (__overflowed_add)
+ return false;
+ }
+
+ _Integral __result = 0;
+ bool __overflowed_mul = __builtin_mul_overflow(__factor, __multiplier, std::addressof(__result));
+ return !__overflowed_mul && __mdspan_detail::__is_representable_as<_To>(__result);
+}
+
+template <template <size_t> class _LayoutTemplate, class _Layout>
+struct __is_layout_specialization_of : false_type {};
+
+template <template <size_t> class _LayoutTemplate, size_t _PaddingValue>
+struct __is_layout_specialization_of<_LayoutTemplate, _LayoutTemplate<_PaddingValue>> : true_type {};
+
+template <class _Mapping>
+concept __layout_left_padded_mapping_of =
+ __layout_mapping_alike<_Mapping> &&
+ __is_layout_specialization_of<layout_left_padded, typename _Mapping::layout_type>::value;
+
+template <class _Mapping>
+concept __layout_right_padded_mapping_of =
+ __layout_mapping_alike<_Mapping> &&
+ __is_layout_specialization_of<layout_right_padded, typename _Mapping::layout_type>::value;
+
+template <class _Mapping>
+concept __layout_right_mapping_of = __layout_mapping_alike<_Mapping> && __is_mapping_of<layout_right, _Mapping>;
+
+template <class _Mapping>
+concept __layout_left_mapping_of = __layout_mapping_alike<_Mapping> && __is_mapping_of<layout_left, _Mapping>;
+
+} // namespace __mdspan_detail
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MDSPAN_LAYOUT_PADDED_COMMON_H
diff --git a/libcxx/include/__mdspan/layout_right_padded.h b/libcxx/include/__mdspan/layout_right_padded.h
new file mode 100644
index 0000000000000..2d89722536ba2
--- /dev/null
+++ b/libcxx/include/__mdspan/layout_right_padded.h
@@ -0,0 +1,428 @@
+// -*- 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_LAYOUT_RIGHT_PADDED_H
+#define _LIBCPP___MDSPAN_LAYOUT_RIGHT_PADDED_H
+
+#include <__assert>
+#include <__config>
+#include <__fwd/mdspan.h>
+#include <__mdspan/concepts.h>
+#include <__mdspan/extents.h>
+#include <__mdspan/layout_left.h>
+#include <__mdspan/layout_padded_common.h>
+#include <__mdspan/layout_right.h>
+#include <__mdspan/layout_stride.h>
+#include <__memory/addressof.h>
+#include <__type_traits/common_type.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__utility/integer_sequence.h>
+#include <array>
+
+#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 >= 26
+
+template <size_t _PaddingValue>
+template <class _Extents>
+class layout_right_padded<_PaddingValue>::mapping {
+public:
+ static_assert(__mdspan_detail::__is_extents<_Extents>::value,
+ "layout_right_padded::mapping template argument must be a specialization of extents.");
+
+ static constexpr size_t padding_value = _PaddingValue;
+
+ using extents_type = _Extents;
+ using index_type = extents_type::index_type;
+ using size_type = extents_type::size_type;
+ using rank_type = extents_type::rank_type;
+ using layout_type = layout_right_padded;
+
+private:
+ static constexpr rank_type __rank_ = extents_type::rank();
+ static constexpr size_t __last_static_extent = __rank_ == 0 ? 0uz : extents_type::static_extent(__rank_ - 1);
+
+ static constexpr size_t __static_padding_stride = [] {
+ if constexpr (__rank_ <= 1)
+ return 0uz;
+ if constexpr (padding_value == dynamic_extent || __last_static_extent == dynamic_extent)
+ return dynamic_extent;
+ return __mdspan_detail::__least_multiple_at_least(padding_value, __last_static_extent);
+ }();
+
+ using __stride_rm2_type = std::extents<index_type, __static_padding_stride>;
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool __index_space_size_is_representable(const extents_type& __ext) {
+ for (rank_type __r = 0; __r < __rank_; ++__r) {
+ if (__ext.extent(__r) == static_cast<index_type>(0))
+ return true;
+ }
+
+ index_type __prod = static_cast<index_type>(1);
+ for (rank_type __r = 0; __r < __rank_; ++__r) {
+ bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod));
+ if (__overflowed)
+ return false;
+ }
+
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool
+ __padded_product_is_representable(const extents_type& __ext, index_type __stride_rm2) {
+ if (__stride_rm2 == static_cast<index_type>(0))
+ return true;
+ for (rank_type __r = 0; __r < __rank_ - 1; ++__r) {
+ if (__ext.extent(__r) == static_cast<index_type>(0))
+ return true;
+ }
+
+ index_type __prod = __stride_rm2;
+ for (rank_type __r = 0; __r < __rank_ - 1; ++__r) {
+ bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), std::addressof(__prod));
+ if (__overflowed)
+ return false;
+ }
+ return true;
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type __stride_rm2() const noexcept {
+ if constexpr (__rank_ <= 1)
+ return static_cast<index_type>(0);
+ if constexpr (__static_padding_stride != dynamic_extent)
+ return static_cast<index_type>(__static_padding_stride);
+ return __stride_rm2_.extent(0);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static consteval bool __static_padded_product_is_representable() {
+ if constexpr (__rank_ <= 1 || padding_value == dynamic_extent || extents_type::rank_dynamic() > 0)
+ return true;
+ for (rank_type __r = 0; __r < __rank_; ++__r) {
+ if (extents_type::static_extent(__r) == 0)
+ return true;
+ }
+ if constexpr (__static_padding_stride == dynamic_extent ||
+ !__mdspan_detail::__is_representable_as<index_type>(__static_padding_stride))
+ return false;
+ size_t __prod = __static_padding_stride;
+ for (rank_type __r = 0; __r < __rank_ - 1; ++__r) {
+ bool __overflowed = __builtin_mul_overflow(__prod, extents_type::static_extent(__r), std::addressof(__prod));
+ if (__overflowed)
+ return false;
+ }
+ return __mdspan_detail::__is_representable_as<index_type>(__prod);
+ }
+
+ static_assert(extents_type::rank_dynamic() != 0 || __index_space_size_is_representable(extents_type{}),
+ "layout_right_padded::mapping index space for static extents must be representable as index_type.");
+
+ static_assert(padding_value == dynamic_extent || __mdspan_detail::__is_representable_as<index_type>(padding_value),
+ "layout_right_padded::mapping padding_value must be representable as index_type.");
+
+ static_assert(__rank_ <= 1 || padding_value == dynamic_extent || __last_static_extent == dynamic_extent ||
+ (__mdspan_detail::__least_multiple_at_least_is_representable_as<size_t>(
+ padding_value, __last_static_extent) &&
+ __mdspan_detail::__least_multiple_at_least_is_representable_as<index_type>(
+ padding_value, __last_static_extent)),
+ "layout_right_padded::mapping padded stride for the last static extent must be representable as "
+ "size_t and index_type.");
+
+ static_assert(__static_padded_product_is_representable(),
+ "layout_right_padded::mapping required span size for static extents must be representable as size_t "
+ "and index_type.");
+
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : mapping(extents_type{}) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext) : __extents_(__ext) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __index_space_size_is_representable(__ext),
+ "layout_right_padded::mapping(extents): index space size must be representable as index_type.");
+
+ if constexpr (__rank_ > 1) {
+ index_type __stride_rm2 = 0;
+ if constexpr (padding_value == dynamic_extent) {
+ __stride_rm2 = __ext.extent(__rank_ - 1);
+ } else {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__least_multiple_at_least_is_representable_as<index_type>(
+ static_cast<index_type>(padding_value), __ext.extent(__rank_ - 1)),
+ "layout_right_padded::mapping(extents): padded stride must be representable as index_type.");
+ __stride_rm2 = __mdspan_detail::__least_multiple_at_least(
+ static_cast<index_type>(padding_value), __ext.extent(__rank_ - 1));
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __padded_product_is_representable(__ext, __stride_rm2),
+ "layout_right_padded::mapping(extents): required span size must be representable as index_type.");
+ }
+ if constexpr (__static_padding_stride == dynamic_extent)
+ __stride_rm2_ = __stride_rm2_type(__stride_rm2);
+ }
+ }
+
+ template <class _OtherIndexType>
+ requires is_convertible_v<_OtherIndexType, index_type> && is_nothrow_constructible_v<index_type, _OtherIndexType>
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, _OtherIndexType __pad) : __extents_(__ext) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__pad),
+ "layout_right_padded::mapping(extents, pad): pad must be representable as index_type.");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ static_cast<index_type>(__pad) > 0, "layout_right_padded::mapping(extents, pad): pad must be greater than 0.");
+
+ if constexpr (padding_value != dynamic_extent)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(padding_value == static_cast<index_type>(__pad),
+ "layout_right_padded::mapping(extents, pad): pad must equal padding_value.");
+
+ if constexpr (__rank_ > 1) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__least_multiple_at_least_is_representable_as<index_type>(
+ static_cast<index_type>(__pad), __ext.extent(__rank_ - 1)),
+ "layout_right_padded::mapping(extents, pad): padded stride must be representable as index_type.");
+
+ const index_type __stride_rm2 =
+ __mdspan_detail::__least_multiple_at_least(static_cast<index_type>(__pad), __ext.extent(__rank_ - 1));
+
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __padded_product_is_representable(__ext, __stride_rm2),
+ "layout_right_padded::mapping(extents, pad): required span size must be representable as index_type.");
+
+ if constexpr (__static_padding_stride == dynamic_extent)
+ __stride_rm2_ = __stride_rm2_type(__stride_rm2);
+ }
+ }
+
+ template <class _OtherExtents>
+ requires is_constructible_v<extents_type, _OtherExtents>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>)
+ mapping(const layout_right::mapping<_OtherExtents>& __other)
+ : mapping(extents_type(__other.extents())) {
+ static_assert(_OtherExtents::rank() <= 1 || __static_padding_stride == dynamic_extent ||
+ _OtherExtents::static_extent(_OtherExtents::rank() - 1) == dynamic_extent ||
+ __static_padding_stride == _OtherExtents::static_extent(_OtherExtents::rank() - 1));
+
+ if constexpr (__rank_ > 1 && padding_value != dynamic_extent) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(__rank_ - 2) ==
+ __mdspan_detail::__least_multiple_at_least(
+ static_cast<index_type>(padding_value),
+ static_cast<index_type>(__other.extents().extent(__rank_ - 1))),
+ "layout_right_padded::mapping from layout_right ctor: source stride must match the padded stride implied by "
+ "padding_value.");
+ }
+
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_right_padded::mapping from layout_right ctor: other.required_span_size() must be representable as "
+ "index_type.");
+ }
+
+ template <class _OtherExtents>
+ requires is_constructible_v<extents_type, _OtherExtents>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(!(__rank_ == 0 && is_convertible_v<_OtherExtents, extents_type>))
+ mapping(const layout_stride::mapping<_OtherExtents>& __other)
+ : __extents_(extents_type(__other.extents())) {
+ if constexpr (__rank_ > 1 && padding_value != dynamic_extent)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(__rank_ - 2) ==
+ __mdspan_detail::__least_multiple_at_least(
+ static_cast<index_type>(padding_value),
+ static_cast<index_type>(__other.extents().extent(__rank_ - 1))),
+ "layout_right_padded::mapping from layout_stride ctor: source stride must match the padded stride implied by "
+ "padding_value.");
+
+ if constexpr (__rank_ > 0)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(__rank_ - 1) == 1,
+ "layout_right_padded::mapping from layout_stride ctor: stride(rank() - 1) must equal 1.");
+
+ if constexpr (__rank_ > 2) {
+ using _Common = common_type_t<index_type, typename layout_stride::mapping<_OtherExtents>::index_type>;
+ _Common __expected = static_cast<_Common>(__other.stride(__rank_ - 2));
+ for (size_t __r = __rank_ - 2; __r-- > 0;) {
+ __expected *= static_cast<_Common>(__other.extents().extent(__r + 1));
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ static_cast<_Common>(__other.stride(__r)) == __expected,
+ "layout_right_padded::mapping from layout_stride ctor: strides are not "
+ "compatible with layout_right_padded.");
+ }
+ }
+
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_right_padded::mapping from layout_stride ctor: other.required_span_size() must be representable as "
+ "index_type.");
+
+ if constexpr (__rank_ > 1 && __static_padding_stride == dynamic_extent) {
+# if 0 // TODO
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.stride(__rank_ - 2)),
+ "layout_right_padded::mapping from layout_stride ctor: source padded stride must be representable as "
+ "index_type.");
+# endif
+ __stride_rm2_ = __stride_rm2_type(static_cast<index_type>(__other.stride(__rank_ - 2)));
+ }
+ }
+
+ template <class _LayoutRightPaddedMapping>
+ requires __mdspan_detail::__layout_right_padded_mapping_of<_LayoutRightPaddedMapping> &&
+ is_constructible_v<extents_type, typename _LayoutRightPaddedMapping::extents_type>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(
+ !is_convertible_v<typename _LayoutRightPaddedMapping::extents_type, extents_type> ||
+ (__rank_ > 1 && (padding_value != dynamic_extent || _LayoutRightPaddedMapping::padding_value == dynamic_extent)))
+ mapping(const _LayoutRightPaddedMapping& __other)
+ : __extents_(extents_type(__other.extents())) {
+ static_assert(
+ __rank_ <= 1 || padding_value == dynamic_extent || _LayoutRightPaddedMapping::padding_value == dynamic_extent ||
+ padding_value == _LayoutRightPaddedMapping::padding_value,
+ "layout_right_padded::mapping converting ctor: incompatible static padding values.");
+
+ if constexpr (__rank_ > 1 && padding_value != dynamic_extent)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(__rank_ - 2) ==
+ __mdspan_detail::__least_multiple_at_least(
+ static_cast<index_type>(padding_value),
+ static_cast<index_type>(__other.extents().extent(__rank_ - 1))),
+ "layout_right_padded::mapping from layout_right_padded ctor: source stride must match the padded stride "
+ "implied by padding_value.");
+
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_right_padded::mapping from layout_right_padded ctor: other.required_span_size() must be representable "
+ "as index_type.");
+
+ if constexpr (__rank_ > 1 && __static_padding_stride == dynamic_extent) {
+# if 0 // TODO
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.stride(__rank_ - 2)),
+ "layout_right_padded::mapping from layout_right_padded ctor: source padded stride must be representable as "
+ "index_type.");
+# endif
+ __stride_rm2_ = __stride_rm2_type(static_cast<index_type>(__other.stride(__rank_ - 2)));
+ }
+ }
+
+ template <class _LayoutLeftPaddedMapping>
+ requires(__mdspan_detail::__layout_left_padded_mapping_of<_LayoutLeftPaddedMapping> ||
+ __mdspan_detail::__layout_left_mapping_of<_LayoutLeftPaddedMapping>) &&
+ (__rank_ <= 1) && is_constructible_v<extents_type, typename _LayoutLeftPaddedMapping::extents_type>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(
+ !is_convertible_v<typename _LayoutLeftPaddedMapping::extents_type, extents_type>)
+ mapping(const _LayoutLeftPaddedMapping& __other) noexcept
+ : __extents_(extents_type(__other.extents())) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_right_padded::mapping converting ctor: other.required_span_size() must be representable as "
+ "index_type.");
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr array<index_type, __rank_> strides() const noexcept {
+ return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ return array<index_type, __rank_>{stride(_Pos)...};
+ }(make_index_sequence<__rank_>());
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept {
+ return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ if (((__extents_.extent(_Pos) == static_cast<index_type>(0)) || ...))
+ return static_cast<index_type>(0);
+
+ return static_cast<index_type>(
+ (*this)(static_cast<index_type>(__extents_.extent(_Pos) - static_cast<index_type>(1))...) +
+ static_cast<index_type>(1));
+ }(make_index_sequence<__rank_>());
+ }
+
+ template <class... _Indices>
+ requires(sizeof...(_Indices) == __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_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...),
+ "layout_right_padded::mapping: out of bounds indexing.");
+ return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ return ((static_cast<index_type>(__idx) * stride(_Pos)) + ... + static_cast<index_type>(0));
+ }(make_index_sequence<sizeof...(_Indices)>());
+ }
+
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; }
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept {
+ if constexpr (__rank_ <= 1)
+ return true;
+ if constexpr (__last_static_extent == dynamic_extent || __static_padding_stride == dynamic_extent)
+ return false;
+ return __last_static_extent == __static_padding_stride;
+ }
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; }
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const noexcept {
+ if constexpr (__rank_ <= 1)
+ return true;
+ return extents().extent(__rank_ - 1) == stride(__rank_ - 2);
+ }
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__r < __rank_, "layout_right_padded::mapping::stride(): invalid rank index.");
+
+ if constexpr (__rank_ == 0)
+ return static_cast<index_type>(1);
+
+ if (__r == __rank_ - 1)
+ return static_cast<index_type>(1);
+
+ if constexpr (__rank_ > 1) {
+ if (__r == __rank_ - 2)
+ return __stride_rm2();
+
+ index_type __stride = __stride_rm2();
+ for (rank_type __i = __rank_ - 2; __i > __r; --__i)
+ __stride *= __extents_.extent(__i);
+ return __stride;
+ }
+
+ return static_cast<index_type>(1);
+ }
+
+ template <class _LayoutRightPaddedMapping>
+ requires __mdspan_detail::__layout_right_padded_mapping_of<_LayoutRightPaddedMapping> &&
+ (_LayoutRightPaddedMapping::extents_type::rank() == __rank_)
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool
+ operator==(const mapping& __x, const _LayoutRightPaddedMapping& __y) noexcept {
+ return __x.extents() == __y.extents() && (__rank_ < 2 || __x.stride(__rank_ - 2) == __y.stride(__rank_ - 2));
+ }
+
+private:
+ _LIBCPP_NO_UNIQUE_ADDRESS __stride_rm2_type __stride_rm2_{};
+ _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{};
+};
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MDSPAN_LAYOUT_RIGHT_PADDED_H
diff --git a/libcxx/include/__mdspan/layout_stride.h b/libcxx/include/__mdspan/layout_stride.h
index eb22475756fde..769cc6c478cbe 100644
--- a/libcxx/include/__mdspan/layout_stride.h
+++ b/libcxx/include/__mdspan/layout_stride.h
@@ -21,6 +21,7 @@
#include <__concepts/same_as.h>
#include <__config>
#include <__fwd/mdspan.h>
+#include <__mdspan/concepts.h>
#include <__mdspan/extents.h>
#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
@@ -47,24 +48,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER >= 23
-namespace __mdspan_detail {
-template <class _Layout, class _Mapping>
-constexpr bool __is_mapping_of =
- is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, _Mapping>;
-
-template <class _Mapping>
-concept __layout_mapping_alike = requires {
- requires __is_mapping_of<typename _Mapping::layout_type, _Mapping>;
- requires __is_extents_v<typename _Mapping::extents_type>;
- { _Mapping::is_always_strided() } -> same_as<bool>;
- { _Mapping::is_always_exhaustive() } -> same_as<bool>;
- { _Mapping::is_always_unique() } -> same_as<bool>;
- bool_constant<_Mapping::is_always_strided()>::value;
- bool_constant<_Mapping::is_always_exhaustive()>::value;
- bool_constant<_Mapping::is_always_unique()>::value;
-};
-} // namespace __mdspan_detail
-
template <class _Extents>
class layout_stride::mapping {
public:
diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan
index 32468a128dc9a..0527524d6211b 100644
--- a/libcxx/include/mdspan
+++ b/libcxx/include/mdspan
@@ -255,6 +255,173 @@ namespace std {
};
}
+// layout_left_padded synopsis
+
+namespace std {
+ template<size_t PaddingValue>
+ template<class Extents>
+ class layout_left_padded<PaddingValue>::mapping {
+ public:
+ static constexpr size_t padding_value = PaddingValue;
+
+ using extents_type = Extents;
+ using index_type = extents_type::index_type;
+ using size_type = extents_type::size_type;
+ using rank_type = extents_type::rank_type;
+ using layout_type = layout_left_padded<PaddingValue>;
+
+ private:
+ static constexpr size_t rank_ = extents_type::rank(); // exposition only
+ static constexpr size_t first-static-extent = // exposition only
+ extents_type::static_extent(0);
+
+ // [mdspan.layout.leftpad.expo], exposition-only members
+ static constexpr size_t static-padding-stride = see below; // exposition only
+
+ public:
+ // [mdspan.layout.leftpad.cons], constructors
+ constexpr mapping() noexcept : mapping(extents_type{}) {}
+ constexpr mapping(const mapping&) noexcept = default;
+ constexpr mapping(const extents_type&);
+ template<class OtherIndexType>
+ constexpr mapping(const extents_type&, OtherIndexType);
+ template<class OtherExtents>
+ constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
+ mapping(const layout_left::mapping<OtherExtents>&);
+ template<class OtherExtents>
+ constexpr explicit(see below)
+ mapping(const layout_stride::mapping<OtherExtents>&);
+ template<class LayoutLeftPaddedMapping>
+ constexpr explicit(see below)
+ mapping(const LayoutLeftPaddedMapping&);
+ template<class LayoutRightPaddedMapping>
+ constexpr explicit(see below)
+ mapping(const LayoutRightPaddedMapping&) noexcept;
+
+ constexpr mapping& operator=(const mapping&) noexcept = default;
+
+ // [mdspan.layout.leftpad.obs], observers
+ constexpr const extents_type& extents() const noexcept { return extents_; }
+ constexpr array<index_type, rank_> strides() const noexcept;
+
+ constexpr index_type required_span_size() const noexcept;
+ template<class... Indices>
+ constexpr index_type operator()(Indices...) const noexcept;
+
+ static constexpr bool is_always_unique() noexcept { return true; }
+ static constexpr bool is_always_exhaustive() noexcept;
+ static constexpr bool is_always_strided() noexcept { return true; }
+
+ static constexpr bool is_unique() noexcept { return true; }
+ constexpr bool is_exhaustive() const noexcept;
+ static constexpr bool is_strided() noexcept { return true; }
+
+ constexpr index_type stride(rank_type) const noexcept;
+
+ template<class LayoutLeftPaddedMapping>
+ friend constexpr bool operator==(const mapping&, const LayoutLeftPaddedMapping&) noexcept;
+
+ private:
+ // [mdspan.layout.leftpad.expo], exposition-only members
+ index_type stride-1 = static-padding-stride; // exposition only
+ extents_type extents_{}; // exposition only
+ // [mdspan.sub.map], submdspan mapping specialization
+ template<class... SliceSpecifiers>
+ constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const // exposition only
+ -> see below;
+
+ template<class... SliceSpecifiers>
+ friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) {
+ return src.submdspan-mapping-impl(slices...);
+ }
+ };
+}
+
+// layout_right_padded synopsis
+
+namespace std {
+ template<size_t PaddingValue>
+ template<class Extents>
+ class layout_right_padded<PaddingValue>::mapping {
+ public:
+ static constexpr size_t padding_value = PaddingValue;
+
+ using extents_type = Extents;
+ using index_type = extents_type::index_type;
+ using size_type = extents_type::size_type;
+ using rank_type = extents_type::rank_type;
+ using layout_type = layout_right_padded<PaddingValue>;
+
+ private:
+ static constexpr size_t rank_ = extents_type::rank(); // exposition only
+ static constexpr size_t last-static-extent = // exposition only
+ extents_type::static_extent(rank_ - 1);
+
+ // [mdspan.layout.rightpad.expo], exposition-only members
+ static constexpr size_t static-padding-stride = see below; // exposition only
+
+ public:
+ // [mdspan.layout.rightpad.cons], constructors
+ constexpr mapping() noexcept : mapping(extents_type{}) {}
+ constexpr mapping(const mapping&) noexcept = default;
+ constexpr mapping(const extents_type&);
+ template<class OtherIndexType>
+ constexpr mapping(const extents_type&, OtherIndexType);
+
+ template<class OtherExtents>
+ constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
+ mapping(const layout_right::mapping<OtherExtents>&);
+ template<class OtherExtents>
+ constexpr explicit(see below)
+ mapping(const layout_stride::mapping<OtherExtents>&);
+ template<class LayoutRightPaddedMapping>
+ constexpr explicit(see below)
+ mapping(const LayoutRightPaddedMapping&);
+ template<class LayoutLeftPaddedMapping>
+ constexpr explicit(see below)
+ mapping(const LayoutLeftPaddedMapping&) noexcept;
+
+ constexpr mapping& operator=(const mapping&) noexcept = default;
+
+ // [mdspan.layout.rightpad.obs], observers
+ constexpr const extents_type& extents() const noexcept { return extents_; }
+ constexpr array<index_type, rank_> strides() const noexcept;
+
+ constexpr index_type required_span_size() const noexcept;
+
+ template<class... Indices>
+ constexpr index_type operator()(Indices...) const noexcept;
+
+ static constexpr bool is_always_unique() noexcept { return true; }
+ static constexpr bool is_always_exhaustive() noexcept;
+ static constexpr bool is_always_strided() noexcept { return true; }
+
+ static constexpr bool is_unique() noexcept { return true; }
+ constexpr bool is_exhaustive() const noexcept;
+ static constexpr bool is_strided() noexcept { return true; }
+
+ constexpr index_type stride(rank_type) const noexcept;
+
+ template<class LayoutRightPaddedMapping>
+ friend constexpr bool operator==(const mapping&, const LayoutRightPaddedMapping&) noexcept;
+
+ private:
+ // [mdspan.layout.rightpad.expo], exposition-only members
+ index_type stride-rm2 = static-padding-stride; // exposition only
+ extents_type extents_{}; // exposition only
+
+ // [mdspan.sub.map], submdspan mapping specialization
+ template<class... SliceSpecifiers>
+ constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const // exposition only
+ -> see below;
+
+ template<class... SliceSpecifiers>
+ friend constexpr auto submdspan_mapping(const mapping& src, SliceSpecifiers... slices) {
+ return src.submdspan-mapping-impl(slices...);
+ }
+ };
+}
+
// default_accessor synopsis
namespace std {
@@ -458,6 +625,10 @@ namespace std {
# include <__mdspan/layout_right.h>
# include <__mdspan/layout_stride.h>
# include <__mdspan/mdspan.h>
+# if _LIBCPP_STD_VER >= 26
+# include <__mdspan/layout_left_padded.h>
+# include <__mdspan/layout_right_padded.h>
+# endif
# endif
# include <version>
diff --git a/libcxx/modules/std/mdspan.inc b/libcxx/modules/std/mdspan.inc
index c8cc78badb7d5..a9dea70b89a7a 100644
--- a/libcxx/modules/std/mdspan.inc
+++ b/libcxx/modules/std/mdspan.inc
@@ -25,6 +25,11 @@ export namespace std {
using std::layout_right;
using std::layout_stride;
+# if _LIBCPP_STD_VER >= 26
+ using std::layout_left_padded;
+ using std::layout_right_padded;
+# endif // _LIBCPP_STD_VER >= 26
+
// [mdspan.accessor.default], class template default_accessor
using std::default_accessor;
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/comparison.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/comparison.pass.cpp
new file mode 100644
index 0000000000000..ff85c44dcf61d
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/comparison.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutLeftPaddedMapping>
+// friend constexpr bool operator==(const mapping&, const LayoutLeftPaddedMapping&) noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class LeftMapping, class RightMapping>
+constexpr void test_comparison(bool equal, const LeftMapping& left, const RightMapping& right) {
+ ASSERT_NOEXCEPT(left == right);
+ assert((left == right) == equal);
+ assert((left != right) == !equal);
+}
+
+struct DoesNotMatch {
+ constexpr bool does_not_match() const { return true; }
+};
+
+constexpr DoesNotMatch compare_layout_mappings(...) { return {}; }
+
+template <class LeftMapping, class RightMapping>
+constexpr auto compare_layout_mappings(const LeftMapping& left, const RightMapping& right) -> decltype(left == right) {
+ (void)left;
+ (void)right;
+ return true;
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using rank0_left = std::layout_left_padded<0>::mapping<std::extents<size_t>>;
+ using rank0_right = std::layout_left_padded<4>::mapping<std::extents<size_t>>;
+ test_comparison(true, rank0_left(), rank0_right());
+ }
+
+ {
+ using rank1_fixed = std::layout_left_padded<4>::mapping<std::extents<size_t, D>>;
+ using rank1_dynamic = std::layout_left_padded<D>::mapping<std::extents<size_t, 5>>;
+ test_comparison(true, rank1_fixed(std::extents<size_t, D>(5)), rank1_dynamic(std::extents<size_t, 5>(), 99));
+ test_comparison(false, rank1_fixed(std::extents<size_t, D>(3)), rank1_dynamic(std::extents<size_t, 5>(), 99));
+ }
+
+ {
+ using fixed_mapping = std::layout_left_padded<4>::mapping<std::extents<size_t, 3, 7>>;
+ using dynamic_mapping = std::layout_left_padded<D>::mapping<std::extents<size_t, 3, 7>>;
+ test_comparison(true, fixed_mapping(), dynamic_mapping(std::extents<size_t, 3, 7>(), 4));
+ test_comparison(false, fixed_mapping(), dynamic_mapping(std::extents<size_t, 3, 7>(), 8));
+ test_comparison(false, fixed_mapping(), std::layout_left_padded<4>::mapping<std::extents<size_t, 3, 4>>());
+ }
+
+ {
+ using dynamic_mapping = std::layout_left_padded<D>::mapping<std::extents<size_t, D, 3>>;
+ test_comparison(
+ true, dynamic_mapping(std::extents<size_t, D, 3>(5), 5), dynamic_mapping(std::extents<size_t, D, 3>(5), 5));
+ test_comparison(
+ false, dynamic_mapping(std::extents<size_t, D, 3>(5), 5), dynamic_mapping(std::extents<size_t, D, 3>(5), 8));
+ }
+
+ static_assert(compare_layout_mappings(
+ std::layout_left_padded<4>::mapping<std::extents<int, D>>(std::extents<int, D>(5)),
+ std::layout_left_padded<4>::mapping<std::extents<int, 5>>()));
+ static_assert(compare_layout_mappings(std::layout_left_padded<4>::mapping<std::extents<int>>(),
+ std::layout_left_padded<4>::mapping<std::extents<int, 1>>())
+ .does_not_match());
+ static_assert(compare_layout_mappings(std::layout_left_padded<4>::mapping<std::extents<int, 5, 7>>(),
+ std::layout_left_padded<4>::mapping<std::extents<int, 5>>())
+ .does_not_match());
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.copy.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.copy.pass.cpp
new file mode 100644
index 0000000000000..c7a2f622aef9e
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.copy.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr mapping(const mapping&) noexcept = default;
+// constexpr mapping& operator=(const mapping&) noexcept = default;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_copy_semantics(const Mapping& source) {
+ ASSERT_NOEXCEPT(Mapping(source));
+ static_assert(noexcept(std::declval<Mapping&>() = source));
+
+ Mapping copy(source);
+ assert(copy == source);
+
+ Mapping assigned;
+ assigned = source;
+ assert(assigned == source);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_copy_semantics(std::layout_left_padded<4>::mapping<std::extents<int32_t>>());
+ test_copy_semantics(std::layout_left_padded<4>::mapping<std::extents<uint32_t, 5, 7>>(std::extents<int32_t, 5, 7>()));
+ test_copy_semantics(std::layout_left_padded<4>::mapping<std::extents<int8_t, D>>(std::extents<int8_t, D>(5)));
+ test_copy_semantics(std::layout_left_padded<4>::mapping<std::extents<uint8_t, D, 7>>(std::extents<uint8_t, D, 7>(5)));
+
+ test_copy_semantics(std::layout_left_padded<D>::mapping<std::extents<int32_t>>());
+ test_copy_semantics(std::layout_left_padded<D>::mapping<std::extents<uint32_t, 5, 7>>(std::extents<int32_t, 5, 7>()));
+ test_copy_semantics(std::layout_left_padded<D>::mapping<std::extents<int8_t, D>>(std::extents<int8_t, D>(5), 5));
+ test_copy_semantics(std::layout_left_padded<D>::mapping<std::extents<uint8_t, D, 7>>(std::extents<uint8_t, D, 7>(5)));
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.default.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..a36e548c72d0d
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.default.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr mapping() noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_construction() {
+ using Extents = typename Mapping::extents_type;
+
+ ASSERT_NOEXCEPT(Mapping{});
+ Mapping mapping;
+ Mapping extents_mapping{Extents()};
+
+ assert(mapping == extents_mapping);
+ assert(mapping.extents() == Extents());
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_construction<std::layout_left_padded<4>::mapping<std::extents<int32_t>>>();
+ test_construction<std::layout_left_padded<4>::mapping<std::extents<int32_t, 1>>>();
+ test_construction<std::layout_left_padded<4>::mapping<std::extents<uint32_t, 2, 3>>>();
+ test_construction<std::layout_left_padded<4>::mapping<std::extents<uint32_t, 4, 5, D>>>();
+
+ test_construction<std::layout_left_padded<D>::mapping<std::extents<int32_t>>>();
+ test_construction<std::layout_left_padded<D>::mapping<std::extents<int32_t, 1>>>();
+ test_construction<std::layout_left_padded<D>::mapping<std::extents<uint32_t, 2, 3>>>();
+ test_construction<std::layout_left_padded<D>::mapping<std::extents<uint32_t, 4, 5, D>>>();
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.extents.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.extents.pass.cpp
new file mode 100644
index 0000000000000..7bc4ffae3c25c
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.extents.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr mapping(const extents_type&);
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+template <size_t PaddingValue, class Extents>
+constexpr void
+test_construction(Extents extents, std::array<typename Extents::index_type, Extents::rank()> expected_strides) {
+ using Mapping = typename std::layout_left_padded<PaddingValue>::template mapping<Extents>;
+ static_assert(Mapping::padding_value == PaddingValue);
+
+ Mapping mapping(extents);
+ assert(mapping.extents() == extents);
+
+ for (typename Mapping::rank_type r = 0; r < Mapping::extents_type::rank(); ++r)
+ assert(mapping.stride(r) == expected_strides[r]);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_construction<4>(std::extents<int32_t>(), {});
+ test_construction<4>(std::extents<int32_t, 5>(), {1});
+ test_construction<4>(std::extents<uint32_t, D>(7), {1});
+ test_construction<4>(std::extents<uint32_t, 5, 7>(), {1, 8});
+ test_construction<4>(std::extents<uint64_t, D, 2, 3>(6), {1, 8, 16});
+ test_construction<D>(std::extents<int32_t>(), {});
+ test_construction<D>(std::extents<int32_t, 5>(), {1});
+ test_construction<D>(std::extents<uint32_t, D>(7), {1});
+ test_construction<D>(std::extents<uint32_t, 0, 7>(), {1, 0});
+ test_construction<D>(std::extents<uint64_t, 5, 7>(), {1, 5});
+ test_construction<D>(std::extents<uint64_t, D, 7>(5), {1, 5});
+ test_construction<0>(std::extents<uint32_t, D, 13>(7), {1, 7});
+ test_construction<0>(std::extents<uint32_t, 0, 7>(), {1, 0});
+ //clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_left.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_left.pass.cpp
new file mode 100644
index 0000000000000..c9abe94b560d1
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_left.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class OtherExtents>
+// constexpr mapping(const layout_left::mapping<OtherExtents>& other);
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_left::mapping<std::extents<size_t>>;
+ using Dst = std::layout_left_padded<4>::mapping<std::extents<size_t>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left::mapping<std::extents<size_t, 3>>;
+ using Dst = std::layout_left_padded<4>::mapping<std::extents<size_t, D>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left::mapping<std::extents<size_t, 4, 7>>;
+ using DstStatic = std::layout_left_padded<4>::mapping<std::extents<size_t, 4, 7>>;
+ using DstDynamic = std::layout_left_padded<D>::mapping<std::extents<size_t, D, 7>>;
+ Src source;
+ test_conversion<true, DstStatic>(source);
+ test_conversion<true, DstDynamic>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_right.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_right.pass.cpp
new file mode 100644
index 0000000000000..0e60913185d0d
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_right.pass.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutRightMapping>
+// constexpr mapping(const LayoutRightMapping& other) noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ ASSERT_NOEXCEPT(Dst(source));
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_right::mapping<std::extents<size_t>>;
+ using Dst = std::layout_left_padded<D>::mapping<std::extents<size_t>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right::mapping<std::extents<size_t, 5>>;
+ using Dst = std::layout_left_padded<4>::mapping<std::extents<size_t, D>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_right_padded.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_right_padded.pass.cpp
new file mode 100644
index 0000000000000..d3c017252db92
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_right_padded.pass.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutRightPaddedMapping>
+// constexpr mapping(const LayoutRightPaddedMapping& other) noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ ASSERT_NOEXCEPT(Dst(source));
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_right_padded<4>::mapping<std::extents<size_t>>;
+ using Dst = std::layout_left_padded<D>::mapping<std::extents<size_t>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right_padded<4>::mapping<std::extents<size_t, 5>>;
+ using Dst = std::layout_left_padded<4>::mapping<std::extents<size_t, D>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_stride.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_stride.pass.cpp
new file mode 100644
index 0000000000000..cceb073556761
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.layout_stride.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class OtherExtents>
+// constexpr mapping(const layout_stride::mapping<OtherExtents>& other);
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_stride::mapping<std::extents<size_t>>;
+ using Dst = std::layout_left_padded<D>::mapping<std::extents<size_t>>;
+ Src source(std::extents<size_t>(), std::array<size_t, 0>{});
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_stride::mapping<std::extents<size_t, 3>>;
+ using Dst = std::layout_left_padded<4>::mapping<std::extents<size_t, 3>>;
+ Src source(std::extents<size_t, 3>(), std::array<size_t, 1>{1});
+ test_conversion<false, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_stride::mapping<std::extents<size_t, 5, 7>>;
+ using Dst = std::layout_left_padded<4>::mapping<std::extents<size_t, D, 7>>;
+ Src source(std::extents<size_t, 5, 7>(), std::array<size_t, 2>{1, 8});
+ test_conversion<false, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.mapping.assert.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.mapping.assert.pass.cpp
new file mode 100644
index 0000000000000..32de4a611da94
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.mapping.assert.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+// UNSUPPORTED: libcpp-hardening-mode=none
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <mdspan>
+
+// constexpr mapping(const layout_stride::mapping<OtherExtents>& other);
+// constexpr mapping(const LayoutLeftPaddedMapping& other);
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <mdspan>
+
+#include "check_assertion.h"
+
+int main() {
+#if 0
+ {
+ using Src = std::layout_left_padded<std::dynamic_extent>::mapping<std::extents<uint32_t, 1, 0>>;
+ using Dst = std::layout_left_padded<std::dynamic_extent>::mapping<std::extents<uint8_t, 1, 0>>;
+
+ Src src(std::extents<uint32_t, 1, 0>(), 256);
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ Dst(src),
+ "layout_left_padded::mapping from layout_left_padded ctor: source padded stride must be "
+ "representable as index_type.");
+ }
+
+ {
+ using Src = std::layout_stride::mapping<std::extents<uint32_t, 1, 0>>;
+ using Dst = std::layout_left_padded<std::dynamic_extent>::mapping<std::extents<uint8_t, 1, 0>>;
+
+ Src src(std::extents<uint32_t, 1, 0>(), std::array<uint32_t, 2>{1, 256});
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ Dst(src),
+ "layout_left_padded::mapping from layout_stride ctor: source padded stride must be "
+ "representable as index_type.");
+ }
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.mapping.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.mapping.pass.cpp
new file mode 100644
index 0000000000000..e020b7abdcffe
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.mapping.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutLeftPaddedMapping>
+// constexpr mapping(const LayoutLeftPaddedMapping& other);
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+#if 0 // TODO
+ {
+ using Src = std::layout_left_padded<4>::mapping<std::extents<size_t, 4, 7>>;
+ using Dst = std::layout_left_padded<4>::mapping<std::extents<size_t, D, 7>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+#endif
+
+ {
+ using Src = std::layout_left_padded<4>::mapping<std::extents<size_t, 3>>;
+ using Dst = std::layout_left_padded<D>::mapping<std::extents<size_t, 3>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left_padded<4>::mapping<std::extents<size_t, 5, 7>>;
+ using Dst = std::layout_left_padded<D>::mapping<std::extents<size_t, D, 7>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left_padded<D>::mapping<std::extents<size_t, D, 7>>;
+ using Dst = std::layout_left_padded<4>::mapping<std::extents<size_t, 4, 7>>;
+ Src source(std::extents<size_t, D, 7>(4), 4);
+ test_conversion<false, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.padding.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.padding.pass.cpp
new file mode 100644
index 0000000000000..9dc2cd19453c7
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.padding.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr mapping(const extents_type& e, index_type padding_stride);
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+template <class Extents, class Padding>
+constexpr void test_construction(
+ Extents extents, Padding padding, std::array<typename Extents::index_type, Extents::rank()> expected_strides) {
+ using Mapping = std::layout_left_padded<std::dynamic_extent>::mapping<Extents>;
+ static_assert(Mapping::padding_value == std::dynamic_extent);
+
+ Mapping mapping(extents, padding);
+ assert(mapping.extents() == extents);
+
+ for (typename Mapping::rank_type r = 0; r < Mapping::extents_type::rank(); ++r)
+ assert(mapping.stride(r) == expected_strides[r]);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_construction(std::extents<unsigned>(), 3, {});
+ test_construction(std::extents<unsigned, D>(7), 1337, {1});
+ test_construction(std::extents<unsigned, D, 7>(5), 6, {1, 6});
+ test_construction(std::extents<unsigned, 5, 7>(), 4, {1, 8});
+ test_construction(std::extents<unsigned, D, 7, D>(7, 3), 4, {1, 8, 56});
+ test_construction(std::extents<unsigned, 0, 7>(), 4, {1, 0});
+ // clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/extents.verify.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/extents.verify.cpp
new file mode 100644
index 0000000000000..03e86d61050f9
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/extents.verify.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class Extents>
+// class layout_left_padded::mapping;
+
+#include <mdspan>
+
+void not_extents() {
+ // expected-error-re@*:* {{static assertion failed {{.*}}layout_left_padded::mapping template argument must be a specialization of extents}}
+ [[maybe_unused]] std::layout_left_padded<4>::mapping<void> mapping;
+}
+
+void index_space_representable() {
+ // expected-error@*:* {{layout_left_padded::mapping index space for static extents must be representable as index_type.}}
+ [[maybe_unused]] std::layout_left_padded<4>::mapping<std::extents<signed char, 20, 20>> mapping;
+}
+
+void padding_stride_representable() {
+ // expected-error@*:* {{layout_left_padded::mapping padded stride for the first static extent must be representable as size_t and index_type.}}
+ [[maybe_unused]] std::layout_left_padded<4>::mapping<std::extents<signed char, 127, 1>> mapping;
+}
+
+void padded_product_representable() {
+ // expected-error@*:* {{layout_left_padded::mapping required span size for static extents must be representable as size_t and index_type.}}
+ [[maybe_unused]] std::layout_left_padded<64>::mapping<std::extents<signed char, 63, 2>> mapping;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/index_operator.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/index_operator.pass.cpp
new file mode 100644
index 0000000000000..ecbf147784d6b
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/index_operator.pass.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class... Indices>
+// constexpr index_type operator()(Indices...) const noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../ConvertibleToIntegral.h"
+
+template <class Mapping, class... Indices>
+concept operator_constraints = requires(Mapping mapping, Indices... idxs) {
+ { std::is_same_v<decltype(mapping(idxs...)), typename Mapping::index_type> };
+};
+
+template <class Mapping, class... Indices>
+ requires(operator_constraints<Mapping, Indices...>)
+constexpr bool check_operator_constraints(Mapping mapping, Indices... idxs) {
+ (void)mapping(idxs...);
+ return true;
+}
+
+template <class Mapping, class... Indices>
+constexpr bool check_operator_constraints(Mapping, Indices...) {
+ return false;
+}
+
+template <class Mapping, class... Args>
+constexpr void iterate_left_padded(Mapping mapping, typename Mapping::index_type expected, Args... args) {
+ constexpr int r = static_cast<int>(Mapping::extents_type::rank()) - 1 - static_cast<int>(sizeof...(Args));
+ if constexpr (-1 == r) {
+ ASSERT_NOEXCEPT(mapping(args...));
+ assert(expected == mapping(args...));
+ } else {
+ for (typename Mapping::index_type i = 0; i < mapping.extents().extent(r); ++i)
+ iterate_left_padded(
+ mapping, static_cast<typename Mapping::index_type>(expected + i * mapping.stride(r)), i, args...);
+ }
+}
+
+template <class Extents, size_t PaddingValue, class... Args>
+constexpr void test_iteration(Args... args) {
+ using Mapping = typename std::layout_left_padded<PaddingValue>::template mapping<Extents>;
+ Mapping mapping(Extents(args...));
+ iterate_left_padded(mapping, typename Extents::index_type(0));
+}
+
+template <class Mapping>
+constexpr void test_iteration(Mapping mapping) {
+ iterate_left_padded(mapping, typename Mapping::index_type(0));
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_iteration<std::extents<int>, 4>();
+ test_iteration<std::extents<unsigned, 7>, 4>();
+ test_iteration<std::extents<unsigned, 5, 7>, 4>();
+ test_iteration<std::extents<signed char, D, 2, 3>, 4>(3);
+
+ test_iteration<std::extents<int>, D>();
+ test_iteration<std::extents<unsigned, D>, D>(7);
+ test_iteration(std::layout_left_padded<D>::mapping<std::extents<unsigned, 5, 7>>(std::extents<unsigned, 5, 7>(), 6));
+ test_iteration(
+ std::layout_left_padded<D>::mapping<std::extents<unsigned, D, 2, 3>>(std::extents<unsigned, D, 2, 3>(3), 4));
+
+ // Check operator constraint for number of arguments
+ static_assert(check_operator_constraints(
+ std::layout_left_padded<D>::mapping<std::extents<int, D>>(std::extents<int, D>(1), 1), 0));
+ static_assert(!check_operator_constraints(
+ std::layout_left_padded<D>::mapping<std::extents<int, D>>(std::extents<int, D>(1), 1), 0, 0));
+
+ // Check operator constraint for convertibility of arguments to index_type
+ static_assert(check_operator_constraints(
+ std::layout_left_padded<D>::mapping<std::extents<int, D>>(std::extents<int, D>(1), 1), IntType(0)));
+ static_assert(!check_operator_constraints(
+ std::layout_left_padded<D>::mapping<std::extents<unsigned, D>>(std::extents<unsigned, D>(1), 1), IntType(0)));
+
+ // Check operator constraint for no-throw-constructibility of index_type from arguments
+ static_assert(!check_operator_constraints(
+ std::layout_left_padded<D>::mapping<std::extents<unsigned char, D>>(std::extents<unsigned char, D>(1), 1),
+ IntType(0)));
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/properties.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/properties.pass.cpp
new file mode 100644
index 0000000000000..b77dcf99c4794
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/properties.pass.cpp
@@ -0,0 +1,88 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// namespace std {
+// template<class Extents>
+// class layout_left_padded::mapping {
+// ...
+// static constexpr bool is_always_unique() noexcept;
+// static constexpr bool is_always_exhaustive() noexcept;
+// static constexpr bool is_always_strided() noexcept;
+// static constexpr bool is_unique() noexcept;
+// constexpr bool is_exhaustive() const noexcept;
+// static constexpr bool is_strided() noexcept;
+// };
+// }
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_properties(const Mapping& mapping, bool exhaustive, bool always_exhaustive) {
+ const Mapping const_mapping = mapping;
+
+ assert(Mapping::is_unique());
+ assert(mapping.is_unique());
+ assert(const_mapping.is_unique());
+
+ assert(mapping.is_exhaustive() == exhaustive);
+ assert(const_mapping.is_exhaustive() == exhaustive);
+
+ assert(Mapping::is_strided());
+ assert(mapping.is_strided());
+ assert(const_mapping.is_strided());
+
+ assert(Mapping::is_always_unique());
+ assert(Mapping::is_always_exhaustive() == always_exhaustive);
+ assert(Mapping::is_always_strided());
+
+ ASSERT_NOEXCEPT(std::declval<Mapping>().is_unique());
+ ASSERT_NOEXCEPT(std::declval<Mapping>().is_exhaustive());
+ ASSERT_NOEXCEPT(std::declval<Mapping>().is_strided());
+ ASSERT_NOEXCEPT(Mapping::is_always_unique());
+ ASSERT_NOEXCEPT(Mapping::is_always_exhaustive());
+ ASSERT_NOEXCEPT(Mapping::is_always_strided());
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<int32_t>>(), true, true);
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<int32_t, 5>>(), true, true);
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<uint32_t, 3, 4>>(), false, false);
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<uint32_t, 4, 6>>(), true, true);
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<int32_t, D, 6>>(
+ std::extents<int32_t, D, 6>(7)), false, false);
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<int32_t, D, 6>>(
+ std::extents<int32_t, D, 6>(8)), true, false);
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<uint32_t>>(), true, true);
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<uint32_t, 0, 6>>(), true, true);
+ test_properties(std::layout_left_padded<4>::mapping<std::extents<uint32_t, 15, 0>>(), false, false);
+
+ test_properties(std::layout_left_padded<D>::mapping<std::extents<int32_t, 4, 6>>(
+ std::extents<int32_t, 4, 6>(), 4), true, false);
+ test_properties(std::layout_left_padded<D>::mapping<std::extents<int32_t, 6, 6>>(
+ std::extents<int32_t, 6, 6>(), 4), false, false);
+ // clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/required_span_size.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/required_span_size.pass.cpp
new file mode 100644
index 0000000000000..8306c7bfd7e7a
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/required_span_size.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr index_type required_span_size() const noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_required_span_size(const Mapping& mapping, typename Mapping::index_type expected_size) {
+ ASSERT_NOEXCEPT(mapping.required_span_size());
+ assert(mapping.required_span_size() == expected_size);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_required_span_size(std::layout_left_padded<4>::mapping<std::extents<int32_t>>(), 1);
+ test_required_span_size(std::layout_left_padded<4>::mapping<std::extents<int32_t, D>>(std::extents<int32_t, D>(0)), 0);
+ test_required_span_size(std::layout_left_padded<4>::mapping<std::extents<uint32_t, D>>(std::extents<uint32_t, D>(7)), 7);
+ test_required_span_size(std::layout_left_padded<4>::mapping<std::extents<uint32_t, 5, 7>>(), 53);
+ test_required_span_size(std::layout_left_padded<4>::mapping<std::extents<int64_t, D, 2, 3>>(std::extents<int64_t, D, 2, 3>(7)), 47);
+ test_required_span_size(std::layout_left_padded<4>::mapping<std::extents<int64_t, 15, 0>>(), 0);
+
+ test_required_span_size(std::layout_left_padded<D>::mapping<std::extents<int32_t>>(), 1);
+ test_required_span_size(std::layout_left_padded<D>::mapping<std::extents<int32_t, D>>(std::extents<int32_t, D>(0)), 0);
+ test_required_span_size(std::layout_left_padded<D>::mapping<std::extents<uint32_t, D>>(std::extents<uint32_t, D>(7)), 7);
+ test_required_span_size(std::layout_left_padded<D>::mapping<std::extents<uint32_t, 5, 7>>(), 35);
+ test_required_span_size(std::layout_left_padded<D>::mapping<std::extents<int64_t, 5, 7>>(std::extents<int64_t, 5, 7>(), 6), 41);
+ test_required_span_size(std::layout_left_padded<D>::mapping<std::extents<int64_t, 0, 7>>(), 0);
+ // clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/static_requirements.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/static_requirements.pass.cpp
new file mode 100644
index 0000000000000..82a9bb90e50f8
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/static_requirements.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+template <class Mapping, size_t... Indices>
+void test_mapping_requirements(std::index_sequence<Indices...>) {
+ using Extents = Mapping::extents_type;
+
+ LIBCPP_STATIC_ASSERT(std::__mdspan_detail::__is_extents_v<Extents>);
+ static_assert(std::is_copy_constructible_v<Mapping>);
+ static_assert(std::is_nothrow_move_constructible_v<Mapping>);
+ static_assert(std::is_nothrow_move_assignable_v<Mapping>);
+ static_assert(std::is_nothrow_swappable_v<Mapping>);
+
+ ASSERT_SAME_TYPE(typename Mapping::index_type, typename Extents::index_type);
+ ASSERT_SAME_TYPE(typename Mapping::size_type, typename Extents::size_type);
+ ASSERT_SAME_TYPE(typename Mapping::rank_type, typename Extents::rank_type);
+ ASSERT_SAME_TYPE(typename Mapping::layout_type, std::layout_left_padded<Mapping::padding_value>);
+ ASSERT_SAME_TYPE(typename Mapping::layout_type::template mapping<Extents>, Mapping);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().extents()), const Extents&>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().strides()),
+ std::array<typename Mapping::index_type, Extents::rank()>>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>()(Indices...)), typename Mapping::index_type>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().required_span_size()), typename Mapping::index_type>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().is_unique()), bool>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().is_exhaustive()), bool>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().is_strided()), bool>);
+ if constexpr (Extents::rank() > 0)
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().stride(0)), typename Mapping::index_type>);
+ static_assert(std::is_same_v<decltype(Mapping::is_always_unique()), bool>);
+ static_assert(std::is_same_v<decltype(Mapping::is_always_exhaustive()), bool>);
+ static_assert(std::is_same_v<decltype(Mapping::is_always_strided()), bool>);
+}
+
+template <class Layout, class Extents>
+void test_layout_mapping_requirements() {
+ test_mapping_requirements<typename Layout::template mapping<Extents>>(std::make_index_sequence<Extents::rank()>());
+}
+
+int main() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_layout_mapping_requirements<std::layout_left_padded<4>, std::extents<int8_t>>();
+ test_layout_mapping_requirements<std::layout_left_padded<4>, std::extents<uint8_t, 4, 6>>();
+ test_layout_mapping_requirements<std::layout_left_padded<4>, std::extents<int32_t, D, 4>>();
+ test_layout_mapping_requirements<std::layout_left_padded<4>, std::extents<uint32_t, D, D>>();
+
+ test_layout_mapping_requirements<std::layout_left_padded<D>, std::extents<int8_t, 1, D, D>>();
+ test_layout_mapping_requirements<std::layout_left_padded<D>, std::extents<uint8_t, D, D, D>>();
+ test_layout_mapping_requirements<std::layout_left_padded<D>, std::extents<int32_t, D, D, D>>();
+ test_layout_mapping_requirements<std::layout_left_padded<D>, std::extents<uint32_t, D, D, D>>();
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/stride.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/stride.pass.cpp
new file mode 100644
index 0000000000000..8f6bea8145ba3
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/stride.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr index_type stride(rank_type) const noexcept;
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <typename Mapping>
+constexpr void test_stride(const Mapping& mapping,
+ std::array<typename Mapping::index_type, Mapping::extents_type::rank()> expected_strides) {
+ ASSERT_NOEXCEPT(mapping.stride(0));
+ for (typename Mapping::rank_type r = 0; r < Mapping::extents_type::rank(); ++r)
+ assert(mapping.stride(r) == expected_strides[r]);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_stride(std::layout_left_padded<4>::mapping<std::extents<int32_t, D>>(
+ std::extents<int32_t, D>(7)), {1});
+ test_stride(std::layout_left_padded<4>::mapping<std::extents<int32_t, 7>>(), {1});
+ test_stride(std::layout_left_padded<4>::mapping<std::extents<uint32_t, 7, 8>>(), {1, 8});
+ test_stride(std::layout_left_padded<4>::mapping<std::extents<uint32_t, D, 8, D, D>>(
+ std::extents<uint32_t, D, 8, D, D>(7, 9, 10)), {1, 8, 64, 576});
+
+ test_stride(std::layout_left_padded<D>::mapping<std::extents<int32_t, D>>(
+ std::extents<int32_t, D>(7)), {1});
+ test_stride(std::layout_left_padded<D>::mapping<std::extents<int32_t, 7>>(), {1});
+ test_stride(std::layout_left_padded<D>::mapping<std::extents<uint32_t, 7, 8>>(), {1, 7});
+ test_stride(std::layout_left_padded<D>::mapping<std::extents<uint32_t, D, 8, D, D>>(
+ std::extents<uint32_t, D, 8, D, D>(7, 9, 10)), {1, 7, 56, 504});
+ test_stride(std::layout_left_padded<D>::mapping<std::extents<int32_t, 7, 8>>(
+ std::extents<int32_t, 7, 8>(), 6), {1, 12});
+ test_stride(std::layout_left_padded<D>::mapping<std::extents<uint32_t, D, 8, D, D>>(
+ std::extents<uint32_t, D, 8, D, D>(7, 9, 10), 6), {1, 12, 96, 864});
+ // clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/comparison.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/comparison.pass.cpp
new file mode 100644
index 0000000000000..90d0a05d6a773
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/comparison.pass.cpp
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutRightPaddedMapping>
+// friend constexpr bool operator==(const mapping&, const LayoutRightPaddedMapping&) noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class LeftMapping, class RightMapping>
+constexpr void test_comparison(bool equal, const LeftMapping& left, const RightMapping& right) {
+ ASSERT_NOEXCEPT(left == right);
+ assert((left == right) == equal);
+ assert((left != right) == !equal);
+}
+
+struct DoesNotMatch {
+ constexpr bool does_not_match() const { return true; }
+};
+
+constexpr DoesNotMatch compare_layout_mappings(...) { return {}; }
+
+template <class LeftMapping, class RightMapping>
+constexpr auto compare_layout_mappings(const LeftMapping& left, const RightMapping& right) -> decltype(left == right) {
+ (void)left;
+ (void)right;
+ return true;
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using rank0_left = std::layout_right_padded<0>::mapping<std::extents<size_t>>;
+ using rank0_right = std::layout_right_padded<4>::mapping<std::extents<size_t>>;
+ test_comparison(true, rank0_left(), rank0_right());
+ }
+
+ {
+ using rank1_fixed = std::layout_right_padded<4>::mapping<std::extents<size_t, D>>;
+ using rank1_dynamic = std::layout_right_padded<D>::mapping<std::extents<size_t, 5>>;
+ test_comparison(true, rank1_fixed(std::extents<size_t, D>(5)), rank1_dynamic(std::extents<size_t, 5>(), 99));
+ test_comparison(false, rank1_fixed(std::extents<size_t, D>(3)), rank1_dynamic(std::extents<size_t, 5>(), 99));
+ }
+
+ {
+ using fixed_mapping = std::layout_right_padded<4>::mapping<std::extents<size_t, 3, 7>>;
+ using dynamic_mapping = std::layout_right_padded<D>::mapping<std::extents<size_t, 3, 7>>;
+ test_comparison(true, fixed_mapping(), dynamic_mapping(std::extents<size_t, 3, 7>(), 4));
+ test_comparison(false, fixed_mapping(), dynamic_mapping(std::extents<size_t, 3, 7>(), 6));
+ test_comparison(false, fixed_mapping(), std::layout_right_padded<4>::mapping<std::extents<size_t, 3, 4>>());
+ }
+
+ {
+ using dynamic_mapping = std::layout_right_padded<D>::mapping<std::extents<size_t, D, 3>>;
+ test_comparison(
+ true, dynamic_mapping(std::extents<size_t, D, 3>(5), 5), dynamic_mapping(std::extents<size_t, D, 3>(5), 5));
+ test_comparison(
+ false, dynamic_mapping(std::extents<size_t, D, 3>(5), 5), dynamic_mapping(std::extents<size_t, D, 3>(5), 8));
+ }
+
+ static_assert(compare_layout_mappings(
+ std::layout_right_padded<4>::mapping<std::extents<int, D>>(std::extents<int, D>(5)),
+ std::layout_right_padded<4>::mapping<std::extents<int, 5>>()));
+ static_assert(compare_layout_mappings(std::layout_right_padded<4>::mapping<std::extents<int>>(),
+ std::layout_right_padded<4>::mapping<std::extents<int, 1>>())
+ .does_not_match());
+ static_assert(compare_layout_mappings(std::layout_right_padded<4>::mapping<std::extents<int, 5, 7>>(),
+ std::layout_right_padded<4>::mapping<std::extents<int, 5>>())
+ .does_not_match());
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.copy.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.copy.pass.cpp
new file mode 100644
index 0000000000000..8bdc53ee4e32b
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.copy.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr mapping(const mapping&) noexcept = default;
+// constexpr mapping& operator=(const mapping&) noexcept = default;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_copy_semantics(const Mapping& source) {
+ ASSERT_NOEXCEPT(Mapping(source));
+ static_assert(noexcept(std::declval<Mapping&>() = source));
+
+ Mapping copy(source);
+ assert(copy == source);
+
+ Mapping assigned;
+ assigned = source;
+ assert(assigned == source);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_copy_semantics(std::layout_right_padded<4>::mapping<std::extents<int32_t>>());
+ test_copy_semantics(
+ std::layout_right_padded<4>::mapping<std::extents<uint32_t, 5, 7>>(std::extents<int32_t, 5, 7>()));
+ test_copy_semantics(std::layout_right_padded<4>::mapping<std::extents<int8_t, D>>(std::extents<int8_t, D>(5)));
+ test_copy_semantics(
+ std::layout_right_padded<4>::mapping<std::extents<uint8_t, D, 7>>(std::extents<uint8_t, D, 7>(5)));
+
+ test_copy_semantics(std::layout_right_padded<D>::mapping<std::extents<int32_t>>());
+ test_copy_semantics(
+ std::layout_right_padded<D>::mapping<std::extents<uint32_t, 5, 7>>(std::extents<int32_t, 5, 7>()));
+ test_copy_semantics(std::layout_right_padded<D>::mapping<std::extents<int8_t, D>>(std::extents<int8_t, D>(5), 5));
+ test_copy_semantics(
+ std::layout_right_padded<D>::mapping<std::extents<uint8_t, D, 7>>(std::extents<uint8_t, D, 7>(5)));
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.default.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..73e6dc3288337
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.default.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr mapping() noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_construction() {
+ using Extents = typename Mapping::extents_type;
+
+ ASSERT_NOEXCEPT(Mapping{});
+ Mapping mapping;
+ Mapping extents_mapping{Extents()};
+
+ assert(mapping == extents_mapping);
+ assert(mapping.extents() == Extents());
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_construction<std::layout_right_padded<4>::mapping<std::extents<int32_t>>>();
+ test_construction<std::layout_right_padded<4>::mapping<std::extents<int32_t, 1>>>();
+ test_construction<std::layout_right_padded<4>::mapping<std::extents<uint32_t, 2, 3>>>();
+ test_construction<std::layout_right_padded<4>::mapping<std::extents<uint32_t, 4, 5, D>>>();
+
+ test_construction<std::layout_right_padded<D>::mapping<std::extents<int32_t>>>();
+ test_construction<std::layout_right_padded<D>::mapping<std::extents<int32_t, 1>>>();
+ test_construction<std::layout_right_padded<D>::mapping<std::extents<uint32_t, 2, 3>>>();
+ test_construction<std::layout_right_padded<D>::mapping<std::extents<uint32_t, 4, 5, D>>>();
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.extents.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.extents.pass.cpp
new file mode 100644
index 0000000000000..6526b54b963f9
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.extents.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr mapping(const extents_type&);
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+template <size_t PaddingValue, class Extents>
+constexpr void
+test_construction(Extents extents, std::array<typename Extents::index_type, Extents::rank()> expected_strides) {
+ using Mapping = typename std::layout_right_padded<PaddingValue>::template mapping<Extents>;
+ static_assert(Mapping::padding_value == PaddingValue);
+
+ Mapping mapping(extents);
+ assert(mapping.extents() == extents);
+
+ for (typename Mapping::rank_type r = 0; r < Mapping::extents_type::rank(); ++r)
+ assert(mapping.stride(r) == expected_strides[r]);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_construction<4>(std::extents<int32_t>(), {});
+ test_construction<4>(std::extents<int32_t, 5>(), {1});
+ test_construction<4>(std::extents<uint32_t, D>(7), {1});
+ test_construction<4>(std::extents<uint32_t, 5, 7>(), {8, 1});
+ test_construction<4>(std::extents<uint64_t, D, 2, 3>(6), {8, 4, 1});
+ test_construction<D>(std::extents<int32_t>(), {});
+ test_construction<D>(std::extents<int32_t, 5>(), {1});
+ test_construction<D>(std::extents<uint32_t, D>(7), {1});
+ test_construction<D>(std::extents<uint32_t, 0, 7>(), {7, 1});
+ test_construction<D>(std::extents<uint64_t, 5, 7>(), {7, 1});
+ test_construction<D>(std::extents<uint64_t, D, 7>(5), {7, 1});
+ test_construction<0>(std::extents<uint32_t, D, 13>(7), {13, 1});
+ test_construction<0>(std::extents<uint32_t, 0, 7>(), {7, 1});
+ //clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_left.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_left.pass.cpp
new file mode 100644
index 0000000000000..c9d1a23c286ce
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_left.pass.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutLeftMapping>
+// constexpr mapping(const LayoutLeftMapping& other) noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ ASSERT_NOEXCEPT(Dst(source));
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_left::mapping<std::extents<size_t>>;
+ using Dst = std::layout_right_padded<D>::mapping<std::extents<size_t>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left::mapping<std::extents<size_t, 5>>;
+ using Dst = std::layout_right_padded<4>::mapping<std::extents<size_t, D>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_left_padded.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_left_padded.pass.cpp
new file mode 100644
index 0000000000000..c1da8426273bd
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_left_padded.pass.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutLeftPaddedMapping>
+// constexpr mapping(const LayoutLeftPaddedMapping& other) noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ ASSERT_NOEXCEPT(Dst(source));
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_left_padded<4>::mapping<std::extents<size_t>>;
+ using Dst = std::layout_right_padded<D>::mapping<std::extents<size_t>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left_padded<4>::mapping<std::extents<size_t, 5>>;
+ using Dst = std::layout_right_padded<4>::mapping<std::extents<size_t, D>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_right.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_right.pass.cpp
new file mode 100644
index 0000000000000..7bbbb52d0394f
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_right.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class OtherExtents>
+// constexpr mapping(const layout_right::mapping<OtherExtents>& other);
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_right::mapping<std::extents<size_t>>;
+ using Dst = std::layout_right_padded<4>::mapping<std::extents<size_t>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right::mapping<std::extents<size_t, 3>>;
+ using Dst = std::layout_right_padded<4>::mapping<std::extents<size_t, D>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right::mapping<std::extents<size_t, 4, 8>>;
+ using DstStatic = std::layout_right_padded<4>::mapping<std::extents<size_t, 4, 8>>;
+ using DstDynamic = std::layout_right_padded<D>::mapping<std::extents<size_t, D, 8>>;
+ Src source;
+ test_conversion<true, DstStatic>(source);
+ test_conversion<true, DstDynamic>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_stride.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_stride.pass.cpp
new file mode 100644
index 0000000000000..ef84dfbc61e8e
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.layout_stride.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class OtherExtents>
+// constexpr mapping(const layout_stride::mapping<OtherExtents>& other);
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_stride::mapping<std::extents<size_t>>;
+ using Dst = std::layout_right_padded<D>::mapping<std::extents<size_t>>;
+ Src source(std::extents<size_t>(), std::array<size_t, 0>{});
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_stride::mapping<std::extents<size_t, 3>>;
+ using Dst = std::layout_right_padded<4>::mapping<std::extents<size_t, 3>>;
+ Src source(std::extents<size_t, 3>(), std::array<size_t, 1>{1});
+ test_conversion<false, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_stride::mapping<std::extents<size_t, 5, 7>>;
+ using Dst = std::layout_right_padded<4>::mapping<std::extents<size_t, D, 7>>;
+ Src source(std::extents<size_t, 5, 7>(), std::array<size_t, 2>{8, 1});
+ test_conversion<false, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.mapping.assert.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.mapping.assert.pass.cpp
new file mode 100644
index 0000000000000..87d2dffb6010d
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.mapping.assert.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+// UNSUPPORTED: libcpp-hardening-mode=none
+// XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
+
+// <mdspan>
+
+// constexpr mapping(const layout_stride::mapping<OtherExtents>& other);
+// constexpr mapping(const LayoutRightPaddedMapping& other);
+
+#include <array>
+#include <cstddef>
+#include <mdspan>
+
+#include "check_assertion.h"
+
+int main() {
+#if 0
+ {
+ using Src = std::layout_right_padded<std::dynamic_extent>::mapping<std::extents<uint32_t, 0, 1>>;
+ using Dst = std::layout_right_padded<std::dynamic_extent>::mapping<std::extents<uint8_t, 0, 1>>;
+
+ Src src(std::extents<uint32_t, 0, 1>(), 256);
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ Dst(src),
+ "layout_right_padded::mapping from layout_right_padded ctor: source padded stride must be "
+ "representable as index_type.");
+ }
+
+ {
+ using Src = std::layout_stride::mapping<std::extents<uint32_t, 0, 1>>;
+ using Dst = std::layout_right_padded<std::dynamic_extent>::mapping<std::extents<uint8_t, 0, 1>>;
+
+ Src src(std::extents<uint32_t, 0, 1>(), std::array<uint32_t, 2>{256, 1});
+
+ TEST_LIBCPP_ASSERT_FAILURE(
+ Dst(src),
+ "layout_right_padded::mapping from layout_stride ctor: source padded stride must be "
+ "representable as index_type.");
+ }
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.mapping.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.mapping.pass.cpp
new file mode 100644
index 0000000000000..66fd8a48b712b
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.mapping.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutRightPaddedMapping>
+// constexpr mapping(const LayoutRightPaddedMapping& other);
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+#if 0 // TODO
+ {
+ using Src = std::layout_right_padded<4>::mapping<std::extents<size_t, 4, 7>>;
+ using Dst = std::layout_right_padded<4>::mapping<std::extents<size_t, D, 7>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+#endif
+
+ {
+ using Src = std::layout_right_padded<4>::mapping<std::extents<size_t, 3>>;
+ using Dst = std::layout_right_padded<D>::mapping<std::extents<size_t, 3>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right_padded<4>::mapping<std::extents<size_t, 5, 7>>;
+ using Dst = std::layout_right_padded<D>::mapping<std::extents<size_t, D, 7>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right_padded<D>::mapping<std::extents<size_t, D, 7>>;
+ using Dst = std::layout_right_padded<4>::mapping<std::extents<size_t, 4, 7>>;
+ Src source(std::extents<size_t, D, 7>(4), 4);
+ test_conversion<false, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.padding.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.padding.pass.cpp
new file mode 100644
index 0000000000000..f016b54cfabbe
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.padding.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr mapping(const extents_type& e, index_type padding_stride);
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+template <class Extents, class Padding>
+constexpr void test_construction(
+ Extents extents, Padding padding, std::array<typename Extents::index_type, Extents::rank()> expected_strides) {
+ using Mapping = std::layout_right_padded<std::dynamic_extent>::mapping<Extents>;
+ static_assert(Mapping::padding_value == std::dynamic_extent);
+
+ Mapping mapping(extents, padding);
+ assert(mapping.extents() == extents);
+
+ for (typename Mapping::rank_type r = 0; r < Mapping::extents_type::rank(); ++r)
+ assert(mapping.stride(r) == expected_strides[r]);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_construction(std::extents<unsigned>(), 3, {});
+ test_construction(std::extents<unsigned, D>(7), 1337, {1});
+ test_construction(std::extents<unsigned, D, 7>(5), 6, {12, 1});
+ test_construction(std::extents<unsigned, 5, 7>(), 4, {8, 1});
+ test_construction(std::extents<unsigned, D, 7, D>(7, 3), 4, {28, 4, 1});
+ test_construction(std::extents<unsigned, 0, 7>(), 4, {8, 1});
+ // clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/extents.verify.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/extents.verify.cpp
new file mode 100644
index 0000000000000..370d8e1b453e4
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/extents.verify.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class Extents>
+// class layout_right_padded::mapping;
+
+#include <mdspan>
+
+void not_extents() {
+ // expected-error-re@*:* {{static assertion failed {{.*}}layout_right_padded::mapping template argument must be a specialization of extents}}
+ [[maybe_unused]] std::layout_right_padded<4>::mapping<void> mapping;
+}
+
+void index_space_representable() {
+ // expected-error@*:* {{layout_right_padded::mapping index space for static extents must be representable as index_type.}}
+ [[maybe_unused]] std::layout_right_padded<4>::mapping<std::extents<signed char, 20, 20>> mapping;
+}
+
+void padding_stride_representable() {
+ // expected-error@*:* {{layout_right_padded::mapping padded stride for the last static extent must be representable as size_t and index_type.}}
+ [[maybe_unused]] std::layout_right_padded<4>::mapping<std::extents<signed char, 0, 127>> mapping;
+}
+
+void padded_product_representable() {
+ // expected-error@*:* {{layout_right_padded::mapping required span size for static extents must be representable as size_t and index_type.}}
+ [[maybe_unused]] std::layout_right_padded<64>::mapping<std::extents<signed char, 2, 63>> mapping;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/index_operator.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/index_operator.pass.cpp
new file mode 100644
index 0000000000000..5dd9275049a0c
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/index_operator.pass.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class... Indices>
+// constexpr index_type operator()(Indices...) const noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+#include "../ConvertibleToIntegral.h"
+
+template <class Mapping, class... Indices>
+concept operator_constraints = requires(Mapping mapping, Indices... idxs) {
+ { std::is_same_v<decltype(mapping(idxs...)), typename Mapping::index_type> };
+};
+
+template <class Mapping, class... Indices>
+ requires(operator_constraints<Mapping, Indices...>)
+constexpr bool check_operator_constraints(Mapping mapping, Indices... idxs) {
+ (void)mapping(idxs...);
+ return true;
+}
+
+template <class Mapping, class... Indices>
+constexpr bool check_operator_constraints(Mapping, Indices...) {
+ return false;
+}
+
+template <class Mapping, class... Args>
+constexpr void iterate_right_padded(Mapping mapping, typename Mapping::index_type expected, Args... args) {
+ constexpr size_t r = sizeof...(Args);
+ if constexpr (Mapping::extents_type::rank() == r) {
+ ASSERT_NOEXCEPT(mapping(args...));
+ assert(expected == mapping(args...));
+ } else {
+ for (typename Mapping::index_type i = 0; i < mapping.extents().extent(r); ++i)
+ iterate_right_padded(
+ mapping, static_cast<typename Mapping::index_type>(expected + i * mapping.stride(r)), args..., i);
+ }
+}
+
+template <class Extents, size_t PaddingValue, class... Args>
+constexpr void test_iteration(Args... args) {
+ using Mapping = typename std::layout_right_padded<PaddingValue>::template mapping<Extents>;
+ Mapping mapping(Extents(args...));
+ iterate_right_padded(mapping, typename Extents::index_type(0));
+}
+
+template <class Mapping>
+constexpr void test_iteration(Mapping mapping) {
+ iterate_right_padded(mapping, typename Mapping::index_type(0));
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_iteration<std::extents<int>, 4>();
+ test_iteration<std::extents<unsigned, 7>, 4>();
+ test_iteration<std::extents<unsigned, 5, 7>, 4>();
+ test_iteration<std::extents<signed char, D, 2, 3>, 4>(3);
+
+ test_iteration<std::extents<int>, D>();
+ test_iteration<std::extents<unsigned, D>, D>(7);
+ test_iteration(std::layout_right_padded<D>::mapping<std::extents<unsigned, 5, 7>>(std::extents<unsigned, 5, 7>(), 6));
+ test_iteration(
+ std::layout_right_padded<D>::mapping<std::extents<unsigned, D, 2, 3>>(std::extents<unsigned, D, 2, 3>(3), 4));
+
+ // Check operator constraint for number of arguments
+ static_assert(check_operator_constraints(
+ std::layout_right_padded<D>::mapping<std::extents<int, D>>(std::extents<int, D>(1), 1), 0));
+ static_assert(!check_operator_constraints(
+ std::layout_right_padded<D>::mapping<std::extents<int, D>>(std::extents<int, D>(1), 1), 0, 0));
+
+ // Check operator constraint for convertibility of arguments to index_type
+ static_assert(check_operator_constraints(
+ std::layout_right_padded<D>::mapping<std::extents<int, D>>(std::extents<int, D>(1), 1), IntType(0)));
+ static_assert(!check_operator_constraints(
+ std::layout_right_padded<D>::mapping<std::extents<unsigned, D>>(std::extents<unsigned, D>(1), 1), IntType(0)));
+
+ // Check operator constraint for no-throw-constructibility of index_type from arguments
+ static_assert(!check_operator_constraints(
+ std::layout_right_padded<D>::mapping<std::extents<unsigned char, D>>(std::extents<unsigned char, D>(1), 1),
+ IntType(0)));
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/properties.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/properties.pass.cpp
new file mode 100644
index 0000000000000..0adaab5c4d14c
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/properties.pass.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// namespace std {
+// template<class Extents>
+// class layout_right_padded::mapping {
+// ...
+// static constexpr bool is_always_unique() noexcept;
+// static constexpr bool is_always_exhaustive() noexcept;
+// static constexpr bool is_always_strided() noexcept;
+// static constexpr bool is_unique() noexcept;
+// constexpr bool is_exhaustive() const noexcept;
+// static constexpr bool is_strided() noexcept;
+// };
+// }
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_properties(const Mapping& mapping, bool exhaustive, bool always_exhaustive) {
+ const Mapping const_mapping = mapping;
+
+ assert(Mapping::is_unique());
+ assert(mapping.is_unique());
+ assert(const_mapping.is_unique());
+
+ assert(mapping.is_exhaustive() == exhaustive);
+ assert(const_mapping.is_exhaustive() == exhaustive);
+
+ assert(Mapping::is_strided());
+ assert(mapping.is_strided());
+ assert(const_mapping.is_strided());
+
+ assert(Mapping::is_always_unique());
+ assert(Mapping::is_always_exhaustive() == always_exhaustive);
+ assert(Mapping::is_always_strided());
+
+ ASSERT_NOEXCEPT(std::declval<Mapping>().is_unique());
+ ASSERT_NOEXCEPT(std::declval<Mapping>().is_exhaustive());
+ ASSERT_NOEXCEPT(std::declval<Mapping>().is_strided());
+ ASSERT_NOEXCEPT(Mapping::is_always_unique());
+ ASSERT_NOEXCEPT(Mapping::is_always_exhaustive());
+ ASSERT_NOEXCEPT(Mapping::is_always_strided());
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_properties(std::layout_right_padded<4>::mapping<std::extents<int32_t>>(), true, true);
+ test_properties(std::layout_right_padded<4>::mapping<std::extents<int32_t, 5>>(), true, true);
+ test_properties(std::layout_right_padded<4>::mapping<std::extents<uint32_t, 3, 4>>(), true, true);
+ test_properties(std::layout_right_padded<4>::mapping<std::extents<uint32_t, 4, 6>>(), false, false);
+ test_properties(std::layout_right_padded<4>::mapping<std::extents<int32_t, 6, D>>(
+ std::extents<int32_t, 6, D>(7)), false, false);
+ test_properties(std::layout_right_padded<4>::mapping<std::extents<int32_t, 6, D>>(
+ std::extents<int32_t, 6, D>(8)), true, false);
+ test_properties(std::layout_right_padded<4>::mapping<std::extents<uint32_t>>(), true, true);
+ test_properties(std::layout_right_padded<4>::mapping<std::extents<uint32_t, 0, 6>>(), false, false);
+
+ test_properties(std::layout_right_padded<D>::mapping<std::extents<int32_t, 6, D>>(
+ std::extents<int32_t, 6, D>(4), 4), true, false);
+ test_properties(std::layout_right_padded<D>::mapping<std::extents<int32_t, 6, D>>(
+ std::extents<int32_t, 6, D>(6), 4), false, false);
+ // clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/required_span_size.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/required_span_size.pass.cpp
new file mode 100644
index 0000000000000..e4289707d5702
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/required_span_size.pass.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr index_type required_span_size() const noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_required_span_size(const Mapping& mapping, typename Mapping::index_type expected_size) {
+ ASSERT_NOEXCEPT(mapping.required_span_size());
+ assert(mapping.required_span_size() == expected_size);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_required_span_size(std::layout_right_padded<4>::mapping<std::extents<int32_t>>(), 1);
+ test_required_span_size(std::layout_right_padded<4>::mapping<std::extents<int32_t, D>>(std::extents<int32_t, D>(0)), 0);
+ test_required_span_size(std::layout_right_padded<4>::mapping<std::extents<uint32_t, D>>(std::extents<uint32_t, D>(7)), 7);
+ test_required_span_size(std::layout_right_padded<4>::mapping<std::extents<uint32_t, 5, 7>>(), 39);
+ test_required_span_size(std::layout_right_padded<4>::mapping<std::extents<int64_t, D, 2, 3>>(std::extents<int64_t, D, 2, 3>(7)), 55);
+ test_required_span_size(std::layout_right_padded<4>::mapping<std::extents<int64_t, 15, 0>>(), 0);
+
+ test_required_span_size(std::layout_right_padded<D>::mapping<std::extents<int32_t>>(), 1);
+ test_required_span_size(std::layout_right_padded<D>::mapping<std::extents<int32_t, D>>(std::extents<int32_t, D>(0)), 0);
+ test_required_span_size(std::layout_right_padded<D>::mapping<std::extents<uint32_t, D>>(std::extents<uint32_t, D>(7)), 7);
+ test_required_span_size(std::layout_right_padded<D>::mapping<std::extents<uint32_t, 5, 7>>(), 35);
+ test_required_span_size(std::layout_right_padded<D>::mapping<std::extents<int64_t, 5, 7>>(std::extents<int64_t, 5, 7>(), 6), 55);
+ test_required_span_size(std::layout_right_padded<D>::mapping<std::extents<int64_t, 0, 7>>(), 0);
+ // clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/static_requirements.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/static_requirements.pass.cpp
new file mode 100644
index 0000000000000..033ffce606911
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/static_requirements.pass.cpp
@@ -0,0 +1,68 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+#include <utility>
+
+#include "test_macros.h"
+
+template <class Mapping, size_t... Indices>
+void test_mapping_requirements(std::index_sequence<Indices...>) {
+ using Extents = Mapping::extents_type;
+
+ LIBCPP_STATIC_ASSERT(std::__mdspan_detail::__is_extents_v<Extents>);
+ static_assert(std::is_copy_constructible_v<Mapping>);
+ static_assert(std::is_nothrow_move_constructible_v<Mapping>);
+ static_assert(std::is_nothrow_move_assignable_v<Mapping>);
+ static_assert(std::is_nothrow_swappable_v<Mapping>);
+
+ ASSERT_SAME_TYPE(typename Mapping::index_type, typename Extents::index_type);
+ ASSERT_SAME_TYPE(typename Mapping::size_type, typename Extents::size_type);
+ ASSERT_SAME_TYPE(typename Mapping::rank_type, typename Extents::rank_type);
+ ASSERT_SAME_TYPE(typename Mapping::layout_type, std::layout_right_padded<Mapping::padding_value>);
+ ASSERT_SAME_TYPE(typename Mapping::layout_type::template mapping<Extents>, Mapping);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().extents()), const Extents&>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().strides()),
+ std::array<typename Mapping::index_type, Extents::rank()>>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>()(Indices...)), typename Mapping::index_type>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().required_span_size()), typename Mapping::index_type>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().is_unique()), bool>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().is_exhaustive()), bool>);
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().is_strided()), bool>);
+ if constexpr (Extents::rank() > 0)
+ static_assert(std::is_same_v<decltype(std::declval<Mapping>().stride(0)), typename Mapping::index_type>);
+ static_assert(std::is_same_v<decltype(Mapping::is_always_unique()), bool>);
+ static_assert(std::is_same_v<decltype(Mapping::is_always_exhaustive()), bool>);
+ static_assert(std::is_same_v<decltype(Mapping::is_always_strided()), bool>);
+}
+
+template <class Layout, class Extents>
+void test_layout_mapping_requirements() {
+ test_mapping_requirements<typename Layout::template mapping<Extents>>(std::make_index_sequence<Extents::rank()>());
+}
+
+int main() {
+ constexpr size_t D = std::dynamic_extent;
+
+ test_layout_mapping_requirements<std::layout_right_padded<4>, std::extents<int8_t>>();
+ test_layout_mapping_requirements<std::layout_right_padded<4>, std::extents<uint8_t, 4, 6>>();
+ test_layout_mapping_requirements<std::layout_right_padded<4>, std::extents<int32_t, D, 4>>();
+ test_layout_mapping_requirements<std::layout_right_padded<4>, std::extents<uint32_t, D, D>>();
+
+ test_layout_mapping_requirements<std::layout_right_padded<D>, std::extents<int8_t, 1, D, D>>();
+ test_layout_mapping_requirements<std::layout_right_padded<D>, std::extents<uint8_t, D, D, D>>();
+ test_layout_mapping_requirements<std::layout_right_padded<D>, std::extents<int32_t, D, D, D>>();
+ test_layout_mapping_requirements<std::layout_right_padded<D>, std::extents<uint32_t, D, D, D>>();
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/stride.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/stride.pass.cpp
new file mode 100644
index 0000000000000..ea65fd104d918
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/stride.pass.cpp
@@ -0,0 +1,61 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// constexpr index_type stride(rank_type) const noexcept;
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <mdspan>
+
+#include "test_macros.h"
+
+template <class Mapping>
+constexpr void test_stride(const Mapping& mapping,
+ std::array<typename Mapping::index_type, Mapping::extents_type::rank()> expected_strides) {
+ ASSERT_NOEXCEPT(mapping.stride(0));
+ for (typename Mapping::rank_type r = 0; r < Mapping::extents_type::rank(); ++r)
+ assert(mapping.stride(r) == expected_strides[r]);
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ // clang-format off
+ test_stride(std::layout_right_padded<4>::mapping<std::extents<int32_t, D>>(
+ std::extents<int32_t, D>(7)), {1});
+ test_stride(std::layout_right_padded<4>::mapping<std::extents<int32_t, 7>>(), {1});
+ test_stride(std::layout_right_padded<4>::mapping<std::extents<uint32_t, 7, 8>>(), {8, 1});
+ test_stride(std::layout_right_padded<4>::mapping<std::extents<uint32_t, D, 8, D, D>>(
+ std::extents<uint32_t, D, 8, D, D>(7, 9, 10)), {864, 108, 12, 1});
+
+ test_stride(std::layout_right_padded<D>::mapping<std::extents<int32_t, D>>(
+ std::extents<int32_t, D>(7)), {1});
+ test_stride(std::layout_right_padded<D>::mapping<std::extents<int32_t, 7>>(), {1});
+ test_stride(std::layout_right_padded<D>::mapping<std::extents<uint32_t, 7, 8>>(), {8, 1});
+ test_stride(std::layout_right_padded<D>::mapping<std::extents<uint32_t, D, 8, D, D>>(
+ std::extents<uint32_t, D, 8, D, D>(7, 9, 10)), {720, 90, 10, 1});
+ test_stride(std::layout_right_padded<D>::mapping<std::extents<int32_t, 7, 8>>(
+ std::extents<int32_t, 7, 8>(), 6), {12, 1});
+ test_stride(std::layout_right_padded<D>::mapping<std::extents<uint32_t, D, 8, D, D>>(
+ std::extents<uint32_t, D, 8, D, D>(7, 9, 10), 6), {864, 108, 12, 1});
+ // clang-format on
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
>From 6454dce6db5efe0e6c0a5262132fa476647c04ab Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Sat, 21 Mar 2026 23:41:50 +0800
Subject: [PATCH 2/6] impl
---
libcxx/include/CMakeLists.txt | 3 +-
libcxx/include/__mdspan/concepts.h | 46 ---------
...layout_padded_common.h => layout_common.h} | 55 ++++++++++-
libcxx/include/__mdspan/layout_left.h | 29 ++++++
libcxx/include/__mdspan/layout_left_padded.h | 12 +--
libcxx/include/__mdspan/layout_right.h | 31 ++++++
libcxx/include/__mdspan/layout_right_padded.h | 13 +--
libcxx/include/__mdspan/layout_stride.h | 18 ++--
libcxx/include/mdspan | 74 +++++++++++---
.../ctor.layout_left_padded.pass.cpp | 97 +++++++++++++++++++
.../ctor.layout_right_padded.pass.cpp | 97 +++++++++++++++++++
11 files changed, 381 insertions(+), 94 deletions(-)
delete mode 100644 libcxx/include/__mdspan/concepts.h
rename libcxx/include/__mdspan/{layout_padded_common.h => layout_common.h} (60%)
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_left_padded.pass.cpp
create mode 100644 libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_right_padded.pass.cpp
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 474f21bc4959d..3a6061099c74d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -572,12 +572,11 @@ set(files
__math/trigonometric_functions.h
__mbstate_t.h
__mdspan/aligned_accessor.h
- __mdspan/concepts.h
__mdspan/default_accessor.h
__mdspan/extents.h
__mdspan/layout_left.h
__mdspan/layout_left_padded.h
- __mdspan/layout_padded_common.h
+ __mdspan/layout_common.h
__mdspan/layout_right_padded.h
__mdspan/layout_right.h
__mdspan/layout_stride.h
diff --git a/libcxx/include/__mdspan/concepts.h b/libcxx/include/__mdspan/concepts.h
deleted file mode 100644
index 9b5d321c79cdb..0000000000000
--- a/libcxx/include/__mdspan/concepts.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _LIBCPP___MDSPAN_CONCEPT_H
-#define _LIBCPP___MDSPAN_CONCEPT_H
-
-#include <__assert>
-#include <__concepts/same_as.h>
-#include <__config>
-#include <__mdspan/extents.h>
-
-#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
-
-namespace __mdspan_detail {
-
-template <class _Layout, class _Mapping>
-constexpr bool __is_mapping_of =
- is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, _Mapping>;
-
-template <class _Mapping>
-concept __layout_mapping_alike = requires {
- requires __is_mapping_of<typename _Mapping::layout_type, _Mapping>;
- requires __is_extents_v<typename _Mapping::extents_type>;
- { _Mapping::is_always_strided() } -> same_as<bool>;
- { _Mapping::is_always_exhaustive() } -> same_as<bool>;
- { _Mapping::is_always_unique() } -> same_as<bool>;
- bool_constant<_Mapping::is_always_strided()>::value;
- bool_constant<_Mapping::is_always_exhaustive()>::value;
- bool_constant<_Mapping::is_always_unique()>::value;
-};
-
-} // namespace __mdspan_detail
-
-#endif // _LIBCPP_STD_VER >= 23
-
-_LIBCPP_END_NAMESPACE_STD
-
-_LIBCPP_POP_MACROS
-
-#endif // _LIBCPP___MDSPAN_CONCEPT_H
diff --git a/libcxx/include/__mdspan/layout_padded_common.h b/libcxx/include/__mdspan/layout_common.h
similarity index 60%
rename from libcxx/include/__mdspan/layout_padded_common.h
rename to libcxx/include/__mdspan/layout_common.h
index aae860f6f8d87..77ad5a0f4e6b4 100644
--- a/libcxx/include/__mdspan/layout_padded_common.h
+++ b/libcxx/include/__mdspan/layout_common.h
@@ -14,12 +14,12 @@
//
//===---------------------------------------------------------------------===//
-#ifndef _LIBCPP___MDSPAN_LAYOUT_PADDED_COMMON_H
-#define _LIBCPP___MDSPAN_LAYOUT_PADDED_COMMON_H
+#ifndef _LIBCPP___MDSPAN_LAYOUT_COMMON_H
+#define _LIBCPP___MDSPAN_LAYOUT_COMMON_H
#include <__config>
#include <__fwd/mdspan.h>
-#include <__mdspan/concepts.h>
+#include <__mdspan/extents.h>
#include <__memory/addressof.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -31,10 +31,28 @@ _LIBCPP_PUSH_MACROS
_LIBCPP_BEGIN_NAMESPACE_STD
-#if _LIBCPP_STD_VER >= 26
+#if _LIBCPP_STD_VER >= 23
namespace __mdspan_detail {
+template <class _Layout, class _Mapping>
+constexpr bool __is_mapping_of =
+ is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, _Mapping>;
+
+template <class _Mapping>
+concept __layout_mapping_alike = requires {
+ requires __is_mapping_of<typename _Mapping::layout_type, _Mapping>;
+ requires __is_extents_v<typename _Mapping::extents_type>;
+ { _Mapping::is_always_strided() } -> same_as<bool>;
+ { _Mapping::is_always_exhaustive() } -> same_as<bool>;
+ { _Mapping::is_always_unique() } -> same_as<bool>;
+ bool_constant<_Mapping::is_always_strided()>::value;
+ bool_constant<_Mapping::is_always_exhaustive()>::value;
+ bool_constant<_Mapping::is_always_unique()>::value;
+};
+
+# if _LIBCPP_STD_VER >= 26
+
template <class _Integral>
_LIBCPP_HIDE_FROM_ABI constexpr _Integral __least_multiple_at_least(_Integral __multiplier, _Integral __minimum) {
if (__multiplier == static_cast<_Integral>(0))
@@ -87,9 +105,36 @@ concept __layout_right_mapping_of = __layout_mapping_alike<_Mapping> && __is_map
template <class _Mapping>
concept __layout_left_mapping_of = __layout_mapping_alike<_Mapping> && __is_mapping_of<layout_left, _Mapping>;
+_LIBCPP_HIDE_FROM_ABI constexpr size_t
+__compute_static_padding_stride(size_t __rank, size_t __padding_value, size_t __static_extent) {
+ if (__rank <= 1)
+ return 0uz;
+ if (__padding_value == dynamic_extent || __static_extent == dynamic_extent)
+ return dynamic_extent;
+ return __least_multiple_at_least(__padding_value, __static_extent);
+}
+
+template <class _Mapping>
+ requires __layout_left_padded_mapping_of<_Mapping> || __layout_right_padded_mapping_of<_Mapping>
+constexpr size_t __static_padding_stride_of = [] {
+ using _Extents = _Mapping::extents_type;
+ constexpr size_t __rank = _Extents::rank();
+
+ if constexpr (__layout_left_padded_mapping_of<_Mapping>) {
+ constexpr size_t __static_extent = __rank == 0 ? 0 : _Extents::static_extent(0);
+ return __compute_static_padding_stride(__rank, _Mapping::padding_value, __static_extent);
+ }
+ if constexpr (__layout_right_padded_mapping_of<_Mapping>) {
+ constexpr size_t __static_extent = __rank == 0 ? 0 : _Extents::static_extent(__rank - 1);
+ return __compute_static_padding_stride(__rank, _Mapping::padding_value, __static_extent);
+ }
+}();
+
+# endif // _LIBCPP_STD_VER >= 26
+
} // namespace __mdspan_detail
-#endif // _LIBCPP_STD_VER >= 26
+#endif // _LIBCPP_STD_VER >= 23
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__mdspan/layout_left.h b/libcxx/include/__mdspan/layout_left.h
index 2f515afb6c860..6eff932067d49 100644
--- a/libcxx/include/__mdspan/layout_left.h
+++ b/libcxx/include/__mdspan/layout_left.h
@@ -21,6 +21,7 @@
#include <__config>
#include <__fwd/mdspan.h>
#include <__mdspan/extents.h>
+#include <__mdspan/layout_common.h>
#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
#include <__type_traits/is_constructible.h>
@@ -109,6 +110,34 @@ class layout_left::mapping {
"layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type.");
}
+# if _LIBCPP_STD_VER >= 26 // _LIBCPP_STD_VER >= 26
+
+ template <class _LayoutLeftPaddedMapping>
+ requires __mdspan_detail::__layout_left_padded_mapping_of<_LayoutLeftPaddedMapping> &&
+ is_constructible_v<extents_type, typename _LayoutLeftPaddedMapping::extents_type>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(
+ !is_convertible_v<typename _LayoutLeftPaddedMapping::extents_type, extents_type>)
+ mapping(const _LayoutLeftPaddedMapping& __other) noexcept
+ : __extents_(__other.extents()) {
+ static_assert(
+ _Extents::rank() <= 1 || _Extents::static_extent(0) == dynamic_extent ||
+ __mdspan_detail::__static_padding_stride_of<_LayoutLeftPaddedMapping> == dynamic_extent ||
+ _Extents::static_extent(0) == __mdspan_detail::__static_padding_stride_of<_LayoutLeftPaddedMapping>,
+ "layout_left::mapping converting from layout_left_padded ctor: incompatible static extent(0) and "
+ "source static padding stride.");
+
+ if constexpr (extents_type::rank() > 1)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(1) == __other.extents().extent(0),
+ "layout_left::mapping from layout_left_padded ctor: other.stride(1) must equal other.extents().extent(0).");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_left::mapping from layout_left_padded ctor: other.required_span_size() must be representable as "
+ "index_type.");
+ }
+
+# endif // _LIBCPP_STD_VER >= 26
+
template <class _OtherExtents>
requires(is_constructible_v<extents_type, _OtherExtents>)
_LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0)
diff --git a/libcxx/include/__mdspan/layout_left_padded.h b/libcxx/include/__mdspan/layout_left_padded.h
index f2709975c49bf..1888fcd5cf691 100644
--- a/libcxx/include/__mdspan/layout_left_padded.h
+++ b/libcxx/include/__mdspan/layout_left_padded.h
@@ -20,10 +20,9 @@
#include <__assert>
#include <__config>
#include <__fwd/mdspan.h>
-#include <__mdspan/concepts.h>
#include <__mdspan/extents.h>
+#include <__mdspan/layout_common.h>
#include <__mdspan/layout_left.h>
-#include <__mdspan/layout_padded_common.h>
#include <__mdspan/layout_right.h>
#include <__mdspan/layout_stride.h>
#include <__memory/addressof.h>
@@ -64,13 +63,8 @@ class layout_left_padded<_PaddingValue>::mapping {
static constexpr rank_type __rank_ = extents_type::rank();
static constexpr size_t __first_static_extent = __rank_ == 0 ? 0uz : extents_type::static_extent(0);
- static constexpr size_t __static_padding_stride = [] {
- if constexpr (__rank_ <= 1)
- return 0uz;
- if constexpr (padding_value == dynamic_extent || __first_static_extent == dynamic_extent)
- return dynamic_extent;
- return __mdspan_detail::__least_multiple_at_least(padding_value, __first_static_extent);
- }();
+ static constexpr size_t __static_padding_stride =
+ __mdspan_detail::__compute_static_padding_stride(__rank_, padding_value, __first_static_extent);
// Do not store value if __static_padding_stride is not dynamic_extent.
using __stride_1_type = std::extents<index_type, __static_padding_stride>;
diff --git a/libcxx/include/__mdspan/layout_right.h b/libcxx/include/__mdspan/layout_right.h
index ccfbd23e28ad7..36f376cd4cf98 100644
--- a/libcxx/include/__mdspan/layout_right.h
+++ b/libcxx/include/__mdspan/layout_right.h
@@ -22,6 +22,7 @@
#include <__cstddef/size_t.h>
#include <__fwd/mdspan.h>
#include <__mdspan/extents.h>
+#include <__mdspan/layout_common.h>
#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
#include <__type_traits/is_constructible.h>
@@ -109,6 +110,36 @@ class layout_right::mapping {
"layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type.");
}
+# if _LIBCPP_STD_VER >= 26 // _LIBCPP_STD_VER >= 26
+
+ template <class _LayoutRightPaddedMapping>
+ requires __mdspan_detail::__layout_right_padded_mapping_of<_LayoutRightPaddedMapping> &&
+ is_constructible_v<extents_type, typename _LayoutRightPaddedMapping::extents_type>
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(
+ !is_convertible_v<typename _LayoutRightPaddedMapping::extents_type, extents_type>)
+ mapping(const _LayoutRightPaddedMapping& __other) noexcept
+ : __extents_(__other.extents()) {
+ static_assert(
+ extents_type::rank() <= 1 || extents_type::static_extent(extents_type::rank() - 1) == dynamic_extent ||
+ __mdspan_detail::__static_padding_stride_of<_LayoutRightPaddedMapping> == dynamic_extent ||
+ extents_type::static_extent(extents_type::rank() - 1) ==
+ __mdspan_detail::__static_padding_stride_of<_LayoutRightPaddedMapping>,
+ "layout_right::mapping converting from layout_right_padded ctor: incompatible static "
+ "extent(extents_type::rank() - 1) and source static padding stride.");
+
+ if constexpr (extents_type::rank() > 1)
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __other.stride(extents_type::rank() - 2) == __other.extents().extent(extents_type::rank() - 1),
+ "layout_right::mapping from layout_right_padded ctor: other.stride(rank() - 2) must equal "
+ "other.extents().extent(rank() - 1).");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_right::mapping from layout_right_padded ctor: other.required_span_size() must be representable as "
+ "index_type.");
+ }
+
+# endif // _LIBCPP_STD_VER >= 26
+
template <class _OtherExtents>
requires(is_constructible_v<extents_type, _OtherExtents>)
_LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0)
diff --git a/libcxx/include/__mdspan/layout_right_padded.h b/libcxx/include/__mdspan/layout_right_padded.h
index 2d89722536ba2..9b479d0b34bef 100644
--- a/libcxx/include/__mdspan/layout_right_padded.h
+++ b/libcxx/include/__mdspan/layout_right_padded.h
@@ -20,10 +20,9 @@
#include <__assert>
#include <__config>
#include <__fwd/mdspan.h>
-#include <__mdspan/concepts.h>
#include <__mdspan/extents.h>
+#include <__mdspan/layout_common.h>
#include <__mdspan/layout_left.h>
-#include <__mdspan/layout_padded_common.h>
#include <__mdspan/layout_right.h>
#include <__mdspan/layout_stride.h>
#include <__memory/addressof.h>
@@ -64,14 +63,10 @@ class layout_right_padded<_PaddingValue>::mapping {
static constexpr rank_type __rank_ = extents_type::rank();
static constexpr size_t __last_static_extent = __rank_ == 0 ? 0uz : extents_type::static_extent(__rank_ - 1);
- static constexpr size_t __static_padding_stride = [] {
- if constexpr (__rank_ <= 1)
- return 0uz;
- if constexpr (padding_value == dynamic_extent || __last_static_extent == dynamic_extent)
- return dynamic_extent;
- return __mdspan_detail::__least_multiple_at_least(padding_value, __last_static_extent);
- }();
+ static constexpr size_t __static_padding_stride =
+ __mdspan_detail::__compute_static_padding_stride(__rank_, padding_value, __last_static_extent);
+ // Do not store value if __static_padding_stride is not dynamic_extent.
using __stride_rm2_type = std::extents<index_type, __static_padding_stride>;
_LIBCPP_HIDE_FROM_ABI static constexpr bool __index_space_size_is_representable(const extents_type& __ext) {
diff --git a/libcxx/include/__mdspan/layout_stride.h b/libcxx/include/__mdspan/layout_stride.h
index 769cc6c478cbe..892a88571bd99 100644
--- a/libcxx/include/__mdspan/layout_stride.h
+++ b/libcxx/include/__mdspan/layout_stride.h
@@ -21,8 +21,8 @@
#include <__concepts/same_as.h>
#include <__config>
#include <__fwd/mdspan.h>
-#include <__mdspan/concepts.h>
#include <__mdspan/extents.h>
+#include <__mdspan/layout_common.h>
#include <__memory/addressof.h>
#include <__type_traits/common_type.h>
#include <__type_traits/is_constructible.h>
@@ -207,12 +207,16 @@ class layout_stride::mapping {
requires(__mdspan_detail::__layout_mapping_alike<_StridedLayoutMapping> &&
is_constructible_v<extents_type, typename _StridedLayoutMapping::extents_type> &&
_StridedLayoutMapping::is_always_unique() && _StridedLayoutMapping::is_always_strided())
- _LIBCPP_HIDE_FROM_ABI constexpr explicit(
- !(is_convertible_v<typename _StridedLayoutMapping::extents_type, extents_type> &&
- (__mdspan_detail::__is_mapping_of<layout_left, _StridedLayoutMapping> ||
- __mdspan_detail::__is_mapping_of<layout_right, _StridedLayoutMapping> ||
- __mdspan_detail::__is_mapping_of<layout_stride, _StridedLayoutMapping>)))
- mapping(const _StridedLayoutMapping& __other) noexcept
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(!(
+ is_convertible_v<typename _StridedLayoutMapping::extents_type, extents_type> &&
+ (__mdspan_detail::__is_mapping_of<layout_left, _StridedLayoutMapping> ||
+ __mdspan_detail::__is_mapping_of<layout_right, _StridedLayoutMapping> ||
+ __mdspan_detail::__is_mapping_of<layout_stride, _StridedLayoutMapping>
+# if _LIBCPP_STD_VER >= 26
+ || __mdspan_detail::__layout_left_padded_mapping_of<_StridedLayoutMapping> ||
+ __mdspan_detail::__layout_right_padded_mapping_of<_StridedLayoutMapping>
+# endif
+ ))) mapping(const _StridedLayoutMapping& __other) noexcept
: __extents_(__other.extents()), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) {
// stride() only compiles for rank > 0
if constexpr (__rank_ > 0) {
diff --git a/libcxx/include/mdspan b/libcxx/include/mdspan
index 0527524d6211b..19114c8b380e5 100644
--- a/libcxx/include/mdspan
+++ b/libcxx/include/mdspan
@@ -97,12 +97,12 @@ namespace std {
class layout_left::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 index_type = extents_type::index_type;
+ using size_type = extents_type::size_type;
+ using rank_type = extents_type::rank_type;
using layout_type = layout_left;
- // [mdspan.layout.right.cons], constructors
+ // [mdspan.layout.left.cons], constructors
constexpr mapping() noexcept = default;
constexpr mapping(const mapping&) noexcept = default;
constexpr mapping(const extents_type&) noexcept;
@@ -112,13 +112,17 @@ namespace std {
template<class OtherExtents>
constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
mapping(const layout_right::mapping<OtherExtents>&) noexcept;
+ template<class LayoutLeftPaddedMapping>
+ constexpr explicit(!is_convertible_v<typename LayoutLeftPaddedMapping::extents_type,
+ extents_type>)
+ mapping(const LayoutLeftPaddedMapping&) noexcept;
template<class OtherExtents>
- constexpr explicit(extents_type::rank() > 0)
- mapping(const layout_stride::mapping<OtherExtents>&) noexcept;
+ constexpr explicit(see below)
+ mapping(const layout_stride::mapping<OtherExtents>&);
constexpr mapping& operator=(const mapping&) noexcept = default;
- // [mdspan.layout.right.obs], observers
+ // [mdspan.layout.left.obs], observers
constexpr const extents_type& extents() const noexcept { return extents_; }
constexpr index_type required_span_size() const noexcept;
@@ -140,7 +144,18 @@ namespace std {
friend constexpr bool operator==(const mapping&, const mapping<OtherExtents>&) noexcept;
private:
- extents_type extents_{}; // exposition only
+ extents_type extents_{}; // exposition only
+
+ // [mdspan.sub.map], submdspan mapping specialization
+ template<class... SliceSpecifiers>
+ constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const // exposition only
+ -> see below;
+
+ template<class... SliceSpecifiers>
+ friend constexpr auto submdspan_mapping(
+ const mapping& src, SliceSpecifiers... slices) {
+ return src.submdspan-mapping-impl(slices...);
+ }
};
}
@@ -151,9 +166,9 @@ namespace std {
class layout_right::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 index_type = extents_type::index_type;
+ using size_type = extents_type::size_type;
+ using rank_type = extents_type::rank_type;
using layout_type = layout_right;
// [mdspan.layout.right.cons], constructors
@@ -166,8 +181,12 @@ namespace std {
template<class OtherExtents>
constexpr explicit(!is_convertible_v<OtherExtents, extents_type>)
mapping(const layout_left::mapping<OtherExtents>&) noexcept;
+ template<class LayoutRightPaddedMapping>
+ constexpr explicit(!is_convertible_v<typename LayoutRightPaddedMapping::extents_type,
+ extents_type>)
+ mapping(const LayoutRightPaddedMapping&) noexcept;
template<class OtherExtents>
- constexpr explicit(extents_type::rank() > 0)
+ constexpr explicit(see below)
mapping(const layout_stride::mapping<OtherExtents>&) noexcept;
constexpr mapping& operator=(const mapping&) noexcept = default;
@@ -195,19 +214,31 @@ namespace std {
private:
extents_type extents_{}; // exposition only
+
+ // [mdspan.sub.map], submdspan mapping specialization
+ template<class... SliceSpecifiers>
+ constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const // exposition only
+ -> see below;
+
+ template<class... SliceSpecifiers>
+ friend constexpr auto submdspan_mapping(
+ const mapping& src, SliceSpecifiers... slices) {
+ return src.submdspan-mapping-impl(slices...);
+ }
};
}
// layout_stride synopsis
+layout_stride provides a layout mapping where the strides are user-defined.
namespace std {
template<class Extents>
class layout_stride::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 index_type = extents_type::index_type;
+ using size_type = extents_type::size_type;
+ using rank_type = extents_type::rank_type;
using layout_type = layout_stride;
private:
@@ -237,7 +268,7 @@ namespace std {
constexpr index_type operator()(Indices...) const noexcept;
static constexpr bool is_always_unique() noexcept { return true; }
- static constexpr bool is_always_exhaustive() noexcept { return false; }
+ static constexpr bool is_always_exhaustive() noexcept;
static constexpr bool is_always_strided() noexcept { return true; }
static constexpr bool is_unique() noexcept { return true; }
@@ -252,6 +283,17 @@ namespace std {
private:
extents_type extents_{}; // exposition only
array<index_type, rank_> strides_{}; // exposition only
+
+ // [mdspan.sub.map], submdspan mapping specialization
+ template<class... SliceSpecifiers>
+ constexpr auto submdspan-mapping-impl(SliceSpecifiers...) const // exposition only
+ -> see below;
+
+ template<class... SliceSpecifiers>
+ friend constexpr auto submdspan_mapping(
+ const mapping& src, SliceSpecifiers... slices) {
+ return src.submdspan-mapping-impl(slices...);
+ }
};
}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_left_padded.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_left_padded.pass.cpp
new file mode 100644
index 0000000000000..581639011b46a
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_left_padded.pass.cpp
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutLeftPaddedMapping>
+// constexpr mapping(const LayoutLeftPaddedMapping& other) noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ ASSERT_NOEXCEPT(Dst(source));
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_left_padded<4>::mapping<std::extents<size_t>>;
+ using Dst = std::layout_left::mapping<std::extents<size_t>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left_padded<4>::mapping<std::extents<size_t, 5>>;
+ using Dst = std::layout_left::mapping<std::extents<size_t, D>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left_padded<4>::mapping<std::extents<size_t, 4, 7>>;
+ using DstStatic = std::layout_left::mapping<std::extents<size_t, 4, 7>>;
+ using DstDynamic = std::layout_left::mapping<std::extents<size_t, D, 7>>;
+ Src source;
+ test_conversion<true, DstStatic>(source);
+ test_conversion<true, DstDynamic>(source);
+ }
+
+ {
+ using Src = std::layout_left_padded<D>::mapping<std::extents<size_t, D, D>>;
+ using Dst = std::layout_left::mapping<std::extents<size_t, D, D>>;
+ Src source(std::extents<size_t, D, D>(7, 4), 7);
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_left_padded<D>::mapping<std::extents<size_t, D, 7>>;
+ using Dst = std::layout_left::mapping<std::extents<size_t, 4, 7>>;
+ Src source(std::extents<size_t, D, 7>(4), 4);
+ test_conversion<false, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_right_padded.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_right_padded.pass.cpp
new file mode 100644
index 0000000000000..7ba04806d9829
--- /dev/null
+++ b/libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_right_padded.pass.cpp
@@ -0,0 +1,97 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: std-at-least-c++26
+
+// <mdspan>
+
+// template<class LayoutRightPaddedMapping>
+// constexpr mapping(const LayoutRightPaddedMapping& other) noexcept;
+
+#include <cassert>
+#include <cstddef>
+#include <mdspan>
+#include <type_traits>
+
+#include "test_macros.h"
+
+template <class Dst, class Src>
+constexpr void assert_same_mapping(const Dst& dst, const Src& src) {
+ assert(dst.extents() == src.extents());
+
+ if constexpr (Dst::extents_type::rank() > 0) {
+ for (typename Dst::rank_type r = 0; r < Dst::extents_type::rank(); ++r)
+ assert(dst.stride(r) == static_cast<typename Dst::index_type>(src.stride(r)));
+ }
+}
+
+template <bool Implicit, class Dst, class Src>
+constexpr void test_conversion(const Src& source) {
+ static_assert(std::is_constructible_v<Dst, Src>);
+
+ ASSERT_NOEXCEPT(Dst(source));
+
+ Dst direct(source);
+ assert_same_mapping(direct, source);
+
+ if constexpr (Implicit) {
+ Dst implicit = source;
+ assert_same_mapping(implicit, source);
+ } else {
+ static_assert(!std::is_convertible_v<Src, Dst>);
+ }
+}
+
+constexpr bool test() {
+ constexpr size_t D = std::dynamic_extent;
+
+ {
+ using Src = std::layout_right_padded<4>::mapping<std::extents<size_t>>;
+ using Dst = std::layout_right::mapping<std::extents<size_t>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right_padded<4>::mapping<std::extents<size_t, 5>>;
+ using Dst = std::layout_right::mapping<std::extents<size_t, D>>;
+ Src source;
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right_padded<4>::mapping<std::extents<size_t, 4, 8>>;
+ using DstStatic = std::layout_right::mapping<std::extents<size_t, 4, 8>>;
+ using DstDynamic = std::layout_right::mapping<std::extents<size_t, D, 8>>;
+ Src source;
+ test_conversion<true, DstStatic>(source);
+ test_conversion<true, DstDynamic>(source);
+ }
+
+ {
+ using Src = std::layout_right_padded<D>::mapping<std::extents<size_t, D, D>>;
+ using Dst = std::layout_right::mapping<std::extents<size_t, D, D>>;
+ Src source(std::extents<size_t, D, D>(4, 7), 7);
+ test_conversion<true, Dst>(source);
+ }
+
+ {
+ using Src = std::layout_right_padded<D>::mapping<std::extents<size_t, D, 8>>;
+ using Dst = std::layout_right::mapping<std::extents<size_t, 4, 8>>;
+ Src source(std::extents<size_t, D, 8>(4), 4);
+ test_conversion<false, Dst>(source);
+ }
+
+ return true;
+}
+
+int main() {
+ test();
+ static_assert(test());
+ return 0;
+}
>From 3eba8b93bf41ee27c008eb58a77822563f168e08 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Sun, 22 Mar 2026 02:06:23 +0800
Subject: [PATCH 3/6] fix CI
---
libcxx/include/CMakeLists.txt | 4 ++--
libcxx/include/module.modulemap.in | 17 ++++++++++-------
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 3a6061099c74d..163b6afd0b7cf 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -574,11 +574,11 @@ set(files
__mdspan/aligned_accessor.h
__mdspan/default_accessor.h
__mdspan/extents.h
+ __mdspan/layout_common.h
__mdspan/layout_left.h
__mdspan/layout_left_padded.h
- __mdspan/layout_common.h
- __mdspan/layout_right_padded.h
__mdspan/layout_right.h
+ __mdspan/layout_right_padded.h
__mdspan/layout_stride.h
__mdspan/mdspan.h
__memory/addressof.h
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index d6e8289b7c8b0..dec1f8fe95191 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1632,13 +1632,16 @@ module std [system] {
}
module mdspan {
- module aligned_accessor { header "__mdspan/aligned_accessor.h" }
- module default_accessor { header "__mdspan/default_accessor.h" }
- module extents { header "__mdspan/extents.h" }
- module fwd { header "__fwd/mdspan.h" }
- module layout_left { header "__mdspan/layout_left.h" }
- module layout_right { header "__mdspan/layout_right.h" }
- module layout_stride { header "__mdspan/layout_stride.h" }
+ module aligned_accessor { header "__mdspan/aligned_accessor.h" }
+ module default_accessor { header "__mdspan/default_accessor.h" }
+ module extents { header "__mdspan/extents.h" }
+ module fwd { header "__fwd/mdspan.h" }
+ module layout_common { header "__mdspan/layout_common.h" }
+ module layout_left { header "__mdspan/layout_left.h" }
+ module layout_left_padded { header "__mdspan/layout_left_padded.h" }
+ module layout_right { header "__mdspan/layout_right.h" }
+ module layout_right_padded { header "__mdspan/layout_right_padded.h" }
+ module layout_stride { header "__mdspan/layout_stride.h" }
module mdspan {
header "__mdspan/mdspan.h"
export std.array // returned by some methods
>From ce389876f6297d02b0042ea2bd5c8d701e8404d7 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Sun, 22 Mar 2026 02:26:32 +0800
Subject: [PATCH 4/6] fix CI
---
libcxx/include/__fwd/mdspan.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__fwd/mdspan.h b/libcxx/include/__fwd/mdspan.h
index 8c069577ab2a9..ea3fac58fe974 100644
--- a/libcxx/include/__fwd/mdspan.h
+++ b/libcxx/include/__fwd/mdspan.h
@@ -18,8 +18,8 @@
#define _LIBCPP___MDSPAN_LAYOUTS_H
#include <__config>
-#include <cstddef>
-#include <span>
+#include <__cstddef/size_t.h>
+#include <__fwd/span.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
>From bc4dec6a4d9943f71952f5f6fd0af8cded9dba8f Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Sun, 22 Mar 2026 18:19:29 +0800
Subject: [PATCH 5/6] fix CI
---
libcxx/include/__mdspan/layout_common.h | 5 +++++
libcxx/include/__mdspan/layout_left.h | 1 +
libcxx/include/__mdspan/layout_left_padded.h | 1 +
libcxx/include/__mdspan/layout_right.h | 1 +
libcxx/include/__mdspan/layout_right_padded.h | 1 +
.../views/mdspan/layout_left_padded/ctor.copy.pass.cpp | 2 ++
.../views/mdspan/layout_left_padded/ctor.default.pass.cpp | 1 +
.../views/mdspan/layout_left_padded/ctor.extents.pass.cpp | 1 +
.../views/mdspan/layout_left_padded/properties.pass.cpp | 2 ++
.../mdspan/layout_left_padded/required_span_size.pass.cpp | 1 +
.../mdspan/layout_left_padded/static_requirements.pass.cpp | 1 +
.../views/mdspan/layout_right_padded/ctor.copy.pass.cpp | 2 ++
.../views/mdspan/layout_right_padded/ctor.default.pass.cpp | 1 +
.../views/mdspan/layout_right_padded/ctor.extents.pass.cpp | 1 +
.../views/mdspan/layout_right_padded/properties.pass.cpp | 2 ++
.../mdspan/layout_right_padded/required_span_size.pass.cpp | 1 +
.../mdspan/layout_right_padded/static_requirements.pass.cpp | 1 +
17 files changed, 25 insertions(+)
diff --git a/libcxx/include/__mdspan/layout_common.h b/libcxx/include/__mdspan/layout_common.h
index 77ad5a0f4e6b4..56748e6343cc4 100644
--- a/libcxx/include/__mdspan/layout_common.h
+++ b/libcxx/include/__mdspan/layout_common.h
@@ -17,10 +17,15 @@
#ifndef _LIBCPP___MDSPAN_LAYOUT_COMMON_H
#define _LIBCPP___MDSPAN_LAYOUT_COMMON_H
+#include <__concepts/same_as.h>
#include <__config>
+#include <__cstddef/size_t.h>
#include <__fwd/mdspan.h>
+#include <__fwd/span.h>
#include <__mdspan/extents.h>
#include <__memory/addressof.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/is_same.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
diff --git a/libcxx/include/__mdspan/layout_left.h b/libcxx/include/__mdspan/layout_left.h
index 6eff932067d49..84ab647bd0792 100644
--- a/libcxx/include/__mdspan/layout_left.h
+++ b/libcxx/include/__mdspan/layout_left.h
@@ -20,6 +20,7 @@
#include <__assert>
#include <__config>
#include <__fwd/mdspan.h>
+#include <__fwd/span.h>
#include <__mdspan/extents.h>
#include <__mdspan/layout_common.h>
#include <__memory/addressof.h>
diff --git a/libcxx/include/__mdspan/layout_left_padded.h b/libcxx/include/__mdspan/layout_left_padded.h
index 1888fcd5cf691..aedffd917f098 100644
--- a/libcxx/include/__mdspan/layout_left_padded.h
+++ b/libcxx/include/__mdspan/layout_left_padded.h
@@ -20,6 +20,7 @@
#include <__assert>
#include <__config>
#include <__fwd/mdspan.h>
+#include <__fwd/span.h>
#include <__mdspan/extents.h>
#include <__mdspan/layout_common.h>
#include <__mdspan/layout_left.h>
diff --git a/libcxx/include/__mdspan/layout_right.h b/libcxx/include/__mdspan/layout_right.h
index 36f376cd4cf98..7e3df54658258 100644
--- a/libcxx/include/__mdspan/layout_right.h
+++ b/libcxx/include/__mdspan/layout_right.h
@@ -21,6 +21,7 @@
#include <__config>
#include <__cstddef/size_t.h>
#include <__fwd/mdspan.h>
+#include <__fwd/span.h>
#include <__mdspan/extents.h>
#include <__mdspan/layout_common.h>
#include <__memory/addressof.h>
diff --git a/libcxx/include/__mdspan/layout_right_padded.h b/libcxx/include/__mdspan/layout_right_padded.h
index 9b479d0b34bef..f6a34972de453 100644
--- a/libcxx/include/__mdspan/layout_right_padded.h
+++ b/libcxx/include/__mdspan/layout_right_padded.h
@@ -20,6 +20,7 @@
#include <__assert>
#include <__config>
#include <__fwd/mdspan.h>
+#include <__fwd/span.h>
#include <__mdspan/extents.h>
#include <__mdspan/layout_common.h>
#include <__mdspan/layout_left.h>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.copy.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.copy.pass.cpp
index c7a2f622aef9e..ca5b5bfc22b7d 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.copy.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.copy.pass.cpp
@@ -15,7 +15,9 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
+#include <utility>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.default.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.default.pass.cpp
index a36e548c72d0d..098ffd1bd414c 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.default.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.default.pass.cpp
@@ -14,6 +14,7 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.extents.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.extents.pass.cpp
index 7bc4ffae3c25c..660ffe331785b 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.extents.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/ctor.extents.pass.cpp
@@ -15,6 +15,7 @@
#include <array>
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
template <size_t PaddingValue, class Extents>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/properties.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/properties.pass.cpp
index b77dcf99c4794..339359ff268f9 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left_padded/properties.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/properties.pass.cpp
@@ -25,7 +25,9 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
+#include <utility>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/required_span_size.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/required_span_size.pass.cpp
index 8306c7bfd7e7a..05cd2211d5918 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left_padded/required_span_size.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/required_span_size.pass.cpp
@@ -14,6 +14,7 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/static_requirements.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/static_requirements.pass.cpp
index 82a9bb90e50f8..56608c7477573 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left_padded/static_requirements.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/static_requirements.pass.cpp
@@ -11,6 +11,7 @@
// <mdspan>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
#include <type_traits>
#include <utility>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.copy.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.copy.pass.cpp
index 8bdc53ee4e32b..7011547a91cc1 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.copy.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.copy.pass.cpp
@@ -15,7 +15,9 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
+#include <utility>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.default.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.default.pass.cpp
index 73e6dc3288337..e34614a4805e8 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.default.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.default.pass.cpp
@@ -14,6 +14,7 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.extents.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.extents.pass.cpp
index 6526b54b963f9..98dd573d77ab3 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.extents.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/ctor.extents.pass.cpp
@@ -15,6 +15,7 @@
#include <array>
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
template <size_t PaddingValue, class Extents>
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/properties.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/properties.pass.cpp
index 0adaab5c4d14c..d1ca3ed28a679 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right_padded/properties.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/properties.pass.cpp
@@ -25,7 +25,9 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
+#include <utility>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/required_span_size.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/required_span_size.pass.cpp
index e4289707d5702..92f0658cc1125 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right_padded/required_span_size.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/required_span_size.pass.cpp
@@ -14,6 +14,7 @@
#include <cassert>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
#include "test_macros.h"
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/static_requirements.pass.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/static_requirements.pass.cpp
index 033ffce606911..27fd566b88829 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right_padded/static_requirements.pass.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/static_requirements.pass.cpp
@@ -11,6 +11,7 @@
// <mdspan>
#include <cstddef>
+#include <cstdint>
#include <mdspan>
#include <type_traits>
#include <utility>
>From 7b32242a766b75b5e7cf52266692f9c054dd3689 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Tue, 24 Mar 2026 12:07:16 +0800
Subject: [PATCH 6/6] add test
---
.../mdspan/layout_left_padded/extents.verify.cpp | 12 +++++++++---
.../mdspan/layout_right_padded/extents.verify.cpp | 12 +++++++++---
2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/libcxx/test/std/containers/views/mdspan/layout_left_padded/extents.verify.cpp b/libcxx/test/std/containers/views/mdspan/layout_left_padded/extents.verify.cpp
index 03e86d61050f9..f061d9a93bb3f 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_left_padded/extents.verify.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_left_padded/extents.verify.cpp
@@ -13,6 +13,7 @@
// template<class Extents>
// class layout_left_padded::mapping;
+#include <cstdint>
#include <mdspan>
void not_extents() {
@@ -22,15 +23,20 @@ void not_extents() {
void index_space_representable() {
// expected-error@*:* {{layout_left_padded::mapping index space for static extents must be representable as index_type.}}
- [[maybe_unused]] std::layout_left_padded<4>::mapping<std::extents<signed char, 20, 20>> mapping;
+ [[maybe_unused]] std::layout_left_padded<4>::mapping<std::extents<int8_t, 20, 20>> mapping;
+}
+
+void padding_value_representable() {
+ // expected-error@*:* {{layout_left_padded::mapping padding_value must be representable as index_type.}}
+ [[maybe_unused]] std::layout_left_padded<128>::mapping<std::extents<int8_t, 1>> mapping;
}
void padding_stride_representable() {
// expected-error@*:* {{layout_left_padded::mapping padded stride for the first static extent must be representable as size_t and index_type.}}
- [[maybe_unused]] std::layout_left_padded<4>::mapping<std::extents<signed char, 127, 1>> mapping;
+ [[maybe_unused]] std::layout_left_padded<4>::mapping<std::extents<int8_t, 127, 1>> mapping;
}
void padded_product_representable() {
// expected-error@*:* {{layout_left_padded::mapping required span size for static extents must be representable as size_t and index_type.}}
- [[maybe_unused]] std::layout_left_padded<64>::mapping<std::extents<signed char, 63, 2>> mapping;
+ [[maybe_unused]] std::layout_left_padded<64>::mapping<std::extents<int8_t, 63, 2>> mapping;
}
diff --git a/libcxx/test/std/containers/views/mdspan/layout_right_padded/extents.verify.cpp b/libcxx/test/std/containers/views/mdspan/layout_right_padded/extents.verify.cpp
index 370d8e1b453e4..238d9ba66dff1 100644
--- a/libcxx/test/std/containers/views/mdspan/layout_right_padded/extents.verify.cpp
+++ b/libcxx/test/std/containers/views/mdspan/layout_right_padded/extents.verify.cpp
@@ -13,6 +13,7 @@
// template<class Extents>
// class layout_right_padded::mapping;
+#include <cstdint>
#include <mdspan>
void not_extents() {
@@ -22,15 +23,20 @@ void not_extents() {
void index_space_representable() {
// expected-error@*:* {{layout_right_padded::mapping index space for static extents must be representable as index_type.}}
- [[maybe_unused]] std::layout_right_padded<4>::mapping<std::extents<signed char, 20, 20>> mapping;
+ [[maybe_unused]] std::layout_right_padded<4>::mapping<std::extents<int8_t, 20, 20>> mapping;
+}
+
+void padding_value_representable() {
+ // expected-error@*:* {{layout_right_padded::mapping padding_value must be representable as index_type.}}
+ [[maybe_unused]] std::layout_right_padded<128>::mapping<std::extents<int8_t, 1>> mapping;
}
void padding_stride_representable() {
// expected-error@*:* {{layout_right_padded::mapping padded stride for the last static extent must be representable as size_t and index_type.}}
- [[maybe_unused]] std::layout_right_padded<4>::mapping<std::extents<signed char, 0, 127>> mapping;
+ [[maybe_unused]] std::layout_right_padded<4>::mapping<std::extents<int8_t, 0, 127>> mapping;
}
void padded_product_representable() {
// expected-error@*:* {{layout_right_padded::mapping required span size for static extents must be representable as size_t and index_type.}}
- [[maybe_unused]] std::layout_right_padded<64>::mapping<std::extents<signed char, 2, 63>> mapping;
+ [[maybe_unused]] std::layout_right_padded<64>::mapping<std::extents<int8_t, 2, 63>> mapping;
}
More information about the libcxx-commits
mailing list