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