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