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