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