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