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