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