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