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#if __cplusplus > 202302L
42#include <bits/align.h>
43#endif
44
45#define __glibcxx_want_mdspan
46#define __glibcxx_want_aligned_accessor
47#define __glibcxx_want_submdspan
48#include <bits/version.h>
49
50#ifdef __glibcxx_mdspan
51
52namespace std _GLIBCXX_VISIBILITY(default)
53{
54_GLIBCXX_BEGIN_NAMESPACE_VERSION
55 namespace __mdspan
56 {
57 consteval bool
58 __all_static(std::span<const size_t> __extents)
59 {
60 for(auto __ext : __extents)
61 if (__ext == dynamic_extent)
62 return false;
63 return true;
64 }
65
66 consteval bool
67 __all_dynamic(std::span<const size_t> __extents)
68 {
69 for(auto __ext : __extents)
70 if (__ext != dynamic_extent)
71 return false;
72 return true;
73 }
74
75 template<typename _IndexType, typename _OIndexType>
76 constexpr _IndexType
77 __index_type_cast(_OIndexType&& __other)
78 {
79 if constexpr (std::is_integral_v<_OIndexType>)
80 {
81 constexpr _IndexType __index_type_max
82 = __gnu_cxx::__int_traits<_IndexType>::__max;
83 constexpr _OIndexType __oindex_type_max
84 = __gnu_cxx::__int_traits<_OIndexType>::__max;
85
86 if constexpr (__index_type_max < __oindex_type_max)
87 __glibcxx_assert(cmp_less_equal(__other, __index_type_max));
88
89 if constexpr (std::is_signed_v<_OIndexType>)
90 __glibcxx_assert(__other >= 0);
91 return static_cast<_IndexType>(__other);
92 }
93 else
94 {
95 auto __ret = static_cast<_IndexType>(std::move(__other));
96 if constexpr (std::is_signed_v<_IndexType>)
97 __glibcxx_assert(__ret >= 0);
98 return __ret;
99 }
100 }
101
102 template<array _Extents>
103 class _StaticExtents
104 {
105 public:
106 static constexpr size_t _S_rank = _Extents.size();
107
108 // For __r in [0, _S_rank], _S_dynamic_index(__r) is the number
109 // of dynamic extents up to (and not including) __r.
110 //
111 // If __r is the index of a dynamic extent, then
112 // _S_dynamic_index[__r] is the index of that extent in
113 // _M_dyn_exts.
114 static constexpr size_t
115 _S_dynamic_index(size_t __r) noexcept
116 { return _S_dynamic_index_data[__r]; }
117
118 static constexpr auto _S_dynamic_index_data = [] consteval
119 {
120 array<size_t, _S_rank+1> __ret;
121 size_t __dyn = 0;
122 for (size_t __i = 0; __i < _S_rank; ++__i)
123 {
124 __ret[__i] = __dyn;
125 __dyn += (_Extents[__i] == dynamic_extent);
126 }
127 __ret[_S_rank] = __dyn;
128 return __ret;
129 }();
130
131 static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank);
132
133 // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv(__r) is the
134 // index of the __r-th dynamic extent in _Extents.
135 static constexpr size_t
136 _S_dynamic_index_inv(size_t __r) noexcept
137 { return _S_dynamic_index_inv_data[__r]; }
138
139 static constexpr auto _S_dynamic_index_inv_data = [] consteval
140 {
141 array<size_t, _S_rank_dynamic> __ret;
142 for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i)
143 if (_Extents[__i] == dynamic_extent)
144 __ret[__r++] = __i;
145 return __ret;
146 }();
147
148 static constexpr size_t
149 _S_static_extent(size_t __r) noexcept
150 { return _Extents[__r]; }
151 };
152
153 template<array _Extents>
154 requires (__all_dynamic<_Extents>())
155 class _StaticExtents<_Extents>
156 {
157 public:
158 static constexpr size_t _S_rank = _Extents.size();
159
160 static constexpr size_t
161 _S_dynamic_index(size_t __r) noexcept
162 { return __r; }
163
164 static constexpr size_t _S_rank_dynamic = _S_rank;
165
166 static constexpr size_t
167 _S_dynamic_index_inv(size_t __k) noexcept
168 { return __k; }
169
170 static constexpr size_t
171 _S_static_extent(size_t) noexcept
172 { return dynamic_extent; }
173 };
174
175 template<typename _IndexType, array _Extents>
176 class _ExtentsStorage : public _StaticExtents<_Extents>
177 {
178 private:
179 using _Base = _StaticExtents<_Extents>;
180
181 public:
182 using _Base::_S_rank;
183 using _Base::_S_rank_dynamic;
184 using _Base::_S_dynamic_index;
185 using _Base::_S_dynamic_index_inv;
186 using _Base::_S_static_extent;
187
188 static constexpr bool
189 _S_is_dynamic(size_t __r) noexcept
190 {
191 if constexpr (__all_static(_Extents))
192 return false;
193 else if constexpr (__all_dynamic(_Extents))
194 return true;
195 else
196 return _Extents[__r] == dynamic_extent;
197 }
198
199 template<typename _OIndexType>
200 static constexpr _IndexType
201 _S_int_cast(const _OIndexType& __other) noexcept
202 { return _IndexType(__other); }
203
204 constexpr _IndexType
205 _M_extent(size_t __r) const noexcept
206 {
207 if (_S_is_dynamic(__r))
208 return _M_dyn_exts[_S_dynamic_index(__r)];
209 else
210 return _S_static_extent(__r);
211 }
212
213 template<size_t _OtherRank, typename _GetOtherExtent>
214 static constexpr bool
215 _S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept
216 {
217 if constexpr (_OtherRank == _S_rank)
218 for (size_t __i = 0; __i < _S_rank; ++__i)
219 if (!_S_is_dynamic(__i)
220 && !cmp_equal(_Extents[__i], _S_int_cast(__get_extent(__i))))
221 return false;
222 return true;
223 }
224
225 template<size_t _OtherRank, typename _GetOtherExtent>
226 constexpr void
227 _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
228 {
229 __glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent));
230 for (size_t __i = 0; __i < _S_rank_dynamic; ++__i)
231 {
232 size_t __di = __i;
233 if constexpr (_OtherRank != _S_rank_dynamic)
234 __di = _S_dynamic_index_inv(__i);
235 _M_dyn_exts[__i] = _S_int_cast(__get_extent(__di));
236 }
237 }
238
239 constexpr
240 _ExtentsStorage() noexcept = default;
241
242 template<typename _OIndexType, array _OExtents>
243 constexpr
244 _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>&
245 __other) noexcept
246 {
247 _M_init_dynamic_extents<_S_rank>([&__other](size_t __i)
248 { return __other._M_extent(__i); });
249 }
250
251 template<typename _OIndexType, size_t _Nm>
252 constexpr
253 _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept
254 {
255 _M_init_dynamic_extents<_Nm>(
256 [&__exts](size_t __i) -> const _OIndexType&
257 { return __exts[__i]; });
258 }
259
260 static constexpr const array<size_t, _S_rank>&
261 _S_static_extents() noexcept
262 { return _Extents; }
263
264 constexpr span<const _IndexType>
265 _M_dynamic_extents(size_t __begin, size_t __end) const noexcept
266 requires (_Extents.size() > 0)
267 {
268 return {_M_dyn_exts + _S_dynamic_index(__begin),
269 _M_dyn_exts + _S_dynamic_index(__end)};
270 }
271
272 private:
273 using _Storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
274 [[no_unique_address]] _Storage _M_dyn_exts{};
275 };
276
277 template<typename _OIndexType, typename _SIndexType>
278 concept __valid_index_type =
279 is_convertible_v<_OIndexType, _SIndexType> &&
280 is_nothrow_constructible_v<_SIndexType, _OIndexType>;
281
282 template<size_t _Extent, typename _IndexType>
283 concept
284 __valid_static_extent = _Extent == dynamic_extent
285 || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max;
286
287 template<typename _Extents>
288 constexpr const array<size_t, _Extents::rank()>&
289 __static_extents() noexcept
290 { return _Extents::_Storage::_S_static_extents(); }
291
292 template<typename _Extents>
293 constexpr span<const size_t>
294 __static_extents(size_t __begin, size_t __end) noexcept
295 {
296 const auto& __sta_exts = __static_extents<_Extents>();
297 return span<const size_t>(__sta_exts.data() + __begin, __end - __begin);
298 }
299
300 // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive)
301 template<array _Extents>
302 constexpr auto __fwd_partial_prods = [] consteval
303 {
304 constexpr size_t __rank = _Extents.size();
305 std::array<size_t, __rank> __ret;
306 size_t __prod = 1;
307 for (size_t __r = 0; __r < __rank; ++__r)
308 {
309 __ret[__r] = __prod;
310 if (size_t __ext = _Extents[__r]; __ext != dynamic_extent)
311 __prod *= __ext;
312 }
313 return __ret;
314 }();
315
316 // Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i]
317 template<array _Extents>
318 constexpr auto __rev_partial_prods = [] consteval
319 {
320 constexpr size_t __rank = _Extents.size();
321 std::array<size_t, __rank> __ret;
322 size_t __prod = 1;
323 for (size_t __r = __rank; __r > 0; --__r)
324 {
325 __ret[__r - 1] = __prod;
326 if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent)
327 __prod *= __ext;
328 }
329 return __ret;
330 }();
331
332 template<typename _Extents>
333 constexpr span<const typename _Extents::index_type>
334 __dynamic_extents(const _Extents& __exts, size_t __begin = 0,
335 size_t __end = _Extents::rank()) noexcept
336 { return __exts._M_exts._M_dynamic_extents(__begin, __end); }
337 }
338
339#if __glibcxx_submdspan
340 struct full_extent_t
341 {
342 explicit full_extent_t() = default;
343 };
344
345 inline constexpr full_extent_t full_extent{};
346
347 template<typename _OffsetType, typename _ExtentType, typename _StrideType>
348 struct strided_slice {
349 static_assert(__is_standard_integer<_OffsetType>::value
350 || __detail::__integral_constant_like<_OffsetType>);
351 static_assert(__is_standard_integer<_ExtentType>::value
352 || __detail::__integral_constant_like<_ExtentType>);
353 static_assert(__is_standard_integer<_StrideType>::value
354 || __detail::__integral_constant_like<_StrideType>);
355
356 using offset_type = _OffsetType;
357 using extent_type = _ExtentType;
358 using stride_type = _StrideType;
359
360 [[no_unique_address]] offset_type offset{};
361 [[no_unique_address]] extent_type extent{};
362 [[no_unique_address]] stride_type stride{};
363 };
364
365 template<typename _Mapping>
366 struct submdspan_mapping_result
367 {
368 [[no_unique_address]] _Mapping mapping = _Mapping();
369 size_t offset{};
370 };
371#endif
372
373 template<typename _IndexType, size_t... _Extents>
374 class extents
375 {
376 static_assert(__is_standard_integer<_IndexType>::value,
377 "IndexType must be a signed or unsigned integer type");
378 static_assert(
379 (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
380 "Extents must either be dynamic or representable as IndexType");
381 public:
382 using index_type = _IndexType;
383 using size_type = make_unsigned_t<index_type>;
384 using rank_type = size_t;
385
386 static constexpr rank_type
387 rank() noexcept { return _Storage::_S_rank; }
388
389 static constexpr rank_type
390 rank_dynamic() noexcept { return _Storage::_S_rank_dynamic; }
391
392 static constexpr size_t
393 static_extent(rank_type __r) noexcept
394 {
395 __glibcxx_assert(__r < rank());
396 if constexpr (rank() == 0)
397 __builtin_trap();
398 else
399 return _Storage::_S_static_extent(__r);
400 }
401
402 constexpr index_type
403 extent(rank_type __r) const noexcept
404 {
405 __glibcxx_assert(__r < rank());
406 if constexpr (rank() == 0)
407 __builtin_trap();
408 else
409 return _M_exts._M_extent(__r);
410 }
411
412 constexpr
413 extents() noexcept = default;
414
415 private:
416 static consteval bool
417 _S_is_less_dynamic(size_t __ext, size_t __oext)
418 { return (__ext != dynamic_extent) && (__oext == dynamic_extent); }
419
420 template<typename _OIndexType, size_t... _OExtents>
421 static consteval bool
422 _S_ctor_explicit()
423 {
424 return (_S_is_less_dynamic(_Extents, _OExtents) || ...)
425 || (__gnu_cxx::__int_traits<index_type>::__max
426 < __gnu_cxx::__int_traits<_OIndexType>::__max);
427 }
428
429 template<size_t... _OExtents>
430 static consteval bool
431 _S_is_compatible_extents()
432 {
433 if constexpr (sizeof...(_OExtents) != rank())
434 return false;
435 else
436 return ((_OExtents == dynamic_extent || _Extents == dynamic_extent
437 || _OExtents == _Extents) && ...);
438 }
439
440 public:
441 template<typename _OIndexType, size_t... _OExtents>
442 requires (_S_is_compatible_extents<_OExtents...>())
443 constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>())
444 extents(const extents<_OIndexType, _OExtents...>& __other) noexcept
445 : _M_exts(__other._M_exts)
446 { }
447
448 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
449 requires (sizeof...(_OIndexTypes) == rank()
450 || sizeof...(_OIndexTypes) == rank_dynamic())
451 constexpr explicit extents(_OIndexTypes... __exts) noexcept
452 : _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>(
453 initializer_list{static_cast<_IndexType>(std::move(__exts))...}))
454 { }
455
456 template<typename _OIndexType, size_t _Nm>
457 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
458 && (_Nm == rank() || _Nm == rank_dynamic())
459 constexpr explicit(_Nm != rank_dynamic())
460 extents(span<_OIndexType, _Nm> __exts) noexcept
461 : _M_exts(span<const _OIndexType, _Nm>(__exts))
462 { }
463
464 template<typename _OIndexType, size_t _Nm>
465 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
466 && (_Nm == rank() || _Nm == rank_dynamic())
467 constexpr explicit(_Nm != rank_dynamic())
468 extents(const array<_OIndexType, _Nm>& __exts) noexcept
469 : _M_exts(span<const _OIndexType, _Nm>(__exts))
470 { }
471
472 template<typename _OIndexType, size_t... _OExtents>
473 friend constexpr bool
474 operator==(const extents& __self,
475 const extents<_OIndexType, _OExtents...>& __other) noexcept
476 {
477 if constexpr (!_S_is_compatible_extents<_OExtents...>())
478 return false;
479 else
480 {
481 auto __impl = [&__self, &__other]<size_t... _Counts>(
482 index_sequence<_Counts...>)
483 { return (cmp_equal(__self.extent(_Counts),
484 __other.extent(_Counts)) && ...); };
485 return __impl(make_index_sequence<__self.rank()>());
486 }
487 }
488
489 private:
490 friend const array<size_t, rank()>&
491 __mdspan::__static_extents<extents>();
492
493 friend span<const index_type>
494 __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t);
495
496 using _Storage = __mdspan::_ExtentsStorage<
497 _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
498 [[no_unique_address]] _Storage _M_exts;
499
500 template<typename _OIndexType, size_t... _OExtents>
501 friend class extents;
502 };
503
504 namespace __mdspan
505 {
506 template<typename _Tp, size_t _Nm>
507 constexpr bool
508 __contains_zero(span<_Tp, _Nm> __exts) noexcept
509 {
510 for (size_t __i = 0; __i < __exts.size(); ++__i)
511 if (__exts[__i] == 0)
512 return true;
513 return false;
514 }
515
516 template<typename _Tp, size_t _Nm>
517 consteval bool
518 __contains_zero(const array<_Tp, _Nm>& __exts) noexcept
519 { return __contains_zero(span<const _Tp>(__exts)); }
520
521 template<typename _Extents>
522 constexpr bool
523 __empty(const _Extents& __exts) noexcept
524 {
525 if constexpr (__contains_zero(__static_extents<_Extents>()))
526 return true;
527 else if constexpr (_Extents::rank_dynamic() > 0)
528 return __contains_zero(__dynamic_extents(__exts));
529 else
530 return false;
531 }
532
533 template<typename _Extents>
534 constexpr typename _Extents::index_type
535 __extents_prod(const _Extents& __exts, size_t __sta_prod, size_t __begin,
536 size_t __end) noexcept
537 {
538 if (__sta_prod == 0)
539 return 0;
540
541 size_t __ret = __sta_prod;
542 if constexpr (_Extents::rank_dynamic() > 0)
543 for (auto __factor : __dynamic_extents(__exts, __begin, __end))
544 __ret *= size_t(__factor);
545 return static_cast<typename _Extents::index_type>(__ret);
546 }
547
548 // Preconditions: _r < _Extents::rank()
549 template<typename _Extents>
550 constexpr typename _Extents::index_type
551 __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept
552 {
553 size_t __sta_prod = [__begin, __end] {
554 span<const size_t> __sta_exts = __static_extents<_Extents>(__begin, __end);
555 size_t __ret = 1;
556 for(auto __ext : __sta_exts)
557 if (__ext != dynamic_extent)
558 __ret *= __ext;
559 return __ret;
560 }();
561 return __extents_prod(__exts, __sta_prod, __begin, __end);
562 }
563
564 template<typename _Extents>
565 constexpr typename _Extents::index_type
566 __fwd_prod(const _Extents& __exts, size_t __r) noexcept
567 {
568 constexpr size_t __rank = _Extents::rank();
569 constexpr auto& __sta_exts = __static_extents<_Extents>();
570 if constexpr (__rank == 1)
571 return 1;
572 else if constexpr (__rank == 2)
573 return __r == 0 ? 1 : __exts.extent(0);
574 else if constexpr (__all_dynamic(std::span(__sta_exts).first(__rank-1)))
575 return __extents_prod(__exts, 1, 0, __r);
576 else
577 {
578 size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r];
579 return __extents_prod(__exts, __sta_prod, 0, __r);
580 }
581 }
582
583 // Preconditions: _r < _Extents::rank()
584 template<typename _Extents>
585 constexpr typename _Extents::index_type
586 __rev_prod(const _Extents& __exts, size_t __r) noexcept
587 {
588 constexpr size_t __rank = _Extents::rank();
589 constexpr auto& __sta_exts = __static_extents<_Extents>();
590 if constexpr (__rank == 1)
591 return 1;
592 else if constexpr (__rank == 2)
593 return __r == 0 ? __exts.extent(1) : 1;
594 else if constexpr (__all_dynamic(std::span(__sta_exts).last(__rank-1)))
595 return __extents_prod(__exts, 1, __r + 1, __rank);
596 else
597 {
598 size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r];
599 return __extents_prod(__exts, __sta_prod, __r + 1, __rank);
600 }
601 }
602
603 template<typename _Extents>
604 constexpr typename _Extents::index_type
605 __size(const _Extents& __exts) noexcept
606 {
607 constexpr size_t __sta_prod = [] {
608 span<const size_t> __sta_exts = __static_extents<_Extents>();
609 size_t __ret = 1;
610 for(auto __ext : __sta_exts)
611 if (__ext != dynamic_extent)
612 __ret *= __ext;
613 return __ret;
614 }();
615 return __extents_prod(__exts, __sta_prod, 0, _Extents::rank());
616 }
617
618 template<typename _IndexType, size_t... _Counts>
619 auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
620 -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
621 }
622
623 template<typename _IndexType, size_t _Rank>
624 using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
625 make_index_sequence<_Rank>()));
626
627#if __glibcxx_mdspan >= 202406L
628 template<size_t _Rank, typename _IndexType = size_t>
629 using dims = dextents<_IndexType, _Rank>;
630#endif
631
632 template<typename... _Integrals>
633 requires (is_convertible_v<_Integrals, size_t> && ...)
634 explicit extents(_Integrals...) ->
635 extents<size_t, __detail::__maybe_static_ext<_Integrals>...>;
636
637 struct layout_left
638 {
639 template<typename _Extents>
640 class mapping;
641 };
642
643 struct layout_right
644 {
645 template<typename _Extents>
646 class mapping;
647 };
648
649 struct layout_stride
650 {
651 template<typename _Extents>
652 class mapping;
653 };
654
655#ifdef __glibcxx_padded_layouts
656 template<size_t _PaddingValue>
657 struct layout_left_padded
658 {
659 template<typename _Extents>
660 class mapping;
661 };
662
663 template<size_t _PaddingValue>
664 struct layout_right_padded
665 {
666 template<typename _Extents>
667 class mapping;
668 };
669#endif
670
671 namespace __mdspan
672 {
673 template<typename _Tp>
674 constexpr bool __is_extents = false;
675
676 template<typename _IndexType, size_t... _Extents>
677 constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true;
678
679 template<typename _Extents, typename... _Indices>
680 constexpr typename _Extents::index_type
681 __linear_index_left(const _Extents& __exts, _Indices... __indices)
682 noexcept
683 {
684 using _IndexType = typename _Extents::index_type;
685 _IndexType __res = 0;
686 if constexpr (sizeof...(__indices) > 0)
687 {
688 _IndexType __mult = 1;
689 auto __update = [&, __pos = 0u](_IndexType __idx) mutable
690 {
691 _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos)));
692 __res += __idx * __mult;
693 __mult *= __exts.extent(__pos);
694 ++__pos;
695 };
696 (__update(__indices), ...);
697 }
698 return __res;
699 }
700
701 template<typename _IndexType>
702 consteval _IndexType
703 __static_quotient(std::span<const size_t> __sta_exts,
704 _IndexType __nom = __gnu_cxx::__int_traits<_IndexType>::__max)
705 {
706 for (auto __factor : __sta_exts)
707 {
708 if (__factor != dynamic_extent)
709 __nom /= _IndexType(__factor);
710 if (__nom == 0)
711 break;
712 }
713 return __nom;
714 }
715
716 template<typename _Extents,
717 typename _IndexType = typename _Extents::index_type>
718 requires __is_extents<_Extents>
719 consteval _IndexType
720 __static_quotient(_IndexType __nom
721 = __gnu_cxx::__int_traits<_IndexType>::__max)
722 {
723 std::span<const size_t> __sta_exts = __static_extents<_Extents>();
724 return __static_quotient<_IndexType>(__sta_exts, __nom);
725 }
726
727 template<typename _Extents>
728 constexpr bool
729 __is_representable_extents(const _Extents& __exts) noexcept
730 {
731 using _IndexType = _Extents::index_type;
732
733 if constexpr (__contains_zero(__static_extents<_Extents>()))
734 return true;
735 else
736 {
737 constexpr auto __sta_quo = __static_quotient<_Extents>();
738 if constexpr (_Extents::rank_dynamic() == 0)
739 return __sta_quo != 0;
740 else
741 {
742 auto __dyn_exts = __dynamic_extents(__exts);
743 if (__contains_zero(__dyn_exts))
744 return true;
745
746 if constexpr (__sta_quo == 0)
747 return false;
748 else
749 {
750 auto __dyn_quo = _IndexType(__sta_quo);
751 for (auto __factor : __dyn_exts)
752 {
753 __dyn_quo /= __factor;
754 if (__dyn_quo == 0)
755 return false;
756 }
757 return true;
758 }
759 }
760 }
761 }
762
763 template<typename _Extents, typename _IndexType>
764 concept __representable_size = _Extents::rank_dynamic() != 0
765 || __contains_zero(__static_extents<_Extents>())
766 || (__static_quotient<_Extents, _IndexType>() != 0);
767
768 template<typename _Layout, typename _Mapping>
769 concept __mapping_of =
770 is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>,
771 _Mapping>;
772
773 template<template<size_t> typename _Layout, typename _Mapping>
774 concept __padded_mapping_of = __mapping_of<
775 _Layout<_Mapping::padding_value>, _Mapping>;
776
777#ifdef __glibcxx_padded_layouts
778 template<typename _Mapping>
779 constexpr bool __is_left_padded_mapping = __padded_mapping_of<
780 layout_left_padded, _Mapping>;
781
782 template<typename _Mapping>
783 constexpr bool __is_right_padded_mapping = __padded_mapping_of<
784 layout_right_padded, _Mapping>;
785#endif
786
787 template<typename _PaddedMapping>
788 consteval size_t
789 __get_static_stride()
790 { return _PaddedMapping::_PaddedStorage::_S_static_stride; }
791
792 template<typename _Mapping>
793 concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
794 || __mapping_of<layout_right, _Mapping>
795 || __mapping_of<layout_stride, _Mapping>
796#ifdef __glibcxx_padded_layouts
797 || __is_left_padded_mapping<_Mapping>
798 || __is_right_padded_mapping<_Mapping>
799#endif
800 ;
801
802 // A tag type to create internal ctors.
803 class __internal_ctor
804 { };
805 }
806
807 template<typename _Extents>
808 class layout_left::mapping
809 {
810 public:
811 using extents_type = _Extents;
812 using index_type = typename extents_type::index_type;
813 using size_type = typename extents_type::size_type;
814 using rank_type = typename extents_type::rank_type;
815 using layout_type = layout_left;
816
817 static_assert(__mdspan::__representable_size<extents_type, index_type>,
818 "The size of extents_type must be representable as index_type");
819
820 constexpr
821 mapping() noexcept = default;
822
823 constexpr
824 mapping(const mapping&) noexcept = default;
825
826 constexpr
827 mapping(const extents_type& __extents) noexcept
828 : _M_extents(__extents)
829 { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
830
831 template<typename _OExtents>
832 requires is_constructible_v<extents_type, _OExtents>
833 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
834 mapping(const mapping<_OExtents>& __other) noexcept
835 : mapping(__other.extents(), __mdspan::__internal_ctor{})
836 { }
837
838 template<typename _OExtents>
839 requires (extents_type::rank() <= 1)
840 && is_constructible_v<extents_type, _OExtents>
841 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
842 mapping(const layout_right::mapping<_OExtents>& __other) noexcept
843 : mapping(__other.extents(), __mdspan::__internal_ctor{})
844 { }
845
846 // noexcept for consistency with other layouts.
847 template<typename _OExtents>
848 requires is_constructible_v<extents_type, _OExtents>
849 constexpr explicit(extents_type::rank() > 0)
850 mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
851 : mapping(__other.extents(), __mdspan::__internal_ctor{})
852 { __glibcxx_assert(*this == __other); }
853
854#if __glibcxx_padded_layouts
855 template<typename _LeftpadMapping>
856 requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
857 && is_constructible_v<extents_type,
858 typename _LeftpadMapping::extents_type>
859 constexpr
860 explicit(!is_convertible_v<typename _LeftpadMapping::extents_type,
861 extents_type>)
862 mapping(const _LeftpadMapping& __other) noexcept
863 : mapping(__other.extents(), __mdspan::__internal_ctor{})
864 {
865 constexpr size_t __ostride_sta
866 = __mdspan::__get_static_stride<_LeftpadMapping>();
867
868 if constexpr (extents_type::rank() > 1)
869 {
870 if constexpr (extents_type::static_extent(0) != dynamic_extent
871 && __ostride_sta != dynamic_extent)
872 static_assert(extents_type::static_extent(0) == __ostride_sta);
873 else
874 __glibcxx_assert(__other.stride(1)
875 == __other.extents().extent(0));
876 }
877 }
878#endif // __glibcxx_padded_layouts
879
880 constexpr mapping&
881 operator=(const mapping&) noexcept = default;
882
883 constexpr const extents_type&
884 extents() const noexcept { return _M_extents; }
885
886 constexpr index_type
887 required_span_size() const noexcept
888 { return __mdspan::__size(_M_extents); }
889
890 // _GLIBCXX_RESOLVE_LIB_DEFECTS
891 // 4314. Missing move in mdspan layout mapping::operator()
892 template<__mdspan::__valid_index_type<index_type>... _Indices>
893 requires (sizeof...(_Indices) == extents_type::rank())
894 constexpr index_type
895 operator()(_Indices... __indices) const noexcept
896 {
897 return __mdspan::__linear_index_left(_M_extents,
898 static_cast<index_type>(std::move(__indices))...);
899 }
900
901 static constexpr bool
902 is_always_unique() noexcept { return true; }
903
904 static constexpr bool
905 is_always_exhaustive() noexcept { return true; }
906
907 static constexpr bool
908 is_always_strided() noexcept { return true; }
909
910 static constexpr bool
911 is_unique() noexcept { return true; }
912
913 static constexpr bool
914 is_exhaustive() noexcept { return true; }
915
916 static constexpr bool
917 is_strided() noexcept { return true; }
918
919 constexpr index_type
920 stride(rank_type __i) const noexcept
921 requires (extents_type::rank() > 0)
922 {
923 __glibcxx_assert(__i < extents_type::rank());
924 return __mdspan::__fwd_prod(_M_extents, __i);
925 }
926
927 template<typename _OExtents>
928 requires (extents_type::rank() == _OExtents::rank())
929 friend constexpr bool
930 operator==(const mapping& __self, const mapping<_OExtents>& __other)
931 noexcept
932 { return __self.extents() == __other.extents(); }
933
934 private:
935 template<typename _OExtents>
936 constexpr explicit
937 mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
938 : _M_extents(__oexts)
939 {
940 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
941 "The size of OtherExtents must be representable as index_type");
942 __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
943 }
944
945 [[no_unique_address]] extents_type _M_extents{};
946 };
947
948 namespace __mdspan
949 {
950 template<typename _Extents, typename... _Indices>
951 constexpr typename _Extents::index_type
952 __linear_index_right(const _Extents& __exts, _Indices... __indices)
953 noexcept
954 {
955 using _IndexType = typename _Extents::index_type;
956 array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
957 _IndexType __res = 0;
958 if constexpr (sizeof...(__indices) > 0)
959 {
960 _IndexType __mult = 1;
961 auto __update = [&, __pos = __exts.rank()](_IndexType) mutable
962 {
963 --__pos;
964 _GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos],
965 __exts.extent(__pos)));
966 __res += __ind_arr[__pos] * __mult;
967 __mult *= __exts.extent(__pos);
968 };
969 (__update(__indices), ...);
970 }
971 return __res;
972 }
973 }
974
975 template<typename _Extents>
976 class layout_right::mapping
977 {
978 public:
979 using extents_type = _Extents;
980 using index_type = typename extents_type::index_type;
981 using size_type = typename extents_type::size_type;
982 using rank_type = typename extents_type::rank_type;
983 using layout_type = layout_right;
984
985 static_assert(__mdspan::__representable_size<extents_type, index_type>,
986 "The size of extents_type must be representable as index_type");
987
988 constexpr
989 mapping() noexcept = default;
990
991 constexpr
992 mapping(const mapping&) noexcept = default;
993
994 constexpr
995 mapping(const extents_type& __extents) noexcept
996 : _M_extents(__extents)
997 { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
998
999 template<typename _OExtents>
1000 requires is_constructible_v<extents_type, _OExtents>
1001 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
1002 mapping(const mapping<_OExtents>& __other) noexcept
1003 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1004 { }
1005
1006 template<typename _OExtents>
1007 requires (extents_type::rank() <= 1)
1008 && is_constructible_v<extents_type, _OExtents>
1009 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
1010 mapping(const layout_left::mapping<_OExtents>& __other) noexcept
1011 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1012 { }
1013
1014 template<typename _OExtents>
1015 requires is_constructible_v<extents_type, _OExtents>
1016 constexpr explicit(extents_type::rank() > 0)
1017 mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
1018 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1019 { __glibcxx_assert(*this == __other); }
1020
1021#if __glibcxx_padded_layouts
1022 template<typename _RightPaddedMapping>
1023 requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
1024 && is_constructible_v<extents_type,
1025 typename _RightPaddedMapping::extents_type>
1026 constexpr
1027 explicit(!is_convertible_v<typename _RightPaddedMapping::extents_type,
1028 extents_type>)
1029 mapping(const _RightPaddedMapping& __other) noexcept
1030 : mapping(__other.extents(), __mdspan::__internal_ctor{})
1031 {
1032 constexpr size_t __rank = extents_type::rank();
1033 constexpr size_t __ostride_sta
1034 = __mdspan::__get_static_stride<_RightPaddedMapping>();
1035
1036 if constexpr (__rank > 1)
1037 {
1038 if constexpr (extents_type::static_extent(__rank - 1) != dynamic_extent
1039 && __ostride_sta != dynamic_extent)
1040 static_assert(extents_type::static_extent(__rank - 1)
1041 == __ostride_sta);
1042 else
1043 __glibcxx_assert(__other.stride(__rank - 2)
1044 == __other.extents().extent(__rank - 1));
1045 }
1046 }
1047#endif
1048
1049 constexpr mapping&
1050 operator=(const mapping&) noexcept = default;
1051
1052 constexpr const extents_type&
1053 extents() const noexcept { return _M_extents; }
1054
1055 constexpr index_type
1056 required_span_size() const noexcept
1057 { return __mdspan::__size(_M_extents); }
1058
1059 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1060 // 4314. Missing move in mdspan layout mapping::operator()
1061 template<__mdspan::__valid_index_type<index_type>... _Indices>
1062 requires (sizeof...(_Indices) == extents_type::rank())
1063 constexpr index_type
1064 operator()(_Indices... __indices) const noexcept
1065 {
1066 return __mdspan::__linear_index_right(
1067 _M_extents, static_cast<index_type>(std::move(__indices))...);
1068 }
1069
1070 static constexpr bool
1071 is_always_unique() noexcept
1072 { return true; }
1073
1074 static constexpr bool
1075 is_always_exhaustive() noexcept
1076 { return true; }
1077
1078 static constexpr bool
1079 is_always_strided() noexcept
1080 { return true; }
1081
1082 static constexpr bool
1083 is_unique() noexcept
1084 { return true; }
1085
1086 static constexpr bool
1087 is_exhaustive() noexcept
1088 { return true; }
1089
1090 static constexpr bool
1091 is_strided() noexcept
1092 { return true; }
1093
1094 constexpr index_type
1095 stride(rank_type __i) const noexcept
1096 requires (extents_type::rank() > 0)
1097 {
1098 __glibcxx_assert(__i < extents_type::rank());
1099 return __mdspan::__rev_prod(_M_extents, __i);
1100 }
1101
1102 template<typename _OExtents>
1103 requires (extents_type::rank() == _OExtents::rank())
1104 friend constexpr bool
1105 operator==(const mapping& __self, const mapping<_OExtents>& __other)
1106 noexcept
1107 { return __self.extents() == __other.extents(); }
1108
1109 private:
1110 template<typename _OExtents>
1111 constexpr explicit
1112 mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
1113 : _M_extents(__oexts)
1114 {
1115 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
1116 "The size of OtherExtents must be representable as index_type");
1117 __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
1118 }
1119
1120 [[no_unique_address]] extents_type _M_extents{};
1121 };
1122
1123 namespace __mdspan
1124 {
1125 template<typename _Mp>
1126 concept __mapping_alike = requires
1127 {
1128 requires __is_extents<typename _Mp::extents_type>;
1129 { _Mp::is_always_strided() } -> same_as<bool>;
1130 { _Mp::is_always_exhaustive() } -> same_as<bool>;
1131 { _Mp::is_always_unique() } -> same_as<bool>;
1132 bool_constant<_Mp::is_always_strided()>::value;
1133 bool_constant<_Mp::is_always_exhaustive()>::value;
1134 bool_constant<_Mp::is_always_unique()>::value;
1135 };
1136
1137 template<typename _Mapping>
1138 constexpr typename _Mapping::index_type
1139 __offset(const _Mapping& __m) noexcept
1140 {
1141 using _IndexType = typename _Mapping::index_type;
1142 constexpr auto __rank = _Mapping::extents_type::rank();
1143
1144 if constexpr (__standardized_mapping<_Mapping>)
1145 return 0;
1146 else if (__empty(__m.extents()))
1147 return 0;
1148 else
1149 {
1150 auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>)
1151 { return __m(((void) _Counts, _IndexType(0))...); };
1152 return __impl(make_index_sequence<__rank>());
1153 }
1154 }
1155
1156 template<typename _Mapping, typename... _Indices>
1157 constexpr typename _Mapping::index_type
1158 __linear_index_strides(const _Mapping& __m, _Indices... __indices)
1159 noexcept
1160 {
1161 using _IndexType = typename _Mapping::index_type;
1162 _IndexType __res = 0;
1163 if constexpr (sizeof...(__indices) > 0)
1164 {
1165 auto __update = [&, __pos = 0u](_IndexType __idx) mutable
1166 {
1167 _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx,
1168 __m.extents().extent(__pos)));
1169 __res += __idx * __m.stride(__pos++);
1170 };
1171 (__update(__indices), ...);
1172 }
1173 return __res;
1174 }
1175 }
1176
1177 template<typename _Extents>
1178 class layout_stride::mapping
1179 {
1180 public:
1181 using extents_type = _Extents;
1182 using index_type = typename extents_type::index_type;
1183 using size_type = typename extents_type::size_type;
1184 using rank_type = typename extents_type::rank_type;
1185 using layout_type = layout_stride;
1186
1187 static_assert(__mdspan::__representable_size<extents_type, index_type>,
1188 "The size of extents_type must be representable as index_type");
1189
1190 constexpr
1191 mapping() noexcept
1192 {
1193 // The precondition is either statically asserted, or automatically
1194 // satisfied because dynamic extents are zero-initialized.
1195 size_t __stride = 1;
1196 for (size_t __i = extents_type::rank(); __i > 0; --__i)
1197 {
1198 _M_strides[__i - 1] = index_type(__stride);
1199 __stride *= size_t(_M_extents.extent(__i - 1));
1200 }
1201 }
1202
1203 constexpr
1204 mapping(const mapping&) noexcept = default;
1205
1206 template<typename _OIndexType>
1207 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1208 constexpr
1209 mapping(const extents_type& __exts,
1210 span<_OIndexType, extents_type::rank()> __strides) noexcept
1211 : _M_extents(__exts)
1212 {
1213 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1214 _M_strides[__i] = index_type(as_const(__strides[__i]));
1215 }
1216
1217 template<typename _OIndexType>
1218 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1219 constexpr
1220 mapping(const extents_type& __exts,
1221 const array<_OIndexType, extents_type::rank()>& __strides)
1222 noexcept
1223 : mapping(__exts,
1224 span<const _OIndexType, extents_type::rank()>(__strides))
1225 { }
1226
1227 template<__mdspan::__mapping_alike _StridedMapping>
1228 requires (is_constructible_v<extents_type,
1229 typename _StridedMapping::extents_type>
1230 && _StridedMapping::is_always_unique()
1231 && _StridedMapping::is_always_strided())
1232 constexpr explicit(!(
1233 is_convertible_v<typename _StridedMapping::extents_type, extents_type>
1234 && __mdspan::__standardized_mapping<_StridedMapping>))
1235 mapping(const _StridedMapping& __other) noexcept
1236 : _M_extents(__other.extents())
1237 {
1238 using _OIndexType = _StridedMapping::index_type;
1239 using _OExtents = _StridedMapping::extents_type;
1240
1241 __glibcxx_assert(__mdspan::__offset(__other) == 0);
1242 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
1243 "The size of StridedMapping::extents_type must be representable as"
1244 " index_type");
1245 if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max,
1246 __gnu_cxx::__int_traits<index_type>::__max))
1247 __glibcxx_assert(!cmp_less(
1248 __gnu_cxx::__int_traits<index_type>::__max,
1249 __other.required_span_size())
1250 && "other.required_span_size() must be representable"
1251 " as index_type");
1252 if constexpr (extents_type::rank() > 0)
1253 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1254 _M_strides[__i] = index_type(__other.stride(__i));
1255 }
1256
1257 constexpr mapping&
1258 operator=(const mapping&) noexcept = default;
1259
1260 constexpr const extents_type&
1261 extents() const noexcept { return _M_extents; }
1262
1263 constexpr array<index_type, extents_type::rank()>
1264 strides() const noexcept
1265 {
1266 array<index_type, extents_type::rank()> __ret;
1267 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1268 __ret[__i] = _M_strides[__i];
1269 return __ret;
1270 }
1271
1272 constexpr index_type
1273 required_span_size() const noexcept
1274 {
1275 if (__mdspan::__empty(_M_extents))
1276 return 0;
1277
1278 index_type __ret = 1;
1279 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1280 __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i];
1281 return __ret;
1282 }
1283
1284 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1285 // 4314. Missing move in mdspan layout mapping::operator()
1286 template<__mdspan::__valid_index_type<index_type>... _Indices>
1287 requires (sizeof...(_Indices) == extents_type::rank())
1288 constexpr index_type
1289 operator()(_Indices... __indices) const noexcept
1290 {
1291 return __mdspan::__linear_index_strides(*this,
1292 static_cast<index_type>(std::move(__indices))...);
1293 }
1294
1295 static constexpr bool
1296 is_always_unique() noexcept { return true; }
1297
1298 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1299 // 4266. layout_stride::mapping should treat empty mappings as exhaustive
1300 static constexpr bool
1301 is_always_exhaustive() noexcept
1302 {
1303 return (_Extents::rank() == 0) || __mdspan::__contains_zero(
1304 __mdspan::__static_extents<extents_type>());
1305 }
1306
1307 static constexpr bool
1308 is_always_strided() noexcept { return true; }
1309
1310 static constexpr bool
1311 is_unique() noexcept { return true; }
1312
1313 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1314 // 4266. layout_stride::mapping should treat empty mappings as exhaustive
1315 constexpr bool
1316 is_exhaustive() const noexcept
1317 {
1318 if constexpr (!is_always_exhaustive())
1319 {
1320 auto __size = __mdspan::__size(_M_extents);
1321 if(__size > 0)
1322 return __size == required_span_size();
1323 }
1324 return true;
1325 }
1326
1327 static constexpr bool
1328 is_strided() noexcept { return true; }
1329
1330 constexpr index_type
1331 stride(rank_type __r) const noexcept { return _M_strides[__r]; }
1332
1333 template<__mdspan::__mapping_alike _OMapping>
1334 requires ((extents_type::rank() == _OMapping::extents_type::rank())
1335 && _OMapping::is_always_strided())
1336 friend constexpr bool
1337 operator==(const mapping& __self, const _OMapping& __other) noexcept
1338 {
1339 if (__self.extents() != __other.extents())
1340 return false;
1341 if constexpr (extents_type::rank() > 0)
1342 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1343 if (!cmp_equal(__self.stride(__i), __other.stride(__i)))
1344 return false;
1345 return __mdspan::__offset(__other) == 0;
1346 }
1347
1348 private:
1349 using _Strides = typename __array_traits<index_type,
1350 extents_type::rank()>::_Type;
1351 [[no_unique_address]] extents_type _M_extents;
1352 [[no_unique_address]] _Strides _M_strides;
1353 };
1354
1355#ifdef __glibcxx_padded_layouts
1356 namespace __mdspan
1357 {
1358 constexpr size_t
1359 __least_multiple(size_t __x, size_t __y)
1360 {
1361 if (__x <= 1)
1362 return __y;
1363 return (__y / __x + (__y % __x != 0)) * __x ;
1364 }
1365
1366 template<typename _IndexType>
1367 constexpr bool
1368 __is_representable_least_multiple(size_t __x, size_t __y)
1369 {
1370 constexpr auto __y_max = __gnu_cxx::__int_traits<_IndexType>::__max;
1371 if(std::cmp_greater(__y, __y_max))
1372 return false;
1373
1374 if(__x <= 1)
1375 return true;
1376
1377 auto __max_delta = __y_max - static_cast<_IndexType>(__y);
1378 auto __y_mod_x = __y % __x;
1379 auto __delta = (__y_mod_x == 0) ? size_t(0) : (__x - __y_mod_x);
1380 return std::cmp_less_equal(__delta, __max_delta);
1381 }
1382
1383 template<typename _Extents, size_t _PaddingValue, typename _LayoutTraits,
1384 size_t _Rank = _Extents::rank()>
1385 concept __valid_static_stride = (_Extents::rank() <= 1)
1386 || (_PaddingValue == dynamic_extent)
1387 || (_Extents::static_extent(_LayoutTraits::_S_ext_idx) == dynamic_extent)
1388 || (__is_representable_least_multiple<size_t>(
1389 _PaddingValue, _Extents::static_extent(_LayoutTraits::_S_ext_idx)));
1390
1391 template<size_t _PaddedStride, typename _Extents,
1392 typename _LayoutTraits>
1393 consteval bool
1394 __is_representable_padded_size()
1395 {
1396 using _IndexType = typename _Extents::index_type;
1397 auto __sta_exts = __static_extents<_Extents>(
1398 _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
1399 size_t __max = __gnu_cxx::__int_traits<_IndexType>::__max;
1400 return __static_quotient(__sta_exts, __max / _PaddedStride) != 0;
1401 }
1402
1403 template<typename _Extents, size_t _PaddedStride, typename _LayoutTraits,
1404 size_t _Rank = _Extents::rank()>
1405 concept __valid_padded_size = (_Rank <= 1)
1406 || (_PaddedStride == dynamic_extent)
1407 || (!__all_static(__static_extents<_Extents>()))
1408 || (__contains_zero(__static_extents<_Extents>()))
1409 || (__is_representable_padded_size<_PaddedStride, _Extents,
1410 _LayoutTraits>());
1411
1412 template<typename _Extents, typename _Stride, typename... _Indices>
1413 constexpr typename _Extents::index_type
1414 __linear_index_leftpad(const _Extents& __exts, _Stride __stride,
1415 _Indices... __indices)
1416 {
1417 // i0 + stride*(i1 + extents.extent(1)*...)
1418 using _IndexType = typename _Extents::index_type;
1419 _IndexType __res = 0;
1420 if constexpr (sizeof...(__indices) > 0)
1421 {
1422 _IndexType __mult = 1;
1423
1424 auto __update_rest = [&, __pos = 1u](_IndexType __idx) mutable
1425 {
1426 __res += __idx * __mult;
1427 __mult *= __exts.extent(__pos);
1428 ++__pos;
1429 };
1430
1431 auto __update = [&](_IndexType __idx, auto... __rest)
1432 {
1433 __res += __idx;
1434 __mult = __stride.extent(0);
1435 (__update_rest(__rest), ...);
1436 };
1437 __update(__indices...);
1438 }
1439 return __res;
1440 }
1441
1442 template<typename _Extents, typename _Stride, typename... _Indices>
1443 constexpr typename _Extents::index_type
1444 __linear_index_rightpad(const _Extents& __exts, _Stride __stride,
1445 _Indices... __indices)
1446 {
1447 // i[n-1] + stride*(i[n-2] + extents.extent(n-2])*...)
1448 using _IndexType = typename _Extents::index_type;
1449 _IndexType __res = 0;
1450 if constexpr (sizeof...(__indices) > 0)
1451 {
1452 _IndexType __mult = 1;
1453 array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
1454
1455 auto __update_rest = [&, __pos = __exts.rank()-1](_IndexType) mutable
1456 {
1457 --__pos;
1458 __res += __ind_arr[__pos] * __mult;
1459 __mult *= __exts.extent(__pos);
1460 };
1461
1462 auto __update = [&](_IndexType, auto... __rest)
1463 {
1464 __res += __ind_arr[__exts.rank() - 1];
1465 __mult = __stride.extent(0);
1466 (__update_rest(__rest), ...);
1467 };
1468 __update(__indices...);
1469 }
1470 return __res;
1471 }
1472
1473 template<size_t _Rank>
1474 struct _LeftPaddedLayoutTraits
1475 {
1476 using _LayoutSame = layout_left;
1477 using _LayoutOther = layout_right;
1478
1479 constexpr static const size_t _S_ext_idx = 0;
1480 constexpr static const size_t _S_stride_idx = 1;
1481 constexpr static const size_t _S_unpad_begin = 1;
1482 constexpr static const size_t _S_unpad_end = _Rank;
1483
1484 template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
1485 constexpr static auto
1486 _S_make_padded_extent(
1487 extents<_IndexType, _StaticStride> __stride,
1488 const extents<_IndexType, _Extents...>& __exts)
1489 {
1490 auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>)
1491 {
1492 return extents<_IndexType, _StaticStride,
1493 (_Extents...[_Is + 1])...>{
1494 __stride.extent(0), __exts.extent(_Is + 1)...};
1495 };
1496 return __impl(make_index_sequence<sizeof...(_Extents) - 1>());
1497 }
1498 };
1499
1500 template<size_t _Rank>
1501 struct _RightPaddedLayoutTraits
1502 {
1503 using _LayoutSame = layout_right;
1504 using _LayoutOther = layout_left;
1505
1506 constexpr static size_t _S_ext_idx = _Rank - 1;
1507 constexpr static size_t _S_stride_idx = _Rank - 2;
1508 constexpr static size_t _S_unpad_begin = 0;
1509 constexpr static size_t _S_unpad_end = _Rank - 1;
1510
1511 template<typename _IndexType, size_t _StaticStride, size_t..._Extents>
1512 constexpr static auto
1513 _S_make_padded_extent(
1514 extents<_IndexType, _StaticStride> __stride,
1515 const extents<_IndexType, _Extents...>& __exts)
1516 {
1517 auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>)
1518 {
1519 return extents<_IndexType, (_Extents...[_Is])..., _StaticStride>{
1520 __exts.extent(_Is)..., __stride.extent(0)};
1521 };
1522 return __impl(make_index_sequence<sizeof...(_Extents) - 1>());
1523 }
1524 };
1525
1526 template<size_t _PaddingValue, typename _Extents, typename _LayoutTraits>
1527 class _PaddedStorage
1528 {
1529 using _LayoutSame = typename _LayoutTraits::_LayoutSame;
1530
1531 public:
1532 using _IndexType = typename _Extents::index_type;
1533 constexpr static size_t _S_rank = _Extents::rank();
1534
1535 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1536 // 4372. Weaken Mandates: for dynamic padding values in padded layouts
1537 static_assert((_PaddingValue == dynamic_extent)
1538 || (cmp_less_equal(_PaddingValue,
1539 __gnu_cxx::__int_traits<_IndexType>::__max)),
1540 "padding_value must be representable as index_type");
1541
1542 static_assert(__representable_size<_Extents, _IndexType>,
1543 "The size of extents_type must be representable as index_type");
1544
1545 static_assert(__valid_static_stride<_Extents, _PaddingValue,
1546 _LayoutTraits>,
1547 "The padded stride must be representable as size_t");
1548
1549 static constexpr size_t _S_static_stride = [] consteval
1550 {
1551 constexpr size_t __rank = _Extents::rank();
1552 if constexpr (__rank <= 1)
1553 return 0;
1554 else
1555 {
1556 constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
1557 constexpr size_t __sta_ext = _Extents::static_extent(__ext_idx);
1558 if constexpr (__sta_ext == 0)
1559 return size_t(0);
1560 else if constexpr (_PaddingValue == dynamic_extent
1561 || __sta_ext == dynamic_extent)
1562 return dynamic_extent;
1563 else
1564 return __least_multiple(_PaddingValue, __sta_ext);
1565 }
1566 }();
1567
1568 static_assert(_S_static_stride == dynamic_extent
1569 || cmp_less_equal(_S_static_stride,
1570 __gnu_cxx::__int_traits<_IndexType>::__max),
1571 "Padded stride must be representable as index_type");
1572
1573 static_assert(__valid_padded_size<_Extents, _S_static_stride,
1574 _LayoutTraits>);
1575
1576 constexpr
1577 _PaddedStorage() noexcept
1578 {
1579 if constexpr (_S_rank > 1)
1580 if constexpr (_S_static_stride == dynamic_extent
1581 && _S_static_padextent() != dynamic_extent)
1582 _M_stride = _Stride{_S_static_padextent()};
1583 }
1584
1585 constexpr explicit
1586 _PaddedStorage(const _Extents& __exts)
1587 : _M_extents(__exts)
1588 {
1589 if constexpr (!__all_static(__static_extents<_Extents>()))
1590 __glibcxx_assert(__is_representable_extents(_M_extents));
1591
1592 if constexpr (_S_rank > 1)
1593 {
1594 _IndexType __stride;
1595 if constexpr (_PaddingValue == dynamic_extent)
1596 __stride = _M_padextent();
1597 else if constexpr (_S_static_padextent() != dynamic_extent)
1598 return;
1599 else
1600 {
1601 __glibcxx_assert(
1602 __is_representable_least_multiple<_IndexType>(
1603 _PaddingValue, _M_padextent()));
1604
1605 __stride = static_cast<_IndexType>(
1606 __least_multiple(_PaddingValue, _M_padextent()));
1607
1608 __glibcxx_assert(__is_representable_extents(
1609 _LayoutTraits::_S_make_padded_extent(
1610 std::dextents<_IndexType, 1>{__stride},
1611 _M_extents)));
1612 }
1613 _M_stride = _Stride{__stride};
1614 }
1615 }
1616
1617 constexpr explicit
1618 _PaddedStorage(const _Extents& __exts, _IndexType __pad)
1619 : _M_extents(__exts)
1620 {
1621 if constexpr (_PaddingValue != dynamic_extent)
1622 __glibcxx_assert(cmp_equal(_PaddingValue, __pad));
1623 if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent)
1624 {
1625 __glibcxx_assert(
1626 __is_representable_least_multiple<_IndexType>(
1627 __pad, _M_padextent()));
1628
1629 _M_stride = _Stride{static_cast<_IndexType>(
1630 __least_multiple(__pad, _M_padextent()))};
1631
1632 __glibcxx_assert(__is_representable_extents(
1633 _LayoutTraits::_S_make_padded_extent(
1634 _M_stride, _M_extents)));
1635 }
1636 }
1637
1638 template<typename _OExtents>
1639 constexpr explicit
1640 _PaddedStorage(const typename _LayoutSame::mapping<_OExtents>&
1641 __other)
1642 : _PaddedStorage(_Extents(__other.extents()))
1643 {
1644 constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
1645 constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx;
1646 if constexpr (_S_rank > 1 && _PaddingValue != dynamic_extent)
1647 {
1648 static_assert(_S_static_stride == dynamic_extent
1649 || _OExtents::static_extent(__ext_idx) == dynamic_extent
1650 || _S_static_stride == _OExtents::static_extent(__ext_idx),
1651 "The padded stride must be compatible with other");
1652
1653 if constexpr (_S_static_stride == dynamic_extent
1654 || _OExtents::static_extent(__stride_idx) == dynamic_extent)
1655 __glibcxx_assert(std::cmp_equal(_M_padstride(),
1656 _M_padextent()));
1657 }
1658 }
1659
1660 template<typename _OExtents>
1661 constexpr explicit
1662 _PaddedStorage(const typename layout_stride::mapping<_OExtents>&
1663 __other)
1664 : _M_extents(__other.extents())
1665 {
1666 __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
1667 __gnu_cxx::__int_traits<_IndexType>
1668 ::__max));
1669
1670 constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
1671 if constexpr (_S_rank > 1)
1672 {
1673 if constexpr (_PaddingValue != dynamic_extent)
1674 __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
1675 _M_calc_padstride())
1676 && "The padded stride must be compatible with other");
1677 if constexpr (_S_static_stride == dynamic_extent)
1678 _M_stride = _Stride{__other.stride(__stride_idx)};
1679 }
1680 }
1681
1682 template<typename _SamePaddedMapping>
1683 constexpr explicit
1684 _PaddedStorage(_LayoutTraits::_LayoutSame,
1685 const _SamePaddedMapping& __other)
1686 : _M_extents(__other.extents())
1687 {
1688 if constexpr (_S_rank > 1)
1689 {
1690 static_assert(_PaddingValue == dynamic_extent
1691 || _SamePaddedMapping::padding_value == dynamic_extent
1692 || _PaddingValue == _SamePaddedMapping::padding_value,
1693 "If neither PaddingValue is dynamic_extent, then they must "
1694 "be equal");
1695
1696 constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx;
1697 if constexpr (_PaddingValue != dynamic_extent)
1698 __glibcxx_assert(cmp_equal(__other.stride(__stride_idx),
1699 _M_calc_padstride())
1700 && "The padded stride must be compatible with other");
1701 if constexpr (_S_static_stride == dynamic_extent)
1702 _M_stride = _Stride{__other.stride(__stride_idx)};
1703 }
1704 __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
1705 __gnu_cxx::__int_traits<_IndexType>::__max));
1706 }
1707
1708 template<typename _OtherPaddedMapping>
1709 constexpr explicit
1710 _PaddedStorage(_LayoutTraits::_LayoutOther,
1711 const _OtherPaddedMapping& __other) noexcept
1712 : _M_extents(__other.extents())
1713 {
1714 __glibcxx_assert(cmp_less_equal(__other.required_span_size(),
1715 __gnu_cxx::__int_traits<_IndexType>::__max));
1716 }
1717
1718 static constexpr bool
1719 _M_is_always_exhaustive() noexcept
1720 {
1721 if constexpr (_S_rank <= 1)
1722 return true;
1723 else
1724 return _S_static_padextent() != dynamic_extent
1725 && _S_static_stride != dynamic_extent
1726 && _S_static_padextent() == _S_static_stride;
1727 }
1728
1729 constexpr bool
1730 _M_is_exhaustive() const noexcept
1731 {
1732 if constexpr (_M_is_always_exhaustive())
1733 return true;
1734 else
1735 return cmp_equal(_M_padextent(), _M_padstride());
1736 }
1737
1738 constexpr static size_t
1739 _S_static_padextent() noexcept
1740 { return _Extents::static_extent(_LayoutTraits::_S_ext_idx); }
1741
1742 constexpr _IndexType
1743 _M_padextent() const noexcept
1744 { return _M_extents.extent(_LayoutTraits::_S_ext_idx); }
1745
1746 constexpr _IndexType
1747 _M_calc_padstride() const noexcept
1748 {
1749 if constexpr (_S_static_stride != dynamic_extent)
1750 return _S_static_stride;
1751 else if constexpr (_PaddingValue != dynamic_extent)
1752 return __least_multiple(_PaddingValue, _M_padextent());
1753 else
1754 return _M_padextent();
1755 }
1756
1757 constexpr _IndexType
1758 _M_padstride() const noexcept
1759 { return _M_stride.extent(0); }
1760
1761 constexpr _IndexType
1762 _M_required_span_size() const noexcept
1763 {
1764 if constexpr (_S_rank == 0)
1765 return 1;
1766 else if (__mdspan::__empty(_M_extents))
1767 return 0;
1768 else
1769 {
1770 size_t __stride = static_cast<size_t>(_M_padstride());
1771 size_t __prod_rest = __mdspan::__fwd_prod(_M_extents,
1772 _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end);
1773 size_t __delta = _M_padstride() - _M_padextent();
1774 return static_cast<_IndexType>(__stride * __prod_rest - __delta);
1775 }
1776 }
1777
1778 template<typename _SamePaddedMapping>
1779 constexpr bool
1780 _M_equal(const _SamePaddedMapping& __other) const noexcept
1781 {
1782 return _M_extents == __other.extents()
1783 && (_S_rank < 2
1784 || cmp_equal(_M_stride.extent(0),
1785 __other.stride(_LayoutTraits::_S_stride_idx)));
1786 }
1787
1788 using _Stride = std::extents<_IndexType, _S_static_stride>;
1789 [[no_unique_address]] _Stride _M_stride;
1790 [[no_unique_address]] _Extents _M_extents;
1791 };
1792 }
1793
1794 template<size_t _PaddingValue>
1795 template<typename _Extents>
1796 class layout_left_padded<_PaddingValue>::mapping
1797 {
1798 public:
1799 static constexpr size_t padding_value = _PaddingValue;
1800
1801 using extents_type = _Extents;
1802 using index_type = typename extents_type::index_type;
1803 using size_type = typename extents_type::size_type;
1804 using rank_type = typename extents_type::rank_type;
1805 using layout_type = layout_left_padded<padding_value>;
1806
1807 private:
1808 static constexpr size_t _S_rank = extents_type::rank();
1809 using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
1810 _Extents, __mdspan::_LeftPaddedLayoutTraits<_S_rank>>;
1811 [[no_unique_address]] _PaddedStorage _M_storage;
1812
1813 consteval friend size_t
1814 __mdspan::__get_static_stride<mapping>();
1815
1816 constexpr index_type
1817 _M_extent(size_t __r) const noexcept
1818 { return _M_storage._M_extents.extent(__r); }
1819
1820 constexpr index_type
1821 _M_padstride() const noexcept
1822 { return _M_storage._M_stride.extent(0); }
1823
1824 public:
1825 constexpr
1826 mapping() noexcept
1827 { }
1828
1829 constexpr
1830 mapping(const mapping&) noexcept = default;
1831
1832 constexpr
1833 mapping(const extents_type& __exts)
1834 : _M_storage(__exts)
1835 { }
1836
1837 template<__mdspan::__valid_index_type<index_type> _OIndexType>
1838 constexpr
1839 mapping(const extents_type& __exts, _OIndexType __pad)
1840 : _M_storage(__exts,
1841 __mdspan::__index_type_cast<index_type>(std::move(__pad)))
1842 { }
1843
1844 template<typename _OExtents>
1845 requires is_constructible_v<extents_type, _OExtents>
1846 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
1847 mapping(const layout_left::mapping<_OExtents>& __other)
1848 : _M_storage(__other)
1849 { }
1850
1851 template<typename _OExtents>
1852 requires is_constructible_v<_OExtents, extents_type>
1853 constexpr explicit(_OExtents::rank() > 0)
1854 mapping(const typename layout_stride::mapping<_OExtents>& __other)
1855 : _M_storage(__other)
1856 { __glibcxx_assert(*this == __other); }
1857
1858 template<typename _LeftpadMapping>
1859 requires __mdspan::__is_left_padded_mapping<_LeftpadMapping>
1860 && is_constructible_v<extents_type,
1861 typename _LeftpadMapping::extents_type>
1862 constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent
1863 || _LeftpadMapping::padding_value == dynamic_extent))
1864 mapping(const _LeftpadMapping& __other)
1865 : _M_storage(layout_left{}, __other)
1866 { }
1867
1868 template<typename _RightPaddedMapping>
1869 requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
1870 || __mdspan::__mapping_of<layout_right, _RightPaddedMapping>)
1871 && (_S_rank <= 1)
1872 && is_constructible_v<extents_type,
1873 typename _RightPaddedMapping::extents_type>
1874 constexpr explicit(!is_convertible_v<
1875 typename _RightPaddedMapping::extents_type, extents_type>)
1876 mapping(const _RightPaddedMapping& __other) noexcept
1877 : _M_storage(layout_right{}, __other)
1878 { }
1879
1880 constexpr mapping&
1881 operator=(const mapping&) noexcept = default;
1882
1883 constexpr const extents_type&
1884 extents() const noexcept { return _M_storage._M_extents; }
1885
1886 constexpr array<index_type, _S_rank>
1887 strides() const noexcept
1888 {
1889 array<index_type, _S_rank> __ret;
1890 if constexpr (_S_rank > 0)
1891 __ret[0] = 1;
1892 if constexpr (_S_rank > 1)
1893 __ret[1] = _M_padstride();
1894 if constexpr (_S_rank > 2)
1895 for(size_t __i = 2; __i < _S_rank; ++__i)
1896 __ret[__i] = __ret[__i - 1] * _M_extent(__i - 1);
1897 return __ret;
1898 }
1899
1900 constexpr index_type
1901 required_span_size() const noexcept
1902 { return _M_storage._M_required_span_size(); }
1903
1904 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1905 // 4314. Missing move in mdspan layout mapping::operator()
1906 template<__mdspan::__valid_index_type<index_type>... _Indices>
1907 requires (sizeof...(_Indices) == _S_rank)
1908 constexpr index_type
1909 operator()(_Indices... __indices) const noexcept
1910 {
1911 return __mdspan::__linear_index_leftpad(
1912 extents(), _M_storage._M_stride,
1913 static_cast<index_type>(std::move(__indices))...);
1914 }
1915
1916 static constexpr bool
1917 is_always_exhaustive() noexcept
1918 { return _PaddedStorage::_M_is_always_exhaustive(); }
1919
1920 constexpr bool
1921 is_exhaustive() noexcept
1922 { return _M_storage._M_is_exhaustive(); }
1923
1924 static constexpr bool
1925 is_always_unique() noexcept { return true; }
1926
1927 static constexpr bool
1928 is_unique() noexcept { return true; }
1929
1930 static constexpr bool
1931 is_always_strided() noexcept { return true; }
1932
1933 static constexpr bool
1934 is_strided() noexcept { return true; }
1935
1936 constexpr index_type
1937 stride(rank_type __r) const noexcept
1938 {
1939 __glibcxx_assert(__r < _S_rank);
1940 if (__r == 0)
1941 return 1;
1942 else
1943 return static_cast<index_type>(
1944 static_cast<size_t>(_M_padstride()) *
1945 static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1, __r)));
1946 }
1947
1948 template<typename _LeftpadMapping>
1949 requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping>
1950 && _LeftpadMapping::extents_type::rank() == _S_rank)
1951 friend constexpr bool
1952 operator==(const mapping& __self, const _LeftpadMapping& __other)
1953 noexcept
1954 { return __self._M_storage._M_equal(__other); }
1955 };
1956
1957 template<size_t _PaddingValue>
1958 template<typename _Extents>
1959 class layout_right_padded<_PaddingValue>::mapping {
1960 public:
1961 static constexpr size_t padding_value = _PaddingValue;
1962 using extents_type = _Extents;
1963 using index_type = typename extents_type::index_type;
1964 using size_type = typename extents_type::size_type;
1965 using rank_type = typename extents_type::rank_type;
1966 using layout_type = layout_right_padded<_PaddingValue>;
1967
1968 private:
1969 static constexpr size_t _S_rank = extents_type::rank();
1970 using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue,
1971 _Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>;
1972 [[no_unique_address]] _PaddedStorage _M_storage;
1973
1974 consteval friend size_t
1975 __mdspan::__get_static_stride<mapping>();
1976
1977 constexpr index_type
1978 _M_extent(size_t __r) const noexcept
1979 { return _M_storage._M_extents.extent(__r); }
1980
1981 constexpr index_type
1982 _M_padstride() const noexcept
1983 { return _M_storage._M_stride.extent(0); }
1984
1985 public:
1986 constexpr
1987 mapping() noexcept
1988 { }
1989
1990 constexpr
1991 mapping(const mapping&) noexcept = default;
1992
1993 constexpr
1994 mapping(const extents_type& __exts)
1995 : _M_storage(__exts)
1996 { }
1997
1998 template<__mdspan::__valid_index_type<index_type> _OIndexType>
1999 constexpr
2000 mapping(const extents_type& __exts, _OIndexType __pad)
2001 : _M_storage(__exts,
2002 __mdspan::__index_type_cast<index_type>(std::move(__pad)))
2003 { }
2004
2005 template<typename _OExtents>
2006 requires is_constructible_v<extents_type, _OExtents>
2007 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
2008 mapping(const layout_right::mapping<_OExtents>& __other)
2009 : _M_storage(__other)
2010 { }
2011
2012 template<typename _OExtents>
2013 requires is_constructible_v<_OExtents, extents_type>
2014 constexpr explicit(_OExtents::rank() > 0)
2015 mapping(const typename layout_stride::mapping<_OExtents>& __other)
2016 : _M_storage(__other)
2017 { __glibcxx_assert(*this == __other); }
2018
2019 template<typename _RightPaddedMapping>
2020 requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping>
2021 && is_constructible_v<extents_type,
2022 typename _RightPaddedMapping::extents_type>
2023 constexpr explicit(_S_rank > 1 && (padding_value != dynamic_extent
2024 || _RightPaddedMapping::padding_value == dynamic_extent))
2025 mapping(const _RightPaddedMapping& __other)
2026 : _M_storage(layout_right{}, __other)
2027 { }
2028
2029 template<typename _LeftPaddedMapping>
2030 requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping>
2031 || __mdspan::__mapping_of<layout_left, _LeftPaddedMapping>)
2032 && (_S_rank <= 1)
2033 && is_constructible_v<extents_type,
2034 typename _LeftPaddedMapping::extents_type>
2035 constexpr explicit(!is_convertible_v<
2036 typename _LeftPaddedMapping::extents_type, extents_type>)
2037 mapping(const _LeftPaddedMapping& __other) noexcept
2038 : _M_storage(layout_left{}, __other)
2039 { }
2040
2041 constexpr mapping& operator=(const mapping&) noexcept = default;
2042
2043 constexpr const extents_type&
2044 extents() const noexcept { return _M_storage._M_extents; }
2045
2046 constexpr array<index_type, _S_rank>
2047 strides() const noexcept
2048 {
2049 array<index_type, _S_rank> __ret;
2050 if constexpr (_S_rank > 0)
2051 __ret[_S_rank - 1] = 1;
2052 if constexpr (_S_rank > 1)
2053 __ret[_S_rank - 2] = _M_padstride();
2054 if constexpr (_S_rank > 2)
2055 for(size_t __i = _S_rank - 2; __i > 0; --__i)
2056 __ret[__i - 1] = __ret[__i] * _M_extent(__i);
2057 return __ret;
2058 }
2059
2060 constexpr index_type
2061 required_span_size() const noexcept
2062 { return _M_storage._M_required_span_size(); }
2063
2064 // _GLIBCXX_RESOLVE_LIB_DEFECTS
2065 // 4314. Missing move in mdspan layout mapping::operator()
2066 template<__mdspan::__valid_index_type<index_type>... _Indices>
2067 requires (sizeof...(_Indices) == _S_rank)
2068 constexpr index_type
2069 operator()(_Indices... __indices) const noexcept
2070 {
2071 return __mdspan::__linear_index_rightpad(
2072 extents(), _M_storage._M_stride,
2073 static_cast<index_type>(std::move(__indices))...);
2074 }
2075
2076 static constexpr bool
2077 is_always_exhaustive() noexcept
2078 { return _PaddedStorage::_M_is_always_exhaustive(); }
2079
2080 constexpr bool
2081 is_exhaustive() noexcept
2082 { return _M_storage._M_is_exhaustive(); }
2083
2084 static constexpr bool
2085 is_always_unique() noexcept { return true; }
2086
2087 static constexpr bool
2088 is_unique() noexcept { return true; }
2089
2090 static constexpr bool
2091 is_always_strided() noexcept { return true; }
2092
2093 static constexpr bool
2094 is_strided() noexcept { return true; }
2095
2096 constexpr index_type
2097 stride(rank_type __r) const noexcept
2098 {
2099 __glibcxx_assert(__r < _S_rank);
2100 if constexpr (_S_rank <= 1)
2101 return 1;
2102 else if (__r == _S_rank - 1)
2103 return 1;
2104 else if (__r == _S_rank - 2)
2105 return _M_padstride();
2106 else
2107 return static_cast<index_type>(
2108 static_cast<size_t>(_M_padstride()) *
2109 static_cast<size_t>(__mdspan::__fwd_prod(
2110 extents(), __r + 1, _S_rank - 1)));
2111 }
2112
2113 template<typename _RightPaddedMapping>
2114 requires(__mdspan::__is_right_padded_mapping<_RightPaddedMapping>
2115 && _RightPaddedMapping::extents_type::rank() == _S_rank)
2116 friend constexpr bool
2117 operator==(const mapping& __self, const _RightPaddedMapping& __other)
2118 noexcept
2119 { return __self._M_storage._M_equal(__other); }
2120 };
2121#endif // __glibcxx_padded_layouts
2122
2123 template<typename _ElementType>
2124 struct default_accessor
2125 {
2126 static_assert(!is_array_v<_ElementType>,
2127 "ElementType must not be an array type");
2128 static_assert(!is_abstract_v<_ElementType>,
2129 "ElementType must not be an abstract class type");
2130
2131 using offset_policy = default_accessor;
2132 using element_type = _ElementType;
2133 using reference = element_type&;
2134 using data_handle_type = element_type*;
2135
2136 constexpr
2137 default_accessor() noexcept = default;
2138
2139 template<typename _OElementType>
2140 requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
2141 constexpr
2142 default_accessor(default_accessor<_OElementType>) noexcept
2143 { }
2144
2145 constexpr reference
2146 access(data_handle_type __p, size_t __i) const noexcept
2147 { return __p[__i]; }
2148
2149 constexpr data_handle_type
2150 offset(data_handle_type __p, size_t __i) const noexcept
2151 { return __p + __i; }
2152 };
2153
2154#ifdef __glibcxx_aligned_accessor
2155 template<typename _ElementType, size_t _ByteAlignment>
2156 struct aligned_accessor
2157 {
2158 static_assert(has_single_bit(_ByteAlignment),
2159 "ByteAlignment must be a power of two");
2160 static_assert(_ByteAlignment >= alignof(_ElementType));
2161
2162 using offset_policy = default_accessor<_ElementType>;
2163 using element_type = _ElementType;
2164 using reference = element_type&;
2165 using data_handle_type = element_type*;
2166
2167 static constexpr size_t byte_alignment = _ByteAlignment;
2168
2169 constexpr
2170 aligned_accessor() noexcept = default;
2171
2172 template<typename _OElementType, size_t _OByteAlignment>
2173 requires (_OByteAlignment >= byte_alignment)
2174 && is_convertible_v<_OElementType(*)[], element_type(*)[]>
2175 constexpr
2176 aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>)
2177 noexcept
2178 { }
2179
2180 template<typename _OElementType>
2181 requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
2182 constexpr explicit
2183 aligned_accessor(default_accessor<_OElementType>) noexcept
2184 { }
2185
2186 template<typename _OElementType>
2187 requires is_convertible_v<element_type(*)[], _OElementType(*)[]>
2188 constexpr
2189 operator default_accessor<_OElementType>() const noexcept
2190 { return {}; }
2191
2192 constexpr reference
2193 access(data_handle_type __p, size_t __i) const noexcept
2194 { return std::assume_aligned<byte_alignment>(__p)[__i]; }
2195
2196 constexpr typename offset_policy::data_handle_type
2197 offset(data_handle_type __p, size_t __i) const noexcept
2198 { return std::assume_aligned<byte_alignment>(__p) + __i; }
2199 };
2200#endif
2201
2202 namespace __mdspan
2203 {
2204 template<typename _Extents, typename _IndexType, size_t _Nm>
2205 constexpr bool
2206 __is_multi_index(const _Extents& __exts, span<_IndexType, _Nm> __indices)
2207 {
2208 static_assert(__exts.rank() == _Nm);
2209 for (size_t __i = 0; __i < __exts.rank(); ++__i)
2210 if (__indices[__i] >= __exts.extent(__i))
2211 return false;
2212 return true;
2213 }
2214 }
2215
2216 template<typename _ElementType, typename _Extents,
2217 typename _LayoutPolicy = layout_right,
2218 typename _AccessorPolicy = default_accessor<_ElementType>>
2219 class mdspan
2220 {
2221 static_assert(!is_array_v<_ElementType>,
2222 "ElementType must not be an array type");
2223 static_assert(!is_abstract_v<_ElementType>,
2224 "ElementType must not be an abstract class type");
2225 static_assert(__mdspan::__is_extents<_Extents>,
2226 "Extents must be a specialization of std::extents");
2227 static_assert(is_same_v<_ElementType,
2228 typename _AccessorPolicy::element_type>);
2229
2230 public:
2231 using extents_type = _Extents;
2232 using layout_type = _LayoutPolicy;
2233 using accessor_type = _AccessorPolicy;
2234 using mapping_type = typename layout_type::template mapping<extents_type>;
2235 using element_type = _ElementType;
2236 using value_type = remove_cv_t<element_type>;
2237 using index_type = typename extents_type::index_type;
2238 using size_type = typename extents_type::size_type;
2239 using rank_type = typename extents_type::rank_type;
2240 using data_handle_type = typename accessor_type::data_handle_type;
2241 using reference = typename accessor_type::reference;
2242
2243 static constexpr rank_type
2244 rank() noexcept { return extents_type::rank(); }
2245
2246 static constexpr rank_type
2247 rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
2248
2249 static constexpr size_t
2250 static_extent(rank_type __r) noexcept
2251 { return extents_type::static_extent(__r); }
2252
2253 constexpr index_type
2254 extent(rank_type __r) const noexcept { return extents().extent(__r); }
2255
2256 constexpr
2257 mdspan()
2258 requires (rank_dynamic() > 0)
2259 && is_default_constructible_v<data_handle_type>
2260 && is_default_constructible_v<mapping_type>
2261 && is_default_constructible_v<accessor_type> = default;
2262
2263 constexpr
2264 mdspan(const mdspan& __other) = default;
2265
2266 constexpr
2267 mdspan(mdspan&& __other) = default;
2268
2269 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
2270 requires (sizeof...(_OIndexTypes) == rank()
2271 || sizeof...(_OIndexTypes) == rank_dynamic())
2272 && is_constructible_v<mapping_type, extents_type>
2273 && is_default_constructible_v<accessor_type>
2274 constexpr explicit
2275 mdspan(data_handle_type __handle, _OIndexTypes... __exts)
2276 : _M_accessor(),
2277 _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)),
2278 _M_handle(std::move(__handle))
2279 { }
2280
2281 template<typename _OIndexType, size_t _Nm>
2282 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
2283 && (_Nm == rank() || _Nm == rank_dynamic())
2284 && is_constructible_v<mapping_type, extents_type>
2285 && is_default_constructible_v<accessor_type>
2286 constexpr explicit(_Nm != rank_dynamic())
2287 mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts)
2288 : _M_accessor(), _M_mapping(extents_type(__exts)),
2289 _M_handle(std::move(__handle))
2290 { }
2291
2292 template<typename _OIndexType, size_t _Nm>
2293 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
2294 && (_Nm == rank() || _Nm == rank_dynamic())
2295 && is_constructible_v<mapping_type, extents_type>
2296 && is_default_constructible_v<accessor_type>
2297 constexpr explicit(_Nm != rank_dynamic())
2298 mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts)
2299 : _M_accessor(), _M_mapping(extents_type(__exts)),
2300 _M_handle(std::move(__handle))
2301 { }
2302
2303 constexpr
2304 mdspan(data_handle_type __handle, const extents_type& __exts)
2305 requires is_constructible_v<mapping_type, const extents_type&>
2306 && is_default_constructible_v<accessor_type>
2307 : _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle))
2308 { }
2309
2310 constexpr
2311 mdspan(data_handle_type __handle, const mapping_type& __mapping)
2312 requires is_default_constructible_v<accessor_type>
2313 : _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle))
2314 { }
2315
2316 constexpr
2317 mdspan(data_handle_type __handle, const mapping_type& __mapping,
2318 const accessor_type& __accessor)
2319 : _M_accessor(__accessor), _M_mapping(__mapping),
2320 _M_handle(std::move(__handle))
2321 { }
2322
2323 template<typename _OElementType, typename _OExtents, typename _OLayout,
2324 typename _OAccessor>
2325 requires is_constructible_v<mapping_type,
2326 const typename _OLayout::template mapping<_OExtents>&>
2327 && is_constructible_v<accessor_type, const _OAccessor&>
2328 constexpr explicit(!is_convertible_v<
2329 const typename _OLayout::template mapping<_OExtents>&, mapping_type>
2330 || !is_convertible_v<const _OAccessor&, accessor_type>)
2331 mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>&
2332 __other)
2333 : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()),
2334 _M_handle(__other.data_handle())
2335 {
2336 static_assert(is_constructible_v<data_handle_type,
2337 const typename _OAccessor::data_handle_type&>);
2338 static_assert(is_constructible_v<extents_type, _OExtents>);
2339 }
2340
2341 constexpr mdspan&
2342 operator=(const mdspan& __other) = default;
2343
2344 constexpr mdspan&
2345 operator=(mdspan&& __other) = default;
2346
2347 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
2348 requires (sizeof...(_OIndexTypes) == rank())
2349 constexpr reference
2350 operator[](_OIndexTypes... __indices) const
2351 {
2352 auto __checked_call = [this](auto... __idxs) -> index_type
2353 {
2354 if constexpr (sizeof...(__idxs) > 0)
2355 __glibcxx_assert(__mdspan::__is_multi_index(extents(),
2356 span<const index_type, sizeof...(__idxs)>({__idxs...})));
2357 return _M_mapping(__idxs...);
2358 };
2359
2360 auto __index = __checked_call(
2361 static_cast<index_type>(std::move(__indices))...);
2362 return _M_accessor.access(_M_handle, __index);
2363 }
2364
2365 template<typename _OIndexType>
2366 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
2367 constexpr reference
2368 operator[](span<_OIndexType, rank()> __indices) const
2369 {
2370 auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
2371 -> reference
2372 { return (*this)[index_type(as_const(__indices[_Counts]))...]; };
2373 return __call(make_index_sequence<rank()>());
2374 }
2375
2376 template<typename _OIndexType>
2377 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
2378 constexpr reference
2379 operator[](const array<_OIndexType, rank()>& __indices) const
2380 { return (*this)[span<const _OIndexType, rank()>(__indices)]; }
2381
2382 constexpr size_type
2383 size() const noexcept
2384 {
2385 __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(),
2386 __gnu_cxx::__int_traits<size_t>
2387 ::__max));
2388 return size_type(__mdspan::__size(extents()));
2389 }
2390
2391 [[nodiscard]]
2392 constexpr bool
2393 empty() const noexcept
2394 { return __mdspan::__empty(extents()); }
2395
2396 friend constexpr void
2397 swap(mdspan& __x, mdspan& __y) noexcept
2398 {
2399 using std::swap;
2400 swap(__x._M_mapping, __y._M_mapping);
2401 swap(__x._M_accessor, __y._M_accessor);
2402 swap(__x._M_handle, __y._M_handle);
2403 }
2404
2405 constexpr const extents_type&
2406 extents() const noexcept { return _M_mapping.extents(); }
2407
2408 constexpr const data_handle_type&
2409 data_handle() const noexcept { return _M_handle; }
2410
2411 constexpr const mapping_type&
2412 mapping() const noexcept { return _M_mapping; }
2413
2414 constexpr const accessor_type&
2415 accessor() const noexcept { return _M_accessor; }
2416
2417 // Strengthened noexcept for all `is_*` methods.
2418
2419 static constexpr bool
2420 is_always_unique() noexcept(noexcept(mapping_type::is_always_unique()))
2421 { return mapping_type::is_always_unique(); }
2422
2423 static constexpr bool
2424 is_always_exhaustive()
2425 noexcept(noexcept(mapping_type::is_always_exhaustive()))
2426 { return mapping_type::is_always_exhaustive(); }
2427
2428 static constexpr bool
2429 is_always_strided()
2430 noexcept(noexcept(mapping_type::is_always_strided()))
2431 { return mapping_type::is_always_strided(); }
2432
2433 constexpr bool
2434 is_unique() const noexcept(noexcept(_M_mapping.is_unique()))
2435 { return _M_mapping.is_unique(); }
2436
2437 constexpr bool
2438 is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive()))
2439 { return _M_mapping.is_exhaustive(); }
2440
2441 constexpr bool
2442 is_strided() const noexcept(noexcept(_M_mapping.is_strided()))
2443 { return _M_mapping.is_strided(); }
2444
2445 constexpr index_type
2446 stride(rank_type __r) const { return _M_mapping.stride(__r); }
2447
2448 private:
2449 [[no_unique_address]] accessor_type _M_accessor = accessor_type();
2450 [[no_unique_address]] mapping_type _M_mapping = mapping_type();
2451 [[no_unique_address]] data_handle_type _M_handle = data_handle_type();
2452 };
2453
2454 template<typename _CArray>
2455 requires is_array_v<_CArray> && (rank_v<_CArray> == 1)
2456 mdspan(_CArray&)
2457 -> mdspan<remove_all_extents_t<_CArray>,
2458 extents<size_t, extent_v<_CArray, 0>>>;
2459
2460 template<typename _Pointer>
2461 requires is_pointer_v<remove_reference_t<_Pointer>>
2462 mdspan(_Pointer&&)
2463 -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>;
2464
2465 template<typename _ElementType, typename... _Integrals>
2466 requires (is_convertible_v<_Integrals, size_t> && ...)
2467 && (sizeof...(_Integrals) > 0)
2468 explicit mdspan(_ElementType*, _Integrals...)
2469 -> mdspan<_ElementType,
2470 extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>;
2471
2472 template<typename _ElementType, typename _OIndexType, size_t _Nm>
2473 mdspan(_ElementType*, span<_OIndexType, _Nm>)
2474 -> mdspan<_ElementType, dextents<size_t, _Nm>>;
2475
2476 template<typename _ElementType, typename _OIndexType, size_t _Nm>
2477 mdspan(_ElementType*, const array<_OIndexType, _Nm>&)
2478 -> mdspan<_ElementType, dextents<size_t, _Nm>>;
2479
2480 template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack>
2481 mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&)
2482 -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>;
2483
2484 template<typename _ElementType, typename _MappingType>
2485 mdspan(_ElementType*, const _MappingType&)
2486 -> mdspan<_ElementType, typename _MappingType::extents_type,
2487 typename _MappingType::layout_type>;
2488
2489 template<typename _MappingType, typename _AccessorType>
2490 mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&,
2491 const _AccessorType&)
2492 -> mdspan<typename _AccessorType::element_type,
2493 typename _MappingType::extents_type,
2494 typename _MappingType::layout_type, _AccessorType>;
2495
2496_GLIBCXX_END_NAMESPACE_VERSION
2497}
2498#endif
2499#endif