libstdc++
mdspan
Go to the documentation of this file.
1// <mdspan> -*- C++ -*-
2
3// Copyright The GNU Toolchain Authors.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file mdspan
26 * This is a Standard C++ Library header.
27 */
28
29#ifndef _GLIBCXX_MDSPAN
30#define _GLIBCXX_MDSPAN 1
31
32#ifdef _GLIBCXX_SYSHDR
33#pragma GCC system_header
34#endif
35
36#include <span>
37#include <array>
38#include <type_traits>
39#include <utility>
40
41#define __glibcxx_want_mdspan
42#define __glibcxx_want_aligned_accessor
43#define __glibcxx_want_submdspan
44#include <bits/version.h>
45
46#if __glibcxx_aligned_accessor
47#include <bits/align.h>
48#endif
49
50#if __glibcxx_submdspan
51#include <tuple>
52#endif
53
54#if __cplusplus > 202302L
56#endif
57
58#ifdef __glibcxx_mdspan
59
60namespace std _GLIBCXX_VISIBILITY(default)
61{
62_GLIBCXX_BEGIN_NAMESPACE_VERSION
63 namespace __mdspan
64 {
65 consteval bool
66 __all_static(std::span<const size_t> __extents)
67 {
68 for(auto __ext : __extents)
69 if (__ext == dynamic_extent)
70 return false;
71 return true;
72 }
73
74 consteval bool
75 __all_dynamic(std::span<const size_t> __extents)
76 {
77 for(auto __ext : __extents)
78 if (__ext != dynamic_extent)
79 return false;
80 return true;
81 }
82
83 template<typename _IndexType, typename _OIndexTypeRef>
84 constexpr _IndexType
85 __index_type_cast(_OIndexTypeRef&& __other)
86 {
87 // _GLIBCXX_RESOLVE_LIB_DEFECTS
88 // 4020. extents::index-cast weirdness
89 using _OIndexType = std::remove_cvref_t<_OIndexTypeRef>;
90 if constexpr (std::is_integral_v<_OIndexType>)
91 {
92 constexpr _IndexType __index_type_max
93 = __gnu_cxx::__int_traits<_IndexType>::__max;
94 constexpr _OIndexType __oindex_type_max
95 = __gnu_cxx::__int_traits<_OIndexType>::__max;
96
97 if constexpr (__index_type_max < __oindex_type_max)
98 __glibcxx_assert(cmp_less_equal(__other, __index_type_max));
99
100 if constexpr (std::is_signed_v<_OIndexType>)
101 __glibcxx_assert(__other >= 0);
102 return static_cast<_IndexType>(__other);
103 }
104 else
105 {
106 // _GLIBCXX_RESOLVE_LIB_DEFECTS
107 // 4314. Missing move in mdspan layout mapping::operator()
108 auto __ret = static_cast<_IndexType>(std::forward<_OIndexTypeRef>(__other));
109 if constexpr (std::is_signed_v<_IndexType>)
110 __glibcxx_assert(__ret >= 0);
111 return __ret;
112 }
113 }
114
115 template<array _Extents>
116 class _StaticExtents
117 {
118 public:
119 static constexpr size_t _S_rank = _Extents.size();
120
121 // For __r in [0, _S_rank], _S_dynamic_index(__r) is the number
122 // of dynamic extents up to (and not including) __r.
123 //
124 // If __r is the index of a dynamic extent, then
125 // _S_dynamic_index[__r] is the index of that extent in
126 // _M_dyn_exts.
127 static constexpr size_t
128 _S_dynamic_index(size_t __r) noexcept
129 { return _S_dynamic_index_data[__r]; }
130
131 static constexpr auto _S_dynamic_index_data = [] consteval
132 {
133 array<size_t, _S_rank+1> __ret;
134 size_t __dyn = 0;
135 for (size_t __i = 0; __i < _S_rank; ++__i)
136 {
137 __ret[__i] = __dyn;
138 __dyn += (_Extents[__i] == dynamic_extent);
139 }
140 __ret[_S_rank] = __dyn;
141 return __ret;
142 }();
143
144 static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank);
145
146 // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv(__r) is the
147 // index of the __r-th dynamic extent in _Extents.
148 static constexpr size_t
149 _S_dynamic_index_inv(size_t __r) noexcept
150 { return _S_dynamic_index_inv_data[__r]; }
151
152 static constexpr auto _S_dynamic_index_inv_data = [] consteval
153 {
154 array<size_t, _S_rank_dynamic> __ret;
155 for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i)
156 if (_Extents[__i] == dynamic_extent)
157 __ret[__r++] = __i;
158 return __ret;
159 }();
160
161 static constexpr size_t
162 _S_static_extent(size_t __r) noexcept
163 { return _Extents[__r]; }
164 };
165
166 template<array _Extents>
167 requires (__all_dynamic<_Extents>())
168 class _StaticExtents<_Extents>
169 {
170 public:
171 static constexpr size_t _S_rank = _Extents.size();
172
173 static constexpr size_t
174 _S_dynamic_index(size_t __r) noexcept
175 { return __r; }
176
177 static constexpr size_t _S_rank_dynamic = _S_rank;
178
179 static constexpr size_t
180 _S_dynamic_index_inv(size_t __k) noexcept
181 { return __k; }
182
183 static constexpr size_t
184 _S_static_extent(size_t) noexcept
185 { return dynamic_extent; }
186 };
187
188 template<typename _IndexType, array _Extents>
189 class _ExtentsStorage : public _StaticExtents<_Extents>
190 {
191 private:
192 using _Base = _StaticExtents<_Extents>;
193
194 public:
195 using _Base::_S_rank;
196 using _Base::_S_rank_dynamic;
197 using _Base::_S_dynamic_index;
198 using _Base::_S_dynamic_index_inv;
199 using _Base::_S_static_extent;
200
201 static constexpr bool
202 _S_is_dynamic(size_t __r) noexcept
203 {
204 if constexpr (__all_static(_Extents))
205 return false;
206 else if constexpr (__all_dynamic(_Extents))
207 return true;
208 else
209 return _Extents[__r] == dynamic_extent;
210 }
211
212 template<typename _OIndexType>
213 static constexpr _IndexType
214 _S_int_cast(const _OIndexType& __other) noexcept
215 { return _IndexType(__other); }
216
217 constexpr _IndexType
218 _M_extent(size_t __r) const noexcept
219 {
220 if (_S_is_dynamic(__r))
221 return _M_dyn_exts[_S_dynamic_index(__r)];
222 else
223 return _S_static_extent(__r);
224 }
225
226 template<size_t _OtherRank, typename _GetOtherExtent>
227 static constexpr bool
228 _S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept
229 {
230 if constexpr (_OtherRank == _S_rank)
231 for (size_t __i = 0; __i < _S_rank; ++__i)
232 if (!_S_is_dynamic(__i)
233 && !cmp_equal(_Extents[__i], _S_int_cast(__get_extent(__i))))
234 return false;
235 return true;
236 }
237
238 template<size_t _OtherRank, typename _GetOtherExtent>
239 constexpr void
240 _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
241 {
242 __glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent));
243 for (size_t __i = 0; __i < _S_rank_dynamic; ++__i)
244 {
245 size_t __di = __i;
246 if constexpr (_OtherRank != _S_rank_dynamic)
247 __di = _S_dynamic_index_inv(__i);
248 _M_dyn_exts[__i] = _S_int_cast(__get_extent(__di));
249 }
250 }
251
252 constexpr
253 _ExtentsStorage() noexcept = default;
254
255 template<typename _OIndexType, array _OExtents>
256 constexpr
257 _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>&
258 __other) noexcept
259 {
260 _M_init_dynamic_extents<_S_rank>([&__other](size_t __i)
261 { return __other._M_extent(__i); });
262 }
263
264 template<typename _OIndexType, size_t _Nm>
265 constexpr
266 _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept
267 {
268 _M_init_dynamic_extents<_Nm>(
269 [&__exts](size_t __i) -> const _OIndexType&
270 { return __exts[__i]; });
271 }
272
273 static constexpr const array<size_t, _S_rank>&
274 _S_static_extents() noexcept
275 { return _Extents; }
276
277 constexpr span<const _IndexType>
278 _M_dynamic_extents(size_t __begin, size_t __end) const noexcept
279 requires (_Extents.size() > 0)
280 {
281 return {_M_dyn_exts + _S_dynamic_index(__begin),
282 _S_dynamic_index(__end) - _S_dynamic_index(__begin)};
283 }
284
285 private:
286 using _Storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
287 [[no_unique_address]] _Storage _M_dyn_exts{};
288 };
289
290 template<typename _OIndexType, typename _SIndexType>
291 concept __valid_index_type =
292 is_convertible_v<_OIndexType, _SIndexType> &&
293 is_nothrow_constructible_v<_SIndexType, _OIndexType>;
294
295 template<size_t _Extent, typename _IndexType>
296 concept
297 __valid_static_extent = _Extent == dynamic_extent
298 || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max;
299
300 template<typename _Extents>
301 constexpr const array<size_t, _Extents::rank()>&
302 __static_extents() noexcept
303 { return _Extents::_Storage::_S_static_extents(); }
304
305 template<typename _Extents>
306 constexpr span<const size_t>
307 __static_extents(size_t __begin, size_t __end) noexcept
308 {
309 const auto& __sta_exts = __static_extents<_Extents>();
310 return span<const size_t>(__sta_exts.data() + __begin, __end - __begin);
311 }
312
313 // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive)
314 template<array _Extents>
315 constexpr auto __fwd_partial_prods = [] consteval
316 {
317 constexpr size_t __rank = _Extents.size();
318 std::array<size_t, __rank> __ret;
319 size_t __prod = 1;
320 for (size_t __r = 0; __r < __rank; ++__r)
321 {
322 __ret[__r] = __prod;
323 if (size_t __ext = _Extents[__r]; __ext != dynamic_extent)
324 __prod *= __ext;
325 }
326 return __ret;
327 }();
328
329 // Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i]
330 template<array _Extents>
331 constexpr auto __rev_partial_prods = [] consteval
332 {
333 constexpr size_t __rank = _Extents.size();
334 std::array<size_t, __rank> __ret;
335 size_t __prod = 1;
336 for (size_t __r = __rank; __r > 0; --__r)
337 {
338 __ret[__r - 1] = __prod;
339 if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent)
340 __prod *= __ext;
341 }
342 return __ret;
343 }();
344
345 template<typename _Extents>
346 constexpr span<const typename _Extents::index_type>
347 __dynamic_extents(const _Extents& __exts, size_t __begin = 0,
348 size_t __end = _Extents::rank()) noexcept
349 { return __exts._M_exts._M_dynamic_extents(__begin, __end); }
350 }
351
352#if __glibcxx_submdspan
353 struct full_extent_t
354 {
355 explicit full_extent_t() = default;
356 };
357
358 inline constexpr full_extent_t full_extent{};
359
360 template<typename _OffsetType, typename _ExtentType, typename _StrideType>
361 struct extent_slice
362 {
363 static_assert(__is_signed_or_unsigned_integer<_OffsetType>::value
364 || __detail::__integral_constant_like<_OffsetType>);
365 static_assert(__is_signed_or_unsigned_integer<_ExtentType>::value
366 || __detail::__integral_constant_like<_ExtentType>);
367 static_assert(__is_signed_or_unsigned_integer<_StrideType>::value
368 || __detail::__integral_constant_like<_StrideType>);
369
370 using offset_type = _OffsetType;
371 using extent_type = _ExtentType;
372 using stride_type = _StrideType;
373
374 [[no_unique_address]] offset_type offset{};
375 [[no_unique_address]] extent_type extent{};
376 [[no_unique_address]] stride_type stride{};
377 };
378
379 template<typename _FirstType, typename _LastType, typename _StrideType = constant_wrapper<1zu>>
380 struct range_slice
381 {
382 static_assert(__is_signed_or_unsigned_integer<_FirstType>::value
383 || __detail::__integral_constant_like<_FirstType>);
384 static_assert(__is_signed_or_unsigned_integer<_LastType>::value
385 || __detail::__integral_constant_like<_LastType>);
386 static_assert(__is_signed_or_unsigned_integer<_StrideType>::value
387 || __detail::__integral_constant_like<_StrideType>);
388
389 [[no_unique_address]] _FirstType first{};
390 [[no_unique_address]] _LastType last{};
391 [[no_unique_address]] _StrideType stride{};
392 };
393
394 template<typename _Mapping>
395 struct submdspan_mapping_result
396 {
397 [[no_unique_address]] _Mapping mapping = _Mapping();
398 size_t offset{};
399 };
400
401 template<typename _Tp>
402 constexpr bool __is_submdspan_mapping_result = false;
403
404 template<typename _Mapping>
405 constexpr bool __is_submdspan_mapping_result<submdspan_mapping_result<_Mapping>> = true;
406
407 template<typename _Mapping>
408 concept __submdspan_mapping_result = __is_submdspan_mapping_result<_Mapping>;
409
410#endif // __glibcxx_submdspan
411
412 template<typename _IndexType, size_t... _Extents>
413 class extents
414 {
415 static_assert(__is_signed_or_unsigned_integer<_IndexType>::value,
416 "IndexType must be a signed or unsigned integer type");
417 static_assert(
418 (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
419 "Extents must either be dynamic or representable as IndexType");
420
421 using _Storage = __mdspan::_ExtentsStorage<
422 _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
423 [[no_unique_address]] _Storage _M_exts;
424
425 public:
426 using index_type = _IndexType;
427 using size_type = make_unsigned_t<index_type>;
428 using rank_type = size_t;
429
430 static constexpr rank_type
431 rank() noexcept { return _Storage::_S_rank; }
432
433 static constexpr rank_type
434 rank_dynamic() noexcept { return _Storage::_S_rank_dynamic; }
435
436 static constexpr size_t
437 static_extent(rank_type __r) noexcept
438 {
439 __glibcxx_assert(__r < rank());
440 if constexpr (rank() == 0)
441 __builtin_trap();
442 else
443 return _Storage::_S_static_extent(__r);
444 }
445
446 constexpr index_type
447 extent(rank_type __r) const noexcept
448 {
449 __glibcxx_assert(__r < rank());
450 if constexpr (rank() == 0)
451 __builtin_trap();
452 else
453 return _M_exts._M_extent(__r);
454 }
455
456 constexpr
457 extents() noexcept = default;
458
459 private:
460 static consteval bool
461 _S_is_less_dynamic(size_t __ext, size_t __oext)
462 { return (__ext != dynamic_extent) && (__oext == dynamic_extent); }
463
464 template<typename _OIndexType, size_t... _OExtents>
465 static consteval bool
466 _S_ctor_explicit()
467 {
468 return (_S_is_less_dynamic(_Extents, _OExtents) || ...)
469 || (__gnu_cxx::__int_traits<index_type>::__max
470 < __gnu_cxx::__int_traits<_OIndexType>::__max);
471 }
472
473 template<size_t... _OExtents>
474 static consteval bool
475 _S_is_compatible_extents()
476 {
477 if constexpr (sizeof...(_OExtents) != rank())
478 return false;
479 else
480 return ((_OExtents == dynamic_extent || _Extents == dynamic_extent
481 || _OExtents == _Extents) && ...);
482 }
483
484 public:
485 template<typename _OIndexType, size_t... _OExtents>
486 requires (_S_is_compatible_extents<_OExtents...>())
487 constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>())
488 extents(const extents<_OIndexType, _OExtents...>& __other) noexcept
489 : _M_exts(__other._M_exts)
490 { }
491
492 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
493 requires (sizeof...(_OIndexTypes) == rank()
494 || sizeof...(_OIndexTypes) == rank_dynamic())
495 constexpr explicit extents(_OIndexTypes... __exts) noexcept
496 : _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>(
497 initializer_list{static_cast<_IndexType>(std::move(__exts))...}))
498 { }
499
500 template<typename _OIndexType, size_t _Nm>
501 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
502 && (_Nm == rank() || _Nm == rank_dynamic())
503 constexpr explicit(_Nm != rank_dynamic())
504 extents(span<_OIndexType, _Nm> __exts) noexcept
505 : _M_exts(span<const _OIndexType, _Nm>(__exts))
506 { }
507
508 template<typename _OIndexType, size_t _Nm>
509 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
510 && (_Nm == rank() || _Nm == rank_dynamic())
511 constexpr explicit(_Nm != rank_dynamic())
512 extents(const array<_OIndexType, _Nm>& __exts) noexcept
513 : _M_exts(span<const _OIndexType, _Nm>(__exts))
514 { }
515
516 template<typename _OIndexType, size_t... _OExtents>
517 friend constexpr bool
518 operator==(const extents& __self,
519 const extents<_OIndexType, _OExtents...>& __other) noexcept
520 {
521 if constexpr (!_S_is_compatible_extents<_OExtents...>())
522 return false;
523 else
524 {
525 auto __impl = [&__self, &__other]<size_t... _Counts>(
526 index_sequence<_Counts...>)
527 { return (cmp_equal(__self.extent(_Counts),
528 __other.extent(_Counts)) && ...); };
529 return __impl(make_index_sequence<__self.rank()>());
530 }
531 }
532
533 private:
534 friend constexpr const array<size_t, rank()>&
535 __mdspan::__static_extents<extents>() noexcept;
536
537 friend constexpr span<const index_type>
538 __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t)
539 noexcept;
540
541 template<typename _OIndexType, size_t... _OExtents>
542 friend class extents;
543 };
544
545 namespace __mdspan
546 {
547 template<typename _Tp, size_t _Nm>
548 constexpr bool
549 __contains_zero(span<_Tp, _Nm> __exts) noexcept
550 {
551 for (size_t __i = 0; __i < __exts.size(); ++__i)
552 if (__exts[__i] == 0)
553 return true;
554 return false;
555 }
556
557 template<typename _Tp, size_t _Nm>
558 consteval bool
559 __contains_zero(const array<_Tp, _Nm>& __exts) noexcept
560 { return __contains_zero(span<const _Tp>(__exts)); }
561
562 template<typename _Extents>
563 constexpr bool
564 __empty(const _Extents& __exts) noexcept
565 {
566 if constexpr (__contains_zero(__static_extents<_Extents>()))
567 return true;
568 else if constexpr (_Extents::rank_dynamic() > 0)
569 return __contains_zero(__dynamic_extents(__exts));
570 else
571 return false;
572 }
573
574 template<typename _Extents>
575 constexpr typename _Extents::index_type
576 __extents_prod(const _Extents& __exts, size_t __sta_prod, size_t __begin,
577 size_t __end) noexcept
578 {
579 if (__sta_prod == 0)
580 return 0;
581
582 size_t __ret = __sta_prod;
583 if constexpr (_Extents::rank_dynamic() > 0)
584 for (auto __factor : __dynamic_extents(__exts, __begin, __end))
585 __ret *= size_t(__factor);
586 return static_cast<typename _Extents::index_type>(__ret);
587 }
588
589 // Preconditions: _r < _Extents::rank()
590 template<typename _Extents>
591 constexpr typename _Extents::index_type
592 __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept
593 {
594 size_t __sta_prod = [__begin, __end] {
595 span<const size_t> __sta_exts
596 = __static_extents<_Extents>(__begin, __end);
597 size_t __ret = 1;
598 for(auto __ext : __sta_exts)
599 if (__ext != dynamic_extent)
600 __ret *= __ext;
601 return __ret;
602 }();
603 return __extents_prod(__exts, __sta_prod, __begin, __end);
604 }
605
606 template<typename _Extents>
607 constexpr typename _Extents::index_type
608 __fwd_prod(const _Extents& __exts, size_t __r) noexcept
609 {
610 constexpr size_t __rank = _Extents::rank();
611 constexpr auto& __sta_exts = __static_extents<_Extents>();
612 if constexpr (__rank == 1)
613 return 1;
614 else if constexpr (__rank == 2)
615 return __r == 0 ? 1 : __exts.extent(0);
616 else if constexpr (__all_dynamic(std::span(__sta_exts).first(__rank-1)))
617 return __extents_prod(__exts, 1, 0, __r);
618 else
619 {
620 size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r];
621 return __extents_prod(__exts, __sta_prod, 0, __r);
622 }
623 }
624
625 template<typename _IndexType, size_t _Nm>
626 consteval _IndexType
627 __fwd_prod(span<const _IndexType, _Nm> __values)
628 {
629 _IndexType __ret = 1;
630 for(auto __value : __values)
631 __ret *= __value;
632 return __ret;
633 }
634
635 // Preconditions: _r < _Extents::rank()
636 template<typename _Extents>
637 constexpr typename _Extents::index_type
638 __rev_prod(const _Extents& __exts, size_t __r) noexcept
639 {
640 constexpr size_t __rank = _Extents::rank();
641 constexpr auto& __sta_exts = __static_extents<_Extents>();
642 if constexpr (__rank == 1)
643 return 1;
644 else if constexpr (__rank == 2)
645 return __r == 0 ? __exts.extent(1) : 1;
646 else if constexpr (__all_dynamic(std::span(__sta_exts).last(__rank-1)))
647 return __extents_prod(__exts, 1, __r + 1, __rank);
648 else
649 {
650 size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r];
651 return __extents_prod(__exts, __sta_prod, __r + 1, __rank);
652 }
653 }
654
655 template<typename _Extents>
656 constexpr typename _Extents::index_type
657 __size(const _Extents& __exts) noexcept
658 {
659 constexpr size_t __sta_prod = [] {
660 span<const size_t> __sta_exts = __static_extents<_Extents>();
661 size_t __ret = 1;
662 for(auto __ext : __sta_exts)
663 if (__ext != dynamic_extent)
664 __ret *= __ext;
665 return __ret;
666 }();
667 return __extents_prod(__exts, __sta_prod, 0, _Extents::rank());
668 }
669
670 template<typename _IndexType, size_t... _Counts>
671 auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
672 -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
673 }
674
675 template<typename _IndexType, size_t _Rank>
676 using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
678
679#if __glibcxx_mdspan >= 202406L
680 template<size_t _Rank, typename _IndexType = size_t>
681 using dims = dextents<_IndexType, _Rank>;
682#endif
683
684 template<typename... _Integrals>
685 requires (is_convertible_v<_Integrals, size_t> && ...)
686 explicit extents(_Integrals...) ->
687 extents<size_t, __detail::__maybe_static_ext<_Integrals>...>;
688
689 struct layout_left
690 {
691 template<typename _Extents>
692 class mapping;
693 };
694
695 struct layout_right
696 {
697 template<typename _Extents>
698 class mapping;
699 };
700
701 struct layout_stride
702 {
703 template<typename _Extents>
704 class mapping;
705 };
706
707#ifdef __glibcxx_padded_layouts
708 template<size_t _PaddingValue>
709 struct layout_left_padded
710 {
711 template<typename _Extents>
712 class mapping;
713 };
714
715 template<size_t _PaddingValue>
716 struct layout_right_padded
717 {
718 template<typename _Extents>
719 class mapping;
720 };
721#endif
722
723 namespace __mdspan
724 {
725 template<typename _Tp>
726 constexpr bool __is_extents = false;
727
728 template<typename _IndexType, size_t... _Extents>
729 constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true;
730
731 template<typename _Extents, typename... _Indices>
732 constexpr typename _Extents::index_type
733 __linear_index_left(const _Extents& __exts, _Indices... __indices)
734 noexcept
735 {
736 using _IndexType = typename _Extents::index_type;
737 _IndexType __res = 0;
738 if constexpr (sizeof...(__indices) > 0)
739 {
740 _IndexType __mult = 1;
741 auto __update = [&, __pos = 0u](_IndexType __idx) mutable
742 {
743 _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos)));
744 __res += __idx * __mult;
745 __mult *= __exts.extent(__pos);
746 ++__pos;
747 };
748 (__update(__indices), ...);
749 }
750 return __res;
751 }
752
753 template<typename _IndexType>
754 consteval _IndexType
755 __static_quotient(std::span<const size_t> __sta_exts,
756 _IndexType __nom = __gnu_cxx::__int_traits<_IndexType>::__max)
757 {
758 for (auto __factor : __sta_exts)
759 {
760 if (__factor != dynamic_extent)
761 __nom /= _IndexType(__factor);
762 if (__nom == 0)
763 break;
764 }
765 return __nom;
766 }
767
768 template<typename _Extents,
769 typename _IndexType = typename _Extents::index_type>
770 requires __is_extents<_Extents>
771 consteval _IndexType
772 __static_quotient(_IndexType __nom
773 = __gnu_cxx::__int_traits<_IndexType>::__max)
774 {
775 std::span<const size_t> __sta_exts = __static_extents<_Extents>();
776 return __static_quotient<_IndexType>(__sta_exts, __nom);
777 }
778
779 template<typename _Extents>
780 constexpr bool
781 __is_representable_extents(const _Extents& __exts) noexcept
782 {
783 using _IndexType = _Extents::index_type;
784
785 if constexpr (__contains_zero(__static_extents<_Extents>()))
786 return true;
787 else
788 {
789 constexpr auto __sta_quo = __static_quotient<_Extents>();
790 if constexpr (_Extents::rank_dynamic() == 0)
791 return __sta_quo != 0;
792 else
793 {
794 auto __dyn_exts = __dynamic_extents(__exts);
795 if (__contains_zero(__dyn_exts))
796 return true;
797
798 if constexpr (__sta_quo == 0)
799 return false;
800 else
801 {
802 auto __dyn_quo = _IndexType(__sta_quo);
803 for (auto __factor : __dyn_exts)
804 {
805 __dyn_quo /= __factor;
806 if (__dyn_quo == 0)
807 return false;
808 }
809 return true;
810 }
811 }
812 }
813 }
814
815 template<typename _Extents, typename _IndexType>
816 concept __representable_size = _Extents::rank_dynamic() != 0
817 || __contains_zero(__static_extents<_Extents>())
818 || (__static_quotient<_Extents, _IndexType>() != 0);
819
820 template<typename _Layout, typename _Mapping>
821 concept __mapping_of =
822 is_same_v<typename _Layout::template mapping<
823 typename _Mapping::extents_type>,
824 _Mapping>;
825
826 template<template<size_t> typename _Layout, typename _Mapping>
827 concept __padded_mapping_of = __mapping_of<
828 _Layout<_Mapping::padding_value>, _Mapping>;
829
830#ifdef __glibcxx_padded_layouts
831 template<typename _Mapping>
832 constexpr bool __is_left_padded_mapping = __padded_mapping_of<
833 layout_left_padded, _Mapping>;
834
835 template<typename _Mapping>
836 constexpr bool __is_right_padded_mapping = __padded_mapping_of<
837 layout_right_padded, _Mapping>;
838
839 template<typename _Mapping>
840 constexpr bool __is_padded_mapping = __is_left_padded_mapping<_Mapping>
841 || __is_right_padded_mapping<_Mapping>;
842#endif
843
844 template<typename _PaddedMapping>
845 consteval size_t
846 __get_static_stride()
847 { return _PaddedMapping::_PaddedStorage::_S_static_stride; }
848
849 template<typename _Mapping>
850 concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
851 || __mapping_of<layout_right, _Mapping>
852 || __mapping_of<layout_stride, _Mapping>
853#ifdef __glibcxx_padded_layouts
854 || __is_left_padded_mapping<_Mapping>
855 || __is_right_padded_mapping<_Mapping>
856#endif
857 ;
858
859 // A tag type to create internal ctors.
860 class __internal_ctor
861 { };
862
863 template<typename _Mapping>
864 constexpr typename _Mapping::index_type
865 __offset(const _Mapping& __m) noexcept
866 {
867 using _IndexType = typename _Mapping::index_type;
868 constexpr auto __rank = _Mapping::extents_type::rank();
869
870 if constexpr (__standardized_mapping<_Mapping>)
871 return 0;
872 else if (__empty(__m.extents()))
873 return 0;
874 else
875 {
876 auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>)
877 { return __m(((void) _Counts, _IndexType(0))...); };
878 return __impl(make_index_sequence<__rank>());
879 }
880 }
881
882#ifdef __glibcxx_submdspan
883 template<typename _Tp>
884 constexpr bool __is_extent_slice = false;
885
886 template<typename _OffsetType, typename _ExtentType, typename _StrideType>
887 constexpr bool __is_extent_slice<extent_slice<_OffsetType,
888 _ExtentType, _StrideType>> = true;
889
890 template<typename _Tp>
891 constexpr bool __is_range_slice = false;
892
893 template<typename _FirstType, typename _LastType, typename _StrideType>
894 constexpr bool __is_range_slice<range_slice<_FirstType,
895 _LastType, _StrideType>> = true;
896
897 template<typename _IndexType, typename _OIndexType>
898 consteval bool
899 __is_representable_integer(_OIndexType __value)
900 {
901 constexpr auto __min = __gnu_cxx::__int_traits<_IndexType>::__min;
902 constexpr auto __max = __gnu_cxx::__int_traits<_IndexType>::__max;
903 return std::cmp_less_equal(__min, __value)
904 && std::cmp_less_equal(__value, __max);
905 }
906
907 template<typename _Tp>
908 constexpr bool __is_constant_wrapper = false;
909
910 template<auto _Xv, typename _Tp>
911 constexpr bool __is_constant_wrapper<constant_wrapper<_Xv, _Tp>>
912 = true;
913
914 template<size_t _Index, typename _Extents>
915 constexpr auto
916 __extract_extent(const _Extents& __exts)
917 {
918 using _IndexType = typename _Extents::index_type;
919 return extents<_IndexType, _Extents::static_extent(_Index)>{
920 __exts.extent(_Index)};
921 }
922
923 template<typename _Slice, typename _IndexType>
924 concept __acceptable_slice_type = same_as<_Slice, full_extent_t>
925 || same_as<_Slice, _IndexType> || __is_constant_wrapper<_Slice>
926 || __is_extent_slice<_Slice>;
927
928 template<typename _IndexType, typename... _Slices>
929 consteval auto
930 __subrank()
931 {
932 return (static_cast<size_t>(!convertible_to<_Slices, _IndexType>)
933 + ... + 0);
934 }
935
936 template<typename _IndexType, typename... _Slices>
937 consteval auto
938 __inv_map_rank()
939 {
940 constexpr auto __rank = sizeof...(_Slices);
941 constexpr auto __sub_rank = __subrank<_IndexType, _Slices...>();
942 auto __map = std::array<size_t, __sub_rank>{};
943 auto __is_int_like = std::array<bool, __rank>{
944 convertible_to<_Slices, _IndexType>...};
945
946 size_t __i = 0;
947 for (size_t __k = 0; __k < __rank; ++__k)
948 if (!__is_int_like[__k])
949 __map[__i++] = __k;
950 return __map;
951 }
952
953 template<typename _Slice>
954 constexpr auto
955 __slice_begin(_Slice __slice)
956 {
957 if constexpr (same_as<_Slice, full_extent_t>)
958 return 0;
959 else if constexpr (__is_extent_slice<_Slice>)
960 return __slice.offset;
961 else
962 return __slice; // collapsing slice
963 }
964
965 template<typename _Mapping, typename... _Slices>
966 constexpr size_t
967 __suboffset(const _Mapping& __mapping, const _Slices&... __slices)
968 {
969 using _IndexType = typename _Mapping::index_type;
970 auto __any_past_the_end = [&]<size_t... _Is>(index_sequence<_Is...>)
971 {
972 auto __is_past_the_end = [](const auto& __slice, const auto& __ext)
973 {
974 using _Slice = remove_cvref_t<decltype(__slice)>;
975 if constexpr (is_convertible_v<_Slice, _IndexType>)
976 return false;
977 else if constexpr (same_as<_Slice, full_extent_t>
978 && __ext.static_extent(0) != 0
979 && __ext.static_extent(0) != dynamic_extent)
980 return false;
981 else
982 return __mdspan::__slice_begin(__slice) == __ext.extent(0);
983 };
984
985 const auto& __exts = __mapping.extents();
986 return ((__is_past_the_end(__slices...[_Is],
987 __mdspan::__extract_extent<_Is>(__exts))) || ...);
988 };
989
990 if constexpr ((same_as<_Slices, full_extent_t> && ...))
991 return __mdspan::__offset(__mapping);
992
993 if (__any_past_the_end(std::make_index_sequence<sizeof...(__slices)>()))
994 return __mapping.required_span_size();
995 return __mapping(__mdspan::__slice_begin(__slices)...);
996 }
997
998 template<typename _IndexType, size_t _Extent, typename _Slice>
999 consteval size_t
1000 __static_slice_extent()
1001 {
1002 if constexpr (same_as<_Slice, full_extent_t>)
1003 return _Extent;
1004 else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>)
1005 return 0;
1006 else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>)
1007 return _Slice::extent_type::value;
1008 else
1009 return dynamic_extent;
1010 }
1011
1012 template<size_t _K, typename _Extents, typename _Slice>
1013 constexpr typename _Extents::index_type
1014 __dynamic_slice_extent(const _Extents& __exts, _Slice __slice)
1015 {
1016 if constexpr (__is_extent_slice<_Slice>)
1017 return __slice.extent;
1018 else
1019 return __exts.extent(_K);
1020 }
1021
1022 template<typename _IndexType, size_t... _Extents, typename... _Slices>
1023 requires (sizeof...(_Slices) == sizeof...(_Extents))
1024 constexpr auto
1025 __subextents(const extents<_IndexType, _Extents...>& __exts,
1026 _Slices... __slices)
1027 {
1028 constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>();
1029 auto __impl = [&]<size_t... _Indices>(std::index_sequence<_Indices...>)
1030 {
1031 using _SubExts = extents<_IndexType,
1032 __mdspan::__static_slice_extent<_IndexType,
1033 _Extents...[__inv_map[_Indices]],
1034 _Slices...[__inv_map[_Indices]]>()...>;
1035 if constexpr (_SubExts::rank_dynamic() == 0)
1036 return _SubExts{};
1037 else
1038 {
1039 using _StaticSubExtents = __mdspan::_StaticExtents<
1040 __mdspan::__static_extents<_SubExts>()>;
1041 auto __create = [&]<size_t... _Is>(std::index_sequence<_Is...>)
1042 {
1043 constexpr auto __slice_idx = [__inv_map](size_t __i) consteval
1044 {
1045 return __inv_map[_StaticSubExtents::_S_dynamic_index_inv(__i)];
1046 };
1047
1048 return _SubExts{__mdspan::__dynamic_slice_extent<__slice_idx(_Is)>(
1049 __exts, __slices...[__slice_idx(_Is)])...};
1050 };
1051 constexpr auto __dyn_subrank = _SubExts::rank_dynamic();
1052 return __create(std::make_index_sequence<__dyn_subrank>());
1053 }
1054 };
1055
1056 return __impl(std::make_index_sequence<__inv_map.size()>());
1057 }
1058
1059 enum class _LayoutSide
1060 {
1061 __left,
1062 __right,
1063 __unknown
1064 };
1065
1066 template<typename _Mapping>
1067 consteval _LayoutSide
1068 __mapping_side()
1069 {
1070 if constexpr (__is_left_padded_mapping<_Mapping>
1071 || __mapping_of<layout_left, _Mapping>)
1072 return _LayoutSide::__left;
1073 if constexpr (__is_right_padded_mapping<_Mapping>
1074 || __mapping_of<layout_right, _Mapping>)
1075 return _LayoutSide::__right;
1076 else
1077 return _LayoutSide::__unknown;
1078 }
1079
1080 template<_LayoutSide _Side, size_t _Rank>
1081 struct _StridesTrait
1082 {
1083 static constexpr const _LayoutSide _S_side = _Side;
1084
1085 static constexpr size_t
1086 _S_idx(size_t __k) noexcept
1087 {
1088 if constexpr (_Side == _LayoutSide::__left)
1089 return __k;
1090 else
1091 return _Rank - 1 - __k;
1092 }
1093
1094 // Unifies the formulas for computing strides for padded and unpadded
1095 // layouts.
1096 template<typename _Mapping>
1097 static constexpr typename _Mapping::index_type
1098 _S_padded_extent(const _Mapping& __mapping, size_t __k)
1099 {
1100 if (__k == 0)
1101 return __mapping.stride(_S_idx(1));
1102 else
1103 return __mapping.extents().extent(_S_idx(__k));
1104 }
1105
1106 template<typename _IndexType, typename... _Slices>
1107 static consteval auto
1108 _S_inv_map()
1109 {
1110 static_assert(_Side != _LayoutSide::__unknown);
1111 auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>)
1112 {
1113 return __mdspan::__inv_map_rank<_IndexType, _Slices...[_S_idx(_Is)]...>();
1114 };
1115 return __impl(std::make_index_sequence<_Rank>());
1116 }
1117 };
1118
1119 template<typename _SubExts, typename _Mapping, typename... _Slices>
1120 constexpr auto
1121 __substrides_generic(const _Mapping& __mapping, const _Slices&... __slices)
1122 {
1123 using _IndexType = typename _Mapping::index_type;
1124 if constexpr (_SubExts::rank() == 0)
1125 return array<_IndexType, _SubExts::rank()>{};
1126 else
1127 {
1128 auto __stride = [&__mapping](size_t __k, auto __slice) -> _IndexType
1129 {
1130 if constexpr (__is_extent_slice<decltype(__slice)>)
1131 if (__slice.extent > 1)
1132 return __mapping.stride(__k) * __slice.stride;
1133 return __mapping.stride(__k);
1134 };
1135
1136 auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>)
1137 {
1138 constexpr auto __inv_map
1139 = __mdspan::__inv_map_rank<_IndexType, _Slices...>();
1140 return array<_IndexType, _SubExts::rank()>{
1141 __stride(__inv_map[_Is], __slices...[__inv_map[_Is]])...};
1142 };
1143 return __impl(std::make_index_sequence<_SubExts::rank()>());
1144 }
1145 };
1146
1147 template<typename _SubExts, typename _Mapping, typename... _Slices>
1148 constexpr auto
1149 __substrides_standardized(const _Mapping& __mapping,
1150 const _Slices&... __slices)
1151 {
1152 using _IndexType = typename _Mapping::index_type;
1153 using _Trait = _StridesTrait<__mapping_side<_Mapping>(),
1154 _Mapping::extents_type::rank()>;
1155 using _SubTrait = _StridesTrait<__mapping_side<_Mapping>(), _SubExts::rank()>;
1156
1157 constexpr size_t __sub_rank = _SubExts::rank();
1158
1159 std::array<_IndexType, __sub_rank> __ret;
1160 if constexpr (__sub_rank > 0)
1161 {
1162 constexpr auto __inv_map
1163 = _Trait::template _S_inv_map<_IndexType, _Slices...>();
1164 auto __loop = [&]<size_t... _Ks>(std::index_sequence<_Ks...>)
1165 {
1166 size_t __i0 = 0;
1167 size_t __stride = 1;
1168 auto __body = [&](size_t __k, auto __slice)
1169 {
1170 for (size_t __i = __i0; __i < __inv_map[__k]; ++__i)
1171 __stride *= _Trait::_S_padded_extent(__mapping, __i);
1172
1173 size_t __krev = _SubTrait::_S_idx(__k);
1174 if constexpr (__is_extent_slice<decltype(__slice)>)
1175 {
1176 if (__slice.extent > 1)
1177 __ret[__krev] = __stride * __slice.stride;
1178 else
1179 __ret[__krev] = __stride;
1180 }
1181 else
1182 __ret[__krev] = __stride;
1183
1184 __i0 = __inv_map[__k];
1185 };
1186
1187 ((__body(_Ks, __slices...[_Trait::_S_idx(__inv_map[_Ks])])),...);
1188 };
1190 }
1191 return __ret;
1192 }
1193
1194
1195 template<typename _SubExts, typename _Mapping, typename... _Slices>
1196 constexpr auto
1197 __substrides(const _Mapping& __mapping, const _Slices&... __slices)
1198 {
1199 if constexpr (__mdspan::__mapping_side<_Mapping>() == _LayoutSide::__unknown)
1200 return __mdspan::__substrides_generic<_SubExts>(__mapping, __slices...);
1201 else
1202 return __mdspan::__substrides_standardized<_SubExts>(__mapping, __slices...);
1203 }
1204
1205 template<typename _Slice>
1206 concept __is_unit_stride_slice = (__mdspan::__is_extent_slice<_Slice>
1207 && __mdspan::__is_constant_wrapper<typename _Slice::stride_type>
1208 && _Slice::stride_type::value == 1)
1209 || std::same_as<_Slice, full_extent_t>;
1210
1211 // These are (forced) exclusive categories:
1212 // - full & collapsing: obvious,
1213 // - unit_extent_slice: extent_slice{a, b, cw<1>}, but not `full`,
1214 // - extent_slice: extent_slice{a, b, c} with c != cw<1>.
1215 enum class _SliceKind
1216 {
1217 __extent_slice,
1218 __unit_stride_slice,
1219 __full,
1220 __collapsing
1221 };
1222
1223 template<typename _Slice>
1224 consteval _SliceKind
1225 __make_slice_kind()
1226 {
1227 if constexpr (std::same_as<_Slice, full_extent_t>)
1228 return _SliceKind::__full;
1229 else if constexpr (__mdspan::__is_extent_slice<_Slice>)
1230 {
1231 if constexpr (__mdspan::__is_unit_stride_slice<_Slice>)
1232 return _SliceKind::__unit_stride_slice;
1233 else
1234 return _SliceKind::__extent_slice;
1235 }
1236 else
1237 return _SliceKind::__collapsing;
1238 }
1239
1240 template<typename... _Slices>
1241 consteval array<_SliceKind, sizeof...(_Slices)>
1242 __make_slice_kind_array()
1243 {
1244 return array<_SliceKind, sizeof...(_Slices)>{
1245 __mdspan::__make_slice_kind<_Slices>()...};
1246 }
1247
1248 // __block_size - 1
1249 // [full, ..., full, unit_slice , *]
1250 consteval bool
1251 __is_block(span<const _SliceKind> __slice_kinds, size_t __block_size)
1252 {
1253 if (__block_size == 0)
1254 return false;
1255
1256 if (__block_size > __slice_kinds.size())
1257 return false;
1258
1259 for (size_t __i = 0; __i < __block_size - 1; ++__i)
1260 if (__slice_kinds[__i] != _SliceKind::__full)
1261 return false;
1262
1263 auto __last = __slice_kinds[__block_size - 1];
1264 return __last == _SliceKind::__full
1265 || __last == _SliceKind::__unit_stride_slice;
1266 }
1267
1268 // __u __u + __sub_rank-2
1269 // [unit_slice, i, ..., k, full, ..., full, unit_slice, *]
1270 static consteval size_t
1271 __padded_block_begin_generic(span<const _SliceKind> __slice_kinds,
1272 size_t __sub_rank)
1273 {
1274 if (__slice_kinds[0] != _SliceKind::__full
1275 && __slice_kinds[0] != _SliceKind::__unit_stride_slice)
1276 return dynamic_extent;
1277 else if (__slice_kinds.size() == 1)
1278 return dynamic_extent;
1279 else
1280 {
1281 size_t __u = 1;
1282 while(__u < __slice_kinds.size()
1283 && __slice_kinds[__u] == _SliceKind::__collapsing)
1284 ++__u;
1285
1286 if (__mdspan::__is_block(__slice_kinds.subspan(__u), __sub_rank -1))
1287 return __u;
1288 return dynamic_extent;
1289 }
1290 }
1291
1292 template<_LayoutSide _Side, size_t _Nm>
1293 static consteval size_t
1294 __padded_block_begin(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank)
1295 {
1296 if constexpr (_Side == _LayoutSide::__left)
1297 return __mdspan::__padded_block_begin_generic(__slice_kinds, __sub_rank);
1298 else
1299 {
1300 std::array<_SliceKind, _Nm> __rev_slices;
1301 for(size_t __i = 0; __i < _Nm; ++__i)
1302 __rev_slices[__i] = __slice_kinds[_Nm - 1 - __i];
1303 auto __rev_slice_kinds = span<const _SliceKind>(__rev_slices);
1304
1305 auto __u = __mdspan::__padded_block_begin_generic(__rev_slice_kinds,
1306 __sub_rank);
1307 return __u == dynamic_extent ? dynamic_extent : _Nm - 1 - __u;
1308 }
1309 }
1310
1311 template<_LayoutSide _Side, bool _Padded>
1312 struct _SubMdspanMapping;
1313
1314 template<>
1315 struct _SubMdspanMapping<_LayoutSide::__left, false>
1316 {
1317 using _Layout = layout_left;
1318 template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>;
1319
1320 template<typename _Mapping, size_t _Us>
1321 static consteval size_t
1322 _S_pad()
1323 {
1324 using _Extents = typename _Mapping::extents_type;
1325 constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(0, _Us);
1326 if constexpr (!__mdspan::__all_static(__sta_exts))
1327 return dynamic_extent;
1328 else
1329 return __mdspan::__fwd_prod(__sta_exts);
1330 }
1331
1332 template<size_t _Nm>
1333 static consteval bool
1334 _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, size_t __sub_rank)
1335 { return __mdspan::__is_block(__slice_kinds, __sub_rank); }
1336 };
1337
1338 template<>
1339 struct _SubMdspanMapping<_LayoutSide::__left, true>
1340 {
1341 using _Layout = layout_left;
1342 template<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>;
1343
1344 template<typename _Mapping, size_t _Us>
1345 static consteval size_t
1346 _S_pad()
1347 {
1348 using _Extents = typename _Mapping::extents_type;
1349 constexpr auto __sta_exts
1350 = __mdspan::__static_extents<_Extents>(1, _Us);
1351 constexpr auto __sta_padstride
1352 = __mdspan::__get_static_stride<_Mapping>();
1353 if constexpr (__sta_padstride == dynamic_extent
1354 || !__mdspan::__all_static(__sta_exts))
1355 return dynamic_extent;
1356 else
1357 return __sta_padstride * __mdspan::__fwd_prod(__sta_exts);
1358 }
1359
1360 template<size_t _Nm>
1361 static consteval bool
1362 _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
1363 size_t __sub_rank)
1364 {
1365 if (__sub_rank == 1)
1366 return __slice_kinds[0] == _SliceKind::__unit_stride_slice
1367 || __slice_kinds[0] == _SliceKind::__full;
1368 else
1369 return false;
1370 }
1371 };
1372
1373 template<>
1374 struct _SubMdspanMapping<_LayoutSide::__right, false>
1375 {
1376 using _Layout = layout_right;
1377 template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>;
1378
1379 template<typename _Mapping, size_t _Us>
1380 static consteval size_t
1381 _S_pad()
1382 {
1383 using _Extents = typename _Mapping::extents_type;
1384 constexpr auto __rank = _Extents::rank();
1385 constexpr auto __sta_exts
1386 = __mdspan::__static_extents<_Extents>(_Us + 1, __rank);
1387 if constexpr (!__mdspan::__all_static(__sta_exts))
1388 return dynamic_extent;
1389 else
1390 return __fwd_prod(__sta_exts);
1391 }
1392
1393 template<size_t _Nm>
1394 static consteval bool
1395 _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
1396 size_t __sub_rank)
1397 {
1398 auto __rev_slice_kinds = array<_SliceKind, _Nm>{};
1399 for(size_t __i = 0; __i < _Nm; ++__i)
1400 __rev_slice_kinds[__i] = __slice_kinds[_Nm - 1 - __i];
1401 return __mdspan::__is_block(span(__rev_slice_kinds), __sub_rank);
1402 }
1403 };
1404
1405 template<>
1406 struct _SubMdspanMapping<_LayoutSide::__right, true>
1407 {
1408 using _Layout = layout_right;
1409 template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>;
1410
1411 template<typename _Mapping, size_t _Us>
1412 static consteval size_t
1413 _S_pad()
1414 {
1415 using _Extents = typename _Mapping::extents_type;
1416 constexpr auto __rank = _Extents::rank();
1417 constexpr auto __sta_exts
1418 = __mdspan::__static_extents<_Extents>(_Us + 1, __rank - 1);
1419 constexpr auto __sta_padstride
1420 = __mdspan::__get_static_stride<_Mapping>();
1421 if constexpr (__sta_padstride == dynamic_extent
1422 || !__mdspan::__all_static(__sta_exts))
1423 return dynamic_extent;
1424 else
1425 return __sta_padstride * __mdspan::__fwd_prod(__sta_exts);
1426 }
1427
1428 template<size_t _Nm>
1429 static consteval bool
1430 _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds,
1431 size_t __sub_rank)
1432 {
1433 if (__sub_rank == 1)
1434 return __slice_kinds[_Nm - 1] == _SliceKind::__unit_stride_slice
1435 || __slice_kinds[_Nm - 1] == _SliceKind::__full;
1436 else
1437 return false;
1438 }
1439 };
1440
1441
1442 template<typename _Mapping>
1443 constexpr auto
1444 __submdspan_mapping_impl(const _Mapping& __mapping)
1445 { return submdspan_mapping_result{__mapping, 0}; }
1446
1447 template<typename _Mapping, typename... _Slices>
1448 requires (sizeof...(_Slices) > 0)
1449 constexpr auto
1450 __submdspan_mapping_impl(const _Mapping& __mapping, _Slices... __slices)
1451 {
1452 using _IndexType = typename _Mapping::index_type;
1453 static_assert((__acceptable_slice_type<_Slices, _IndexType> && ...));
1454
1455 constexpr auto __side = __mdspan::__mapping_side<_Mapping>();
1456 constexpr auto __rank = sizeof...(_Slices);
1457 using _Trait = _SubMdspanMapping<__side, __is_padded_mapping<_Mapping>>;
1458 using _SliceView = span<const _SliceKind, __rank>;
1459
1460 constexpr auto __slice_kinds = __mdspan::__make_slice_kind_array<_Slices...>();
1461 auto __offset = __mdspan::__suboffset(__mapping, __slices...);
1462 auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...);
1463 using _SubExts = decltype(__sub_exts);
1464 constexpr auto __sub_rank = _SubExts::rank();
1465 if constexpr (__sub_rank == 0)
1466 return submdspan_mapping_result{
1467 typename _Trait::_Layout::mapping(__sub_exts), __offset};
1468 else if constexpr (_Trait::_S_is_unpadded_submdspan(
1469 _SliceView(__slice_kinds), __sub_rank))
1470 return submdspan_mapping_result{
1471 typename _Trait::_Layout::mapping(__sub_exts), __offset};
1472 else if constexpr (
1473 constexpr auto __u = __padded_block_begin<__side>(
1474 _SliceView(__slice_kinds), __sub_rank);
1475 __u != dynamic_extent)
1476 {
1477 constexpr auto __pad = _Trait::template _S_pad<_Mapping, __u>();
1478 using _Layout = typename _Trait::template _PaddedLayout<__pad>;
1479 return submdspan_mapping_result{
1480 typename _Layout::mapping(__sub_exts, __mapping.stride(__u)),
1481 __offset};
1482 }
1483 else
1484 {
1485 auto __sub_strides
1486 = __mdspan::__substrides<_SubExts>(__mapping, __slices...);
1487 return submdspan_mapping_result{
1488 layout_stride::mapping(__sub_exts, __sub_strides), __offset};
1489 }
1490 }
1491#endif // __glibcxx_submdspan
1492 }
1493
1494 template<typename _Extents>
1495 class layout_left::mapping
1496 {
1497 public:
1498 using extents_type = _Extents;
1499 using index_type = typename extents_type::index_type;
1500 using size_type = typename extents_type::size_type;
1501 using rank_type = typename extents_type::rank_type;
1502 using layout_type = layout_left;
1503
1504 static_assert(__mdspan::__representable_size<extents_type, index_type>,
1505 "The size of extents_type must be representable as index_type");
1506
1507 constexpr
1508 mapping() noexcept = default;
1509
1510 constexpr
1511 mapping(const mapping&) noexcept = default;
1512
1513 constexpr
1514 mapping(const extents_type& __extents) noexcept
1515 : _M_extents(__extents)
1516 { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
1517
1518 template<typename _OExtents>
1519 requires is_constructible_v<extents_type, _OExtents>
1520 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
1521 mapping(const mapping<_OExtents>& __other) noexcept
1522 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1523 { }
1524
1525 template<typename _OExtents>
1526 requires (extents_type::rank() <= 1)
1527 && is_constructible_v<extents_type, _OExtents>
1528 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
1529 mapping(const layout_right::mapping<_OExtents>& __other) noexcept
1530 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1531 { }
1532
1533 // noexcept for consistency with other layouts.
1534 template<typename _OExtents>
1535 requires is_constructible_v<extents_type, _OExtents>
1536 constexpr explicit(!(extents_type::rank() == 0
1537 && is_convertible_v<_OExtents, extents_type>))
1538 mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
1539 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1540 { __glibcxx_assert(*this == __other); }
1541
1542#if __glibcxx_padded_layouts
1543 template<typename _LeftpadMapping>
1544 requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
1545 && is_constructible_v<extents_type,
1546 typename _LeftpadMapping::extents_type>
1547 constexpr
1548 explicit(!is_convertible_v<typename _LeftpadMapping::extents_type,
1549 extents_type>)
1550 mapping(const _LeftpadMapping& __other) noexcept
1551 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1552 {
1553 constexpr size_t __ostride_sta
1554 = __mdspan::__get_static_stride<_LeftpadMapping>();
1555
1556 if constexpr (extents_type::rank() > 1)
1557 {
1558 if constexpr (extents_type::static_extent(0) != dynamic_extent
1559 && __ostride_sta != dynamic_extent)
1560 static_assert(extents_type::static_extent(0) == __ostride_sta);
1561 else
1562 __glibcxx_assert(__other.stride(1)
1563 == __other.extents().extent(0));
1564 }
1565 }
1566#endif // __glibcxx_padded_layouts
1567
1568 constexpr mapping&
1569 operator=(const mapping&) noexcept = default;
1570
1571 constexpr const extents_type&
1572 extents() const noexcept { return _M_extents; }
1573
1574 constexpr index_type
1575 required_span_size() const noexcept
1576 { return __mdspan::__size(_M_extents); }
1577
1578 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1579 // 4314. Missing move in mdspan layout mapping::operator()
1580 template<__mdspan::__valid_index_type<index_type>... _Indices>
1581 requires (sizeof...(_Indices) == extents_type::rank())
1582 constexpr index_type
1583 operator()(_Indices... __indices) const noexcept
1584 {
1585 return __mdspan::__linear_index_left(_M_extents,
1586 static_cast<index_type>(std::move(__indices))...);
1587 }
1588
1589 static constexpr bool
1590 is_always_unique() noexcept { return true; }
1591
1592 static constexpr bool
1593 is_always_exhaustive() noexcept { return true; }
1594
1595 static constexpr bool
1596 is_always_strided() noexcept { return true; }
1597
1598 static constexpr bool
1599 is_unique() noexcept { return true; }
1600
1601 static constexpr bool
1602 is_exhaustive() noexcept { return true; }
1603
1604 static constexpr bool
1605 is_strided() noexcept { return true; }
1606
1607 constexpr index_type
1608 stride(rank_type __i) const noexcept
1609 requires (extents_type::rank() > 0)
1610 {
1611 __glibcxx_assert(__i < extents_type::rank());
1612 return __mdspan::__fwd_prod(_M_extents, __i);
1613 }
1614
1615 template<typename _OExtents>
1616 requires (extents_type::rank() == _OExtents::rank())
1617 friend constexpr bool
1618 operator==(const mapping& __self, const mapping<_OExtents>& __other)
1619 noexcept
1620 { return __self.extents() == __other.extents(); }
1621
1622 private:
1623 template<typename _OExtents>
1624 constexpr explicit
1625 mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
1626 : _M_extents(__oexts)
1627 {
1628 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
1629 "The size of OtherExtents must be representable as index_type");
1630 __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
1631 }
1632
1633#if __glibcxx_submdspan
1634 template<typename... _Slices>
1635 requires (extents_type::rank() == sizeof...(_Slices))
1636 friend constexpr auto
1637 submdspan_mapping(const mapping& __mapping, _Slices... __slices)
1638 { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
1639#endif // __glibcxx_submdspan
1640
1641 [[no_unique_address]] extents_type _M_extents{};
1642 };
1643
1644 namespace __mdspan
1645 {
1646 template<typename _Extents, typename... _Indices>
1647 constexpr typename _Extents::index_type
1648 __linear_index_right(const _Extents& __exts, _Indices... __indices)
1649 noexcept
1650 {
1651 using _IndexType = typename _Extents::index_type;
1652 array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
1653 _IndexType __res = 0;
1654 if constexpr (sizeof...(__indices) > 0)
1655 {
1656 _IndexType __mult = 1;
1657 auto __update = [&, __pos = __exts.rank()](_IndexType) mutable
1658 {
1659 --__pos;
1660 _GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos],
1661 __exts.extent(__pos)));
1662 __res += __ind_arr[__pos] * __mult;
1663 __mult *= __exts.extent(__pos);
1664 };
1665 (__update(__indices), ...);
1666 }
1667 return __res;
1668 }
1669 }
1670
1671 template<typename _Extents>
1672 class layout_right::mapping
1673 {
1674 public:
1675 using extents_type = _Extents;
1676 using index_type = typename extents_type::index_type;
1677 using size_type = typename extents_type::size_type;
1678 using rank_type = typename extents_type::rank_type;
1679 using layout_type = layout_right;
1680
1681 static_assert(__mdspan::__representable_size<extents_type, index_type>,
1682 "The size of extents_type must be representable as index_type");
1683
1684 constexpr
1685 mapping() noexcept = default;
1686
1687 constexpr
1688 mapping(const mapping&) noexcept = default;
1689
1690 constexpr
1691 mapping(const extents_type& __extents) noexcept
1692 : _M_extents(__extents)
1693 { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
1694
1695 template<typename _OExtents>
1696 requires is_constructible_v<extents_type, _OExtents>
1697 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
1698 mapping(const mapping<_OExtents>& __other) noexcept
1699 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1700 { }
1701
1702 template<typename _OExtents>
1703 requires (extents_type::rank() <= 1)
1704 && is_constructible_v<extents_type, _OExtents>
1705 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
1706 mapping(const layout_left::mapping<_OExtents>& __other) noexcept
1707 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1708 { }
1709
1710 template<typename _OExtents>
1711 requires is_constructible_v<extents_type, _OExtents>
1712 constexpr explicit(!(extents_type::rank() == 0
1713 && is_convertible_v<_OExtents, extents_type>))
1714 mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
1715 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1716 { __glibcxx_assert(*this == __other); }
1717
1718#if __glibcxx_padded_layouts
1719 template<typename _RightPaddedMapping>
1720 requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
1721 && is_constructible_v<extents_type,
1722 typename _RightPaddedMapping::extents_type>
1723 constexpr
1724 explicit(!is_convertible_v<typename _RightPaddedMapping::extents_type,
1725 extents_type>)
1726 mapping(const _RightPaddedMapping& __other) noexcept
1727 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1728 {
1729 constexpr size_t __rank = extents_type::rank();
1730 constexpr size_t __ostride_sta
1731 = __mdspan::__get_static_stride<_RightPaddedMapping>();
1732
1733 if constexpr (__rank > 1)
1734 {
1735 if constexpr (extents_type::static_extent(__rank - 1) != dynamic_extent
1736 && __ostride_sta != dynamic_extent)
1737 static_assert(extents_type::static_extent(__rank - 1)
1738 == __ostride_sta);
1739 else
1740 __glibcxx_assert(__other.stride(__rank - 2)
1741 == __other.extents().extent(__rank - 1));
1742 }
1743 }
1744#endif
1745
1746 constexpr mapping&
1747 operator=(const mapping&) noexcept = default;
1748
1749 constexpr const extents_type&
1750 extents() const noexcept { return _M_extents; }
1751
1752 constexpr index_type
1753 required_span_size() const noexcept
1754 { return __mdspan::__size(_M_extents); }
1755
1756 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1757 // 4314. Missing move in mdspan layout mapping::operator()
1758 template<__mdspan::__valid_index_type<index_type>... _Indices>
1759 requires (sizeof...(_Indices) == extents_type::rank())
1760 constexpr index_type
1761 operator()(_Indices... __indices) const noexcept
1762 {
1763 return __mdspan::__linear_index_right(
1764 _M_extents, static_cast<index_type>(std::move(__indices))...);
1765 }
1766
1767 static constexpr bool
1768 is_always_unique() noexcept
1769 { return true; }
1770
1771 static constexpr bool
1772 is_always_exhaustive() noexcept
1773 { return true; }
1774
1775 static constexpr bool
1776 is_always_strided() noexcept
1777 { return true; }
1778
1779 static constexpr bool
1780 is_unique() noexcept
1781 { return true; }
1782
1783 static constexpr bool
1784 is_exhaustive() noexcept
1785 { return true; }
1786
1787 static constexpr bool
1788 is_strided() noexcept
1789 { return true; }
1790
1791 constexpr index_type
1792 stride(rank_type __i) const noexcept
1793 requires (extents_type::rank() > 0)
1794 {
1795 __glibcxx_assert(__i < extents_type::rank());
1796 return __mdspan::__rev_prod(_M_extents, __i);
1797 }
1798
1799 template<typename _OExtents>
1800 requires (extents_type::rank() == _OExtents::rank())
1801 friend constexpr bool
1802 operator==(const mapping& __self, const mapping<_OExtents>& __other)
1803 noexcept
1804 { return __self.extents() == __other.extents(); }
1805
1806 private:
1807 template<typename _OExtents>
1808 constexpr explicit
1809 mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
1810 : _M_extents(__oexts)
1811 {
1812 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
1813 "The size of OtherExtents must be representable as index_type");
1814 __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
1815 }
1816
1817#if __glibcxx_submdspan
1818 template<typename... _Slices>
1819 requires (extents_type::rank() == sizeof...(_Slices))
1820 friend constexpr auto
1821 submdspan_mapping(const mapping& __mapping, _Slices... __slices)
1822 { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
1823#endif // __glibcxx_submdspan
1824
1825 [[no_unique_address]] extents_type _M_extents{};
1826 };
1827
1828 namespace __mdspan
1829 {
1830 template<typename _Mp>
1831 concept __mapping_alike = requires
1832 {
1833 requires __is_extents<typename _Mp::extents_type>;
1834 { _Mp::is_always_strided() } -> same_as<bool>;
1835 { _Mp::is_always_exhaustive() } -> same_as<bool>;
1836 { _Mp::is_always_unique() } -> same_as<bool>;
1837 bool_constant<_Mp::is_always_strided()>::value;
1838 bool_constant<_Mp::is_always_exhaustive()>::value;
1839 bool_constant<_Mp::is_always_unique()>::value;
1840 };
1841
1842 template<typename _Mapping, typename... _Indices>
1843 constexpr typename _Mapping::index_type
1844 __linear_index_strides(const _Mapping& __m, _Indices... __indices)
1845 noexcept
1846 {
1847 using _IndexType = typename _Mapping::index_type;
1848 _IndexType __res = 0;
1849 if constexpr (sizeof...(__indices) > 0)
1850 {
1851 auto __update = [&, __pos = 0u](_IndexType __idx) mutable
1852 {
1853 _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx,
1854 __m.extents().extent(__pos)));
1855 __res += __idx * __m.stride(__pos++);
1856 };
1857 (__update(__indices), ...);
1858 }
1859 return __res;
1860 }
1861 }
1862
1863 template<typename _Extents>
1864 class layout_stride::mapping
1865 {
1866 public:
1867 using extents_type = _Extents;
1868 using index_type = typename extents_type::index_type;
1869 using size_type = typename extents_type::size_type;
1870 using rank_type = typename extents_type::rank_type;
1871 using layout_type = layout_stride;
1872
1873 static_assert(__mdspan::__representable_size<extents_type, index_type>,
1874 "The size of extents_type must be representable as index_type");
1875
1876 constexpr
1877 mapping() noexcept
1878 {
1879 // The precondition is either statically asserted, or automatically
1880 // satisfied because dynamic extents are zero-initialized.
1881 size_t __stride = 1;
1882 for (size_t __i = extents_type::rank(); __i > 0; --__i)
1883 {
1884 _M_strides[__i - 1] = index_type(__stride);
1885 __stride *= size_t(_M_extents.extent(__i - 1));
1886 }
1887 }
1888
1889 constexpr
1890 mapping(const mapping&) noexcept = default;
1891
1892 template<typename _OIndexType>
1893 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1894 constexpr
1895 mapping(const extents_type& __exts,
1896 span<_OIndexType, extents_type::rank()> __strides) noexcept
1897 : _M_extents(__exts)
1898 {
1899 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1900 _M_strides[__i] =
1901 __mdspan::__index_type_cast<index_type>(as_const(__strides[__i]));
1902
1903 if constexpr (extents_type::rank() > 0)
1904 __glibcxx_assert(_M_check_unique());
1905 }
1906
1907 template<typename _OIndexType>
1908 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1909 constexpr
1910 mapping(const extents_type& __exts,
1911 const array<_OIndexType, extents_type::rank()>& __strides)
1912 noexcept
1913 : mapping(__exts,
1914 span<const _OIndexType, extents_type::rank()>(__strides))
1915 { }
1916
1917 template<__mdspan::__mapping_alike _StridedMapping>
1918 requires (is_constructible_v<extents_type,
1919 typename _StridedMapping::extents_type>
1920 && _StridedMapping::is_always_unique()
1921 && _StridedMapping::is_always_strided())
1922 constexpr explicit(!(
1923 is_convertible_v<typename _StridedMapping::extents_type, extents_type>
1924 && __mdspan::__standardized_mapping<_StridedMapping>))
1925 mapping(const _StridedMapping& __other) noexcept
1926 : _M_extents(__other.extents())
1927 {
1928 using _OIndexType = _StridedMapping::index_type;
1929 using _OExtents = _StridedMapping::extents_type;
1930
1931 __glibcxx_assert(__mdspan::__offset(__other) == 0);
1932 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
1933 "The size of StridedMapping::extents_type must be representable as"
1934 " index_type");
1935 if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max,
1936 __gnu_cxx::__int_traits<index_type>::__max))
1937 __glibcxx_assert(!cmp_less(
1938 __gnu_cxx::__int_traits<index_type>::__max,
1939 __other.required_span_size())
1940 && "other.required_span_size() must be representable"
1941 " as index_type");
1942 if constexpr (extents_type::rank() > 0)
1943 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1944 _M_strides[__i] = index_type(__other.stride(__i));
1945 }
1946
1947 constexpr mapping&
1948 operator=(const mapping&) noexcept = default;
1949
1950 constexpr const extents_type&
1951 extents() const noexcept { return _M_extents; }
1952
1953 constexpr array<index_type, extents_type::rank()>
1954 strides() const noexcept
1955 {
1956 array<index_type, extents_type::rank()> __ret;
1957 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1958 __ret[__i] = _M_strides[__i];
1959 return __ret;
1960 }
1961
1962 constexpr index_type
1963 required_span_size() const noexcept
1964 {
1965 if (__mdspan::__empty(_M_extents))
1966 return 0;
1967
1968 index_type __ret = 1;
1969 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1970 __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i];
1971 return __ret;
1972 }
1973
1974 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1975 // 4314. Missing move in mdspan layout mapping::operator()
1976 template<__mdspan::__valid_index_type<index_type>... _Indices>
1977 requires (sizeof...(_Indices) == extents_type::rank())
1978 constexpr index_type
1979 operator()(_Indices... __indices) const noexcept
1980 {
1981 return __mdspan::__linear_index_strides(*this,
1982 static_cast<index_type>(std::move(__indices))...);
1983 }
1984
1985 static constexpr bool
1986 is_always_unique() noexcept { return true; }
1987
1988 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1989 // 4266. layout_stride::mapping should treat empty mappings as exhaustive
1990 static constexpr bool
1991 is_always_exhaustive() noexcept
1992 {
1993 return (_Extents::rank() == 0) || __mdspan::__contains_zero(
1994 __mdspan::__static_extents<extents_type>());
1995 }
1996
1997 static constexpr bool
1998 is_always_strided() noexcept { return true; }
1999
2000 static constexpr bool
2001 is_unique() noexcept { return true; }
2002
2003 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2004 // 4266. layout_stride::mapping should treat empty mappings as exhaustive
2005 constexpr bool
2006 is_exhaustive() const noexcept
2007 {
2008 if constexpr (!is_always_exhaustive())
2009 {
2010 auto __size = __mdspan::__size(_M_extents);
2011 if(__size > 0)
2012 return __size == required_span_size();
2013 }
2014 return true;
2015 }
2016
2017 static constexpr bool
2018 is_strided() noexcept { return true; }
2019
2020 constexpr index_type
2021 stride(rank_type __r) const noexcept { return _M_strides[__r]; }
2022
2023 template<__mdspan::__mapping_alike _OMapping>
2024 requires ((extents_type::rank() == _OMapping::extents_type::rank())
2025 && _OMapping::is_always_strided())
2026 friend constexpr bool
2027 operator==(const mapping& __self, const _OMapping& __other) noexcept
2028 {
2029 if (__self.extents() != __other.extents())
2030 return false;
2031 if constexpr (extents_type::rank() > 0)
2032 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
2033 if (!cmp_equal(__self.stride(__i), __other.stride(__i)))
2034 return false;
2035 return __mdspan::__offset(__other) == 0;
2036 }
2037
2038 private:
2039 using _Strides = typename __array_traits<index_type,
2040 extents_type::rank()>::_Type;
2041
2042 constexpr bool
2043 _M_check_unique() const
2044 {
2045 constexpr size_t __rank = extents_type::rank();
2046 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2047 // 4603. `layout_stride` should accept zero strides for empty `extents`
2048 // 4606. Bullet (4.3) preconditions are too strict to implement submdspan
2049
2050 if (__mdspan::__empty(_M_extents))
2051 return true;
2052
2053 auto __stride_nonzero = [&](size_t __idx)
2054 { return (_M_strides[__idx] > 0) || (_M_extents.extent(__idx) == 1); };
2055
2056 if constexpr (__rank == 1)
2057 return __stride_nonzero(0);
2058 else if constexpr (__rank == 2)
2059 {
2060 if (_M_extents.extent(0) == 1)
2061 return __stride_nonzero(1);
2062 if (_M_extents.extent(1) == 1)
2063 return __stride_nonzero(0);
2064 if (!_M_strides[0] || !_M_strides[1])
2065 return false;
2066 return (_M_strides[1] > _M_strides[0] * (_M_extents.extent(0) - 1))
2067 || (_M_strides[0] > _M_strides[1] * (_M_extents.extent(1) - 1));
2068 }
2069 else
2070 {
2071 // This is necessary, but not sufficient condition for uniqueness.
2072 // It requires computation in range of call of operator(), so check
2073 // if first, also in non-debug mode.
2074 if (required_span_size() < __mdspan::__size(_M_extents))
2075 return false;
2076
2077 // Checking for a valid permutation of strides is O(rank^2) so
2078 // so enabled only in debug mode.
2079#ifdef _GLIBCXX_DEBUG
2080 size_t __perm[__rank];
2081 for (size_t __i = 0; __i < __rank; ++__i)
2082 __perm[__i] = __i;
2083
2084 auto __getstride = [&](size_t __idx) { return _M_strides[__idx]; };
2085 auto __getextent = [&](size_t __idx) { return _M_extents.extent(__idx); };
2086 auto __popmin = [&](size_t __from, auto __getter)
2087 {
2088 size_t __min = __perm[__rank - 1];
2089 for (size_t __i = __rank - 1; __i > __from; --__i)
2090 {
2091 const size_t __cur = __perm[__i - 1];
2092 if (__getter(__cur) < __getter(__min))
2093 {
2094 __perm[__i] = __min;
2095 __min = __cur;
2096 }
2097 else
2098 __perm[__i] = __cur;
2099 }
2100 __perm[__from] = __min;
2101 return __getter(__min);
2102 };
2103
2104 // We use eager insertion-sort based algorithm to permute the __perm.
2105 size_t __idx = 0;
2106
2107 // Stride values are not relevant for dimension with single element
2108 while (__popmin(__idx, __getextent) == 1)
2109 if (++__idx == __rank)
2110 return true;
2111
2112 size_t __prev_span = 1;
2113 for (; __idx < __rank; ++__idx)
2114 {
2115 const size_t __stride = __popmin(__idx, __getstride);
2116 if (__stride < __prev_span)
2117 return false;
2118 __prev_span += __stride * (__getextent(__perm[__idx]) - 1);
2119 }
2120#else
2121 // Otherwise check obvious cases where stride is zero.
2122 for (size_t __idx = 0; __idx < __rank; ++__idx)
2123 if (!__stride_nonzero(__idx))
2124 return false;
2125#endif
2126 return true;
2127 }
2128 }
2129
2130#if __glibcxx_submdspan
2131 template<typename... _Slices>
2132 requires (extents_type::rank() == sizeof...(_Slices))
2133 friend constexpr auto
2134 submdspan_mapping(const mapping& __mapping, _Slices... __slices)
2135 {
2136 if constexpr (sizeof...(_Slices) == 0)
2137 return submdspan_mapping_result{__mapping, 0};
2138 else
2139 {
2140 auto __offset = __mdspan::__suboffset(__mapping, __slices...);
2141 auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...);
2142 auto __sub_strides
2143 = __mdspan::__substrides<decltype(__sub_exts)>(__mapping, __slices...);
2144 return submdspan_mapping_result{
2145 layout_stride::mapping(__sub_exts, __sub_strides), __offset};
2146 }
2147 }
2148#endif
2149
2150 [[no_unique_address]] extents_type _M_extents;
2151 [[no_unique_address]] _Strides _M_strides;
2152 };
2153
2154#ifdef __glibcxx_padded_layouts
2155 namespace __mdspan
2156 {
2157 constexpr size_t
2158 __least_multiple(size_t __x, size_t __y)
2159 {
2160 if (__x <= 1)
2161 return __y;
2162 return (__y / __x + (__y % __x != 0)) * __x ;
2163 }
2164
2165 template<typename _IndexType>
2166 constexpr bool
2167 __is_representable_least_multiple(size_t __x, size_t __y)
2168 {
2169 constexpr auto __y_max = __gnu_cxx::__int_traits<_IndexType>::__max;
2170 if(std::cmp_greater(__y, __y_max))
2171 return false;
2172
2173 if(__x <= 1)
2174 return true;
2175
2176 auto __max_delta = __y_max - static_cast<_IndexType>(__y);
2177 auto __y_mod_x = __y % __x;
2178 auto __delta = (__y_mod_x == 0) ? size_t(0) : (__x - __y_mod_x);
2179 return std::cmp_less_equal(__delta, __max_delta);
2180 }
2181
2182 template<typename _Extents, size_t _PaddingValue, typename _LayoutTraits,
2183 size_t _Rank = _Extents::rank()>
2184 concept __valid_static_stride = (_Extents::rank() <= 1)
2185 || (_PaddingValue == dynamic_extent)
2186 || (_Extents::static_extent(_LayoutTraits::_S_ext_idx) == dynamic_extent)
2187 || (__is_representable_least_multiple<size_t>(
2188 _PaddingValue, _Extents::static_extent(_LayoutTraits::_S_ext_idx)));
2189
2190 template<size_t _PaddedStride, typename _Extents,
2191 typename _LayoutTraits>
2192 consteval bool
2193 __is_representable_padded_size()
2194 {
2195 using _IndexType = typename _Extents::index_type;
2196 auto __sta_exts = __static_extents<_Extents>(
2197 _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
2198 size_t __max = __gnu_cxx::__int_traits<_IndexType>::__max;
2199 return __static_quotient(__sta_exts, __max / _PaddedStride) != 0;
2200 }
2201
2202 template<typename _Extents, size_t _PaddedStride, typename _LayoutTraits,
2203 size_t _Rank = _Extents::rank()>
2204 concept __valid_padded_size = (_Rank <= 1)
2205 || (_PaddedStride == dynamic_extent)
2206 || (!__all_static(__static_extents<_Extents>()))
2207 || (__contains_zero(__static_extents<_Extents>()))
2208 || (__is_representable_padded_size<_PaddedStride, _Extents,
2209 _LayoutTraits>());
2210
2211 template<typename _Extents, typename _Stride, typename... _Indices>
2212 constexpr typename _Extents::index_type
2213 __linear_index_leftpad(const _Extents& __exts, _Stride __stride,
2214 _Indices... __indices)
2215 {
2216 // i0 + stride*(i1 + extents.extent(1)*...)
2217 using _IndexType = typename _Extents::index_type;
2218 _IndexType __res = 0;
2219 if constexpr (sizeof...(__indices) > 0)
2220 {
2221 _IndexType __mult = 1;
2222
2223 auto __update_rest = [&, __pos = 1u](_IndexType __idx) mutable
2224 {
2225 __res += __idx * __mult;
2226 __mult *= __exts.extent(__pos);
2227 ++__pos;
2228 };
2229
2230 auto __update = [&](_IndexType __idx, auto... __rest)
2231 {
2232 __res += __idx;
2233 __mult = __stride.extent(0);
2234 (__update_rest(__rest), ...);
2235 };
2236 __update(__indices...);
2237 }
2238 return __res;
2239 }
2240
2241 template<typename _Extents, typename _Stride, typename... _Indices>
2242 constexpr typename _Extents::index_type
2243 __linear_index_rightpad(const _Extents& __exts, _Stride __stride,
2244 _Indices... __indices)
2245 {
2246 // i[n-1] + stride*(i[n-2] + extents.extent(n-2])*...)
2247 using _IndexType = typename _Extents::index_type;
2248 _IndexType __res = 0;
2249 if constexpr (sizeof...(__indices) > 0)
2250 {
2251 _IndexType __mult = 1;
2252 array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
2253
2254 auto __update_rest = [&, __pos = __exts.rank()-1](_IndexType) mutable
2255 {
2256 --__pos;
2257 __res += __ind_arr[__pos] * __mult;
2258 __mult *= __exts.extent(__pos);
2259 };
2260
2261 auto __update = [&](_IndexType, auto... __rest)
2262 {
2263 __res += __ind_arr[__exts.rank() - 1];
2264 __mult = __stride.extent(0);
2265 (__update_rest(__rest), ...);
2266 };
2267 __update(__indices...);
2268 }
2269 return __res;
2270 }
2271
2272 template<size_t _Rank>
2273 struct _LeftPaddedLayoutTraits
2274 {
2275 using _LayoutSame = layout_left;
2276 using _LayoutOther = layout_right;
2277
2278 constexpr static const size_t _S_ext_idx = 0;
2279 constexpr static const size_t _S_stride_idx = 1;
2280 constexpr static const size_t _S_unpad_begin = 1;
2281 constexpr static const size_t _S_unpad_end = _Rank;
2282
2283 template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
2284 constexpr static auto
2285 _S_make_padded_extent(
2286 extents<_IndexType, _StaticStride> __stride,
2287 const extents<_IndexType, _Extents...>& __exts)
2288 {
2289 auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>)
2290 {
2291 return extents<_IndexType, _StaticStride,
2292 (_Extents...[_Is + 1])...>{
2293 __stride.extent(0), __exts.extent(_Is + 1)...};
2294 };
2295 return __impl(make_index_sequence<sizeof...(_Extents) - 1>());
2296 }
2297 };
2298
2299 template<size_t _Rank>
2300 struct _RightPaddedLayoutTraits
2301 {
2302 using _LayoutSame = layout_right;
2303 using _LayoutOther = layout_left;
2304
2305 constexpr static size_t _S_ext_idx = _Rank - 1;
2306 constexpr static size_t _S_stride_idx = _Rank - 2;
2307 constexpr static size_t _S_unpad_begin = 0;
2308 constexpr static size_t _S_unpad_end = _Rank - 1;
2309
2310 template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
2311 constexpr static auto
2312 _S_make_padded_extent(
2313 extents<_IndexType, _StaticStride> __stride,
2314 const extents<_IndexType, _Extents...>& __exts)
2315 {
2316 auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>)
2317 {
2318 return extents<_IndexType, (_Extents...[_Is])..., _StaticStride>{
2319 __exts.extent(_Is)..., __stride.extent(0)};
2320 };
2321 return __impl(make_index_sequence<sizeof...(_Extents) - 1>());
2322 }
2323 };
2324
2325 template<size_t _PaddingValue, typename _Extents, typename _LayoutTraits>
2326 class _PaddedStorage
2327 {
2328 using _LayoutSame = typename _LayoutTraits::_LayoutSame;
2329
2330 public:
2331 using _IndexType = typename _Extents::index_type;
2332 constexpr static size_t _S_rank = _Extents::rank();
2333
2334 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2335 // 4372. Weaken Mandates: for dynamic padding values in padded layouts
2336 static_assert((_PaddingValue == dynamic_extent)
2337 || (cmp_less_equal(_PaddingValue,
2338 __gnu_cxx::__int_traits<_IndexType>::__max)),
2339 "padding_value must be representable as index_type");
2340
2341 static_assert(__representable_size<_Extents, _IndexType>,
2342 "The size of extents_type must be representable as index_type");
2343
2344 static_assert(__valid_static_stride<_Extents, _PaddingValue,
2345 _LayoutTraits>,
2346 "The padded stride must be representable as size_t");
2347
2348 static constexpr size_t _S_static_stride = [] consteval
2349 {
2350 constexpr size_t __rank = _Extents::rank();
2351 if constexpr (__rank <= 1)
2352 return 0;
2353 else
2354 {
2355 constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
2356 constexpr size_t __sta_ext = _Extents::static_extent(__ext_idx);
2357 if constexpr (__sta_ext == 0)
2358 return size_t(0);
2359 else if constexpr (_PaddingValue == dynamic_extent
2360 || __sta_ext == dynamic_extent)
2361 return dynamic_extent;
2362 else
2363 return __least_multiple(_PaddingValue, __sta_ext);
2364 }
2365 }();
2366
2367 static_assert(_S_static_stride == dynamic_extent
2368 || cmp_less_equal(_S_static_stride,
2369 __gnu_cxx::__int_traits<_IndexType>::__max),
2370 "Padded stride must be representable as index_type");
2371
2372 static_assert(__valid_padded_size<_Extents, _S_static_stride,
2373 _LayoutTraits>);
2374
2375 constexpr
2376 _PaddedStorage() noexcept
2377 {
2378 if constexpr (_S_rank > 1)
2379 if constexpr (_S_static_stride == dynamic_extent
2380 && _S_static_padextent() != dynamic_extent)
2381 _M_stride = _Stride{_S_static_padextent()};
2382 }
2383
2384 constexpr explicit
2385 _PaddedStorage(const _Extents& __exts)
2386 : _M_extents(__exts)
2387 {
2388 if constexpr (!__all_static(__static_extents<_Extents>()))
2389 __glibcxx_assert(__is_representable_extents(_M_extents));
2390
2391 if constexpr (_S_rank > 1)
2392 {
2393 _IndexType __stride;
2394 if constexpr (_PaddingValue == dynamic_extent)
2395 __stride = _M_padextent();
2396 else if constexpr (_S_static_padextent() != dynamic_extent)
2397 return;
2398 else
2399 {
2400 __glibcxx_assert(
2401 __is_representable_least_multiple<_IndexType>(
2402 _PaddingValue, _M_padextent()));
2403
2404 __stride = static_cast<_IndexType>(
2405 __least_multiple(_PaddingValue, _M_padextent()));
2406
2407 __glibcxx_assert(__is_representable_extents(
2408 _LayoutTraits::_S_make_padded_extent(
2409 std::dextents<_IndexType, 1>{__stride},
2410 _M_extents)));
2411 }
2412 _M_stride = _Stride{__stride};
2413 }
2414 }
2415
2416 constexpr explicit
2417 _PaddedStorage(const _Extents& __exts, _IndexType __pad)
2418 : _M_extents(__exts)
2419 {
2420 if constexpr (_PaddingValue != dynamic_extent)
2421 __glibcxx_assert(cmp_equal(_PaddingValue, __pad));
2422 if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent)
2423 {
2424 __glibcxx_assert(
2425 __is_representable_least_multiple<_IndexType>(
2426 __pad, _M_padextent()));
2427
2428 _M_stride = _Stride{static_cast<_IndexType>(
2429 __least_multiple(__pad, _M_padextent()))};
2430
2431 __glibcxx_assert(__is_representable_extents(
2432 _LayoutTraits::_S_make_padded_extent(
2433 _M_stride, _M_extents)));
2434 }
2435 }
2436
2437 template<typename _OExtents>
2438 constexpr explicit
2439 _PaddedStorage(
2440 const typename _LayoutSame::template mapping<_OExtents>& __other)
2441 : _PaddedStorage(_Extents(__other.extents()))
2442 {
2443 constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
2444 constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
2445 if constexpr (_S_rank > 1 && _PaddingValue != dynamic_extent)
2446 {
2447 static_assert(_S_static_stride == dynamic_extent
2448 || _OExtents::static_extent(__ext_idx) == dynamic_extent
2449 || _S_static_stride == _OExtents::static_extent(__ext_idx),
2450 "The padded stride must be compatible with other");
2451
2452 if constexpr (_S_static_stride == dynamic_extent
2453 || _OExtents::static_extent(__stride_idx) == dynamic_extent)
2454 __glibcxx_assert(std::cmp_equal(_M_padstride(),
2455 _M_padextent()));
2456 }
2457 }
2458
2459 template<typename _OExtents>
2460 constexpr explicit
2461 _PaddedStorage(const typename layout_stride::mapping<_OExtents>&
2462 __other)
2463 : _M_extents(__other.extents())
2464 {
2465 __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
2467 ::__max));
2468
2469 constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
2470 if constexpr (_S_rank > 1)
2471 {
2472 if constexpr (_PaddingValue != dynamic_extent)
2473 __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
2474 _M_calc_padstride())
2475 && "The padded stride must be compatible with other");
2476 if constexpr (_S_static_stride == dynamic_extent)
2477 _M_stride = _Stride{__other.stride(__stride_idx)};
2478 }
2479 }
2480
2481 template<typename _SamePaddedMapping>
2482 constexpr explicit
2483 _PaddedStorage(_LayoutTraits::_LayoutSame,
2484 const _SamePaddedMapping& __other)
2485 : _M_extents(__other.extents())
2486 {
2487 if constexpr (_S_rank > 1)
2488 {
2489 static_assert(_PaddingValue == dynamic_extent
2490 || _SamePaddedMapping::padding_value == dynamic_extent
2491 || _PaddingValue == _SamePaddedMapping::padding_value,
2492 "If neither PaddingValue is dynamic_extent, then they must "
2493 "be equal");
2494
2495 constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
2496 if constexpr (_PaddingValue != dynamic_extent)
2497 __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
2498 _M_calc_padstride())
2499 && "The padded stride must be compatible with other");
2500 if constexpr (_S_static_stride == dynamic_extent)
2501 _M_stride = _Stride{__other.stride(__stride_idx)};
2502 }
2503 __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
2504 __gnu_cxx::__int_traits<_IndexType>::__max));
2505 }
2506
2507 template<typename _OtherPaddedMapping>
2508 constexpr explicit
2509 _PaddedStorage(_LayoutTraits::_LayoutOther,
2510 const _OtherPaddedMapping& __other) noexcept
2511 : _M_extents(__other.extents())
2512 {
2513 __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
2514 __gnu_cxx::__int_traits<_IndexType>::__max));
2515 }
2516
2517 static constexpr bool
2518 _M_is_always_exhaustive() noexcept
2519 {
2520 if constexpr (_S_rank <= 1)
2521 return true;
2522 else
2523 return _S_static_padextent() != dynamic_extent
2524 && _S_static_stride != dynamic_extent
2525 && _S_static_padextent() == _S_static_stride;
2526 }
2527
2528 constexpr bool
2529 _M_is_exhaustive() const noexcept
2530 {
2531 if constexpr (_M_is_always_exhaustive())
2532 return true;
2533 else
2534 return cmp_equal(_M_padextent(), _M_padstride());
2535 }
2536
2537 constexpr static size_t
2538 _S_static_padextent() noexcept
2539 { return _Extents::static_extent(_LayoutTraits::_S_ext_idx); }
2540
2541 constexpr _IndexType
2542 _M_padextent() const noexcept
2543 { return _M_extents.extent(_LayoutTraits::_S_ext_idx); }
2544
2545 constexpr _IndexType
2546 _M_calc_padstride() const noexcept
2547 {
2548 if constexpr (_S_static_stride != dynamic_extent)
2549 return _S_static_stride;
2550 else if constexpr (_PaddingValue != dynamic_extent)
2551 return __least_multiple(_PaddingValue, _M_padextent());
2552 else
2553 return _M_padextent();
2554 }
2555
2556 constexpr _IndexType
2557 _M_padstride() const noexcept
2558 { return _M_stride.extent(0); }
2559
2560 constexpr _IndexType
2561 _M_required_span_size() const noexcept
2562 {
2563 if constexpr (_S_rank == 0)
2564 return 1;
2565 else if (__mdspan::__empty(_M_extents))
2566 return 0;
2567 else
2568 {
2569 size_t __stride = static_cast<size_t>(_M_padstride());
2570 size_t __prod_rest = __mdspan::__fwd_prod(_M_extents,
2571 _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
2572 size_t __delta = _M_padstride() - _M_padextent();
2573 return static_cast<_IndexType>(__stride * __prod_rest - __delta);
2574 }
2575 }
2576
2577 template<typename _SamePaddedMapping>
2578 constexpr bool
2579 _M_equal(const _SamePaddedMapping& __other) const noexcept
2580 {
2581 return _M_extents == __other.extents()
2582 && (_S_rank < 2
2583 || cmp_equal(_M_stride.extent(0),
2584 __other.stride(_LayoutTraits::_S_stride_idx)));
2585 }
2586
2587 using _Stride = std::extents<_IndexType, _S_static_stride>;
2588 [[no_unique_address]] _Stride _M_stride;
2589 [[no_unique_address]] _Extents _M_extents;
2590 };
2591 }
2592
2593 template<size_t _PaddingValue>
2594 template<typename _Extents>
2595 class layout_left_padded<_PaddingValue>::mapping
2596 {
2597 public:
2598 static constexpr size_t padding_value = _PaddingValue;
2599
2600 using extents_type = _Extents;
2601 using index_type = typename extents_type::index_type;
2602 using size_type = typename extents_type::size_type;
2603 using rank_type = typename extents_type::rank_type;
2604 using layout_type = layout_left_padded<padding_value>;
2605
2606 private:
2607 static constexpr size_t _S_rank = extents_type::rank();
2608 using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
2609 _Extents, __mdspan::_LeftPaddedLayoutTraits<_S_rank>>;
2610 [[no_unique_address]] _PaddedStorage _M_storage;
2611
2612 consteval friend size_t
2613 __mdspan::__get_static_stride<mapping>();
2614
2615 constexpr index_type
2616 _M_extent(size_t __r) const noexcept
2617 { return _M_storage._M_extents.extent(__r); }
2618
2619 constexpr index_type
2620 _M_padstride() const noexcept
2621 { return _M_storage._M_stride.extent(0); }
2622
2623 public:
2624 constexpr
2625 mapping() noexcept
2626 { }
2627
2628 constexpr
2629 mapping(const mapping&) noexcept = default;
2630
2631 constexpr
2632 mapping(const extents_type& __exts)
2633 : _M_storage(__exts)
2634 { }
2635
2636 template<__mdspan::__valid_index_type<index_type> _OIndexType>
2637 constexpr
2638 mapping(const extents_type& __exts, _OIndexType __pad)
2639 : _M_storage(__exts,
2640 __mdspan::__index_type_cast<index_type>(std::move(__pad)))
2641 { }
2642
2643 template<typename _OExtents>
2644 requires is_constructible_v<extents_type, _OExtents>
2645 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
2646 mapping(const layout_left::mapping<_OExtents>& __other)
2647 : _M_storage(__other)
2648 { }
2649
2650 template<typename _OExtents>
2651 requires is_constructible_v<_OExtents, extents_type>
2652 constexpr explicit(!(_OExtents::rank() == 0
2653 && is_convertible_v<_OExtents, extents_type>))
2654 mapping(const typename layout_stride::mapping<_OExtents>& __other)
2655 : _M_storage(__other)
2656 { __glibcxx_assert(*this == __other); }
2657
2658 template<typename _LeftPaddedMapping>
2659 requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
2660 && is_constructible_v<extents_type,
2661 typename _LeftPaddedMapping::extents_type>
2662 constexpr explicit(
2663 !is_convertible_v<typename _LeftPaddedMapping::extents_type,
2664 extents_type>
2665 || _S_rank > 1 && (padding_value != dynamic_extent
2666 || _LeftPaddedMapping::padding_value == dynamic_extent))
2667 mapping(const _LeftPaddedMapping& __other)
2668 : _M_storage(layout_left{}, __other)
2669 { }
2670
2671 template<typename _RightPaddedMapping>
2672 requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
2673 || __mdspan::__mapping_of<layout_right, _RightPaddedMapping>)
2674 && (_S_rank <= 1)
2675 && is_constructible_v<extents_type,
2676 typename _RightPaddedMapping::extents_type>
2677 constexpr explicit(!is_convertible_v<
2678 typename _RightPaddedMapping::extents_type, extents_type>)
2679 mapping(const _RightPaddedMapping& __other) noexcept
2680 : _M_storage(layout_right{}, __other)
2681 { }
2682
2683 constexpr mapping&
2684 operator=(const mapping&) noexcept = default;
2685
2686 constexpr const extents_type&
2687 extents() const noexcept { return _M_storage._M_extents; }
2688
2689 constexpr array<index_type, _S_rank>
2690 strides() const noexcept
2691 {
2692 array<index_type, _S_rank> __ret;
2693 if constexpr (_S_rank > 0)
2694 __ret[0] = 1;
2695 if constexpr (_S_rank > 1)
2696 __ret[1] = _M_padstride();
2697 if constexpr (_S_rank > 2)
2698 for(size_t __i = 2; __i < _S_rank; ++__i)
2699 __ret[__i] = __ret[__i - 1] * _M_extent(__i - 1);
2700 return __ret;
2701 }
2702
2703 constexpr index_type
2704 required_span_size() const noexcept
2705 { return _M_storage._M_required_span_size(); }
2706
2707 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2708 // 4314. Missing move in mdspan layout mapping::operator()
2709 template<__mdspan::__valid_index_type<index_type>... _Indices>
2710 requires (sizeof...(_Indices) == _S_rank)
2711 constexpr index_type
2712 operator()(_Indices... __indices) const noexcept
2713 {
2714 return __mdspan::__linear_index_leftpad(
2715 extents(), _M_storage._M_stride,
2716 static_cast<index_type>(std::move(__indices))...);
2717 }
2718
2719 static constexpr bool
2720 is_always_exhaustive() noexcept
2721 { return _PaddedStorage::_M_is_always_exhaustive(); }
2722
2723 constexpr bool
2724 is_exhaustive() const noexcept
2725 { return _M_storage._M_is_exhaustive(); }
2726
2727 static constexpr bool
2728 is_always_unique() noexcept { return true; }
2729
2730 static constexpr bool
2731 is_unique() noexcept { return true; }
2732
2733 static constexpr bool
2734 is_always_strided() noexcept { return true; }
2735
2736 static constexpr bool
2737 is_strided() noexcept { return true; }
2738
2739 constexpr index_type
2740 stride(rank_type __r) const noexcept
2741 {
2742 __glibcxx_assert(__r < _S_rank);
2743 if (__r == 0)
2744 return 1;
2745 else
2746 return static_cast<index_type>(
2747 static_cast<size_t>(_M_padstride()) *
2748 static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1, __r)));
2749 }
2750
2751 template<typename _LeftpadMapping>
2752 requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping>
2753 && _LeftpadMapping::extents_type::rank() == _S_rank)
2754 friend constexpr bool
2755 operator==(const mapping& __self, const _LeftpadMapping& __other)
2756 noexcept
2757 { return __self._M_storage._M_equal(__other); }
2758
2759 private:
2760#if __glibcxx_submdspan
2761 template<typename... _Slices>
2762 requires (extents_type::rank() == sizeof...(_Slices))
2763 friend constexpr auto
2764 submdspan_mapping(const mapping& __mapping, _Slices... __slices)
2765 { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
2766#endif // __glibcxx_submdspan
2767 };
2768
2769 template<size_t _PaddingValue>
2770 template<typename _Extents>
2771 class layout_right_padded<_PaddingValue>::mapping {
2772 public:
2773 static constexpr size_t padding_value = _PaddingValue;
2774 using extents_type = _Extents;
2775 using index_type = typename extents_type::index_type;
2776 using size_type = typename extents_type::size_type;
2777 using rank_type = typename extents_type::rank_type;
2778 using layout_type = layout_right_padded<_PaddingValue>;
2779
2780 private:
2781 static constexpr size_t _S_rank = extents_type::rank();
2782 using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
2783 _Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>;
2784 [[no_unique_address]] _PaddedStorage _M_storage;
2785
2786 consteval friend size_t
2787 __mdspan::__get_static_stride<mapping>();
2788
2789 constexpr index_type
2790 _M_extent(size_t __r) const noexcept
2791 { return _M_storage._M_extents.extent(__r); }
2792
2793 constexpr index_type
2794 _M_padstride() const noexcept
2795 { return _M_storage._M_stride.extent(0); }
2796
2797 public:
2798 constexpr
2799 mapping() noexcept
2800 { }
2801
2802 constexpr
2803 mapping(const mapping&) noexcept = default;
2804
2805 constexpr
2806 mapping(const extents_type& __exts)
2807 : _M_storage(__exts)
2808 { }
2809
2810 template<__mdspan::__valid_index_type<index_type> _OIndexType>
2811 constexpr
2812 mapping(const extents_type& __exts, _OIndexType __pad)
2813 : _M_storage(__exts,
2814 __mdspan::__index_type_cast<index_type>(std::move(__pad)))
2815 { }
2816
2817 template<typename _OExtents>
2818 requires is_constructible_v<extents_type, _OExtents>
2819 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
2820 mapping(const layout_right::mapping<_OExtents>& __other)
2821 : _M_storage(__other)
2822 { }
2823
2824 template<typename _OExtents>
2825 requires is_constructible_v<_OExtents, extents_type>
2826 constexpr explicit(!(_OExtents::rank() == 0
2827 && is_convertible_v<_OExtents, extents_type>))
2828 mapping(const typename layout_stride::mapping<_OExtents>& __other)
2829 : _M_storage(__other)
2830 { __glibcxx_assert(*this == __other); }
2831
2832 template<typename _RightPaddedMapping>
2833 requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
2834 && is_constructible_v<extents_type,
2835 typename _RightPaddedMapping::extents_type>
2836 constexpr explicit(
2837 !is_convertible_v<typename _RightPaddedMapping::extents_type,
2838 extents_type>
2839 || _S_rank > 1 && (padding_value != dynamic_extent
2840 || _RightPaddedMapping::padding_value == dynamic_extent))
2841 mapping(const _RightPaddedMapping& __other)
2842 : _M_storage(layout_right{}, __other)
2843 { }
2844
2845 template<typename _LeftPaddedMapping>
2846 requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
2847 || __mdspan::__mapping_of<layout_left, _LeftPaddedMapping>)
2848 && (_S_rank <= 1)
2849 && is_constructible_v<extents_type,
2850 typename _LeftPaddedMapping::extents_type>
2851 constexpr explicit(!is_convertible_v<
2852 typename _LeftPaddedMapping::extents_type, extents_type>)
2853 mapping(const _LeftPaddedMapping& __other) noexcept
2854 : _M_storage(layout_left{}, __other)
2855 { }
2856
2857 constexpr mapping& operator=(const mapping&) noexcept = default;
2858
2859 constexpr const extents_type&
2860 extents() const noexcept { return _M_storage._M_extents; }
2861
2862 constexpr array<index_type, _S_rank>
2863 strides() const noexcept
2864 {
2865 array<index_type, _S_rank> __ret;
2866 if constexpr (_S_rank > 0)
2867 __ret[_S_rank - 1] = 1;
2868 if constexpr (_S_rank > 1)
2869 __ret[_S_rank - 2] = _M_padstride();
2870 if constexpr (_S_rank > 2)
2871 for(size_t __i = _S_rank - 2; __i > 0; --__i)
2872 __ret[__i - 1] = __ret[__i] * _M_extent(__i);
2873 return __ret;
2874 }
2875
2876 constexpr index_type
2877 required_span_size() const noexcept
2878 { return _M_storage._M_required_span_size(); }
2879
2880 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2881 // 4314. Missing move in mdspan layout mapping::operator()
2882 template<__mdspan::__valid_index_type<index_type>... _Indices>
2883 requires (sizeof...(_Indices) == _S_rank)
2884 constexpr index_type
2885 operator()(_Indices... __indices) const noexcept
2886 {
2887 return __mdspan::__linear_index_rightpad(
2888 extents(), _M_storage._M_stride,
2889 static_cast<index_type>(std::move(__indices))...);
2890 }
2891
2892 static constexpr bool
2893 is_always_exhaustive() noexcept
2894 { return _PaddedStorage::_M_is_always_exhaustive(); }
2895
2896 constexpr bool
2897 is_exhaustive() const noexcept
2898 { return _M_storage._M_is_exhaustive(); }
2899
2900 static constexpr bool
2901 is_always_unique() noexcept { return true; }
2902
2903 static constexpr bool
2904 is_unique() noexcept { return true; }
2905
2906 static constexpr bool
2907 is_always_strided() noexcept { return true; }
2908
2909 static constexpr bool
2910 is_strided() noexcept { return true; }
2911
2912 constexpr index_type
2913 stride(rank_type __r) const noexcept
2914 {
2915 __glibcxx_assert(__r < _S_rank);
2916 if constexpr (_S_rank <= 1)
2917 return 1;
2918 else if (__r == _S_rank - 1)
2919 return 1;
2920 else if (__r == _S_rank - 2)
2921 return _M_padstride();
2922 else
2923 return static_cast<index_type>(
2924 static_cast<size_t>(_M_padstride()) *
2925 static_cast<size_t>(__mdspan::__fwd_prod(
2926 extents(), __r + 1, _S_rank - 1)));
2927 }
2928
2929 template<typename _RightPaddedMapping>
2930 requires(__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
2931 && _RightPaddedMapping::extents_type::rank() == _S_rank)
2932 friend constexpr bool
2933 operator==(const mapping& __self, const _RightPaddedMapping& __other)
2934 noexcept
2935 { return __self._M_storage._M_equal(__other); }
2936
2937#if __glibcxx_submdspan
2938 private:
2939 template<typename... _Slices>
2940 requires (extents_type::rank() == sizeof...(_Slices))
2941 friend constexpr auto
2942 submdspan_mapping(const mapping& __mapping, _Slices... __slices)
2943 { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); }
2944#endif // __glibcxx_submdspan
2945 };
2946#endif // __glibcxx_padded_layouts
2947
2948 template<typename _ElementType>
2949 struct default_accessor
2950 {
2951 static_assert(!is_array_v<_ElementType>,
2952 "ElementType must not be an array type");
2953 static_assert(!is_abstract_v<_ElementType>,
2954 "ElementType must not be an abstract class type");
2955
2956 using offset_policy = default_accessor;
2957 using element_type = _ElementType;
2958 using reference = element_type&;
2959 using data_handle_type = element_type*;
2960
2961 constexpr
2962 default_accessor() noexcept = default;
2963
2964 template<typename _OElementType>
2965 requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
2966 constexpr
2967 default_accessor(default_accessor<_OElementType>) noexcept
2968 { }
2969
2970 constexpr reference
2971 access(data_handle_type __p, size_t __i) const noexcept
2972 { return __p[__i]; }
2973
2974 constexpr data_handle_type
2975 offset(data_handle_type __p, size_t __i) const noexcept
2976 { return __p + __i; }
2977 };
2978
2979#ifdef __glibcxx_aligned_accessor
2980 template<typename _ElementType, size_t _ByteAlignment>
2981 struct aligned_accessor
2982 {
2983 static_assert(has_single_bit(_ByteAlignment),
2984 "ByteAlignment must be a power of two");
2985 static_assert(_ByteAlignment >= alignof(_ElementType));
2986
2987 using offset_policy = default_accessor<_ElementType>;
2988 using element_type = _ElementType;
2989 using reference = element_type&;
2990 using data_handle_type = element_type*;
2991
2992 static constexpr size_t byte_alignment = _ByteAlignment;
2993
2994 constexpr
2995 aligned_accessor() noexcept = default;
2996
2997 template<typename _OElementType, size_t _OByteAlignment>
2998 requires (_OByteAlignment >= byte_alignment)
2999 && is_convertible_v<_OElementType(*)[], element_type(*)[]>
3000 constexpr
3001 aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>)
3002 noexcept
3003 { }
3004
3005 template<typename _OElementType>
3006 requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
3007 constexpr explicit
3008 aligned_accessor(default_accessor<_OElementType>) noexcept
3009 { }
3010
3011 template<typename _OElementType>
3012 requires is_convertible_v<element_type(*)[], _OElementType(*)[]>
3013 constexpr
3014 operator default_accessor<_OElementType>() const noexcept
3015 { return {}; }
3016
3017 constexpr reference
3018 access(data_handle_type __p, size_t __i) const noexcept
3019 { return std::assume_aligned<byte_alignment>(__p)[__i]; }
3020
3021 constexpr typename offset_policy::data_handle_type
3022 offset(data_handle_type __p, size_t __i) const noexcept
3023 { return std::assume_aligned<byte_alignment>(__p) + __i; }
3024 };
3025#endif
3026
3027 template<typename _ElementType, typename _Extents,
3028 typename _LayoutPolicy = layout_right,
3029 typename _AccessorPolicy = default_accessor<_ElementType>>
3030 class mdspan
3031 {
3032 static_assert(!is_array_v<_ElementType>,
3033 "ElementType must not be an array type");
3034 static_assert(!is_abstract_v<_ElementType>,
3035 "ElementType must not be an abstract class type");
3036 static_assert(__mdspan::__is_extents<_Extents>,
3037 "Extents must be a specialization of std::extents");
3038 static_assert(is_same_v<_ElementType,
3039 typename _AccessorPolicy::element_type>);
3040
3041 public:
3042 using extents_type = _Extents;
3043 using layout_type = _LayoutPolicy;
3044 using accessor_type = _AccessorPolicy;
3045 using mapping_type = typename layout_type::template mapping<extents_type>;
3046 using element_type = _ElementType;
3047 using value_type = remove_cv_t<element_type>;
3048 using index_type = typename extents_type::index_type;
3049 using size_type = typename extents_type::size_type;
3050 using rank_type = typename extents_type::rank_type;
3051 using data_handle_type = typename accessor_type::data_handle_type;
3052 using reference = typename accessor_type::reference;
3053
3054 static constexpr rank_type
3055 rank() noexcept { return extents_type::rank(); }
3056
3057 static constexpr rank_type
3058 rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
3059
3060 static constexpr size_t
3061 static_extent(rank_type __r) noexcept
3062 { return extents_type::static_extent(__r); }
3063
3064 constexpr index_type
3065 extent(rank_type __r) const noexcept { return extents().extent(__r); }
3066
3067 constexpr
3068 mdspan()
3069 requires (rank_dynamic() > 0)
3070 && is_default_constructible_v<data_handle_type>
3071 && is_default_constructible_v<mapping_type>
3072 && is_default_constructible_v<accessor_type> = default;
3073
3074 constexpr
3075 mdspan(const mdspan& __other) = default;
3076
3077 constexpr
3078 mdspan(mdspan&& __other) = default;
3079
3080 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
3081 requires (sizeof...(_OIndexTypes) == rank()
3082 || sizeof...(_OIndexTypes) == rank_dynamic())
3083 && is_constructible_v<mapping_type, extents_type>
3084 && is_default_constructible_v<accessor_type>
3085 constexpr explicit
3086 mdspan(data_handle_type __handle, _OIndexTypes... __exts)
3087 : _M_accessor(),
3088 _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)),
3089 _M_handle(std::move(__handle))
3090 { }
3091
3092 template<typename _OIndexType, size_t _Nm>
3093 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
3094 && (_Nm == rank() || _Nm == rank_dynamic())
3095 && is_constructible_v<mapping_type, extents_type>
3096 && is_default_constructible_v<accessor_type>
3097 constexpr explicit(_Nm != rank_dynamic())
3098 mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts)
3099 : _M_accessor(), _M_mapping(extents_type(__exts)),
3100 _M_handle(std::move(__handle))
3101 { }
3102
3103 template<typename _OIndexType, size_t _Nm>
3104 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
3105 && (_Nm == rank() || _Nm == rank_dynamic())
3106 && is_constructible_v<mapping_type, extents_type>
3107 && is_default_constructible_v<accessor_type>
3108 constexpr explicit(_Nm != rank_dynamic())
3109 mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts)
3110 : _M_accessor(), _M_mapping(extents_type(__exts)),
3111 _M_handle(std::move(__handle))
3112 { }
3113
3114 constexpr
3115 mdspan(data_handle_type __handle, const extents_type& __exts)
3116 requires is_constructible_v<mapping_type, const extents_type&>
3117 && is_default_constructible_v<accessor_type>
3118 : _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle))
3119 { }
3120
3121 constexpr
3122 mdspan(data_handle_type __handle, const mapping_type& __mapping)
3123 requires is_default_constructible_v<accessor_type>
3124 : _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle))
3125 { }
3126
3127 constexpr
3128 mdspan(data_handle_type __handle, const mapping_type& __mapping,
3129 const accessor_type& __accessor)
3130 : _M_accessor(__accessor), _M_mapping(__mapping),
3131 _M_handle(std::move(__handle))
3132 { }
3133
3134 template<typename _OElementType, typename _OExtents, typename _OLayout,
3135 typename _OAccessor>
3136 requires is_constructible_v<mapping_type,
3137 const typename _OLayout::template mapping<_OExtents>&>
3138 && is_constructible_v<accessor_type, const _OAccessor&>
3139 constexpr explicit(!is_convertible_v<
3140 const typename _OLayout::template mapping<_OExtents>&, mapping_type>
3141 || !is_convertible_v<const _OAccessor&, accessor_type>)
3142 mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>&
3143 __other)
3144 : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()),
3145 _M_handle(__other.data_handle())
3146 {
3147 static_assert(is_constructible_v<data_handle_type,
3148 const typename _OAccessor::data_handle_type&>);
3149 static_assert(is_constructible_v<extents_type, _OExtents>);
3150 }
3151
3152 constexpr mdspan&
3153 operator=(const mdspan& __other) = default;
3154
3155 constexpr mdspan&
3156 operator=(mdspan&& __other) = default;
3157
3158 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
3159 requires (sizeof...(_OIndexTypes) == rank())
3160 constexpr reference
3161 operator[](_OIndexTypes... __indices) const
3162 {
3163 if constexpr (rank() == 0)
3164 return _M_accessor.access(_M_handle, _M_mapping());
3165 else if constexpr (!(is_same_v<_OIndexTypes, index_type> && ...))
3166 return operator[](
3167 __mdspan::__index_type_cast<index_type>(std::move(__indices))...);
3168 else
3169 {
3170 auto __is_multi_index = [&]<size_t... _Counts>(index_sequence<_Counts...>)
3171 { return ((__indices < extents().extent(_Counts)) && ...); };
3172
3173 __glibcxx_assert(__is_multi_index(make_index_sequence<rank()>()));
3174 return _M_accessor.access(_M_handle, _M_mapping(__indices...));
3175 }
3176 }
3177
3178 template<typename _OIndexType>
3179 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
3180 constexpr reference
3181 operator[](span<_OIndexType, rank()> __indices) const
3182 {
3183 auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
3184 -> reference
3185 {
3186 return operator[](
3187 __mdspan::__index_type_cast<index_type>(as_const(__indices[_Counts]))...);
3188 };
3189 return __call(make_index_sequence<rank()>());
3190 }
3191
3192 template<typename _OIndexType>
3193 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
3194 constexpr reference
3195 operator[](const array<_OIndexType, rank()>& __indices) const
3196 { return operator[](span<const _OIndexType, rank()>(__indices)); }
3197
3198#if __cplusplus > 202302L
3199 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
3200 requires (sizeof...(_OIndexTypes) == rank())
3201 constexpr reference
3202 at(_OIndexTypes... __indices) const
3203 {
3204 if constexpr (rank() == 0)
3205 return _M_accessor.access(_M_handle, _M_mapping());
3206 else if constexpr (!(is_integral_v<_OIndexTypes> && ...))
3207 return at(__index_int_t<_OIndexTypes>(std::move(__indices))...);
3208 else
3209 {
3210 auto __check_bound = [&]<typename _OIntType>(size_t __dim, _OIntType __index)
3211 {
3212 if constexpr (is_signed_v<_OIntType>)
3213 if (__index < 0)
3214 std::__throw_out_of_range_fmt(
3215 __N("mdspan::at: %zuth index is negative"), __dim);
3216
3217 const auto __ext = extents().extent(__dim);
3218 if (std::cmp_greater_equal(__index, __ext))
3219 std::__throw_out_of_range_fmt(
3220 __N("mdspan::at: %zuth index (which is %zu)"
3221 " >= extent(%zu) (which is %zu)"),
3222 __dim, size_t(__index), __dim, size_t(__ext));
3223 };
3224 auto __check_bounds = [&]<size_t... _Counts>(index_sequence<_Counts...>)
3225 { (__check_bound(_Counts, __indices), ...); };
3226
3227 __check_bounds(make_index_sequence<rank()>());
3228 auto __index = _M_mapping(static_cast<index_type>(__indices)...);
3229 return _M_accessor.access(_M_handle, __index);
3230 }
3231 }
3232
3233 template<typename _OIndexType>
3234 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
3235 constexpr reference
3236 at(span<_OIndexType, rank()> __indices) const
3237 {
3238 auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
3239 -> reference
3240 {
3241 return at(
3242 __index_int_t<_OIndexType>(as_const(__indices[_Counts]))...);
3243 };
3244 return __call(make_index_sequence<rank()>());
3245 }
3246
3247 template<typename _OIndexType>
3248 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
3249 constexpr reference
3250 at(const array<_OIndexType, rank()>& __indices) const
3251 { return at(span<const _OIndexType, rank()>(__indices)); }
3252#endif // C++26
3253
3254 constexpr size_type
3255 size() const noexcept
3256 {
3257 __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(),
3259 ::__max));
3260 return size_type(__mdspan::__size(extents()));
3261 }
3262
3263 [[nodiscard]]
3264 constexpr bool
3265 empty() const noexcept
3266 { return __mdspan::__empty(extents()); }
3267
3268 friend constexpr void
3269 swap(mdspan& __x, mdspan& __y) noexcept
3270 {
3271 using std::swap;
3272 swap(__x._M_mapping, __y._M_mapping);
3273 swap(__x._M_accessor, __y._M_accessor);
3274 swap(__x._M_handle, __y._M_handle);
3275 }
3276
3277 constexpr const extents_type&
3278 extents() const noexcept { return _M_mapping.extents(); }
3279
3280 constexpr const data_handle_type&
3281 data_handle() const noexcept { return _M_handle; }
3282
3283 constexpr const mapping_type&
3284 mapping() const noexcept { return _M_mapping; }
3285
3286 constexpr const accessor_type&
3287 accessor() const noexcept { return _M_accessor; }
3288
3289 // Strengthened noexcept for all `is_*` methods.
3290
3291 static constexpr bool
3292 is_always_unique() noexcept(noexcept(mapping_type::is_always_unique()))
3293 { return mapping_type::is_always_unique(); }
3294
3295 static constexpr bool
3296 is_always_exhaustive()
3297 noexcept(noexcept(mapping_type::is_always_exhaustive()))
3298 { return mapping_type::is_always_exhaustive(); }
3299
3300 static constexpr bool
3301 is_always_strided()
3302 noexcept(noexcept(mapping_type::is_always_strided()))
3303 { return mapping_type::is_always_strided(); }
3304
3305 constexpr bool
3306 is_unique() const noexcept(noexcept(_M_mapping.is_unique()))
3307 { return _M_mapping.is_unique(); }
3308
3309 constexpr bool
3310 is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive()))
3311 { return _M_mapping.is_exhaustive(); }
3312
3313 constexpr bool
3314 is_strided() const noexcept(noexcept(_M_mapping.is_strided()))
3315 { return _M_mapping.is_strided(); }
3316
3317 constexpr index_type
3318 stride(rank_type __r) const { return _M_mapping.stride(__r); }
3319
3320 private:
3321 template<typename _OIndexType>
3322 using __index_int_t = std::__conditional_t<
3323 is_integral_v<_OIndexType>, _OIndexType, index_type>;
3324
3325 [[no_unique_address]] accessor_type _M_accessor = accessor_type();
3326 [[no_unique_address]] mapping_type _M_mapping = mapping_type();
3327 [[no_unique_address]] data_handle_type _M_handle = data_handle_type();
3328 };
3329
3330 template<typename _CArray>
3331 requires is_array_v<_CArray> && (rank_v<_CArray> == 1)
3332 mdspan(_CArray&)
3333 -> mdspan<remove_all_extents_t<_CArray>,
3334 extents<size_t, extent_v<_CArray, 0>>>;
3335
3336 template<typename _Pointer>
3337 requires is_pointer_v<remove_reference_t<_Pointer>>
3338 mdspan(_Pointer&&)
3339 -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>;
3340
3341 template<typename _ElementType, typename... _Integrals>
3342 requires (is_convertible_v<_Integrals, size_t> && ...)
3343 && (sizeof...(_Integrals) > 0)
3344 explicit mdspan(_ElementType*, _Integrals...)
3345 -> mdspan<_ElementType,
3346 extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>;
3347
3348 template<typename _ElementType, typename _OIndexType, size_t _Nm>
3349 mdspan(_ElementType*, span<_OIndexType, _Nm>)
3350 -> mdspan<_ElementType, dextents<size_t, _Nm>>;
3351
3352 template<typename _ElementType, typename _OIndexType, size_t _Nm>
3353 mdspan(_ElementType*, const array<_OIndexType, _Nm>&)
3354 -> mdspan<_ElementType, dextents<size_t, _Nm>>;
3355
3356 template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack>
3357 mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&)
3358 -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>;
3359
3360 template<typename _ElementType, typename _MappingType>
3361 mdspan(_ElementType*, const _MappingType&)
3362 -> mdspan<_ElementType, typename _MappingType::extents_type,
3363 typename _MappingType::layout_type>;
3364
3365 // _GLIBCXX_RESOLVE_LIB_DEFECTS
3366 // 4511. Inconsistency between the deduction guide of std::mdspan taking...
3367 template<typename _MappingType, typename _AccessorType>
3368 mdspan(typename _AccessorType::data_handle_type, const _MappingType&,
3369 const _AccessorType&)
3370 -> mdspan<typename _AccessorType::element_type,
3371 typename _MappingType::extents_type,
3372 typename _MappingType::layout_type, _AccessorType>;
3373
3374#if __glibcxx_submdspan
3375 namespace __mdspan
3376 {
3377 template<typename _IndexType, typename _Slice>
3378 constexpr auto
3379 __canonical_index(_Slice&& __slice)
3380 {
3381 if constexpr (__detail::__integral_constant_like<_Slice>)
3382 {
3383 static_assert(__is_representable_integer<_IndexType>(_Slice::value));
3384 static_assert(_Slice::value >= 0);
3385 return std::cw<_IndexType(_Slice::value)>;
3386 }
3387 else
3388 return __mdspan::__index_type_cast<_IndexType>(std::move(__slice));
3389 }
3390
3391 template<typename _IndexType,
3392 typename _OffsetType, typename _SpanType, typename _StrideType>
3393 constexpr auto
3394 __canonical_range_slice(_OffsetType __offset, _SpanType __span,
3395 _StrideType __stride)
3396 {
3397 if constexpr (is_same_v<_SpanType, constant_wrapper<_IndexType(0)>>
3398 || is_same_v<_StrideType, constant_wrapper<_IndexType(1)>>)
3399 return extent_slice{
3400 .offset = __offset,
3401 .extent = __span,
3402 .stride = cw<_IndexType(1)>
3403 };
3404 else if constexpr (__is_constant_wrapper<_StrideType>)
3405 {
3406 static_assert(_StrideType::value > 0);
3407 if constexpr (__is_constant_wrapper<_SpanType>)
3408 return extent_slice{
3409 .offset = __offset,
3410 .extent = cw<_IndexType(1 + (_SpanType::value - 1) / _StrideType::value)>,
3411 .stride = __stride
3412 };
3413 else
3414 return extent_slice{
3415 .offset = __offset,
3416 .extent = _IndexType(__span > 0 ? 1 + (__span - 1) / _StrideType::value : 0),
3417 .stride = __stride
3418 };
3419 }
3420 else if (__span == 0 || __stride == 1)
3421 return extent_slice{
3422 .offset = __offset,
3423 .extent = _IndexType(__span),
3424 .stride = _IndexType(1)
3425 };
3426 else
3427 {
3428 __glibcxx_assert(__stride > 0);
3429 return extent_slice{
3430 .offset = __offset,
3431 .extent = _IndexType(1 + (__span - 1) / __stride),
3432 .stride = __stride
3433 };
3434 }
3435 }
3436
3437 template<typename _IndexType, typename _Slice>
3438 constexpr auto
3439 __slice_cast(_Slice&& __slice)
3440 {
3441 using _SliceType = remove_cvref_t<_Slice>;
3442 if constexpr (is_convertible_v<_SliceType, full_extent_t>)
3443 return static_cast<full_extent_t>(std::move(__slice));
3444 else if constexpr (is_convertible_v<_SliceType, _IndexType>)
3445 return __mdspan::__canonical_index<_IndexType>(std::move(__slice));
3446 else if constexpr (__is_extent_slice<_SliceType>)
3447 return extent_slice{
3448 .offset = __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset)),
3449 .extent = __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent)),
3450 .stride = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))
3451 };
3452 else if constexpr (__is_range_slice<_SliceType>)
3453 {
3454 auto __first
3455 = __mdspan::__canonical_index<_IndexType>(std::move(__slice.first));
3456 auto __last
3457 = __mdspan::__canonical_index<_IndexType>(std::move(__slice.last));
3458 return __mdspan::__canonical_range_slice<_IndexType>(
3459 __first,
3460 __mdspan::__canonical_index<_IndexType>(__last - __first),
3461 __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride)));
3462 }
3463 else
3464 {
3465 auto [__sbegin, __send] = std::move(__slice);
3466 auto __cbegin
3467 = __mdspan::__canonical_index<_IndexType>(std::move(__sbegin));
3468 auto __cend
3469 = __mdspan::__canonical_index<_IndexType>(std::move(__send));
3470 auto __cspan
3471 = __mdspan::__canonical_index<_IndexType>(__cend - __cbegin);
3472 return __mdspan::__canonical_range_slice<_IndexType>(
3473 __cbegin, __cspan, cw<_IndexType(1)>);
3474 }
3475 }
3476
3477 template<typename _IndexType, size_t _Extent, typename _OIndexType>
3478 constexpr void
3479 __check_inrange_index(const extents<_IndexType, _Extent>& __ext,
3480 const _OIndexType& __idx)
3481 {
3482 if constexpr (__is_constant_wrapper<_OIndexType>
3483 && _Extent != dynamic_extent)
3484 {
3485 static_assert(_OIndexType::value >= 0);
3486 static_assert(std::cmp_less(_OIndexType::value, _Extent));
3487 }
3488 else
3489 __glibcxx_assert(__idx < __ext.extent(0));
3490 }
3491
3492 template<typename _IndexType, size_t _Extent, typename _OIndexType>
3493 constexpr void
3494 __check_valid_index(const extents<_IndexType, _Extent>& __ext,
3495 const _OIndexType& __idx)
3496 {
3497 if constexpr (__is_constant_wrapper<_OIndexType>
3498 && _Extent != dynamic_extent)
3499 {
3500 static_assert(_OIndexType::value >= 0);
3501 static_assert(std::cmp_less_equal(_OIndexType::value, _Extent));
3502 }
3503 else
3504 __glibcxx_assert(__idx <= __ext.extent(0));
3505 }
3506
3507 template<typename _IndexType, size_t _Extent, typename _Slice>
3508 constexpr void
3509 __check_valid_slice(const extents<_IndexType, _Extent>& __ext,
3510 const _Slice& __slice)
3511 {
3512 if constexpr (__is_extent_slice<_Slice>)
3513 {
3514 __mdspan::__check_valid_index(__ext, __slice.extent);
3515 // DEVIATION: For empty slices, P3663r3 does not allow us to check
3516 // that this is less than or equal to the k-th extent (at runtime).
3517 // We're only allowed to check if __slice.offset, __slice.extent
3518 // are constant wrappers and __ext is a static extent.
3519 if constexpr (is_same_v<typename _Slice::extent_type,
3520 constant_wrapper<_IndexType(0)>>)
3521 __mdspan::__check_valid_index(__ext, __slice.offset);
3522 else if constexpr (is_same_v<typename _Slice::extent_type,
3523 constant_wrapper<_IndexType(1)>>)
3524 __mdspan::__check_inrange_index(__ext, __slice.offset);
3525 else if constexpr (__is_constant_wrapper<typename _Slice::extent_type>)
3526 {
3527 __mdspan::__check_inrange_index(__ext, __slice.offset);
3528 if constexpr (__is_constant_wrapper<typename _Slice::stride_type>)
3529 static_assert(_Slice::stride_type::value > 0);
3530 else
3531 __glibcxx_assert(__slice.stride > 0);
3532
3533 if constexpr (_Extent != dynamic_extent
3534 && __is_constant_wrapper<typename _Slice::offset_type>)
3535 static_assert(std::cmp_greater_equal(
3536 _Extent - _Slice::offset_type::value,
3537 _Slice::extent_type::value));
3538 if constexpr (_Extent != dynamic_extent
3539 && __is_constant_wrapper<typename _Slice::stride_type>)
3540 static_assert(std::cmp_greater(
3541 _Extent,
3542 (_Slice::extent_type::value - 1) * _Slice::stride_type::value));
3543
3544 if constexpr (_Extent != dynamic_extent
3545 && __is_constant_wrapper<typename _Slice::offset_type>
3546 && __is_constant_wrapper<typename _Slice::stride_type>)
3547 static_assert(std::cmp_greater(
3548 _Extent - _Slice::offset_type::value,
3549 (_Slice::extent_type::value - 1) * _Slice::stride_type::value));
3550 else
3551 __glibcxx_assert(std::cmp_greater(
3552 __ext.extent(0) - __slice.offset,
3553 (_Slice::extent_type::value - 1) * __slice.stride));
3554 }
3555 else if constexpr (is_same_v<typename _Slice::stride_type,
3556 constant_wrapper<_IndexType(1)>>)
3557 {
3558 __mdspan::__check_valid_index(__ext, __slice.offset);
3559 __glibcxx_assert(std::cmp_greater_equal(
3560 __ext.extent(0) - __slice.offset,
3561 __slice.extent));
3562 }
3563 else if (__slice.extent == 0)
3564 __mdspan::__check_valid_index(__ext, __slice.offset);
3565 else
3566 {
3567 __glibcxx_assert(__slice.offset < __ext.extent(0));
3568 __glibcxx_assert(__slice.extent == 1 || __slice.stride > 0);
3569 __glibcxx_assert(__slice.extent == 1 || std::cmp_greater(
3570 __ext.extent(0) - __slice.offset,
3571 (__slice.extent - 1) * __slice.stride));
3572 }
3573 }
3574 else if constexpr (!is_same_v<_Slice, full_extent_t>)
3575 __mdspan::__check_inrange_index(__ext, __slice);
3576 }
3577
3578 template<typename _Extents, typename... _Slices>
3579 constexpr void
3580 __check_valid_slices(const _Extents& __exts, const _Slices&... __slices)
3581 {
3582 constexpr auto __rank = _Extents::rank();
3583 auto __impl = [&]<size_t... _Is>(index_sequence<_Is...>)
3584 {
3585 ((__mdspan::__check_valid_slice(__extract_extent<_Is>(__exts),
3586 __slices...[_Is])),...);
3587 };
3588 __impl(make_index_sequence<__rank>());
3589 }
3590
3591 template<typename _Slice>
3592 using __full_extent_t = std::full_extent_t;
3593
3594 // Enables ADL-only calls from submdspan.
3595 void submdspan_mapping() = delete;
3596
3597 template<typename _Mapping, typename... _Slices>
3598 concept __sliceable_mapping = requires(const _Mapping __m, _Slices... __slices)
3599 {
3600 { submdspan_mapping(__m, __slices...) } -> __submdspan_mapping_result;
3601 };
3602
3603 template<typename _Mapping, typename... _Slices>
3604 constexpr auto
3605 __submapping(const _Mapping& __mapping, _Slices... __slices)
3606 {
3607 __mdspan::__check_valid_slices(__mapping.extents(), __slices...);
3608 return submdspan_mapping(__mapping, __slices...);
3609 }
3610 }
3611
3612 template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
3613 requires (sizeof...(_RawSlices) == sizeof...(_Extents))
3614 constexpr auto
3615 subextents(const extents<_IndexType, _Extents...>& __exts,
3616 _RawSlices... __raw_slices)
3617 {
3618 auto __impl = [&__exts](auto... __slices)
3619 {
3620 __mdspan::__check_valid_slices(__exts, __slices...);
3621 return __mdspan::__subextents(__exts, __slices...);
3622 };
3623 return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
3624 }
3625
3626 template<typename _IndexType, size_t... _Extents, typename... _RawSlices>
3627 requires (sizeof...(_Extents) == sizeof...(_RawSlices))
3628 constexpr auto
3629 canonical_slices(const extents<_IndexType, _Extents...>& __exts,
3630 _RawSlices... __raw_slices)
3631 {
3632 auto __impl = [&__exts](auto... __slices)
3633 {
3634 __mdspan::__check_valid_slices(__exts, __slices...);
3635 return std::make_tuple(__slices...);
3636 };
3637 return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...);
3638 }
3639
3640 template<typename _ElementType, typename _Extents, typename _Layout,
3641 typename _Accessor, typename... _RawSlices>
3642 requires (sizeof...(_RawSlices) == _Extents::rank()
3643 && __mdspan::__sliceable_mapping<typename _Layout::template mapping<_Extents>,
3644 __mdspan::__full_extent_t<_RawSlices>...>)
3645 constexpr auto
3646 submdspan(
3647 const mdspan<_ElementType, _Extents, _Layout, _Accessor>& __md,
3648 _RawSlices... __raw_slices)
3649 {
3650 using _IndexType = typename _Extents::index_type;
3651 auto [__mapping, __offset] = __mdspan::__submapping(
3652 __md.mapping(), __mdspan::__slice_cast<_IndexType>(__raw_slices)...);
3653 return std::mdspan(
3654 __md.accessor().offset(__md.data_handle(), __offset),
3655 std::move(__mapping),
3656 typename _Accessor::offset_policy(__md.accessor()));
3657 }
3658#endif // __glibcxx_submdspan
3659
3660_GLIBCXX_END_NAMESPACE_VERSION
3661}
3662#endif
3663#endif
constexpr _Tp * assume_aligned(_Tp *__ptr) noexcept
Inform the compiler that a pointer is aligned.
Definition align.h:90
typename make_unsigned< _Tp >::type make_unsigned_t
Alias template for make_unsigned.
Definition type_traits:2250
constexpr tuple< typename __decay_and_strip< _Elements >::__type... > make_tuple(_Elements &&... __args)
Create a tuple containing copies of the arguments.
Definition tuple:2725
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
ISO C++ entities toplevel namespace is std.
make_integer_sequence< size_t, _Num > make_index_sequence
Alias template make_index_sequence.
Definition utility.h:527
integer_sequence< size_t, _Idx... > index_sequence
Alias template index_sequence.
Definition utility.h:523
__numeric_traits_integer< _Tp > __int_traits
Convenience alias for __numeric_traits<integer-type>.