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