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#if __cplusplus > 202302L
42#include <bits/align.h>
43#endif
44
45#define __glibcxx_want_mdspan
46#define __glibcxx_want_aligned_accessor
47#include <bits/version.h>
48
49#ifdef __glibcxx_mdspan
50
51namespace std _GLIBCXX_VISIBILITY(default)
52{
53_GLIBCXX_BEGIN_NAMESPACE_VERSION
54 namespace __mdspan
55 {
56 consteval bool
57 __all_static(std::span<const size_t> __extents)
58 {
59 for(auto __ext : __extents)
60 if (__ext == dynamic_extent)
61 return false;
62 return true;
63 }
64
65 consteval bool
66 __all_dynamic(std::span<const size_t> __extents)
67 {
68 for(auto __ext : __extents)
69 if (__ext != dynamic_extent)
70 return false;
71 return true;
72 }
73
74 template<array _Extents>
75 class _StaticExtents
76 {
77 public:
78 static constexpr size_t _S_rank = _Extents.size();
79
80 // For __r in [0, _S_rank], _S_dynamic_index(__r) is the number
81 // of dynamic extents up to (and not including) __r.
82 //
83 // If __r is the index of a dynamic extent, then
84 // _S_dynamic_index[__r] is the index of that extent in
85 // _M_dyn_exts.
86 static constexpr size_t
87 _S_dynamic_index(size_t __r) noexcept
88 { return _S_dynamic_index_data[__r]; }
89
90 static constexpr auto _S_dynamic_index_data = [] consteval
91 {
92 array<size_t, _S_rank+1> __ret;
93 size_t __dyn = 0;
94 for (size_t __i = 0; __i < _S_rank; ++__i)
95 {
96 __ret[__i] = __dyn;
97 __dyn += (_Extents[__i] == dynamic_extent);
98 }
99 __ret[_S_rank] = __dyn;
100 return __ret;
101 }();
102
103 static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank);
104
105 // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv(__r) is the
106 // index of the __r-th dynamic extent in _Extents.
107 static constexpr size_t
108 _S_dynamic_index_inv(size_t __r) noexcept
109 { return _S_dynamic_index_inv_data[__r]; }
110
111 static constexpr auto _S_dynamic_index_inv_data = [] consteval
112 {
113 array<size_t, _S_rank_dynamic> __ret;
114 for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i)
115 if (_Extents[__i] == dynamic_extent)
116 __ret[__r++] = __i;
117 return __ret;
118 }();
119
120 static constexpr size_t
121 _S_static_extent(size_t __r) noexcept
122 { return _Extents[__r]; }
123 };
124
125 template<array _Extents>
126 requires (__all_dynamic<_Extents>())
127 class _StaticExtents<_Extents>
128 {
129 public:
130 static constexpr size_t _S_rank = _Extents.size();
131
132 static constexpr size_t
133 _S_dynamic_index(size_t __r) noexcept
134 { return __r; }
135
136 static constexpr size_t _S_rank_dynamic = _S_rank;
137
138 static constexpr size_t
139 _S_dynamic_index_inv(size_t __k) noexcept
140 { return __k; }
141
142 static constexpr size_t
143 _S_static_extent(size_t) noexcept
144 { return dynamic_extent; }
145 };
146
147 template<typename _IndexType, array _Extents>
148 class _ExtentsStorage : public _StaticExtents<_Extents>
149 {
150 private:
151 using _Base = _StaticExtents<_Extents>;
152
153 public:
154 using _Base::_S_rank;
155 using _Base::_S_rank_dynamic;
156 using _Base::_S_dynamic_index;
157 using _Base::_S_dynamic_index_inv;
158 using _Base::_S_static_extent;
159
160 static constexpr bool
161 _S_is_dynamic(size_t __r) noexcept
162 {
163 if constexpr (__all_static(_Extents))
164 return false;
165 else if constexpr (__all_dynamic(_Extents))
166 return true;
167 else
168 return _Extents[__r] == dynamic_extent;
169 }
170
171 template<typename _OIndexType>
172 static constexpr _IndexType
173 _S_int_cast(const _OIndexType& __other) noexcept
174 { return _IndexType(__other); }
175
176 constexpr _IndexType
177 _M_extent(size_t __r) const noexcept
178 {
179 if (_S_is_dynamic(__r))
180 return _M_dyn_exts[_S_dynamic_index(__r)];
181 else
182 return _S_static_extent(__r);
183 }
184
185 template<size_t _OtherRank, typename _GetOtherExtent>
186 static constexpr bool
187 _S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept
188 {
189 if constexpr (_OtherRank == _S_rank)
190 for (size_t __i = 0; __i < _S_rank; ++__i)
191 if (!_S_is_dynamic(__i)
192 && !cmp_equal(_Extents[__i], _S_int_cast(__get_extent(__i))))
193 return false;
194 return true;
195 }
196
197 template<size_t _OtherRank, typename _GetOtherExtent>
198 constexpr void
199 _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
200 {
201 __glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent));
202 for (size_t __i = 0; __i < _S_rank_dynamic; ++__i)
203 {
204 size_t __di = __i;
205 if constexpr (_OtherRank != _S_rank_dynamic)
206 __di = _S_dynamic_index_inv(__i);
207 _M_dyn_exts[__i] = _S_int_cast(__get_extent(__di));
208 }
209 }
210
211 constexpr
212 _ExtentsStorage() noexcept = default;
213
214 template<typename _OIndexType, array _OExtents>
215 constexpr
216 _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>&
217 __other) noexcept
218 {
219 _M_init_dynamic_extents<_S_rank>([&__other](size_t __i)
220 { return __other._M_extent(__i); });
221 }
222
223 template<typename _OIndexType, size_t _Nm>
224 constexpr
225 _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept
226 {
227 _M_init_dynamic_extents<_Nm>(
228 [&__exts](size_t __i) -> const _OIndexType&
229 { return __exts[__i]; });
230 }
231
232 static constexpr const array<size_t, _S_rank>&
233 _S_static_extents() noexcept
234 { return _Extents; }
235
236 constexpr span<const _IndexType>
237 _M_dynamic_extents(size_t __begin, size_t __end) const noexcept
238 requires (_Extents.size() > 0)
239 {
240 return {_M_dyn_exts + _S_dynamic_index(__begin),
241 _M_dyn_exts + _S_dynamic_index(__end)};
242 }
243
244 private:
245 using _Storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
246 [[no_unique_address]] _Storage _M_dyn_exts{};
247 };
248
249 template<typename _OIndexType, typename _SIndexType>
250 concept __valid_index_type =
251 is_convertible_v<_OIndexType, _SIndexType> &&
252 is_nothrow_constructible_v<_SIndexType, _OIndexType>;
253
254 template<size_t _Extent, typename _IndexType>
255 concept
256 __valid_static_extent = _Extent == dynamic_extent
257 || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max;
258
259 template<typename _Extents>
260 constexpr const array<size_t, _Extents::rank()>&
261 __static_extents() noexcept
262 { return _Extents::_Storage::_S_static_extents(); }
263
264 // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive)
265 template<array _Extents>
266 constexpr auto __fwd_partial_prods = [] consteval
267 {
268 constexpr size_t __rank = _Extents.size();
269 std::array<size_t, __rank> __ret;
270 size_t __prod = 1;
271 for (size_t __r = 0; __r < __rank; ++__r)
272 {
273 __ret[__r] = __prod;
274 if (size_t __ext = _Extents[__r]; __ext != dynamic_extent)
275 __prod *= __ext;
276 }
277 return __ret;
278 }();
279
280 // Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i]
281 template<array _Extents>
282 constexpr auto __rev_partial_prods = [] consteval
283 {
284 constexpr size_t __rank = _Extents.size();
285 std::array<size_t, __rank> __ret;
286 size_t __prod = 1;
287 for (size_t __r = __rank; __r > 0; --__r)
288 {
289 __ret[__r - 1] = __prod;
290 if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent)
291 __prod *= __ext;
292 }
293 return __ret;
294 }();
295
296 template<typename _Extents>
297 constexpr span<const typename _Extents::index_type>
298 __dynamic_extents(const _Extents& __exts, size_t __begin = 0,
299 size_t __end = _Extents::rank()) noexcept
300 { return __exts._M_exts._M_dynamic_extents(__begin, __end); }
301 }
302
303 template<typename _IndexType, size_t... _Extents>
304 class extents
305 {
306 static_assert(__is_standard_integer<_IndexType>::value,
307 "IndexType must be a signed or unsigned integer type");
308 static_assert(
309 (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
310 "Extents must either be dynamic or representable as IndexType");
311 public:
312 using index_type = _IndexType;
313 using size_type = make_unsigned_t<index_type>;
314 using rank_type = size_t;
315
316 static constexpr rank_type
317 rank() noexcept { return _Storage::_S_rank; }
318
319 static constexpr rank_type
320 rank_dynamic() noexcept { return _Storage::_S_rank_dynamic; }
321
322 static constexpr size_t
323 static_extent(rank_type __r) noexcept
324 {
325 __glibcxx_assert(__r < rank());
326 if constexpr (rank() == 0)
327 __builtin_trap();
328 else
329 return _Storage::_S_static_extent(__r);
330 }
331
332 constexpr index_type
333 extent(rank_type __r) const noexcept
334 {
335 __glibcxx_assert(__r < rank());
336 if constexpr (rank() == 0)
337 __builtin_trap();
338 else
339 return _M_exts._M_extent(__r);
340 }
341
342 constexpr
343 extents() noexcept = default;
344
345 private:
346 static consteval bool
347 _S_is_less_dynamic(size_t __ext, size_t __oext)
348 { return (__ext != dynamic_extent) && (__oext == dynamic_extent); }
349
350 template<typename _OIndexType, size_t... _OExtents>
351 static consteval bool
352 _S_ctor_explicit()
353 {
354 return (_S_is_less_dynamic(_Extents, _OExtents) || ...)
355 || (__gnu_cxx::__int_traits<index_type>::__max
356 < __gnu_cxx::__int_traits<_OIndexType>::__max);
357 }
358
359 template<size_t... _OExtents>
360 static consteval bool
361 _S_is_compatible_extents()
362 {
363 if constexpr (sizeof...(_OExtents) != rank())
364 return false;
365 else
366 return ((_OExtents == dynamic_extent || _Extents == dynamic_extent
367 || _OExtents == _Extents) && ...);
368 }
369
370 public:
371 template<typename _OIndexType, size_t... _OExtents>
372 requires (_S_is_compatible_extents<_OExtents...>())
373 constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>())
374 extents(const extents<_OIndexType, _OExtents...>& __other) noexcept
375 : _M_exts(__other._M_exts)
376 { }
377
378 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
379 requires (sizeof...(_OIndexTypes) == rank()
380 || sizeof...(_OIndexTypes) == rank_dynamic())
381 constexpr explicit extents(_OIndexTypes... __exts) noexcept
382 : _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>(
383 initializer_list{static_cast<_IndexType>(std::move(__exts))...}))
384 { }
385
386 template<typename _OIndexType, size_t _Nm>
387 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
388 && (_Nm == rank() || _Nm == rank_dynamic())
389 constexpr explicit(_Nm != rank_dynamic())
390 extents(span<_OIndexType, _Nm> __exts) noexcept
391 : _M_exts(span<const _OIndexType, _Nm>(__exts))
392 { }
393
394 template<typename _OIndexType, size_t _Nm>
395 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
396 && (_Nm == rank() || _Nm == rank_dynamic())
397 constexpr explicit(_Nm != rank_dynamic())
398 extents(const array<_OIndexType, _Nm>& __exts) noexcept
399 : _M_exts(span<const _OIndexType, _Nm>(__exts))
400 { }
401
402 template<typename _OIndexType, size_t... _OExtents>
403 friend constexpr bool
404 operator==(const extents& __self,
405 const extents<_OIndexType, _OExtents...>& __other) noexcept
406 {
407 if constexpr (!_S_is_compatible_extents<_OExtents...>())
408 return false;
409 else
410 {
411 auto __impl = [&__self, &__other]<size_t... _Counts>(
412 index_sequence<_Counts...>)
413 { return (cmp_equal(__self.extent(_Counts),
414 __other.extent(_Counts)) && ...); };
415 return __impl(make_index_sequence<__self.rank()>());
416 }
417 }
418
419 private:
420 friend const array<size_t, rank()>&
421 __mdspan::__static_extents<extents>();
422
423 friend span<const index_type>
424 __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t);
425
426 using _Storage = __mdspan::_ExtentsStorage<
427 _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
428 [[no_unique_address]] _Storage _M_exts;
429
430 template<typename _OIndexType, size_t... _OExtents>
431 friend class extents;
432 };
433
434 namespace __mdspan
435 {
436 template<typename _Tp, size_t _Nm>
437 constexpr bool
438 __contains_zero(span<_Tp, _Nm> __exts) noexcept
439 {
440 for (size_t __i = 0; __i < __exts.size(); ++__i)
441 if (__exts[__i] == 0)
442 return true;
443 return false;
444 }
445
446 template<typename _Tp, size_t _Nm>
447 consteval bool
448 __contains_zero(const array<_Tp, _Nm>& __exts) noexcept
449 { return __contains_zero(span<const _Tp>(__exts)); }
450
451 template<typename _Extents>
452 constexpr bool
453 __empty(const _Extents& __exts) noexcept
454 {
455 if constexpr (__contains_zero(__static_extents<_Extents>()))
456 return true;
457 else if constexpr (_Extents::rank_dynamic() > 0)
458 return __contains_zero(__dynamic_extents(__exts));
459 else
460 return false;
461 }
462
463 template<typename _Extents>
464 constexpr typename _Extents::index_type
465 __extents_prod(const _Extents& __exts, size_t __sta_prod, size_t __begin,
466 size_t __end) noexcept
467 {
468 if (__sta_prod == 0)
469 return 0;
470
471 size_t __ret = __sta_prod;
472 if constexpr (_Extents::rank_dynamic() > 0)
473 for (auto __factor : __dynamic_extents(__exts, __begin, __end))
474 __ret *= size_t(__factor);
475 return static_cast<typename _Extents::index_type>(__ret);
476 }
477
478 // Preconditions: _r < _Extents::rank()
479 template<typename _Extents>
480 constexpr typename _Extents::index_type
481 __fwd_prod(const _Extents& __exts, size_t __r) noexcept
482 {
483 constexpr size_t __rank = _Extents::rank();
484 constexpr auto& __sta_exts = __static_extents<_Extents>();
485 if constexpr (__rank == 1)
486 return 1;
487 else if constexpr (__rank == 2)
488 return __r == 0 ? 1 : __exts.extent(0);
489 else if constexpr (__all_dynamic(std::span(__sta_exts).first(__rank-1)))
490 return __extents_prod(__exts, 1, 0, __r);
491 else
492 {
493 size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r];
494 return __extents_prod(__exts, __sta_prod, 0, __r);
495 }
496 }
497
498 // Preconditions: _r < _Extents::rank()
499 template<typename _Extents>
500 constexpr typename _Extents::index_type
501 __rev_prod(const _Extents& __exts, size_t __r) noexcept
502 {
503 constexpr size_t __rank = _Extents::rank();
504 constexpr auto& __sta_exts = __static_extents<_Extents>();
505 if constexpr (__rank == 1)
506 return 1;
507 else if constexpr (__rank == 2)
508 return __r == 0 ? __exts.extent(1) : 1;
509 else if constexpr (__all_dynamic(std::span(__sta_exts).last(__rank-1)))
510 return __extents_prod(__exts, 1, __r + 1, __rank);
511 else
512 {
513 size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r];
514 return __extents_prod(__exts, __sta_prod, __r + 1, __rank);
515 }
516 }
517
518 template<typename _Extents>
519 constexpr typename _Extents::index_type
520 __size(const _Extents& __exts) noexcept
521 {
522 constexpr size_t __sta_prod = [] {
523 span<const size_t> __sta_exts = __static_extents<_Extents>();
524 size_t __ret = 1;
525 for(auto __ext : __sta_exts)
526 if (__ext != dynamic_extent)
527 __ret *= __ext;
528 return __ret;
529 }();
530 return __extents_prod(__exts, __sta_prod, 0, _Extents::rank());
531 }
532
533 template<typename _IndexType, size_t... _Counts>
534 auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
535 -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
536 }
537
538 template<typename _IndexType, size_t _Rank>
539 using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
540 make_index_sequence<_Rank>()));
541
542#if __glibcxx_mdspan >= 202406L
543 template<size_t _Rank, typename _IndexType = size_t>
544 using dims = dextents<_IndexType, _Rank>;
545#endif
546
547 template<typename... _Integrals>
548 requires (is_convertible_v<_Integrals, size_t> && ...)
549 explicit extents(_Integrals...) ->
550 extents<size_t, __detail::__maybe_static_ext<_Integrals>...>;
551
552 struct layout_left
553 {
554 template<typename _Extents>
555 class mapping;
556 };
557
558 struct layout_right
559 {
560 template<typename _Extents>
561 class mapping;
562 };
563
564 struct layout_stride
565 {
566 template<typename _Extents>
567 class mapping;
568 };
569
570 namespace __mdspan
571 {
572 template<typename _Tp>
573 constexpr bool __is_extents = false;
574
575 template<typename _IndexType, size_t... _Extents>
576 constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true;
577
578 template<typename _Extents, typename... _Indices>
579 constexpr typename _Extents::index_type
580 __linear_index_left(const _Extents& __exts, _Indices... __indices)
581 noexcept
582 {
583 using _IndexType = typename _Extents::index_type;
584 _IndexType __res = 0;
585 if constexpr (sizeof...(__indices) > 0)
586 {
587 _IndexType __mult = 1;
588 auto __update = [&, __pos = 0u](_IndexType __idx) mutable
589 {
590 _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos)));
591 __res += __idx * __mult;
592 __mult *= __exts.extent(__pos);
593 ++__pos;
594 };
595 (__update(__indices), ...);
596 }
597 return __res;
598 }
599
600 template<typename _IndexType>
601 consteval _IndexType
602 __static_quotient(std::span<const size_t> __sta_exts,
603 _IndexType __nom = __gnu_cxx::__int_traits<_IndexType>::__max)
604 {
605 for (auto __factor : __sta_exts)
606 {
607 if (__factor != dynamic_extent)
608 __nom /= _IndexType(__factor);
609 if (__nom == 0)
610 break;
611 }
612 return __nom;
613 }
614
615 template<typename _Extents,
616 typename _IndexType = typename _Extents::index_type>
617 requires __is_extents<_Extents>
618 consteval _IndexType
619 __static_quotient(_IndexType __nom
620 = __gnu_cxx::__int_traits<_IndexType>::__max)
621 {
622 std::span<const size_t> __sta_exts = __static_extents<_Extents>();
623 return __static_quotient<_IndexType>(__sta_exts, __nom);
624 }
625
626 template<typename _Extents>
627 constexpr bool
628 __is_representable_extents(const _Extents& __exts) noexcept
629 {
630 using _IndexType = _Extents::index_type;
631
632 if constexpr (__contains_zero(__static_extents<_Extents>()))
633 return true;
634 else
635 {
636 constexpr auto __sta_quo = __static_quotient<_Extents>();
637 if constexpr (_Extents::rank_dynamic() == 0)
638 return __sta_quo != 0;
639 else
640 {
641 auto __dyn_exts = __dynamic_extents(__exts);
642 if (__contains_zero(__dyn_exts))
643 return true;
644
645 if constexpr (__sta_quo == 0)
646 return false;
647 else
648 {
649 auto __dyn_quo = _IndexType(__sta_quo);
650 for (auto __factor : __dyn_exts)
651 {
652 __dyn_quo /= __factor;
653 if (__dyn_quo == 0)
654 return false;
655 }
656 return true;
657 }
658 }
659 }
660 }
661
662 template<typename _Extents, typename _IndexType>
663 concept __representable_size = _Extents::rank_dynamic() != 0
664 || __contains_zero(__static_extents<_Extents>())
665 || (__static_quotient<_Extents, _IndexType>() != 0);
666
667 template<typename _Layout, typename _Mapping>
668 concept __mapping_of =
669 is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>,
670 _Mapping>;
671
672 template<typename _Mapping>
673 concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
674 || __mapping_of<layout_right, _Mapping>
675 || __mapping_of<layout_stride, _Mapping>;
676
677 // A tag type to create internal ctors.
678 class __internal_ctor
679 { };
680 }
681
682 template<typename _Extents>
683 class layout_left::mapping
684 {
685 public:
686 using extents_type = _Extents;
687 using index_type = typename extents_type::index_type;
688 using size_type = typename extents_type::size_type;
689 using rank_type = typename extents_type::rank_type;
690 using layout_type = layout_left;
691
692 static_assert(__mdspan::__representable_size<extents_type, index_type>,
693 "The size of extents_type must be representable as index_type");
694
695 constexpr
696 mapping() noexcept = default;
697
698 constexpr
699 mapping(const mapping&) noexcept = default;
700
701 constexpr
702 mapping(const extents_type& __extents) noexcept
703 : _M_extents(__extents)
704 { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
705
706 template<typename _OExtents>
707 requires is_constructible_v<extents_type, _OExtents>
708 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
709 mapping(const mapping<_OExtents>& __other) noexcept
710 : mapping(__other.extents(), __mdspan::__internal_ctor{})
711 { }
712
713 template<typename _OExtents>
714 requires (extents_type::rank() <= 1)
715 && is_constructible_v<extents_type, _OExtents>
716 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
717 mapping(const layout_right::mapping<_OExtents>& __other) noexcept
718 : mapping(__other.extents(), __mdspan::__internal_ctor{})
719 { }
720
721 // noexcept for consistency with other layouts.
722 template<typename _OExtents>
723 requires is_constructible_v<extents_type, _OExtents>
724 constexpr explicit(extents_type::rank() > 0)
725 mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
726 : mapping(__other.extents(), __mdspan::__internal_ctor{})
727 { __glibcxx_assert(*this == __other); }
728
729 constexpr mapping&
730 operator=(const mapping&) noexcept = default;
731
732 constexpr const extents_type&
733 extents() const noexcept { return _M_extents; }
734
735 constexpr index_type
736 required_span_size() const noexcept
737 { return __mdspan::__size(_M_extents); }
738
739 // _GLIBCXX_RESOLVE_LIB_DEFECTS
740 // 4314. Missing move in mdspan layout mapping::operator()
741 template<__mdspan::__valid_index_type<index_type>... _Indices>
742 requires (sizeof...(_Indices) == extents_type::rank())
743 constexpr index_type
744 operator()(_Indices... __indices) const noexcept
745 {
746 return __mdspan::__linear_index_left(_M_extents,
747 static_cast<index_type>(std::move(__indices))...);
748 }
749
750 static constexpr bool
751 is_always_unique() noexcept { return true; }
752
753 static constexpr bool
754 is_always_exhaustive() noexcept { return true; }
755
756 static constexpr bool
757 is_always_strided() noexcept { return true; }
758
759 static constexpr bool
760 is_unique() noexcept { return true; }
761
762 static constexpr bool
763 is_exhaustive() noexcept { return true; }
764
765 static constexpr bool
766 is_strided() noexcept { return true; }
767
768 constexpr index_type
769 stride(rank_type __i) const noexcept
770 requires (extents_type::rank() > 0)
771 {
772 __glibcxx_assert(__i < extents_type::rank());
773 return __mdspan::__fwd_prod(_M_extents, __i);
774 }
775
776 template<typename _OExtents>
777 requires (extents_type::rank() == _OExtents::rank())
778 friend constexpr bool
779 operator==(const mapping& __self, const mapping<_OExtents>& __other)
780 noexcept
781 { return __self.extents() == __other.extents(); }
782
783 private:
784 template<typename _OExtents>
785 constexpr explicit
786 mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
787 : _M_extents(__oexts)
788 {
789 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
790 "The size of OtherExtents must be representable as index_type");
791 __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
792 }
793
794 [[no_unique_address]] extents_type _M_extents{};
795 };
796
797 namespace __mdspan
798 {
799 template<typename _Extents, typename... _Indices>
800 constexpr typename _Extents::index_type
801 __linear_index_right(const _Extents& __exts, _Indices... __indices)
802 noexcept
803 {
804 using _IndexType = typename _Extents::index_type;
805 array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
806 _IndexType __res = 0;
807 if constexpr (sizeof...(__indices) > 0)
808 {
809 _IndexType __mult = 1;
810 auto __update = [&, __pos = __exts.rank()](_IndexType) mutable
811 {
812 --__pos;
813 _GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos],
814 __exts.extent(__pos)));
815 __res += __ind_arr[__pos] * __mult;
816 __mult *= __exts.extent(__pos);
817 };
818 (__update(__indices), ...);
819 }
820 return __res;
821 }
822 }
823
824 template<typename _Extents>
825 class layout_right::mapping
826 {
827 public:
828 using extents_type = _Extents;
829 using index_type = typename extents_type::index_type;
830 using size_type = typename extents_type::size_type;
831 using rank_type = typename extents_type::rank_type;
832 using layout_type = layout_right;
833
834 static_assert(__mdspan::__representable_size<extents_type, index_type>,
835 "The size of extents_type must be representable as index_type");
836
837 constexpr
838 mapping() noexcept = default;
839
840 constexpr
841 mapping(const mapping&) noexcept = default;
842
843 constexpr
844 mapping(const extents_type& __extents) noexcept
845 : _M_extents(__extents)
846 { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
847
848 template<typename _OExtents>
849 requires is_constructible_v<extents_type, _OExtents>
850 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
851 mapping(const mapping<_OExtents>& __other) noexcept
852 : mapping(__other.extents(), __mdspan::__internal_ctor{})
853 { }
854
855 template<typename _OExtents>
856 requires (extents_type::rank() <= 1)
857 && is_constructible_v<extents_type, _OExtents>
858 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
859 mapping(const layout_left::mapping<_OExtents>& __other) noexcept
860 : mapping(__other.extents(), __mdspan::__internal_ctor{})
861 { }
862
863 template<typename _OExtents>
864 requires is_constructible_v<extents_type, _OExtents>
865 constexpr explicit(extents_type::rank() > 0)
866 mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
867 : mapping(__other.extents(), __mdspan::__internal_ctor{})
868 { __glibcxx_assert(*this == __other); }
869
870 constexpr mapping&
871 operator=(const mapping&) noexcept = default;
872
873 constexpr const extents_type&
874 extents() const noexcept { return _M_extents; }
875
876 constexpr index_type
877 required_span_size() const noexcept
878 { return __mdspan::__size(_M_extents); }
879
880 // _GLIBCXX_RESOLVE_LIB_DEFECTS
881 // 4314. Missing move in mdspan layout mapping::operator()
882 template<__mdspan::__valid_index_type<index_type>... _Indices>
883 requires (sizeof...(_Indices) == extents_type::rank())
884 constexpr index_type
885 operator()(_Indices... __indices) const noexcept
886 {
887 return __mdspan::__linear_index_right(
888 _M_extents, static_cast<index_type>(std::move(__indices))...);
889 }
890
891 static constexpr bool
892 is_always_unique() noexcept
893 { return true; }
894
895 static constexpr bool
896 is_always_exhaustive() noexcept
897 { return true; }
898
899 static constexpr bool
900 is_always_strided() noexcept
901 { return true; }
902
903 static constexpr bool
904 is_unique() noexcept
905 { return true; }
906
907 static constexpr bool
908 is_exhaustive() noexcept
909 { return true; }
910
911 static constexpr bool
912 is_strided() noexcept
913 { return true; }
914
915 constexpr index_type
916 stride(rank_type __i) const noexcept
917 requires (extents_type::rank() > 0)
918 {
919 __glibcxx_assert(__i < extents_type::rank());
920 return __mdspan::__rev_prod(_M_extents, __i);
921 }
922
923 template<typename _OExtents>
924 requires (extents_type::rank() == _OExtents::rank())
925 friend constexpr bool
926 operator==(const mapping& __self, const mapping<_OExtents>& __other)
927 noexcept
928 { return __self.extents() == __other.extents(); }
929
930 private:
931 template<typename _OExtents>
932 constexpr explicit
933 mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
934 : _M_extents(__oexts)
935 {
936 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
937 "The size of OtherExtents must be representable as index_type");
938 __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
939 }
940
941 [[no_unique_address]] extents_type _M_extents{};
942 };
943
944 namespace __mdspan
945 {
946 template<typename _Mp>
947 concept __mapping_alike = requires
948 {
949 requires __is_extents<typename _Mp::extents_type>;
950 { _Mp::is_always_strided() } -> same_as<bool>;
951 { _Mp::is_always_exhaustive() } -> same_as<bool>;
952 { _Mp::is_always_unique() } -> same_as<bool>;
953 bool_constant<_Mp::is_always_strided()>::value;
954 bool_constant<_Mp::is_always_exhaustive()>::value;
955 bool_constant<_Mp::is_always_unique()>::value;
956 };
957
958 template<typename _Mapping>
959 constexpr typename _Mapping::index_type
960 __offset(const _Mapping& __m) noexcept
961 {
962 using _IndexType = typename _Mapping::index_type;
963 constexpr auto __rank = _Mapping::extents_type::rank();
964
965 if constexpr (__standardized_mapping<_Mapping>)
966 return 0;
967 else if (__empty(__m.extents()))
968 return 0;
969 else
970 {
971 auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>)
972 { return __m(((void) _Counts, _IndexType(0))...); };
973 return __impl(make_index_sequence<__rank>());
974 }
975 }
976
977 template<typename _Mapping, typename... _Indices>
978 constexpr typename _Mapping::index_type
979 __linear_index_strides(const _Mapping& __m, _Indices... __indices)
980 noexcept
981 {
982 using _IndexType = typename _Mapping::index_type;
983 _IndexType __res = 0;
984 if constexpr (sizeof...(__indices) > 0)
985 {
986 auto __update = [&, __pos = 0u](_IndexType __idx) mutable
987 {
988 _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx,
989 __m.extents().extent(__pos)));
990 __res += __idx * __m.stride(__pos++);
991 };
992 (__update(__indices), ...);
993 }
994 return __res;
995 }
996 }
997
998 template<typename _Extents>
999 class layout_stride::mapping
1000 {
1001 public:
1002 using extents_type = _Extents;
1003 using index_type = typename extents_type::index_type;
1004 using size_type = typename extents_type::size_type;
1005 using rank_type = typename extents_type::rank_type;
1006 using layout_type = layout_stride;
1007
1008 static_assert(__mdspan::__representable_size<extents_type, index_type>,
1009 "The size of extents_type must be representable as index_type");
1010
1011 constexpr
1012 mapping() noexcept
1013 {
1014 // The precondition is either statically asserted, or automatically
1015 // satisfied because dynamic extents are zero-initialized.
1016 size_t __stride = 1;
1017 for (size_t __i = extents_type::rank(); __i > 0; --__i)
1018 {
1019 _M_strides[__i - 1] = index_type(__stride);
1020 __stride *= size_t(_M_extents.extent(__i - 1));
1021 }
1022 }
1023
1024 constexpr
1025 mapping(const mapping&) noexcept = default;
1026
1027 template<typename _OIndexType>
1028 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1029 constexpr
1030 mapping(const extents_type& __exts,
1031 span<_OIndexType, extents_type::rank()> __strides) noexcept
1032 : _M_extents(__exts)
1033 {
1034 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1035 _M_strides[__i] = index_type(as_const(__strides[__i]));
1036 }
1037
1038 template<typename _OIndexType>
1039 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1040 constexpr
1041 mapping(const extents_type& __exts,
1042 const array<_OIndexType, extents_type::rank()>& __strides)
1043 noexcept
1044 : mapping(__exts,
1045 span<const _OIndexType, extents_type::rank()>(__strides))
1046 { }
1047
1048 template<__mdspan::__mapping_alike _StridedMapping>
1049 requires (is_constructible_v<extents_type,
1050 typename _StridedMapping::extents_type>
1051 && _StridedMapping::is_always_unique()
1052 && _StridedMapping::is_always_strided())
1053 constexpr explicit(!(
1054 is_convertible_v<typename _StridedMapping::extents_type, extents_type>
1055 && __mdspan::__standardized_mapping<_StridedMapping>))
1056 mapping(const _StridedMapping& __other) noexcept
1057 : _M_extents(__other.extents())
1058 {
1059 using _OIndexType = _StridedMapping::index_type;
1060 using _OExtents = _StridedMapping::extents_type;
1061
1062 __glibcxx_assert(__mdspan::__offset(__other) == 0);
1063 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
1064 "The size of StridedMapping::extents_type must be representable as"
1065 " index_type");
1066 if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max,
1067 __gnu_cxx::__int_traits<index_type>::__max))
1068 __glibcxx_assert(!cmp_less(
1069 __gnu_cxx::__int_traits<index_type>::__max,
1070 __other.required_span_size())
1071 && "other.required_span_size() must be representable"
1072 " as index_type");
1073 if constexpr (extents_type::rank() > 0)
1074 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1075 _M_strides[__i] = index_type(__other.stride(__i));
1076 }
1077
1078 constexpr mapping&
1079 operator=(const mapping&) noexcept = default;
1080
1081 constexpr const extents_type&
1082 extents() const noexcept { return _M_extents; }
1083
1084 constexpr array<index_type, extents_type::rank()>
1085 strides() const noexcept
1086 {
1087 array<index_type, extents_type::rank()> __ret;
1088 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1089 __ret[__i] = _M_strides[__i];
1090 return __ret;
1091 }
1092
1093 constexpr index_type
1094 required_span_size() const noexcept
1095 {
1096 if (__mdspan::__empty(_M_extents))
1097 return 0;
1098
1099 index_type __ret = 1;
1100 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1101 __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i];
1102 return __ret;
1103 }
1104
1105 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1106 // 4314. Missing move in mdspan layout mapping::operator()
1107 template<__mdspan::__valid_index_type<index_type>... _Indices>
1108 requires (sizeof...(_Indices) == extents_type::rank())
1109 constexpr index_type
1110 operator()(_Indices... __indices) const noexcept
1111 {
1112 return __mdspan::__linear_index_strides(*this,
1113 static_cast<index_type>(std::move(__indices))...);
1114 }
1115
1116 static constexpr bool
1117 is_always_unique() noexcept { return true; }
1118
1119 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1120 // 4266. layout_stride::mapping should treat empty mappings as exhaustive
1121 static constexpr bool
1122 is_always_exhaustive() noexcept
1123 {
1124 return (_Extents::rank() == 0) || __mdspan::__contains_zero(
1125 __mdspan::__static_extents<extents_type>());
1126 }
1127
1128 static constexpr bool
1129 is_always_strided() noexcept { return true; }
1130
1131 static constexpr bool
1132 is_unique() noexcept { return true; }
1133
1134 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1135 // 4266. layout_stride::mapping should treat empty mappings as exhaustive
1136 constexpr bool
1137 is_exhaustive() const noexcept
1138 {
1139 if constexpr (!is_always_exhaustive())
1140 {
1141 auto __size = __mdspan::__size(_M_extents);
1142 if(__size > 0)
1143 return __size == required_span_size();
1144 }
1145 return true;
1146 }
1147
1148 static constexpr bool
1149 is_strided() noexcept { return true; }
1150
1151 constexpr index_type
1152 stride(rank_type __r) const noexcept { return _M_strides[__r]; }
1153
1154 template<__mdspan::__mapping_alike _OMapping>
1155 requires ((extents_type::rank() == _OMapping::extents_type::rank())
1156 && _OMapping::is_always_strided())
1157 friend constexpr bool
1158 operator==(const mapping& __self, const _OMapping& __other) noexcept
1159 {
1160 if (__self.extents() != __other.extents())
1161 return false;
1162 if constexpr (extents_type::rank() > 0)
1163 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1164 if (!cmp_equal(__self.stride(__i), __other.stride(__i)))
1165 return false;
1166 return __mdspan::__offset(__other) == 0;
1167 }
1168
1169 private:
1170 using _Strides = typename __array_traits<index_type,
1171 extents_type::rank()>::_Type;
1172 [[no_unique_address]] extents_type _M_extents;
1173 [[no_unique_address]] _Strides _M_strides;
1174 };
1175
1176 template<typename _ElementType>
1177 struct default_accessor
1178 {
1179 static_assert(!is_array_v<_ElementType>,
1180 "ElementType must not be an array type");
1181 static_assert(!is_abstract_v<_ElementType>,
1182 "ElementType must not be an abstract class type");
1183
1184 using offset_policy = default_accessor;
1185 using element_type = _ElementType;
1186 using reference = element_type&;
1187 using data_handle_type = element_type*;
1188
1189 constexpr
1190 default_accessor() noexcept = default;
1191
1192 template<typename _OElementType>
1193 requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
1194 constexpr
1195 default_accessor(default_accessor<_OElementType>) noexcept
1196 { }
1197
1198 constexpr reference
1199 access(data_handle_type __p, size_t __i) const noexcept
1200 { return __p[__i]; }
1201
1202 constexpr data_handle_type
1203 offset(data_handle_type __p, size_t __i) const noexcept
1204 { return __p + __i; }
1205 };
1206
1207#ifdef __glibcxx_aligned_accessor
1208 template<typename _ElementType, size_t _ByteAlignment>
1209 struct aligned_accessor
1210 {
1211 static_assert(has_single_bit(_ByteAlignment),
1212 "ByteAlignment must be a power of two");
1213 static_assert(_ByteAlignment >= alignof(_ElementType));
1214
1215 using offset_policy = default_accessor<_ElementType>;
1216 using element_type = _ElementType;
1217 using reference = element_type&;
1218 using data_handle_type = element_type*;
1219
1220 static constexpr size_t byte_alignment = _ByteAlignment;
1221
1222 constexpr
1223 aligned_accessor() noexcept = default;
1224
1225 template<typename _OElementType, size_t _OByteAlignment>
1226 requires (_OByteAlignment >= byte_alignment)
1227 && is_convertible_v<_OElementType(*)[], element_type(*)[]>
1228 constexpr
1229 aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>)
1230 noexcept
1231 { }
1232
1233 template<typename _OElementType>
1234 requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
1235 constexpr explicit
1236 aligned_accessor(default_accessor<_OElementType>) noexcept
1237 { }
1238
1239 template<typename _OElementType>
1240 requires is_convertible_v<element_type(*)[], _OElementType(*)[]>
1241 constexpr
1242 operator default_accessor<_OElementType>() const noexcept
1243 { return {}; }
1244
1245 constexpr reference
1246 access(data_handle_type __p, size_t __i) const noexcept
1247 { return std::assume_aligned<byte_alignment>(__p)[__i]; }
1248
1249 constexpr typename offset_policy::data_handle_type
1250 offset(data_handle_type __p, size_t __i) const noexcept
1251 { return std::assume_aligned<byte_alignment>(__p) + __i; }
1252 };
1253#endif
1254
1255 namespace __mdspan
1256 {
1257 template<typename _Extents, typename _IndexType, size_t _Nm>
1258 constexpr bool
1259 __is_multi_index(const _Extents& __exts, span<_IndexType, _Nm> __indices)
1260 {
1261 static_assert(__exts.rank() == _Nm);
1262 for (size_t __i = 0; __i < __exts.rank(); ++__i)
1263 if (__indices[__i] >= __exts.extent(__i))
1264 return false;
1265 return true;
1266 }
1267 }
1268
1269 template<typename _ElementType, typename _Extents,
1270 typename _LayoutPolicy = layout_right,
1271 typename _AccessorPolicy = default_accessor<_ElementType>>
1272 class mdspan
1273 {
1274 static_assert(!is_array_v<_ElementType>,
1275 "ElementType must not be an array type");
1276 static_assert(!is_abstract_v<_ElementType>,
1277 "ElementType must not be an abstract class type");
1278 static_assert(__mdspan::__is_extents<_Extents>,
1279 "Extents must be a specialization of std::extents");
1280 static_assert(is_same_v<_ElementType,
1281 typename _AccessorPolicy::element_type>);
1282
1283 public:
1284 using extents_type = _Extents;
1285 using layout_type = _LayoutPolicy;
1286 using accessor_type = _AccessorPolicy;
1287 using mapping_type = typename layout_type::template mapping<extents_type>;
1288 using element_type = _ElementType;
1289 using value_type = remove_cv_t<element_type>;
1290 using index_type = typename extents_type::index_type;
1291 using size_type = typename extents_type::size_type;
1292 using rank_type = typename extents_type::rank_type;
1293 using data_handle_type = typename accessor_type::data_handle_type;
1294 using reference = typename accessor_type::reference;
1295
1296 static constexpr rank_type
1297 rank() noexcept { return extents_type::rank(); }
1298
1299 static constexpr rank_type
1300 rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
1301
1302 static constexpr size_t
1303 static_extent(rank_type __r) noexcept
1304 { return extents_type::static_extent(__r); }
1305
1306 constexpr index_type
1307 extent(rank_type __r) const noexcept { return extents().extent(__r); }
1308
1309 constexpr
1310 mdspan()
1311 requires (rank_dynamic() > 0)
1312 && is_default_constructible_v<data_handle_type>
1313 && is_default_constructible_v<mapping_type>
1314 && is_default_constructible_v<accessor_type> = default;
1315
1316 constexpr
1317 mdspan(const mdspan& __other) = default;
1318
1319 constexpr
1320 mdspan(mdspan&& __other) = default;
1321
1322 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
1323 requires (sizeof...(_OIndexTypes) == rank()
1324 || sizeof...(_OIndexTypes) == rank_dynamic())
1325 && is_constructible_v<mapping_type, extents_type>
1326 && is_default_constructible_v<accessor_type>
1327 constexpr explicit
1328 mdspan(data_handle_type __handle, _OIndexTypes... __exts)
1329 : _M_accessor(),
1330 _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)),
1331 _M_handle(std::move(__handle))
1332 { }
1333
1334 template<typename _OIndexType, size_t _Nm>
1335 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1336 && (_Nm == rank() || _Nm == rank_dynamic())
1337 && is_constructible_v<mapping_type, extents_type>
1338 && is_default_constructible_v<accessor_type>
1339 constexpr explicit(_Nm != rank_dynamic())
1340 mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts)
1341 : _M_accessor(), _M_mapping(extents_type(__exts)),
1342 _M_handle(std::move(__handle))
1343 { }
1344
1345 template<typename _OIndexType, size_t _Nm>
1346 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1347 && (_Nm == rank() || _Nm == rank_dynamic())
1348 && is_constructible_v<mapping_type, extents_type>
1349 && is_default_constructible_v<accessor_type>
1350 constexpr explicit(_Nm != rank_dynamic())
1351 mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts)
1352 : _M_accessor(), _M_mapping(extents_type(__exts)),
1353 _M_handle(std::move(__handle))
1354 { }
1355
1356 constexpr
1357 mdspan(data_handle_type __handle, const extents_type& __exts)
1358 requires is_constructible_v<mapping_type, const extents_type&>
1359 && is_default_constructible_v<accessor_type>
1360 : _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle))
1361 { }
1362
1363 constexpr
1364 mdspan(data_handle_type __handle, const mapping_type& __mapping)
1365 requires is_default_constructible_v<accessor_type>
1366 : _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle))
1367 { }
1368
1369 constexpr
1370 mdspan(data_handle_type __handle, const mapping_type& __mapping,
1371 const accessor_type& __accessor)
1372 : _M_accessor(__accessor), _M_mapping(__mapping),
1373 _M_handle(std::move(__handle))
1374 { }
1375
1376 template<typename _OElementType, typename _OExtents, typename _OLayout,
1377 typename _OAccessor>
1378 requires is_constructible_v<mapping_type,
1379 const typename _OLayout::template mapping<_OExtents>&>
1380 && is_constructible_v<accessor_type, const _OAccessor&>
1381 constexpr explicit(!is_convertible_v<
1382 const typename _OLayout::template mapping<_OExtents>&, mapping_type>
1383 || !is_convertible_v<const _OAccessor&, accessor_type>)
1384 mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>&
1385 __other)
1386 : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()),
1387 _M_handle(__other.data_handle())
1388 {
1389 static_assert(is_constructible_v<data_handle_type,
1390 const typename _OAccessor::data_handle_type&>);
1391 static_assert(is_constructible_v<extents_type, _OExtents>);
1392 }
1393
1394 constexpr mdspan&
1395 operator=(const mdspan& __other) = default;
1396
1397 constexpr mdspan&
1398 operator=(mdspan&& __other) = default;
1399
1400 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
1401 requires (sizeof...(_OIndexTypes) == rank())
1402 constexpr reference
1403 operator[](_OIndexTypes... __indices) const
1404 {
1405 auto __checked_call = [this](auto... __idxs) -> index_type
1406 {
1407 if constexpr (sizeof...(__idxs) > 0)
1408 __glibcxx_assert(__mdspan::__is_multi_index(extents(),
1409 span<const index_type, sizeof...(__idxs)>({__idxs...})));
1410 return _M_mapping(__idxs...);
1411 };
1412
1413 auto __index = __checked_call(
1414 static_cast<index_type>(std::move(__indices))...);
1415 return _M_accessor.access(_M_handle, __index);
1416 }
1417
1418 template<typename _OIndexType>
1419 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1420 constexpr reference
1421 operator[](span<_OIndexType, rank()> __indices) const
1422 {
1423 auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
1424 -> reference
1425 { return (*this)[index_type(as_const(__indices[_Counts]))...]; };
1426 return __call(make_index_sequence<rank()>());
1427 }
1428
1429 template<typename _OIndexType>
1430 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1431 constexpr reference
1432 operator[](const array<_OIndexType, rank()>& __indices) const
1433 { return (*this)[span<const _OIndexType, rank()>(__indices)]; }
1434
1435 constexpr size_type
1436 size() const noexcept
1437 {
1438 __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(),
1439 __gnu_cxx::__int_traits<size_t>
1440 ::__max));
1441 return size_type(__mdspan::__size(extents()));
1442 }
1443
1444 [[nodiscard]]
1445 constexpr bool
1446 empty() const noexcept
1447 { return __mdspan::__empty(extents()); }
1448
1449 friend constexpr void
1450 swap(mdspan& __x, mdspan& __y) noexcept
1451 {
1452 using std::swap;
1453 swap(__x._M_mapping, __y._M_mapping);
1454 swap(__x._M_accessor, __y._M_accessor);
1455 swap(__x._M_handle, __y._M_handle);
1456 }
1457
1458 constexpr const extents_type&
1459 extents() const noexcept { return _M_mapping.extents(); }
1460
1461 constexpr const data_handle_type&
1462 data_handle() const noexcept { return _M_handle; }
1463
1464 constexpr const mapping_type&
1465 mapping() const noexcept { return _M_mapping; }
1466
1467 constexpr const accessor_type&
1468 accessor() const noexcept { return _M_accessor; }
1469
1470 // Strengthened noexcept for all `is_*` methods.
1471
1472 static constexpr bool
1473 is_always_unique() noexcept(noexcept(mapping_type::is_always_unique()))
1474 { return mapping_type::is_always_unique(); }
1475
1476 static constexpr bool
1477 is_always_exhaustive()
1478 noexcept(noexcept(mapping_type::is_always_exhaustive()))
1479 { return mapping_type::is_always_exhaustive(); }
1480
1481 static constexpr bool
1482 is_always_strided()
1483 noexcept(noexcept(mapping_type::is_always_strided()))
1484 { return mapping_type::is_always_strided(); }
1485
1486 constexpr bool
1487 is_unique() const noexcept(noexcept(_M_mapping.is_unique()))
1488 { return _M_mapping.is_unique(); }
1489
1490 constexpr bool
1491 is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive()))
1492 { return _M_mapping.is_exhaustive(); }
1493
1494 constexpr bool
1495 is_strided() const noexcept(noexcept(_M_mapping.is_strided()))
1496 { return _M_mapping.is_strided(); }
1497
1498 constexpr index_type
1499 stride(rank_type __r) const { return _M_mapping.stride(__r); }
1500
1501 private:
1502 [[no_unique_address]] accessor_type _M_accessor = accessor_type();
1503 [[no_unique_address]] mapping_type _M_mapping = mapping_type();
1504 [[no_unique_address]] data_handle_type _M_handle = data_handle_type();
1505 };
1506
1507 template<typename _CArray>
1508 requires is_array_v<_CArray> && (rank_v<_CArray> == 1)
1509 mdspan(_CArray&)
1510 -> mdspan<remove_all_extents_t<_CArray>,
1511 extents<size_t, extent_v<_CArray, 0>>>;
1512
1513 template<typename _Pointer>
1514 requires is_pointer_v<remove_reference_t<_Pointer>>
1515 mdspan(_Pointer&&)
1516 -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>;
1517
1518 template<typename _ElementType, typename... _Integrals>
1519 requires (is_convertible_v<_Integrals, size_t> && ...)
1520 && (sizeof...(_Integrals) > 0)
1521 explicit mdspan(_ElementType*, _Integrals...)
1522 -> mdspan<_ElementType,
1523 extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>;
1524
1525 template<typename _ElementType, typename _OIndexType, size_t _Nm>
1526 mdspan(_ElementType*, span<_OIndexType, _Nm>)
1527 -> mdspan<_ElementType, dextents<size_t, _Nm>>;
1528
1529 template<typename _ElementType, typename _OIndexType, size_t _Nm>
1530 mdspan(_ElementType*, const array<_OIndexType, _Nm>&)
1531 -> mdspan<_ElementType, dextents<size_t, _Nm>>;
1532
1533 template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack>
1534 mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&)
1535 -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>;
1536
1537 template<typename _ElementType, typename _MappingType>
1538 mdspan(_ElementType*, const _MappingType&)
1539 -> mdspan<_ElementType, typename _MappingType::extents_type,
1540 typename _MappingType::layout_type>;
1541
1542 template<typename _MappingType, typename _AccessorType>
1543 mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&,
1544 const _AccessorType&)
1545 -> mdspan<typename _AccessorType::element_type,
1546 typename _MappingType::extents_type,
1547 typename _MappingType::layout_type, _AccessorType>;
1548
1549_GLIBCXX_END_NAMESPACE_VERSION
1550}
1551#endif
1552#endif