[libcxx-commits] [libcxx] [libc++] mdspan - implement layout_stride (PR #69650)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Oct 19 15:27:18 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: Christian Trott (crtrott)
<details>
<summary>Changes</summary>
This implements layout_stride for C++23 and with that completes the implementation of the C++23 mdspan header. The feature test macro is added, and the status pages updated.
Co-authored-by: Damien L-G <dalg24@<!-- -->gmail.com>
Differential Revision: https://reviews.llvm.org/D157171
---
Patch is 156.98 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/69650.diff
67 Files Affected:
- (modified) libcxx/docs/FeatureTestMacroTable.rst (+1-1)
- (modified) libcxx/docs/Status/Cxx23.rst (-1)
- (modified) libcxx/docs/Status/Cxx23Papers.csv (+4-4)
- (modified) libcxx/include/CMakeLists.txt (+1)
- (modified) libcxx/include/__fwd/mdspan.h (+2-5)
- (modified) libcxx/include/__mdspan/layout_left.h (+21-6)
- (modified) libcxx/include/__mdspan/layout_right.h (+21-6)
- (added) libcxx/include/__mdspan/layout_stride.h (+366)
- (modified) libcxx/include/mdspan (+59)
- (modified) libcxx/include/module.modulemap.in (+1)
- (modified) libcxx/include/version (+1-1)
- (modified) libcxx/modules/std/mdspan.inc (+1-1)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_left/assert.ctor.layout_stride.pass.cpp (+83)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_right/assert.ctor.layout_stride.pass.cpp (+83)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.conversion.pass.cpp (+112)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.non_unique.pass.cpp (+67)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_array.pass.cpp (+73)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.non_unique.pass.cpp (+70)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.ctor.extents_span.pass.cpp (+80)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.index_operator.pass.cpp (+88)
- (added) libcxx/test/libcxx/containers/views/mdspan/layout_stride/assert.stride.pass.cpp (+36)
- (modified) libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.conversion.pass.cpp (+1-1)
- (modified) libcxx/test/libcxx/containers/views/mdspan/mdspan/assert.size.pass.cpp (+1-1)
- (modified) libcxx/test/libcxx/transitive_includes/cxx03.csv (+1)
- (modified) libcxx/test/libcxx/transitive_includes/cxx11.csv (+1)
- (modified) libcxx/test/libcxx/transitive_includes/cxx14.csv (+1)
- (modified) libcxx/test/libcxx/transitive_includes/cxx17.csv (+1)
- (modified) libcxx/test/libcxx/transitive_includes/cxx20.csv (+1)
- (modified) libcxx/test/libcxx/transitive_includes/cxx23.csv (+1)
- (modified) libcxx/test/libcxx/transitive_includes/cxx26.csv (+1)
- (renamed) libcxx/test/std/containers/views/mdspan/CustomTestLayouts.h (+30-17)
- (added) libcxx/test/std/containers/views/mdspan/layout_left/ctor.layout_stride.pass.cpp (+114)
- (added) libcxx/test/std/containers/views/mdspan/layout_right/ctor.layout_stride.pass.cpp (+114)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/comparison.pass.cpp (+198)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/ctor.default.pass.cpp (+73)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/ctor.extents_array.pass.cpp (+138)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/ctor.extents_span.pass.cpp (+141)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/ctor.strided_mapping.pass.cpp (+187)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/deduction.pass.cpp (+55)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/extents.verify.cpp (+33)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/index_operator.pass.cpp (+121)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/is_exhaustive_corner_case.pass.cpp (+54)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/properties.pass.cpp (+116)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/required_span_size.pass.cpp (+56)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/static_requirements.pass.cpp (+131)
- (added) libcxx/test/std/containers/views/mdspan/layout_stride/stride.pass.cpp (+57)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/assign.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/conversion.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/conversion.verify.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.copy.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.default.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_array.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_extents.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_integers.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_map_acc.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.dh_span.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/ctor.move.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/deduction.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/index_operator.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/move.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/properties.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/swap.pass.cpp (+1-1)
- (modified) libcxx/test/std/containers/views/mdspan/mdspan/types.pass.cpp (+1-1)
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/mdspan.version.compile.pass.cpp (+10-22)
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+10-22)
- (modified) libcxx/utils/generate_feature_test_macro_components.py (-1)
``````````diff
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 2b21ec3d2fe23ac..10afd64e0a39469 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -332,7 +332,7 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_is_scoped_enum`` ``202011L``
--------------------------------------------------- -----------------
- ``__cpp_lib_mdspan`` *unimplemented*
+ ``__cpp_lib_mdspan`` ``202207L``
--------------------------------------------------- -----------------
``__cpp_lib_move_only_function`` *unimplemented*
--------------------------------------------------- -----------------
diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst
index 5b4d9a6fe943d45..839640a7c7e881b 100644
--- a/libcxx/docs/Status/Cxx23.rst
+++ b/libcxx/docs/Status/Cxx23.rst
@@ -40,7 +40,6 @@ Paper Status
.. note::
- .. [#note-P0009R18] P0009R18: ``extents``, ``dextents``, ``layout_left``, ``layout_right``, and ``default_accessor`` are implemented.
.. [#note-P0533R9] P0533R9: ``isfinite``, ``isinf``, ``isnan`` and ``isnormal`` are implemented.
.. [#note-P1413R3] P1413R3: ``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but
clang doesn't issue a diagnostic for deprecated using template declarations.
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index 35319fb7576d3c6..0513a4a6e9fe9b5 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -51,7 +51,7 @@
"`P2442R1 <https://wg21.link/P2442R1>`__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|"
"`P2443R1 <https://wg21.link/P2443R1>`__","LWG","``views::chunk_by``","February 2022","|Complete|","18.0","|ranges|"
"","","","","","",""
-"`P0009R18 <https://wg21.link/P0009R18>`__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","|In progress| [#note-P0009R18]_",""
+"`P0009R18 <https://wg21.link/P0009R18>`__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","|Complete|","18.0"
"`P0429R9 <https://wg21.link/P0429R9>`__","LWG","A Standard ``flat_map``","July 2022","",""
"`P1169R4 <https://wg21.link/P1169R4>`__","LWG","``static operator()``","July 2022","|Complete|","16.0"
"`P1222R4 <https://wg21.link/P1222R4>`__","LWG","A Standard ``flat_set``","July 2022","",""
@@ -89,9 +89,9 @@
"`P2549R1 <https://wg21.link/P2549R1>`__","LWG","``std::unexpected`` should have ``error()`` as member accessor","July 2022","|Complete|","16.0"
"`P2585R0 <https://wg21.link/P2585R0>`__","LWG","Improving default container formatting","July 2022","|Complete|","17.0"
"`P2590R2 <https://wg21.link/P2590R2>`__","LWG","Explicit lifetime management","July 2022","",""
-"`P2599R2 <https://wg21.link/P2599R2>`__","LWG","``mdspan::size_type`` should be ``index_type``","July 2022","",""
-"`P2604R0 <https://wg21.link/P2604R0>`__","LWG","mdspan: rename pointer and contiguous","July 2022","",""
-"`P2613R1 <https://wg21.link/P2613R1>`__","LWG","Add the missing ``empty`` to ``mdspan``","July 2022","",""
+"`P2599R2 <https://wg21.link/P2599R2>`__","LWG","``mdspan::size_type`` should be ``index_type``","July 2022","|Complete|","18.0"
+"`P2604R0 <https://wg21.link/P2604R0>`__","LWG","mdspan: rename pointer and contiguous","July 2022","|Complete|","18.0"
+"`P2613R1 <https://wg21.link/P2613R1>`__","LWG","Add the missing ``empty`` to ``mdspan``","July 2022","|Complete|","18.0"
"","","","","","",""
"`P1202R5 <https://wg21.link/P1202R5>`__","LWG", "Asymmetric Fences", "November 2022","","","|concurrency TS|"
"`P1264R2 <https://wg21.link/P1264R2>`__","LWG", "Revising the wording of ``stream`` input operations", "November 2022","|Complete|","9.0",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 9b03430a87d8338..85470c5b337f39f 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -508,6 +508,7 @@ set(files
__mdspan/extents.h
__mdspan/layout_left.h
__mdspan/layout_right.h
+ __mdspan/layout_stride.h
__mdspan/mdspan.h
__memory/addressof.h
__memory/align.h
diff --git a/libcxx/include/__fwd/mdspan.h b/libcxx/include/__fwd/mdspan.h
index a3628c2d60dcc8f..8889567a047f6ec 100644
--- a/libcxx/include/__fwd/mdspan.h
+++ b/libcxx/include/__fwd/mdspan.h
@@ -42,14 +42,11 @@ struct layout_right {
class mapping;
};
-/*
-// Will be implemented with follow on revision
// Layout policy with a unique mapping where strides are arbitrary
struct layout_stride {
- template<class Extents>
- class mapping;
+ template <class _Extents>
+ class mapping;
};
-*/
#endif // _LIBCPP_STD_VER >= 23
diff --git a/libcxx/include/__mdspan/layout_left.h b/libcxx/include/__mdspan/layout_left.h
index 5faae597f6f81fd..fd644fa0c53226b 100644
--- a/libcxx/include/__mdspan/layout_left.h
+++ b/libcxx/include/__mdspan/layout_left.h
@@ -110,12 +110,27 @@ class layout_left::mapping {
"layout_left::mapping converting ctor: other.required_span_size() must be representable as index_type.");
}
-// FIXME: add when we add other layouts
-# if 0
- template<class _OtherExtents>
- constexpr explicit(extents_type::rank() > 0)
- mapping(const layout_stride::mapping_<OtherExtents>&) noexcept;
-# endif
+ template <class _OtherExtents>
+ requires(is_constructible_v<extents_type, _OtherExtents>)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0)
+ mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept
+ : __extents_(__other.extents()) {
+ if constexpr (extents_type::rank() > 0) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ ([&]() {
+ using _CommonType = common_type_t<typename extents_type::index_type, typename _OtherExtents::index_type>;
+ for (rank_type __r = 0; __r < extents_type::rank(); __r++)
+ if (static_cast<_CommonType>(stride(__r)) != static_cast<_CommonType>(__other.stride(__r)))
+ return false;
+ return true;
+ }()),
+ "layout_left::mapping from layout_stride ctor: strides are not compatible with layout_left.");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_left::mapping from layout_stride ctor: other.required_span_size() must be representable as "
+ "index_type.");
+ }
+ }
_LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default;
diff --git a/libcxx/include/__mdspan/layout_right.h b/libcxx/include/__mdspan/layout_right.h
index 4f95789a2fafcc9..8e64d07dd52309c 100644
--- a/libcxx/include/__mdspan/layout_right.h
+++ b/libcxx/include/__mdspan/layout_right.h
@@ -109,12 +109,27 @@ class layout_right::mapping {
"layout_right::mapping converting ctor: other.required_span_size() must be representable as index_type.");
}
-// FIXME: add when we add other layouts
-# if 0
- template<class _OtherExtents>
- constexpr explicit(extents_type::rank() > 0)
- mapping(const layout_stride::mapping_<OtherExtents>&) noexcept;
-# endif
+ template <class _OtherExtents>
+ requires(is_constructible_v<extents_type, _OtherExtents>)
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit(extents_type::rank() > 0)
+ mapping(const layout_stride::mapping<_OtherExtents>& __other) noexcept
+ : __extents_(__other.extents()) {
+ if constexpr (extents_type::rank() > 0) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ ([&]() {
+ using _CommonType = common_type_t<typename extents_type::index_type, typename _OtherExtents::index_type>;
+ for (rank_type __r = 0; __r < extents_type::rank(); __r++)
+ if (static_cast<_CommonType>(stride(__r)) != static_cast<_CommonType>(__other.stride(__r)))
+ return false;
+ return true;
+ }()),
+ "layout_right::mapping from layout_stride ctor: strides are not compatible with layout_right.");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_right::mapping from layout_stride ctor: other.required_span_size() must be representable as "
+ "index_type.");
+ }
+ }
_LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default;
diff --git a/libcxx/include/__mdspan/layout_stride.h b/libcxx/include/__mdspan/layout_stride.h
new file mode 100644
index 000000000000000..77934bfa11d9de0
--- /dev/null
+++ b/libcxx/include/__mdspan/layout_stride.h
@@ -0,0 +1,366 @@
+// -*- 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_STRIDE_H
+#define _LIBCPP___MDSPAN_LAYOUT_STRIDE_H
+
+#include <__assert>
+#include <__config>
+#include <__fwd/mdspan.h>
+#include <__mdspan/extents.h>
+#include <__type_traits/is_constructible.h>
+#include <__type_traits/is_convertible.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__utility/as_const.h>
+#include <__utility/integer_sequence.h>
+#include <__utility/swap.h>
+#include <array>
+#include <cinttypes>
+#include <cstddef>
+#include <limits>
+
+#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
+
+template <class _Extents>
+class layout_stride::mapping {
+public:
+ static_assert(__mdspan_detail::__is_extents<_Extents>::value,
+ "layout_stride::mapping template argument must be a specialization of extents.");
+
+ using extents_type = _Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = layout_stride;
+
+private:
+ static constexpr rank_type __rank_ = extents_type::rank();
+
+ // Used for default construction check and mandates
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) {
+ if constexpr (__rank_ == 0)
+ return true;
+
+ index_type __prod = __ext.extent(0);
+ for (rank_type __r = 1; __r < __rank_; __r++) {
+ bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod);
+ if (__overflowed)
+ return false;
+ }
+ return true;
+ }
+
+ template <class _OtherIndexType>
+ _LIBCPP_HIDE_FROM_ABI static constexpr bool
+ __required_span_size_is_representable(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) {
+ if constexpr (__rank_ == 0)
+ return true;
+
+ index_type __size = 1;
+ for (rank_type __r = 0; __r < __rank_; __r++) {
+ // We can only check correct conversion of _OtherIndexType if it is an integral
+ if constexpr (is_integral_v<_OtherIndexType>) {
+ using _CommonType = common_type_t<index_type, _OtherIndexType>;
+ if (static_cast<_CommonType>(__strides[__r]) > static_cast<_CommonType>(numeric_limits<index_type>::max()))
+ return false;
+ }
+ if (__ext.extent(__r) == static_cast<index_type>(0))
+ return true;
+ index_type __prod = (__ext.extent(__r) - 1);
+ bool __overflowed_mul = __builtin_mul_overflow(__prod, static_cast<index_type>(__strides[__r]), &__prod);
+ if (__overflowed_mul)
+ return false;
+ bool __overflowed_add = __builtin_add_overflow(__size, __prod, &__size);
+ if (__overflowed_add)
+ return false;
+ }
+ return true;
+ }
+
+ // compute offset of a strided layout mapping
+ template <class _StridedMapping>
+ _LIBCPP_HIDE_FROM_ABI static constexpr index_type __offset(const _StridedMapping& __mapping) {
+ if constexpr (_StridedMapping::extents_type::rank() == 0) {
+ return static_cast<index_type>(__mapping());
+ } else if (__mapping.required_span_size() == static_cast<typename _StridedMapping::index_type>(0)) {
+ return static_cast<index_type>(0);
+ } else {
+ return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ return static_cast<index_type>(__mapping((_Pos ? 0 : 0)...));
+ }(make_index_sequence<__rank_>());
+ }
+ }
+
+ // compute the permutation for sorting the stride array
+ // we never actually sort the stride array
+ _LIBCPP_HIDE_FROM_ABI constexpr void __bubble_sort_by_strides(array<rank_type, __rank_>& __permute) const {
+ for (rank_type __i = __rank_ - 1; __i > 0; __i--) {
+ for (rank_type __r = 0; __r < __i; __r++) {
+ if (__strides_[__permute[__r]] > __strides_[__permute[__r + 1]]) {
+ swap(__permute[__r], __permute[__r + 1]);
+ } else {
+ // if two strides are the same then one of the associated extents must be 1 or 0
+ // both could be, but you can't have one larger than 1 come first
+ if ((__strides_[__permute[__r]] == __strides_[__permute[__r + 1]]) &&
+ (__extents_.extent(__permute[__r]) > static_cast<index_type>(1)))
+ swap(__permute[__r], __permute[__r + 1]);
+ }
+ }
+ }
+ }
+
+ static_assert((extents_type::rank_dynamic() > 0) || __required_span_size_is_representable(extents_type()),
+ "layout_stride::mapping product of static extents must be representable as index_type.");
+
+public:
+ // [mdspan.layout.stride.cons], constructors
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : __extents_(extents_type()) {
+ // Note the nominal precondition is covered by above static assert since
+ // if rank_dynamic is != 0 required_span_size is zero for default construction
+ if constexpr (__rank_ > 0) {
+ index_type __stride = 1;
+ for (rank_type __r = __rank_ - 1; __r > static_cast<rank_type>(0); __r--) {
+ __strides_[__r] = __stride;
+ __stride *= __extents_.extent(__r);
+ }
+ __strides_[0] = __stride;
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
+
+ template <class _OtherIndexType>
+ requires(is_convertible_v<const _OtherIndexType&, index_type> &&
+ is_nothrow_constructible_v<index_type, const _OtherIndexType&>)
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) noexcept
+ : __extents_(__ext), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ return __mdspan_detail::__possibly_empty_array<index_type, __rank_>{
+ static_cast<index_type>(std::as_const(__strides[_Pos]))...};
+ }(make_index_sequence<__rank_>())) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ ([&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ // For integrals we can do a pre-conversion check, for other types not
+ if constexpr (is_integral_v<_OtherIndexType>) {
+ return ((__strides[_Pos] > static_cast<_OtherIndexType>(0)) && ... && true);
+ } else {
+ return ((static_cast<index_type>(__strides[_Pos]) > static_cast<index_type>(0)) && ... && true);
+ }
+ }(make_index_sequence<__rank_>())),
+ "layout_stride::mapping ctor: all strides must be greater than 0");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __required_span_size_is_representable(__ext, __strides),
+ "layout_stride::mapping ctor: required span size is not representable as index_type.");
+ if constexpr (__rank_ > 1) {
+ _LIBCPP_ASSERT_UNCATEGORIZED(
+ ([&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ // basically sort the dimensions based on strides and extents, sorting is represented in permute array
+ array<rank_type, __rank_> __permute{_Pos...};
+ __bubble_sort_by_strides(__permute);
+
+ // check that this permutations represents a growing set
+ for (rank_type __i = 1; __i < __rank_; __i++)
+ if (static_cast<index_type>(__strides[__permute[__i]]) <
+ static_cast<index_type>(__strides[__permute[__i - 1]]) * __extents_.extent(__permute[__i - 1]))
+ return false;
+ return true;
+ }(make_index_sequence<__rank_>())),
+ "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping");
+ }
+ }
+
+ template <class _OtherIndexType>
+ requires(is_convertible_v<const _OtherIndexType&, index_type> &&
+ is_nothrow_constructible_v<index_type, const _OtherIndexType&>)
+ _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext,
+ const array<_OtherIndexType, __rank_>& __strides) noexcept
+ : mapping(__ext, span(__strides)) {}
+
+ template <class _StridedLayoutMapping>
+ 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
+ : __extents_(__other.extents()), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ // stride() only compiles for rank > 0
+ if constexpr (__rank_ > 0) {
+ return __mdspan_detail::__possibly_empty_array<index_type, __rank_>{
+ static_cast<index_type>(__other.stride(_Pos))...};
+ } else {
+ return __mdspan_detail::__possibly_empty_array<index_type, 0>{};
+ }
+ }(make_index_sequence<__rank_>())) {
+ // stride() only compiles for rank > 0
+ if constexpr (__rank_ > 0) {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ ([&]<size_t... _Pos>(index_sequence<_Pos...>) {
+ return ((static_cast<index_type>(__other.stride(_Pos)) > static_cast<index_type>(0)) && ... && true);
+ }(make_index_sequence<__rank_>())),
+ "layout_stride::mapping converting ctor: all strides must be greater than 0");
+ }
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+ __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
+ "layout_stride::mapping converting ctor: other.required_span_size() must be representable as index_type.");
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(static_cast<index_type>(0) == __offset(__other),
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/69650
More information about the libcxx-commits
mailing list