libstdc++: mdspan Source File

libstdc++

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