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