File indexing completed on 2026-05-03 08:13:55
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef _LIBCPP___MDSPAN_LAYOUT_STRIDE_H
0018 #define _LIBCPP___MDSPAN_LAYOUT_STRIDE_H
0019
0020 #include <__assert>
0021 #include <__concepts/same_as.h>
0022 #include <__config>
0023 #include <__fwd/mdspan.h>
0024 #include <__mdspan/extents.h>
0025 #include <__type_traits/common_type.h>
0026 #include <__type_traits/is_constructible.h>
0027 #include <__type_traits/is_convertible.h>
0028 #include <__type_traits/is_integral.h>
0029 #include <__type_traits/is_nothrow_constructible.h>
0030 #include <__type_traits/is_same.h>
0031 #include <__utility/as_const.h>
0032 #include <__utility/integer_sequence.h>
0033 #include <__utility/swap.h>
0034 #include <array>
0035 #include <limits>
0036 #include <span>
0037
0038 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0039 # pragma GCC system_header
0040 #endif
0041
0042 _LIBCPP_PUSH_MACROS
0043 #include <__undef_macros>
0044
0045 _LIBCPP_BEGIN_NAMESPACE_STD
0046
0047 #if _LIBCPP_STD_VER >= 23
0048
0049 namespace __mdspan_detail {
0050 template <class _Layout, class _Mapping>
0051 constexpr bool __is_mapping_of =
0052 is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>, _Mapping>;
0053
0054 template <class _Mapping>
0055 concept __layout_mapping_alike = requires {
0056 requires __is_mapping_of<typename _Mapping::layout_type, _Mapping>;
0057 requires __is_extents_v<typename _Mapping::extents_type>;
0058 { _Mapping::is_always_strided() } -> same_as<bool>;
0059 { _Mapping::is_always_exhaustive() } -> same_as<bool>;
0060 { _Mapping::is_always_unique() } -> same_as<bool>;
0061 bool_constant<_Mapping::is_always_strided()>::value;
0062 bool_constant<_Mapping::is_always_exhaustive()>::value;
0063 bool_constant<_Mapping::is_always_unique()>::value;
0064 };
0065 }
0066
0067 template <class _Extents>
0068 class layout_stride::mapping {
0069 public:
0070 static_assert(__mdspan_detail::__is_extents<_Extents>::value,
0071 "layout_stride::mapping template argument must be a specialization of extents.");
0072
0073 using extents_type = _Extents;
0074 using index_type = typename extents_type::index_type;
0075 using size_type = typename extents_type::size_type;
0076 using rank_type = typename extents_type::rank_type;
0077 using layout_type = layout_stride;
0078
0079 private:
0080 static constexpr rank_type __rank_ = extents_type::rank();
0081
0082
0083 _LIBCPP_HIDE_FROM_ABI static constexpr bool __required_span_size_is_representable(const extents_type& __ext) {
0084 if constexpr (__rank_ == 0)
0085 return true;
0086
0087 index_type __prod = __ext.extent(0);
0088 for (rank_type __r = 1; __r < __rank_; __r++) {
0089 bool __overflowed = __builtin_mul_overflow(__prod, __ext.extent(__r), &__prod);
0090 if (__overflowed)
0091 return false;
0092 }
0093 return true;
0094 }
0095
0096 template <class _OtherIndexType>
0097 _LIBCPP_HIDE_FROM_ABI static constexpr bool
0098 __required_span_size_is_representable(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) {
0099 if constexpr (__rank_ == 0)
0100 return true;
0101
0102 index_type __size = 1;
0103 for (rank_type __r = 0; __r < __rank_; __r++) {
0104
0105 if constexpr (is_integral_v<_OtherIndexType>) {
0106 using _CommonType = common_type_t<index_type, _OtherIndexType>;
0107 if (static_cast<_CommonType>(__strides[__r]) > static_cast<_CommonType>(numeric_limits<index_type>::max()))
0108 return false;
0109 }
0110 if (__ext.extent(__r) == static_cast<index_type>(0))
0111 return true;
0112 index_type __prod = (__ext.extent(__r) - 1);
0113 bool __overflowed_mul = __builtin_mul_overflow(__prod, static_cast<index_type>(__strides[__r]), &__prod);
0114 if (__overflowed_mul)
0115 return false;
0116 bool __overflowed_add = __builtin_add_overflow(__size, __prod, &__size);
0117 if (__overflowed_add)
0118 return false;
0119 }
0120 return true;
0121 }
0122
0123
0124 template <class _StridedMapping>
0125 _LIBCPP_HIDE_FROM_ABI static constexpr index_type __offset(const _StridedMapping& __mapping) {
0126 if constexpr (_StridedMapping::extents_type::rank() == 0) {
0127 return static_cast<index_type>(__mapping());
0128 } else if (__mapping.required_span_size() == static_cast<typename _StridedMapping::index_type>(0)) {
0129 return static_cast<index_type>(0);
0130 } else {
0131 return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
0132 return static_cast<index_type>(__mapping((_Pos ? 0 : 0)...));
0133 }(make_index_sequence<__rank_>());
0134 }
0135 }
0136
0137
0138
0139 _LIBCPP_HIDE_FROM_ABI constexpr void __bubble_sort_by_strides(array<rank_type, __rank_>& __permute) const {
0140 for (rank_type __i = __rank_ - 1; __i > 0; __i--) {
0141 for (rank_type __r = 0; __r < __i; __r++) {
0142 if (__strides_[__permute[__r]] > __strides_[__permute[__r + 1]]) {
0143 swap(__permute[__r], __permute[__r + 1]);
0144 } else {
0145
0146
0147 if ((__strides_[__permute[__r]] == __strides_[__permute[__r + 1]]) &&
0148 (__extents_.extent(__permute[__r]) > static_cast<index_type>(1)))
0149 swap(__permute[__r], __permute[__r + 1]);
0150 }
0151 }
0152 }
0153 }
0154
0155 static_assert(extents_type::rank_dynamic() > 0 || __required_span_size_is_representable(extents_type()),
0156 "layout_stride::mapping product of static extents must be representable as index_type.");
0157
0158 public:
0159
0160 _LIBCPP_HIDE_FROM_ABI constexpr mapping() noexcept : __extents_(extents_type()) {
0161
0162
0163 if constexpr (__rank_ > 0) {
0164 index_type __stride = 1;
0165 for (rank_type __r = __rank_ - 1; __r > static_cast<rank_type>(0); __r--) {
0166 __strides_[__r] = __stride;
0167 __stride *= __extents_.extent(__r);
0168 }
0169 __strides_[0] = __stride;
0170 }
0171 }
0172
0173 _LIBCPP_HIDE_FROM_ABI constexpr mapping(const mapping&) noexcept = default;
0174
0175 template <class _OtherIndexType>
0176 requires(is_convertible_v<const _OtherIndexType&, index_type> &&
0177 is_nothrow_constructible_v<index_type, const _OtherIndexType&>)
0178 _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext, span<_OtherIndexType, __rank_> __strides) noexcept
0179 : __extents_(__ext), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) {
0180 return __mdspan_detail::__possibly_empty_array<index_type, __rank_>{
0181 static_cast<index_type>(std::as_const(__strides[_Pos]))...};
0182 }(make_index_sequence<__rank_>())) {
0183 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0184 ([&]<size_t... _Pos>(index_sequence<_Pos...>) {
0185
0186 if constexpr (is_integral_v<_OtherIndexType>) {
0187 return ((__strides[_Pos] > static_cast<_OtherIndexType>(0)) && ... && true);
0188 } else {
0189 return ((static_cast<index_type>(__strides[_Pos]) > static_cast<index_type>(0)) && ... && true);
0190 }
0191 }(make_index_sequence<__rank_>())),
0192 "layout_stride::mapping ctor: all strides must be greater than 0");
0193 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0194 __required_span_size_is_representable(__ext, __strides),
0195 "layout_stride::mapping ctor: required span size is not representable as index_type.");
0196 if constexpr (__rank_ > 1) {
0197 _LIBCPP_ASSERT_UNCATEGORIZED(
0198 ([&]<size_t... _Pos>(index_sequence<_Pos...>) {
0199
0200 array<rank_type, __rank_> __permute{_Pos...};
0201 __bubble_sort_by_strides(__permute);
0202
0203
0204 for (rank_type __i = 1; __i < __rank_; __i++)
0205 if (static_cast<index_type>(__strides[__permute[__i]]) <
0206 static_cast<index_type>(__strides[__permute[__i - 1]]) * __extents_.extent(__permute[__i - 1]))
0207 return false;
0208 return true;
0209 }(make_index_sequence<__rank_>())),
0210 "layout_stride::mapping ctor: the provided extents and strides lead to a non-unique mapping");
0211 }
0212 }
0213
0214 template <class _OtherIndexType>
0215 requires(is_convertible_v<const _OtherIndexType&, index_type> &&
0216 is_nothrow_constructible_v<index_type, const _OtherIndexType&>)
0217 _LIBCPP_HIDE_FROM_ABI constexpr mapping(const extents_type& __ext,
0218 const array<_OtherIndexType, __rank_>& __strides) noexcept
0219 : mapping(__ext, span(__strides)) {}
0220
0221 template <class _StridedLayoutMapping>
0222 requires(__mdspan_detail::__layout_mapping_alike<_StridedLayoutMapping> &&
0223 is_constructible_v<extents_type, typename _StridedLayoutMapping::extents_type> &&
0224 _StridedLayoutMapping::is_always_unique() && _StridedLayoutMapping::is_always_strided())
0225 _LIBCPP_HIDE_FROM_ABI constexpr explicit(
0226 !(is_convertible_v<typename _StridedLayoutMapping::extents_type, extents_type> &&
0227 (__mdspan_detail::__is_mapping_of<layout_left, _StridedLayoutMapping> ||
0228 __mdspan_detail::__is_mapping_of<layout_right, _StridedLayoutMapping> ||
0229 __mdspan_detail::__is_mapping_of<layout_stride, _StridedLayoutMapping>)))
0230 mapping(const _StridedLayoutMapping& __other) noexcept
0231 : __extents_(__other.extents()), __strides_([&]<size_t... _Pos>(index_sequence<_Pos...>) {
0232
0233 if constexpr (__rank_ > 0) {
0234 return __mdspan_detail::__possibly_empty_array<index_type, __rank_>{
0235 static_cast<index_type>(__other.stride(_Pos))...};
0236 } else {
0237 return __mdspan_detail::__possibly_empty_array<index_type, 0>{};
0238 }
0239 }(make_index_sequence<__rank_>())) {
0240
0241 if constexpr (__rank_ > 0) {
0242 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0243 ([&]<size_t... _Pos>(index_sequence<_Pos...>) {
0244 return ((static_cast<index_type>(__other.stride(_Pos)) > static_cast<index_type>(0)) && ... && true);
0245 }(make_index_sequence<__rank_>())),
0246 "layout_stride::mapping converting ctor: all strides must be greater than 0");
0247 }
0248 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
0249 __mdspan_detail::__is_representable_as<index_type>(__other.required_span_size()),
0250 "layout_stride::mapping converting ctor: other.required_span_size() must be representable as index_type.");
0251 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(static_cast<index_type>(0) == __offset(__other),
0252 "layout_stride::mapping converting ctor: base offset of mapping must be zero.");
0253 }
0254
0255 _LIBCPP_HIDE_FROM_ABI constexpr mapping& operator=(const mapping&) noexcept = default;
0256
0257
0258 _LIBCPP_HIDE_FROM_ABI constexpr const extents_type& extents() const noexcept { return __extents_; }
0259
0260 _LIBCPP_HIDE_FROM_ABI constexpr array<index_type, __rank_> strides() const noexcept {
0261 return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
0262 return array<index_type, __rank_>{__strides_[_Pos]...};
0263 }(make_index_sequence<__rank_>());
0264 }
0265
0266 _LIBCPP_HIDE_FROM_ABI constexpr index_type required_span_size() const noexcept {
0267 if constexpr (__rank_ == 0) {
0268 return static_cast<index_type>(1);
0269 } else {
0270 return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
0271 if ((__extents_.extent(_Pos) * ... * 1) == 0)
0272 return static_cast<index_type>(0);
0273 else
0274 return static_cast<index_type>(
0275 static_cast<index_type>(1) +
0276 (((__extents_.extent(_Pos) - static_cast<index_type>(1)) * __strides_[_Pos]) + ... +
0277 static_cast<index_type>(0)));
0278 }(make_index_sequence<__rank_>());
0279 }
0280 }
0281
0282 template <class... _Indices>
0283 requires((sizeof...(_Indices) == __rank_) && (is_convertible_v<_Indices, index_type> && ...) &&
0284 (is_nothrow_constructible_v<index_type, _Indices> && ...))
0285 _LIBCPP_HIDE_FROM_ABI constexpr index_type operator()(_Indices... __idx) const noexcept {
0286
0287
0288
0289
0290 _LIBCPP_ASSERT_UNCATEGORIZED(__mdspan_detail::__is_multidimensional_index_in(__extents_, __idx...),
0291 "layout_stride::mapping: out of bounds indexing");
0292 return [&]<size_t... _Pos>(index_sequence<_Pos...>) {
0293 return ((static_cast<index_type>(__idx) * __strides_[_Pos]) + ... + index_type(0));
0294 }(make_index_sequence<sizeof...(_Indices)>());
0295 }
0296
0297 _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_unique() noexcept { return true; }
0298 _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_exhaustive() noexcept { return false; }
0299 _LIBCPP_HIDE_FROM_ABI static constexpr bool is_always_strided() noexcept { return true; }
0300
0301 _LIBCPP_HIDE_FROM_ABI static constexpr bool is_unique() noexcept { return true; }
0302
0303
0304
0305
0306 _LIBCPP_HIDE_FROM_ABI constexpr bool is_exhaustive() const noexcept {
0307 if constexpr (__rank_ == 0)
0308 return true;
0309 else {
0310 index_type __span_size = required_span_size();
0311 if (__span_size == static_cast<index_type>(0)) {
0312 if constexpr (__rank_ == 1)
0313 return __strides_[0] == 1;
0314 else {
0315 rank_type __r_largest = 0;
0316 for (rank_type __r = 1; __r < __rank_; __r++)
0317 if (__strides_[__r] > __strides_[__r_largest])
0318 __r_largest = __r;
0319 for (rank_type __r = 0; __r < __rank_; __r++)
0320 if (__extents_.extent(__r) == 0 && __r != __r_largest)
0321 return false;
0322 return true;
0323 }
0324 } else {
0325 return required_span_size() == [&]<size_t... _Pos>(index_sequence<_Pos...>) {
0326 return (__extents_.extent(_Pos) * ... * static_cast<index_type>(1));
0327 }(make_index_sequence<__rank_>());
0328 }
0329 }
0330 }
0331 _LIBCPP_HIDE_FROM_ABI static constexpr bool is_strided() noexcept { return true; }
0332
0333
0334
0335 _LIBCPP_HIDE_FROM_ABI constexpr index_type stride(rank_type __r) const noexcept {
0336 _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__r < __rank_, "layout_stride::mapping::stride(): invalid rank index");
0337 return __strides_[__r];
0338 }
0339
0340 template <class _OtherMapping>
0341 requires(__mdspan_detail::__layout_mapping_alike<_OtherMapping> &&
0342 (_OtherMapping::extents_type::rank() == __rank_) && _OtherMapping::is_always_strided())
0343 _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const mapping& __lhs, const _OtherMapping& __rhs) noexcept {
0344 if (__offset(__rhs))
0345 return false;
0346 if constexpr (__rank_ == 0)
0347 return true;
0348 else {
0349 return __lhs.extents() == __rhs.extents() && [&]<size_t... _Pos>(index_sequence<_Pos...>) {
0350
0351 using _CommonType = common_type_t<index_type, typename _OtherMapping::index_type>;
0352 return ((static_cast<_CommonType>(__lhs.stride(_Pos)) == static_cast<_CommonType>(__rhs.stride(_Pos))) && ... &&
0353 true);
0354 }(make_index_sequence<__rank_>());
0355 }
0356 }
0357
0358 private:
0359 _LIBCPP_NO_UNIQUE_ADDRESS extents_type __extents_{};
0360 _LIBCPP_NO_UNIQUE_ADDRESS __mdspan_detail::__possibly_empty_array<index_type, __rank_> __strides_{};
0361 };
0362
0363 #endif
0364
0365 _LIBCPP_END_NAMESPACE_STD
0366
0367 _LIBCPP_POP_MACROS
0368
0369 #endif