3// Copyright The GNU Toolchain Authors.
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)
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.
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.
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/>.
26 * This is a Standard C++ Library header.
29#ifndef _GLIBCXX_MDSPAN
30#define _GLIBCXX_MDSPAN 1
33#pragma GCC system_header
41#if __cplusplus > 202302L
42#include <bits/align.h>
45#define __glibcxx_want_mdspan
46#define __glibcxx_want_aligned_accessor
47#include <bits/version.h>
49#ifdef __glibcxx_mdspan
51namespace std _GLIBCXX_VISIBILITY(default)
53_GLIBCXX_BEGIN_NAMESPACE_VERSION
57 __all_static(std::span<const size_t> __extents)
59 for(auto __ext : __extents)
60 if (__ext == dynamic_extent)
66 __all_dynamic(std::span<const size_t> __extents)
68 for(auto __ext : __extents)
69 if (__ext != dynamic_extent)
74 template<array _Extents>
78 static constexpr size_t _S_rank = _Extents.size();
80 // For __r in [0, _S_rank], _S_dynamic_index(__r) is the number
81 // of dynamic extents up to (and not including) __r.
83 // If __r is the index of a dynamic extent, then
84 // _S_dynamic_index[__r] is the index of that extent in
86 static constexpr size_t
87 _S_dynamic_index(size_t __r) noexcept
88 { return _S_dynamic_index_data[__r]; }
90 static constexpr auto _S_dynamic_index_data = [] consteval
92 array<size_t, _S_rank+1> __ret;
94 for (size_t __i = 0; __i < _S_rank; ++__i)
97 __dyn += (_Extents[__i] == dynamic_extent);
99 __ret[_S_rank] = __dyn;
103 static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank);
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]; }
111 static constexpr auto _S_dynamic_index_inv_data = [] consteval
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)
120 static constexpr size_t
121 _S_static_extent(size_t __r) noexcept
122 { return _Extents[__r]; }
125 template<array _Extents>
126 requires (__all_dynamic<_Extents>())
127 class _StaticExtents<_Extents>
130 static constexpr size_t _S_rank = _Extents.size();
132 static constexpr size_t
133 _S_dynamic_index(size_t __r) noexcept
136 static constexpr size_t _S_rank_dynamic = _S_rank;
138 static constexpr size_t
139 _S_dynamic_index_inv(size_t __k) noexcept
142 static constexpr size_t
143 _S_static_extent(size_t) noexcept
144 { return dynamic_extent; }
147 template<typename _IndexType, array _Extents>
148 class _ExtentsStorage : public _StaticExtents<_Extents>
151 using _S_base = _StaticExtents<_Extents>;
154 using _S_base::_S_rank;
155 using _S_base::_S_rank_dynamic;
156 using _S_base::_S_dynamic_index;
157 using _S_base::_S_dynamic_index_inv;
158 using _S_base::_S_static_extent;
160 static constexpr bool
161 _S_is_dynamic(size_t __r) noexcept
163 if constexpr (__all_static(_Extents))
165 else if constexpr (__all_dynamic(_Extents))
168 return _Extents[__r] == dynamic_extent;
171 template<typename _OIndexType>
172 static constexpr _IndexType
173 _S_int_cast(const _OIndexType& __other) noexcept
174 { return _IndexType(__other); }
177 _M_extent(size_t __r) const noexcept
179 if (_S_is_dynamic(__r))
180 return _M_dyn_exts[_S_dynamic_index(__r)];
182 return _S_static_extent(__r);
185 template<size_t _OtherRank, typename _GetOtherExtent>
186 static constexpr bool
187 _S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept
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))))
197 template<size_t _OtherRank, typename _GetOtherExtent>
199 _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept
201 __glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent));
202 for (size_t __i = 0; __i < _S_rank_dynamic; ++__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));
212 _ExtentsStorage() noexcept = default;
214 template<typename _OIndexType, array _OExtents>
216 _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>&
219 _M_init_dynamic_extents<_S_rank>([&__other](size_t __i)
220 { return __other._M_extent(__i); });
223 template<typename _OIndexType, size_t _Nm>
225 _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept
227 _M_init_dynamic_extents<_Nm>(
228 [&__exts](size_t __i) -> const _OIndexType&
229 { return __exts[__i]; });
232 static constexpr const array<size_t, _S_rank>&
233 _S_static_extents() noexcept
236 constexpr span<const _IndexType>
237 _M_dynamic_extents(size_t __begin, size_t __end) const noexcept
238 requires (_Extents.size() > 0)
240 return {_M_dyn_exts + _S_dynamic_index(__begin),
241 _M_dyn_exts + _S_dynamic_index(__end)};
245 using _S_storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type;
246 [[no_unique_address]] _S_storage _M_dyn_exts{};
249 template<typename _OIndexType, typename _SIndexType>
250 concept __valid_index_type =
251 is_convertible_v<_OIndexType, _SIndexType> &&
252 is_nothrow_constructible_v<_SIndexType, _OIndexType>;
254 template<size_t _Extent, typename _IndexType>
256 __valid_static_extent = _Extent == dynamic_extent
257 || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max;
259 template<typename _Extents>
260 constexpr const array<size_t, _Extents::rank()>&
261 __static_extents() noexcept
262 { return _Extents::_S_storage::_S_static_extents(); }
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
268 constexpr size_t __rank = _Extents.size();
269 std::array<size_t, __rank> __ret;
271 for (size_t __r = 0; __r < __rank; ++__r)
274 if (size_t __ext = _Extents[__r]; __ext != dynamic_extent)
280 // Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i]
281 template<array _Extents>
282 constexpr auto __rev_partial_prods = [] consteval
284 constexpr size_t __rank = _Extents.size();
285 std::array<size_t, __rank> __ret;
287 for (size_t __r = __rank; __r > 0; --__r)
289 __ret[__r - 1] = __prod;
290 if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent)
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); }
303 template<typename _IndexType, size_t... _Extents>
306 static_assert(__is_standard_integer<_IndexType>::value,
307 "IndexType must be a signed or unsigned integer type");
309 (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...),
310 "Extents must either be dynamic or representable as IndexType");
312 using index_type = _IndexType;
313 using size_type = make_unsigned_t<index_type>;
314 using rank_type = size_t;
316 static constexpr rank_type
317 rank() noexcept { return _S_storage::_S_rank; }
319 static constexpr rank_type
320 rank_dynamic() noexcept { return _S_storage::_S_rank_dynamic; }
322 static constexpr size_t
323 static_extent(rank_type __r) noexcept
325 __glibcxx_assert(__r < rank());
326 if constexpr (rank() == 0)
329 return _S_storage::_S_static_extent(__r);
333 extent(rank_type __r) const noexcept
335 __glibcxx_assert(__r < rank());
336 if constexpr (rank() == 0)
339 return _M_exts._M_extent(__r);
343 extents() noexcept = default;
346 static consteval bool
347 _S_is_less_dynamic(size_t __ext, size_t __oext)
348 { return (__ext != dynamic_extent) && (__oext == dynamic_extent); }
350 template<typename _OIndexType, size_t... _OExtents>
351 static consteval bool
354 return (_S_is_less_dynamic(_Extents, _OExtents) || ...)
355 || (__gnu_cxx::__int_traits<index_type>::__max
356 < __gnu_cxx::__int_traits<_OIndexType>::__max);
359 template<size_t... _OExtents>
360 static consteval bool
361 _S_is_compatible_extents()
363 if constexpr (sizeof...(_OExtents) != rank())
366 return ((_OExtents == dynamic_extent || _Extents == dynamic_extent
367 || _OExtents == _Extents) && ...);
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)
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))...}))
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))
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))
402 template<typename _OIndexType, size_t... _OExtents>
403 friend constexpr bool
404 operator==(const extents& __self,
405 const extents<_OIndexType, _OExtents...>& __other) noexcept
407 if constexpr (!_S_is_compatible_extents<_OExtents...>())
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()>());
420 friend const array<size_t, rank()>&
421 __mdspan::__static_extents<extents>();
423 friend span<const index_type>
424 __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t);
426 using _S_storage = __mdspan::_ExtentsStorage<
427 _IndexType, array<size_t, sizeof...(_Extents)>{_Extents...}>;
428 [[no_unique_address]] _S_storage _M_exts;
430 template<typename _OIndexType, size_t... _OExtents>
431 friend class extents;
436 template<typename _Tp, size_t _Nm>
438 __contains_zero(span<_Tp, _Nm> __exts) noexcept
440 for (size_t __i = 0; __i < __exts.size(); ++__i)
441 if (__exts[__i] == 0)
446 template<typename _Tp, size_t _Nm>
448 __contains_zero(const array<_Tp, _Nm>& __exts) noexcept
449 { return __contains_zero(span<const _Tp>(__exts)); }
451 template<typename _Extents>
453 __empty(const _Extents& __exts) noexcept
455 if constexpr (__contains_zero(__static_extents<_Extents>()))
457 else if constexpr (_Extents::rank_dynamic() > 0)
458 return __contains_zero(__dynamic_extents(__exts));
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
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);
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
483 constexpr size_t __rank = _Extents::rank();
484 constexpr auto& __sta_exts = __static_extents<_Extents>();
485 if constexpr (__rank == 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);
493 size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r];
494 return __extents_prod(__exts, __sta_prod, 0, __r);
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
503 constexpr size_t __rank = _Extents::rank();
504 constexpr auto& __sta_exts = __static_extents<_Extents>();
505 if constexpr (__rank == 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);
513 size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r];
514 return __extents_prod(__exts, __sta_prod, __r + 1, __rank);
518 template<typename _Extents>
519 constexpr typename _Extents::index_type
520 __size(const _Extents& __exts) noexcept
522 constexpr size_t __sta_prod = [] {
523 span<const size_t> __sta_exts = __static_extents<_Extents>();
525 for(auto __ext : __sta_exts)
526 if (__ext != dynamic_extent)
530 return __extents_prod(__exts, __sta_prod, 0, _Extents::rank());
533 template<typename _IndexType, size_t... _Counts>
534 auto __build_dextents_type(integer_sequence<size_t, _Counts...>)
535 -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>;
538 template<typename _IndexType, size_t _Rank>
539 using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>(
540 make_index_sequence<_Rank>()));
542#if __glibcxx_mdspan >= 202406L
543 template<size_t _Rank, typename _IndexType = size_t>
544 using dims = dextents<_IndexType, _Rank>;
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>...>;
554 template<typename _Extents>
560 template<typename _Extents>
566 template<typename _Extents>
572 template<typename _Tp>
573 constexpr bool __is_extents = false;
575 template<typename _IndexType, size_t... _Extents>
576 constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true;
578 template<typename _Extents, typename... _Indices>
579 constexpr typename _Extents::index_type
580 __linear_index_left(const _Extents& __exts, _Indices... __indices)
583 using _IndexType = typename _Extents::index_type;
584 _IndexType __res = 0;
585 if constexpr (sizeof...(__indices) > 0)
587 _IndexType __mult = 1;
588 auto __update = [&, __pos = 0u](_IndexType __idx) mutable
590 _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos)));
591 __res += __idx * __mult;
592 __mult *= __exts.extent(__pos);
595 (__update(__indices), ...);
600 template<typename _Extents,
601 typename _IndexType = typename _Extents::index_type>
603 __static_quotient(_IndexType __nom = __gnu_cxx::__int_traits<_IndexType>
606 std::span<const size_t> __sta_exts = __static_extents<_Extents>();
607 for (auto __factor : __sta_exts)
609 if (__factor != dynamic_extent)
610 __nom /= _IndexType(__factor);
617 template<typename _Extents>
619 __is_representable_extents(const _Extents& __exts) noexcept
621 using _IndexType = _Extents::index_type;
623 if constexpr (__contains_zero(__static_extents<_Extents>()))
627 constexpr auto __sta_quo = __static_quotient<_Extents>();
628 if constexpr (_Extents::rank_dynamic() == 0)
629 return __sta_quo != 0;
632 auto __dyn_exts = __dynamic_extents(__exts);
633 if (__contains_zero(__dyn_exts))
636 if constexpr (__sta_quo == 0)
640 auto __dyn_quo = _IndexType(__sta_quo);
641 for (auto __factor : __dyn_exts)
643 __dyn_quo /= __factor;
653 template<typename _Extents, typename _IndexType>
654 concept __representable_size = _Extents::rank_dynamic() != 0
655 || __contains_zero(__static_extents<_Extents>())
656 || (__static_quotient<_Extents, _IndexType>() != 0);
658 template<typename _Layout, typename _Mapping>
659 concept __mapping_of =
660 is_same_v<typename _Layout::template mapping<typename _Mapping::extents_type>,
663 template<typename _Mapping>
664 concept __standardized_mapping = __mapping_of<layout_left, _Mapping>
665 || __mapping_of<layout_right, _Mapping>
666 || __mapping_of<layout_stride, _Mapping>;
668 // A tag type to create internal ctors.
669 class __internal_ctor
673 template<typename _Extents>
674 class layout_left::mapping
677 using extents_type = _Extents;
678 using index_type = typename extents_type::index_type;
679 using size_type = typename extents_type::size_type;
680 using rank_type = typename extents_type::rank_type;
681 using layout_type = layout_left;
683 static_assert(__mdspan::__representable_size<extents_type, index_type>,
684 "The size of extents_type must be representable as index_type");
687 mapping() noexcept = default;
690 mapping(const mapping&) noexcept = default;
693 mapping(const extents_type& __extents) noexcept
694 : _M_extents(__extents)
695 { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
697 template<typename _OExtents>
698 requires is_constructible_v<extents_type, _OExtents>
699 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
700 mapping(const mapping<_OExtents>& __other) noexcept
701 : mapping(__other.extents(), __mdspan::__internal_ctor{})
704 template<typename _OExtents>
705 requires (extents_type::rank() <= 1)
706 && is_constructible_v<extents_type, _OExtents>
707 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
708 mapping(const layout_right::mapping<_OExtents>& __other) noexcept
709 : mapping(__other.extents(), __mdspan::__internal_ctor{})
712 // noexcept for consistency with other layouts.
713 template<typename _OExtents>
714 requires is_constructible_v<extents_type, _OExtents>
715 constexpr explicit(extents_type::rank() > 0)
716 mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
717 : mapping(__other.extents(), __mdspan::__internal_ctor{})
718 { __glibcxx_assert(*this == __other); }
721 operator=(const mapping&) noexcept = default;
723 constexpr const extents_type&
724 extents() const noexcept { return _M_extents; }
727 required_span_size() const noexcept
728 { return __mdspan::__size(_M_extents); }
730 // _GLIBCXX_RESOLVE_LIB_DEFECTS
731 // 4314. Missing move in mdspan layout mapping::operator()
732 template<__mdspan::__valid_index_type<index_type>... _Indices>
733 requires (sizeof...(_Indices) == extents_type::rank())
735 operator()(_Indices... __indices) const noexcept
737 return __mdspan::__linear_index_left(_M_extents,
738 static_cast<index_type>(std::move(__indices))...);
741 static constexpr bool
742 is_always_unique() noexcept { return true; }
744 static constexpr bool
745 is_always_exhaustive() noexcept { return true; }
747 static constexpr bool
748 is_always_strided() noexcept { return true; }
750 static constexpr bool
751 is_unique() noexcept { return true; }
753 static constexpr bool
754 is_exhaustive() noexcept { return true; }
756 static constexpr bool
757 is_strided() noexcept { return true; }
760 stride(rank_type __i) const noexcept
761 requires (extents_type::rank() > 0)
763 __glibcxx_assert(__i < extents_type::rank());
764 return __mdspan::__fwd_prod(_M_extents, __i);
767 template<typename _OExtents>
768 requires (extents_type::rank() == _OExtents::rank())
769 friend constexpr bool
770 operator==(const mapping& __self, const mapping<_OExtents>& __other)
772 { return __self.extents() == __other.extents(); }
775 template<typename _OExtents>
777 mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
778 : _M_extents(__oexts)
780 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
781 "The size of OtherExtents must be representable as index_type");
782 __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
785 [[no_unique_address]] extents_type _M_extents{};
790 template<typename _Extents, typename... _Indices>
791 constexpr typename _Extents::index_type
792 __linear_index_right(const _Extents& __exts, _Indices... __indices)
795 using _IndexType = typename _Extents::index_type;
796 array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...};
797 _IndexType __res = 0;
798 if constexpr (sizeof...(__indices) > 0)
800 _IndexType __mult = 1;
801 auto __update = [&, __pos = __exts.rank()](_IndexType) mutable
804 _GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos],
805 __exts.extent(__pos)));
806 __res += __ind_arr[__pos] * __mult;
807 __mult *= __exts.extent(__pos);
809 (__update(__indices), ...);
815 template<typename _Extents>
816 class layout_right::mapping
819 using extents_type = _Extents;
820 using index_type = typename extents_type::index_type;
821 using size_type = typename extents_type::size_type;
822 using rank_type = typename extents_type::rank_type;
823 using layout_type = layout_right;
825 static_assert(__mdspan::__representable_size<extents_type, index_type>,
826 "The size of extents_type must be representable as index_type");
829 mapping() noexcept = default;
832 mapping(const mapping&) noexcept = default;
835 mapping(const extents_type& __extents) noexcept
836 : _M_extents(__extents)
837 { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); }
839 template<typename _OExtents>
840 requires is_constructible_v<extents_type, _OExtents>
841 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
842 mapping(const mapping<_OExtents>& __other) noexcept
843 : mapping(__other.extents(), __mdspan::__internal_ctor{})
846 template<typename _OExtents>
847 requires (extents_type::rank() <= 1)
848 && is_constructible_v<extents_type, _OExtents>
849 constexpr explicit(!is_convertible_v<_OExtents, extents_type>)
850 mapping(const layout_left::mapping<_OExtents>& __other) noexcept
851 : mapping(__other.extents(), __mdspan::__internal_ctor{})
854 template<typename _OExtents>
855 requires is_constructible_v<extents_type, _OExtents>
856 constexpr explicit(extents_type::rank() > 0)
857 mapping(const layout_stride::mapping<_OExtents>& __other) noexcept
858 : mapping(__other.extents(), __mdspan::__internal_ctor{})
859 { __glibcxx_assert(*this == __other); }
862 operator=(const mapping&) noexcept = default;
864 constexpr const extents_type&
865 extents() const noexcept { return _M_extents; }
868 required_span_size() const noexcept
869 { return __mdspan::__size(_M_extents); }
871 // _GLIBCXX_RESOLVE_LIB_DEFECTS
872 // 4314. Missing move in mdspan layout mapping::operator()
873 template<__mdspan::__valid_index_type<index_type>... _Indices>
874 requires (sizeof...(_Indices) == extents_type::rank())
876 operator()(_Indices... __indices) const noexcept
878 return __mdspan::__linear_index_right(
879 _M_extents, static_cast<index_type>(std::move(__indices))...);
882 static constexpr bool
883 is_always_unique() noexcept
886 static constexpr bool
887 is_always_exhaustive() noexcept
890 static constexpr bool
891 is_always_strided() noexcept
894 static constexpr bool
898 static constexpr bool
899 is_exhaustive() noexcept
902 static constexpr bool
903 is_strided() noexcept
907 stride(rank_type __i) const noexcept
908 requires (extents_type::rank() > 0)
910 __glibcxx_assert(__i < extents_type::rank());
911 return __mdspan::__rev_prod(_M_extents, __i);
914 template<typename _OExtents>
915 requires (extents_type::rank() == _OExtents::rank())
916 friend constexpr bool
917 operator==(const mapping& __self, const mapping<_OExtents>& __other)
919 { return __self.extents() == __other.extents(); }
922 template<typename _OExtents>
924 mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept
925 : _M_extents(__oexts)
927 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
928 "The size of OtherExtents must be representable as index_type");
929 __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents));
932 [[no_unique_address]] extents_type _M_extents{};
937 template<typename _Mp>
938 concept __mapping_alike = requires
940 requires __is_extents<typename _Mp::extents_type>;
941 { _Mp::is_always_strided() } -> same_as<bool>;
942 { _Mp::is_always_exhaustive() } -> same_as<bool>;
943 { _Mp::is_always_unique() } -> same_as<bool>;
944 bool_constant<_Mp::is_always_strided()>::value;
945 bool_constant<_Mp::is_always_exhaustive()>::value;
946 bool_constant<_Mp::is_always_unique()>::value;
949 template<typename _Mapping>
950 constexpr typename _Mapping::index_type
951 __offset(const _Mapping& __m) noexcept
953 using _IndexType = typename _Mapping::index_type;
954 constexpr auto __rank = _Mapping::extents_type::rank();
956 if constexpr (__standardized_mapping<_Mapping>)
958 else if (__empty(__m.extents()))
962 auto __impl = [&__m]<size_t... _Counts>(index_sequence<_Counts...>)
963 { return __m(((void) _Counts, _IndexType(0))...); };
964 return __impl(make_index_sequence<__rank>());
968 template<typename _Mapping, typename... _Indices>
969 constexpr typename _Mapping::index_type
970 __linear_index_strides(const _Mapping& __m, _Indices... __indices)
973 using _IndexType = typename _Mapping::index_type;
974 _IndexType __res = 0;
975 if constexpr (sizeof...(__indices) > 0)
977 auto __update = [&, __pos = 0u](_IndexType __idx) mutable
979 _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx,
980 __m.extents().extent(__pos)));
981 __res += __idx * __m.stride(__pos++);
983 (__update(__indices), ...);
989 template<typename _Extents>
990 class layout_stride::mapping
993 using extents_type = _Extents;
994 using index_type = typename extents_type::index_type;
995 using size_type = typename extents_type::size_type;
996 using rank_type = typename extents_type::rank_type;
997 using layout_type = layout_stride;
999 static_assert(__mdspan::__representable_size<extents_type, index_type>,
1000 "The size of extents_type must be representable as index_type");
1005 // The precondition is either statically asserted, or automatically
1006 // satisfied because dynamic extents are zero-initialized.
1007 size_t __stride = 1;
1008 for (size_t __i = extents_type::rank(); __i > 0; --__i)
1010 _M_strides[__i - 1] = index_type(__stride);
1011 __stride *= size_t(_M_extents.extent(__i - 1));
1016 mapping(const mapping&) noexcept = default;
1018 template<typename _OIndexType>
1019 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1021 mapping(const extents_type& __exts,
1022 span<_OIndexType, extents_type::rank()> __strides) noexcept
1023 : _M_extents(__exts)
1025 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1026 _M_strides[__i] = index_type(as_const(__strides[__i]));
1029 template<typename _OIndexType>
1030 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1032 mapping(const extents_type& __exts,
1033 const array<_OIndexType, extents_type::rank()>& __strides)
1036 span<const _OIndexType, extents_type::rank()>(__strides))
1039 template<__mdspan::__mapping_alike _StridedMapping>
1040 requires (is_constructible_v<extents_type,
1041 typename _StridedMapping::extents_type>
1042 && _StridedMapping::is_always_unique()
1043 && _StridedMapping::is_always_strided())
1044 constexpr explicit(!(
1045 is_convertible_v<typename _StridedMapping::extents_type, extents_type>
1046 && __mdspan::__standardized_mapping<_StridedMapping>))
1047 mapping(const _StridedMapping& __other) noexcept
1048 : _M_extents(__other.extents())
1050 using _OIndexType = _StridedMapping::index_type;
1051 using _OExtents = _StridedMapping::extents_type;
1053 __glibcxx_assert(__mdspan::__offset(__other) == 0);
1054 static_assert(__mdspan::__representable_size<_OExtents, index_type>,
1055 "The size of StridedMapping::extents_type must be representable as"
1057 if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max,
1058 __gnu_cxx::__int_traits<index_type>::__max))
1059 __glibcxx_assert(!cmp_less(
1060 __gnu_cxx::__int_traits<index_type>::__max,
1061 __other.required_span_size())
1062 && "other.required_span_size() must be representable"
1064 if constexpr (extents_type::rank() > 0)
1065 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1066 _M_strides[__i] = index_type(__other.stride(__i));
1070 operator=(const mapping&) noexcept = default;
1072 constexpr const extents_type&
1073 extents() const noexcept { return _M_extents; }
1075 constexpr array<index_type, extents_type::rank()>
1076 strides() const noexcept
1078 array<index_type, extents_type::rank()> __ret;
1079 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1080 __ret[__i] = _M_strides[__i];
1084 constexpr index_type
1085 required_span_size() const noexcept
1087 if (__mdspan::__empty(_M_extents))
1090 index_type __ret = 1;
1091 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1092 __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i];
1096 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1097 // 4314. Missing move in mdspan layout mapping::operator()
1098 template<__mdspan::__valid_index_type<index_type>... _Indices>
1099 requires (sizeof...(_Indices) == extents_type::rank())
1100 constexpr index_type
1101 operator()(_Indices... __indices) const noexcept
1103 return __mdspan::__linear_index_strides(*this,
1104 static_cast<index_type>(std::move(__indices))...);
1107 static constexpr bool
1108 is_always_unique() noexcept { return true; }
1110 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1111 // 4266. layout_stride::mapping should treat empty mappings as exhaustive
1112 static constexpr bool
1113 is_always_exhaustive() noexcept
1115 return (_Extents::rank() == 0) || __mdspan::__contains_zero(
1116 __mdspan::__static_extents<extents_type>());
1119 static constexpr bool
1120 is_always_strided() noexcept { return true; }
1122 static constexpr bool
1123 is_unique() noexcept { return true; }
1125 // _GLIBCXX_RESOLVE_LIB_DEFECTS
1126 // 4266. layout_stride::mapping should treat empty mappings as exhaustive
1128 is_exhaustive() const noexcept
1130 if constexpr (!is_always_exhaustive())
1132 auto __size = __mdspan::__size(_M_extents);
1134 return __size == required_span_size();
1139 static constexpr bool
1140 is_strided() noexcept { return true; }
1142 constexpr index_type
1143 stride(rank_type __r) const noexcept { return _M_strides[__r]; }
1145 template<__mdspan::__mapping_alike _OMapping>
1146 requires ((extents_type::rank() == _OMapping::extents_type::rank())
1147 && _OMapping::is_always_strided())
1148 friend constexpr bool
1149 operator==(const mapping& __self, const _OMapping& __other) noexcept
1151 if (__self.extents() != __other.extents())
1153 if constexpr (extents_type::rank() > 0)
1154 for (size_t __i = 0; __i < extents_type::rank(); ++__i)
1155 if (!cmp_equal(__self.stride(__i), __other.stride(__i)))
1157 return __mdspan::__offset(__other) == 0;
1161 using _S_strides_t = typename __array_traits<index_type,
1162 extents_type::rank()>::_Type;
1163 [[no_unique_address]] extents_type _M_extents;
1164 [[no_unique_address]] _S_strides_t _M_strides;
1167 template<typename _ElementType>
1168 struct default_accessor
1170 static_assert(!is_array_v<_ElementType>,
1171 "ElementType must not be an array type");
1172 static_assert(!is_abstract_v<_ElementType>,
1173 "ElementType must not be an abstract class type");
1175 using offset_policy = default_accessor;
1176 using element_type = _ElementType;
1177 using reference = element_type&;
1178 using data_handle_type = element_type*;
1181 default_accessor() noexcept = default;
1183 template<typename _OElementType>
1184 requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
1186 default_accessor(default_accessor<_OElementType>) noexcept
1190 access(data_handle_type __p, size_t __i) const noexcept
1191 { return __p[__i]; }
1193 constexpr data_handle_type
1194 offset(data_handle_type __p, size_t __i) const noexcept
1195 { return __p + __i; }
1198#ifdef __glibcxx_aligned_accessor
1199 template<typename _ElementType, size_t _ByteAlignment>
1200 struct aligned_accessor
1202 static_assert(has_single_bit(_ByteAlignment),
1203 "ByteAlignment must be a power of two");
1204 static_assert(_ByteAlignment >= alignof(_ElementType));
1206 using offset_policy = default_accessor<_ElementType>;
1207 using element_type = _ElementType;
1208 using reference = element_type&;
1209 using data_handle_type = element_type*;
1211 static constexpr size_t byte_alignment = _ByteAlignment;
1214 aligned_accessor() noexcept = default;
1216 template<typename _OElementType, size_t _OByteAlignment>
1217 requires (_OByteAlignment >= byte_alignment)
1218 && is_convertible_v<_OElementType(*)[], element_type(*)[]>
1220 aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>)
1224 template<typename _OElementType>
1225 requires is_convertible_v<_OElementType(*)[], element_type(*)[]>
1227 aligned_accessor(default_accessor<_OElementType>) noexcept
1230 template<typename _OElementType>
1231 requires is_convertible_v<element_type(*)[], _OElementType(*)[]>
1233 operator default_accessor<_OElementType>() const noexcept
1237 access(data_handle_type __p, size_t __i) const noexcept
1238 { return std::assume_aligned<byte_alignment>(__p)[__i]; }
1240 constexpr typename offset_policy::data_handle_type
1241 offset(data_handle_type __p, size_t __i) const noexcept
1242 { return std::assume_aligned<byte_alignment>(__p) + __i; }
1248 template<typename _Extents, typename _IndexType, size_t _Nm>
1250 __is_multi_index(const _Extents& __exts, span<_IndexType, _Nm> __indices)
1252 static_assert(__exts.rank() == _Nm);
1253 for (size_t __i = 0; __i < __exts.rank(); ++__i)
1254 if (__indices[__i] >= __exts.extent(__i))
1260 template<typename _ElementType, typename _Extents,
1261 typename _LayoutPolicy = layout_right,
1262 typename _AccessorPolicy = default_accessor<_ElementType>>
1265 static_assert(!is_array_v<_ElementType>,
1266 "ElementType must not be an array type");
1267 static_assert(!is_abstract_v<_ElementType>,
1268 "ElementType must not be an abstract class type");
1269 static_assert(__mdspan::__is_extents<_Extents>,
1270 "Extents must be a specialization of std::extents");
1271 static_assert(is_same_v<_ElementType,
1272 typename _AccessorPolicy::element_type>);
1275 using extents_type = _Extents;
1276 using layout_type = _LayoutPolicy;
1277 using accessor_type = _AccessorPolicy;
1278 using mapping_type = typename layout_type::template mapping<extents_type>;
1279 using element_type = _ElementType;
1280 using value_type = remove_cv_t<element_type>;
1281 using index_type = typename extents_type::index_type;
1282 using size_type = typename extents_type::size_type;
1283 using rank_type = typename extents_type::rank_type;
1284 using data_handle_type = typename accessor_type::data_handle_type;
1285 using reference = typename accessor_type::reference;
1287 static constexpr rank_type
1288 rank() noexcept { return extents_type::rank(); }
1290 static constexpr rank_type
1291 rank_dynamic() noexcept { return extents_type::rank_dynamic(); }
1293 static constexpr size_t
1294 static_extent(rank_type __r) noexcept
1295 { return extents_type::static_extent(__r); }
1297 constexpr index_type
1298 extent(rank_type __r) const noexcept { return extents().extent(__r); }
1302 requires (rank_dynamic() > 0)
1303 && is_default_constructible_v<data_handle_type>
1304 && is_default_constructible_v<mapping_type>
1305 && is_default_constructible_v<accessor_type> = default;
1308 mdspan(const mdspan& __other) = default;
1311 mdspan(mdspan&& __other) = default;
1313 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
1314 requires (sizeof...(_OIndexTypes) == rank()
1315 || sizeof...(_OIndexTypes) == rank_dynamic())
1316 && is_constructible_v<mapping_type, extents_type>
1317 && is_default_constructible_v<accessor_type>
1319 mdspan(data_handle_type __handle, _OIndexTypes... __exts)
1321 _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)),
1322 _M_handle(std::move(__handle))
1325 template<typename _OIndexType, size_t _Nm>
1326 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1327 && (_Nm == rank() || _Nm == rank_dynamic())
1328 && is_constructible_v<mapping_type, extents_type>
1329 && is_default_constructible_v<accessor_type>
1330 constexpr explicit(_Nm != rank_dynamic())
1331 mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts)
1332 : _M_accessor(), _M_mapping(extents_type(__exts)),
1333 _M_handle(std::move(__handle))
1336 template<typename _OIndexType, size_t _Nm>
1337 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1338 && (_Nm == rank() || _Nm == rank_dynamic())
1339 && is_constructible_v<mapping_type, extents_type>
1340 && is_default_constructible_v<accessor_type>
1341 constexpr explicit(_Nm != rank_dynamic())
1342 mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts)
1343 : _M_accessor(), _M_mapping(extents_type(__exts)),
1344 _M_handle(std::move(__handle))
1348 mdspan(data_handle_type __handle, const extents_type& __exts)
1349 requires is_constructible_v<mapping_type, const extents_type&>
1350 && is_default_constructible_v<accessor_type>
1351 : _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle))
1355 mdspan(data_handle_type __handle, const mapping_type& __mapping)
1356 requires is_default_constructible_v<accessor_type>
1357 : _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle))
1361 mdspan(data_handle_type __handle, const mapping_type& __mapping,
1362 const accessor_type& __accessor)
1363 : _M_accessor(__accessor), _M_mapping(__mapping),
1364 _M_handle(std::move(__handle))
1367 template<typename _OElementType, typename _OExtents, typename _OLayout,
1368 typename _OAccessor>
1369 requires is_constructible_v<mapping_type,
1370 const typename _OLayout::template mapping<_OExtents>&>
1371 && is_constructible_v<accessor_type, const _OAccessor&>
1372 constexpr explicit(!is_convertible_v<
1373 const typename _OLayout::template mapping<_OExtents>&, mapping_type>
1374 || !is_convertible_v<const _OAccessor&, accessor_type>)
1375 mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>&
1377 : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()),
1378 _M_handle(__other.data_handle())
1380 static_assert(is_constructible_v<data_handle_type,
1381 const typename _OAccessor::data_handle_type&>);
1382 static_assert(is_constructible_v<extents_type, _OExtents>);
1386 operator=(const mdspan& __other) = default;
1389 operator=(mdspan&& __other) = default;
1391 template<__mdspan::__valid_index_type<index_type>... _OIndexTypes>
1392 requires (sizeof...(_OIndexTypes) == rank())
1394 operator[](_OIndexTypes... __indices) const
1396 auto __checked_call = [this](auto... __idxs) -> index_type
1398 if constexpr (sizeof...(__idxs) > 0)
1399 __glibcxx_assert(__mdspan::__is_multi_index(extents(),
1400 span<const index_type, sizeof...(__idxs)>({__idxs...})));
1401 return _M_mapping(__idxs...);
1404 auto __index = __checked_call(
1405 static_cast<index_type>(std::move(__indices))...);
1406 return _M_accessor.access(_M_handle, __index);
1409 template<typename _OIndexType>
1410 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1412 operator[](span<_OIndexType, rank()> __indices) const
1414 auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>)
1416 { return (*this)[index_type(as_const(__indices[_Counts]))...]; };
1417 return __call(make_index_sequence<rank()>());
1420 template<typename _OIndexType>
1421 requires __mdspan::__valid_index_type<const _OIndexType&, index_type>
1423 operator[](const array<_OIndexType, rank()>& __indices) const
1424 { return (*this)[span<const _OIndexType, rank()>(__indices)]; }
1427 size() const noexcept
1429 __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(),
1430 __gnu_cxx::__int_traits<size_t>
1432 return size_type(__mdspan::__size(extents()));
1437 empty() const noexcept
1438 { return __mdspan::__empty(extents()); }
1440 friend constexpr void
1441 swap(mdspan& __x, mdspan& __y) noexcept
1444 swap(__x._M_mapping, __y._M_mapping);
1445 swap(__x._M_accessor, __y._M_accessor);
1446 swap(__x._M_handle, __y._M_handle);
1449 constexpr const extents_type&
1450 extents() const noexcept { return _M_mapping.extents(); }
1452 constexpr const data_handle_type&
1453 data_handle() const noexcept { return _M_handle; }
1455 constexpr const mapping_type&
1456 mapping() const noexcept { return _M_mapping; }
1458 constexpr const accessor_type&
1459 accessor() const noexcept { return _M_accessor; }
1461 // Strengthened noexcept for all `is_*` methods.
1463 static constexpr bool
1464 is_always_unique() noexcept(noexcept(mapping_type::is_always_unique()))
1465 { return mapping_type::is_always_unique(); }
1467 static constexpr bool
1468 is_always_exhaustive()
1469 noexcept(noexcept(mapping_type::is_always_exhaustive()))
1470 { return mapping_type::is_always_exhaustive(); }
1472 static constexpr bool
1474 noexcept(noexcept(mapping_type::is_always_strided()))
1475 { return mapping_type::is_always_strided(); }
1478 is_unique() const noexcept(noexcept(_M_mapping.is_unique()))
1479 { return _M_mapping.is_unique(); }
1482 is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive()))
1483 { return _M_mapping.is_exhaustive(); }
1486 is_strided() const noexcept(noexcept(_M_mapping.is_strided()))
1487 { return _M_mapping.is_strided(); }
1489 constexpr index_type
1490 stride(rank_type __r) const { return _M_mapping.stride(__r); }
1493 [[no_unique_address]] accessor_type _M_accessor = accessor_type();
1494 [[no_unique_address]] mapping_type _M_mapping = mapping_type();
1495 [[no_unique_address]] data_handle_type _M_handle = data_handle_type();
1498 template<typename _CArray>
1499 requires is_array_v<_CArray> && (rank_v<_CArray> == 1)
1501 -> mdspan<remove_all_extents_t<_CArray>,
1502 extents<size_t, extent_v<_CArray, 0>>>;
1504 template<typename _Pointer>
1505 requires is_pointer_v<remove_reference_t<_Pointer>>
1507 -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>;
1509 template<typename _ElementType, typename... _Integrals>
1510 requires (is_convertible_v<_Integrals, size_t> && ...)
1511 && (sizeof...(_Integrals) > 0)
1512 explicit mdspan(_ElementType*, _Integrals...)
1513 -> mdspan<_ElementType,
1514 extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>;
1516 template<typename _ElementType, typename _OIndexType, size_t _Nm>
1517 mdspan(_ElementType*, span<_OIndexType, _Nm>)
1518 -> mdspan<_ElementType, dextents<size_t, _Nm>>;
1520 template<typename _ElementType, typename _OIndexType, size_t _Nm>
1521 mdspan(_ElementType*, const array<_OIndexType, _Nm>&)
1522 -> mdspan<_ElementType, dextents<size_t, _Nm>>;
1524 template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack>
1525 mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&)
1526 -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>;
1528 template<typename _ElementType, typename _MappingType>
1529 mdspan(_ElementType*, const _MappingType&)
1530 -> mdspan<_ElementType, typename _MappingType::extents_type,
1531 typename _MappingType::layout_type>;
1533 template<typename _MappingType, typename _AccessorType>
1534 mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&,
1535 const _AccessorType&)
1536 -> mdspan<typename _AccessorType::element_type,
1537 typename _MappingType::extents_type,
1538 typename _MappingType::layout_type, _AccessorType>;
1540_GLIBCXX_END_NAMESPACE_VERSION