// -*- C++ -*- // Copyright The GNU Toolchain Authors. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . /** @file mdspan * This is a Standard C++ Library header. */ #ifndef _GLIBCXX_MDSPAN #define _GLIBCXX_MDSPAN 1 #ifdef _GLIBCXX_SYSHDR #pragma GCC system_header #endif #include #include #include #include #define __glibcxx_want_mdspan #define __glibcxx_want_aligned_accessor #define __glibcxx_want_submdspan #include #if __glibcxx_aligned_accessor #include #endif #if __glibcxx_submdspan #include #endif #ifdef __glibcxx_mdspan namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace __mdspan { consteval bool __all_static(std::span __extents) { for(auto __ext : __extents) if (__ext == dynamic_extent) return false; return true; } consteval bool __all_dynamic(std::span __extents) { for(auto __ext : __extents) if (__ext != dynamic_extent) return false; return true; } template constexpr _IndexType __index_type_cast(_OIndexType&& __other) { if constexpr (std::is_integral_v<_OIndexType>) { constexpr _IndexType __index_type_max = __gnu_cxx::__int_traits<_IndexType>::__max; constexpr _OIndexType __oindex_type_max = __gnu_cxx::__int_traits<_OIndexType>::__max; if constexpr (__index_type_max < __oindex_type_max) __glibcxx_assert(cmp_less_equal(__other, __index_type_max)); if constexpr (std::is_signed_v<_OIndexType>) __glibcxx_assert(__other >= 0); return static_cast<_IndexType>(__other); } else { auto __ret = static_cast<_IndexType>(std::move(__other)); if constexpr (std::is_signed_v<_IndexType>) __glibcxx_assert(__ret >= 0); return __ret; } } template class _StaticExtents { public: static constexpr size_t _S_rank = _Extents.size(); // For __r in [0, _S_rank], _S_dynamic_index(__r) is the number // of dynamic extents up to (and not including) __r. // // If __r is the index of a dynamic extent, then // _S_dynamic_index[__r] is the index of that extent in // _M_dyn_exts. static constexpr size_t _S_dynamic_index(size_t __r) noexcept { return _S_dynamic_index_data[__r]; } static constexpr auto _S_dynamic_index_data = [] consteval { array __ret; size_t __dyn = 0; for (size_t __i = 0; __i < _S_rank; ++__i) { __ret[__i] = __dyn; __dyn += (_Extents[__i] == dynamic_extent); } __ret[_S_rank] = __dyn; return __ret; }(); static constexpr size_t _S_rank_dynamic = _S_dynamic_index(_S_rank); // For __r in [0, _S_rank_dynamic), _S_dynamic_index_inv(__r) is the // index of the __r-th dynamic extent in _Extents. static constexpr size_t _S_dynamic_index_inv(size_t __r) noexcept { return _S_dynamic_index_inv_data[__r]; } static constexpr auto _S_dynamic_index_inv_data = [] consteval { array __ret; for (size_t __i = 0, __r = 0; __i < _S_rank; ++__i) if (_Extents[__i] == dynamic_extent) __ret[__r++] = __i; return __ret; }(); static constexpr size_t _S_static_extent(size_t __r) noexcept { return _Extents[__r]; } }; template requires (__all_dynamic<_Extents>()) class _StaticExtents<_Extents> { public: static constexpr size_t _S_rank = _Extents.size(); static constexpr size_t _S_dynamic_index(size_t __r) noexcept { return __r; } static constexpr size_t _S_rank_dynamic = _S_rank; static constexpr size_t _S_dynamic_index_inv(size_t __k) noexcept { return __k; } static constexpr size_t _S_static_extent(size_t) noexcept { return dynamic_extent; } }; template class _ExtentsStorage : public _StaticExtents<_Extents> { private: using _Base = _StaticExtents<_Extents>; public: using _Base::_S_rank; using _Base::_S_rank_dynamic; using _Base::_S_dynamic_index; using _Base::_S_dynamic_index_inv; using _Base::_S_static_extent; static constexpr bool _S_is_dynamic(size_t __r) noexcept { if constexpr (__all_static(_Extents)) return false; else if constexpr (__all_dynamic(_Extents)) return true; else return _Extents[__r] == dynamic_extent; } template static constexpr _IndexType _S_int_cast(const _OIndexType& __other) noexcept { return _IndexType(__other); } constexpr _IndexType _M_extent(size_t __r) const noexcept { if (_S_is_dynamic(__r)) return _M_dyn_exts[_S_dynamic_index(__r)]; else return _S_static_extent(__r); } template static constexpr bool _S_is_compatible_extents(_GetOtherExtent __get_extent) noexcept { if constexpr (_OtherRank == _S_rank) for (size_t __i = 0; __i < _S_rank; ++__i) if (!_S_is_dynamic(__i) && !cmp_equal(_Extents[__i], _S_int_cast(__get_extent(__i)))) return false; return true; } template constexpr void _M_init_dynamic_extents(_GetOtherExtent __get_extent) noexcept { __glibcxx_assert(_S_is_compatible_extents<_OtherRank>(__get_extent)); for (size_t __i = 0; __i < _S_rank_dynamic; ++__i) { size_t __di = __i; if constexpr (_OtherRank != _S_rank_dynamic) __di = _S_dynamic_index_inv(__i); _M_dyn_exts[__i] = _S_int_cast(__get_extent(__di)); } } constexpr _ExtentsStorage() noexcept = default; template constexpr _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>& __other) noexcept { _M_init_dynamic_extents<_S_rank>([&__other](size_t __i) { return __other._M_extent(__i); }); } template constexpr _ExtentsStorage(span __exts) noexcept { _M_init_dynamic_extents<_Nm>( [&__exts](size_t __i) -> const _OIndexType& { return __exts[__i]; }); } static constexpr const array& _S_static_extents() noexcept { return _Extents; } constexpr span _M_dynamic_extents(size_t __begin, size_t __end) const noexcept requires (_Extents.size() > 0) { return {_M_dyn_exts + _S_dynamic_index(__begin), _S_dynamic_index(__end) - _S_dynamic_index(__begin)}; } private: using _Storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type; [[no_unique_address]] _Storage _M_dyn_exts{}; }; template concept __valid_index_type = is_convertible_v<_OIndexType, _SIndexType> && is_nothrow_constructible_v<_SIndexType, _OIndexType>; template concept __valid_static_extent = _Extent == dynamic_extent || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max; template constexpr const array& __static_extents() noexcept { return _Extents::_Storage::_S_static_extents(); } template constexpr span __static_extents(size_t __begin, size_t __end) noexcept { const auto& __sta_exts = __static_extents<_Extents>(); return span(__sta_exts.data() + __begin, __end - __begin); } // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive) template constexpr auto __fwd_partial_prods = [] consteval { constexpr size_t __rank = _Extents.size(); std::array __ret; size_t __prod = 1; for (size_t __r = 0; __r < __rank; ++__r) { __ret[__r] = __prod; if (size_t __ext = _Extents[__r]; __ext != dynamic_extent) __prod *= __ext; } return __ret; }(); // Pre-compute: \prod_{i = r+1}^{n-1} _Extents[i] template constexpr auto __rev_partial_prods = [] consteval { constexpr size_t __rank = _Extents.size(); std::array __ret; size_t __prod = 1; for (size_t __r = __rank; __r > 0; --__r) { __ret[__r - 1] = __prod; if (size_t __ext = _Extents[__r - 1]; __ext != dynamic_extent) __prod *= __ext; } return __ret; }(); template constexpr span __dynamic_extents(const _Extents& __exts, size_t __begin = 0, size_t __end = _Extents::rank()) noexcept { return __exts._M_exts._M_dynamic_extents(__begin, __end); } } #if __glibcxx_submdspan struct full_extent_t { explicit full_extent_t() = default; }; inline constexpr full_extent_t full_extent{}; template struct strided_slice { static_assert(__is_signed_or_unsigned_integer<_OffsetType>::value || __detail::__integral_constant_like<_OffsetType>); static_assert(__is_signed_or_unsigned_integer<_ExtentType>::value || __detail::__integral_constant_like<_ExtentType>); static_assert(__is_signed_or_unsigned_integer<_StrideType>::value || __detail::__integral_constant_like<_StrideType>); using offset_type = _OffsetType; using extent_type = _ExtentType; using stride_type = _StrideType; [[no_unique_address]] offset_type offset{}; [[no_unique_address]] extent_type extent{}; [[no_unique_address]] stride_type stride{}; }; template struct submdspan_mapping_result { [[no_unique_address]] _Mapping mapping = _Mapping(); size_t offset{}; }; template constexpr bool __is_submdspan_mapping_result = false; template constexpr bool __is_submdspan_mapping_result> = true; template concept __submdspan_mapping_result = __is_submdspan_mapping_result<_Mapping>; #endif // __glibcxx_submdspan template class extents { static_assert(__is_signed_or_unsigned_integer<_IndexType>::value, "IndexType must be a signed or unsigned integer type"); static_assert( (__mdspan::__valid_static_extent<_Extents, _IndexType> && ...), "Extents must either be dynamic or representable as IndexType"); using _Storage = __mdspan::_ExtentsStorage< _IndexType, array{_Extents...}>; [[no_unique_address]] _Storage _M_exts; public: using index_type = _IndexType; using size_type = make_unsigned_t; using rank_type = size_t; static constexpr rank_type rank() noexcept { return _Storage::_S_rank; } static constexpr rank_type rank_dynamic() noexcept { return _Storage::_S_rank_dynamic; } static constexpr size_t static_extent(rank_type __r) noexcept { __glibcxx_assert(__r < rank()); if constexpr (rank() == 0) __builtin_trap(); else return _Storage::_S_static_extent(__r); } constexpr index_type extent(rank_type __r) const noexcept { __glibcxx_assert(__r < rank()); if constexpr (rank() == 0) __builtin_trap(); else return _M_exts._M_extent(__r); } constexpr extents() noexcept = default; private: static consteval bool _S_is_less_dynamic(size_t __ext, size_t __oext) { return (__ext != dynamic_extent) && (__oext == dynamic_extent); } template static consteval bool _S_ctor_explicit() { return (_S_is_less_dynamic(_Extents, _OExtents) || ...) || (__gnu_cxx::__int_traits::__max < __gnu_cxx::__int_traits<_OIndexType>::__max); } template static consteval bool _S_is_compatible_extents() { if constexpr (sizeof...(_OExtents) != rank()) return false; else return ((_OExtents == dynamic_extent || _Extents == dynamic_extent || _OExtents == _Extents) && ...); } public: template requires (_S_is_compatible_extents<_OExtents...>()) constexpr explicit(_S_ctor_explicit<_OIndexType, _OExtents...>()) extents(const extents<_OIndexType, _OExtents...>& __other) noexcept : _M_exts(__other._M_exts) { } template<__mdspan::__valid_index_type... _OIndexTypes> requires (sizeof...(_OIndexTypes) == rank() || sizeof...(_OIndexTypes) == rank_dynamic()) constexpr explicit extents(_OIndexTypes... __exts) noexcept : _M_exts(span( initializer_list{static_cast<_IndexType>(std::move(__exts))...})) { } template requires __mdspan::__valid_index_type && (_Nm == rank() || _Nm == rank_dynamic()) constexpr explicit(_Nm != rank_dynamic()) extents(span<_OIndexType, _Nm> __exts) noexcept : _M_exts(span(__exts)) { } template requires __mdspan::__valid_index_type && (_Nm == rank() || _Nm == rank_dynamic()) constexpr explicit(_Nm != rank_dynamic()) extents(const array<_OIndexType, _Nm>& __exts) noexcept : _M_exts(span(__exts)) { } template friend constexpr bool operator==(const extents& __self, const extents<_OIndexType, _OExtents...>& __other) noexcept { if constexpr (!_S_is_compatible_extents<_OExtents...>()) return false; else { auto __impl = [&__self, &__other]( index_sequence<_Counts...>) { return (cmp_equal(__self.extent(_Counts), __other.extent(_Counts)) && ...); }; return __impl(make_index_sequence<__self.rank()>()); } } private: friend constexpr const array& __mdspan::__static_extents() noexcept; friend constexpr span __mdspan::__dynamic_extents(const extents&, size_t, size_t) noexcept; template friend class extents; }; namespace __mdspan { template constexpr bool __contains_zero(span<_Tp, _Nm> __exts) noexcept { for (size_t __i = 0; __i < __exts.size(); ++__i) if (__exts[__i] == 0) return true; return false; } template consteval bool __contains_zero(const array<_Tp, _Nm>& __exts) noexcept { return __contains_zero(span(__exts)); } template constexpr bool __empty(const _Extents& __exts) noexcept { if constexpr (__contains_zero(__static_extents<_Extents>())) return true; else if constexpr (_Extents::rank_dynamic() > 0) return __contains_zero(__dynamic_extents(__exts)); else return false; } template constexpr typename _Extents::index_type __extents_prod(const _Extents& __exts, size_t __sta_prod, size_t __begin, size_t __end) noexcept { if (__sta_prod == 0) return 0; size_t __ret = __sta_prod; if constexpr (_Extents::rank_dynamic() > 0) for (auto __factor : __dynamic_extents(__exts, __begin, __end)) __ret *= size_t(__factor); return static_cast(__ret); } // Preconditions: _r < _Extents::rank() template constexpr typename _Extents::index_type __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept { size_t __sta_prod = [__begin, __end] { span __sta_exts = __static_extents<_Extents>(__begin, __end); size_t __ret = 1; for(auto __ext : __sta_exts) if (__ext != dynamic_extent) __ret *= __ext; return __ret; }(); return __extents_prod(__exts, __sta_prod, __begin, __end); } template constexpr typename _Extents::index_type __fwd_prod(const _Extents& __exts, size_t __r) noexcept { constexpr size_t __rank = _Extents::rank(); constexpr auto& __sta_exts = __static_extents<_Extents>(); if constexpr (__rank == 1) return 1; else if constexpr (__rank == 2) return __r == 0 ? 1 : __exts.extent(0); else if constexpr (__all_dynamic(std::span(__sta_exts).first(__rank-1))) return __extents_prod(__exts, 1, 0, __r); else { size_t __sta_prod = __fwd_partial_prods<__sta_exts>[__r]; return __extents_prod(__exts, __sta_prod, 0, __r); } } template consteval _IndexType __fwd_prod(span __values) { _IndexType __ret = 1; for(auto __value : __values) __ret *= __value; return __ret; } // Preconditions: _r < _Extents::rank() template constexpr typename _Extents::index_type __rev_prod(const _Extents& __exts, size_t __r) noexcept { constexpr size_t __rank = _Extents::rank(); constexpr auto& __sta_exts = __static_extents<_Extents>(); if constexpr (__rank == 1) return 1; else if constexpr (__rank == 2) return __r == 0 ? __exts.extent(1) : 1; else if constexpr (__all_dynamic(std::span(__sta_exts).last(__rank-1))) return __extents_prod(__exts, 1, __r + 1, __rank); else { size_t __sta_prod = __rev_partial_prods<__sta_exts>[__r]; return __extents_prod(__exts, __sta_prod, __r + 1, __rank); } } template constexpr typename _Extents::index_type __size(const _Extents& __exts) noexcept { constexpr size_t __sta_prod = [] { span __sta_exts = __static_extents<_Extents>(); size_t __ret = 1; for(auto __ext : __sta_exts) if (__ext != dynamic_extent) __ret *= __ext; return __ret; }(); return __extents_prod(__exts, __sta_prod, 0, _Extents::rank()); } template auto __build_dextents_type(integer_sequence) -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>; } template using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>( make_index_sequence<_Rank>())); #if __glibcxx_mdspan >= 202406L template using dims = dextents<_IndexType, _Rank>; #endif template requires (is_convertible_v<_Integrals, size_t> && ...) explicit extents(_Integrals...) -> extents...>; struct layout_left { template class mapping; }; struct layout_right { template class mapping; }; struct layout_stride { template class mapping; }; #ifdef __glibcxx_padded_layouts template struct layout_left_padded { template class mapping; }; template struct layout_right_padded { template class mapping; }; #endif namespace __mdspan { template constexpr bool __is_extents = false; template constexpr bool __is_extents> = true; template constexpr typename _Extents::index_type __linear_index_left(const _Extents& __exts, _Indices... __indices) noexcept { using _IndexType = typename _Extents::index_type; _IndexType __res = 0; if constexpr (sizeof...(__indices) > 0) { _IndexType __mult = 1; auto __update = [&, __pos = 0u](_IndexType __idx) mutable { _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos))); __res += __idx * __mult; __mult *= __exts.extent(__pos); ++__pos; }; (__update(__indices), ...); } return __res; } template consteval _IndexType __static_quotient(std::span __sta_exts, _IndexType __nom = __gnu_cxx::__int_traits<_IndexType>::__max) { for (auto __factor : __sta_exts) { if (__factor != dynamic_extent) __nom /= _IndexType(__factor); if (__nom == 0) break; } return __nom; } template requires __is_extents<_Extents> consteval _IndexType __static_quotient(_IndexType __nom = __gnu_cxx::__int_traits<_IndexType>::__max) { std::span __sta_exts = __static_extents<_Extents>(); return __static_quotient<_IndexType>(__sta_exts, __nom); } template constexpr bool __is_representable_extents(const _Extents& __exts) noexcept { using _IndexType = _Extents::index_type; if constexpr (__contains_zero(__static_extents<_Extents>())) return true; else { constexpr auto __sta_quo = __static_quotient<_Extents>(); if constexpr (_Extents::rank_dynamic() == 0) return __sta_quo != 0; else { auto __dyn_exts = __dynamic_extents(__exts); if (__contains_zero(__dyn_exts)) return true; if constexpr (__sta_quo == 0) return false; else { auto __dyn_quo = _IndexType(__sta_quo); for (auto __factor : __dyn_exts) { __dyn_quo /= __factor; if (__dyn_quo == 0) return false; } return true; } } } } template concept __representable_size = _Extents::rank_dynamic() != 0 || __contains_zero(__static_extents<_Extents>()) || (__static_quotient<_Extents, _IndexType>() != 0); template concept __mapping_of = is_same_v, _Mapping>; template typename _Layout, typename _Mapping> concept __padded_mapping_of = __mapping_of< _Layout<_Mapping::padding_value>, _Mapping>; #ifdef __glibcxx_padded_layouts template constexpr bool __is_left_padded_mapping = __padded_mapping_of< layout_left_padded, _Mapping>; template constexpr bool __is_right_padded_mapping = __padded_mapping_of< layout_right_padded, _Mapping>; template constexpr bool __is_padded_mapping = __is_left_padded_mapping<_Mapping> || __is_right_padded_mapping<_Mapping>; #endif template consteval size_t __get_static_stride() { return _PaddedMapping::_PaddedStorage::_S_static_stride; } template concept __standardized_mapping = __mapping_of || __mapping_of || __mapping_of #ifdef __glibcxx_padded_layouts || __is_left_padded_mapping<_Mapping> || __is_right_padded_mapping<_Mapping> #endif ; // A tag type to create internal ctors. class __internal_ctor { }; template constexpr typename _Mapping::index_type __offset(const _Mapping& __m) noexcept { using _IndexType = typename _Mapping::index_type; constexpr auto __rank = _Mapping::extents_type::rank(); if constexpr (__standardized_mapping<_Mapping>) return 0; else if (__empty(__m.extents())) return 0; else { auto __impl = [&__m](index_sequence<_Counts...>) { return __m(((void) _Counts, _IndexType(0))...); }; return __impl(make_index_sequence<__rank>()); } } #ifdef __glibcxx_submdspan template constexpr bool __is_strided_slice = false; template constexpr bool __is_strided_slice> = true; template consteval bool __is_representable_integer(_OIndexType __value) { constexpr auto __min = __gnu_cxx::__int_traits<_IndexType>::__min; constexpr auto __max = __gnu_cxx::__int_traits<_IndexType>::__max; return std::cmp_less_equal(__min, __value) && std::cmp_less_equal(__value, __max); } template constexpr bool __is_constant_wrapper = false; template<_CwFixedValue _Xv, typename _Tp> constexpr bool __is_constant_wrapper> = true; template constexpr auto __extract_extent(const _Extents& __exts) { using _IndexType = typename _Extents::index_type; return extents<_IndexType, _Extents::static_extent(_Index)>{ __exts.extent(_Index)}; } template concept __acceptable_slice_type = same_as<_Slice, full_extent_t> || same_as<_Slice, _IndexType> || __is_constant_wrapper<_Slice> || __is_strided_slice<_Slice>; template consteval auto __subrank() { return (static_cast(!convertible_to<_Slices, _IndexType>) + ... + 0); } template consteval auto __inv_map_rank() { constexpr auto __rank = sizeof...(_Slices); constexpr auto __sub_rank = __subrank<_IndexType, _Slices...>(); auto __map = std::array{}; auto __is_int_like = std::array{ convertible_to<_Slices, _IndexType>...}; size_t __i = 0; for (size_t __k = 0; __k < __rank; ++__k) if (!__is_int_like[__k]) __map[__i++] = __k; return __map; } template constexpr auto __slice_begin(_Slice __slice) { if constexpr (same_as<_Slice, full_extent_t>) return 0; else if constexpr (__is_strided_slice<_Slice>) return __slice.offset; else return __slice; // collapsing slice } template constexpr size_t __suboffset(const _Mapping& __mapping, const _Slices&... __slices) { using _IndexType = typename _Mapping::index_type; auto __any_past_the_end = [&](index_sequence<_Is...>) { auto __is_past_the_end = [](const auto& __slice, const auto& __ext) { using _Slice = remove_cvref_t; if constexpr (is_convertible_v<_Slice, _IndexType>) return false; else if constexpr (same_as<_Slice, full_extent_t> && __ext.static_extent(0) != 0 && __ext.static_extent(0) != dynamic_extent) return false; else return __mdspan::__slice_begin(__slice) == __ext.extent(0); }; const auto& __exts = __mapping.extents(); return ((__is_past_the_end(__slices...[_Is], __mdspan::__extract_extent<_Is>(__exts))) || ...); }; if constexpr ((same_as<_Slices, full_extent_t> && ...)) return __mdspan::__offset(__mapping); if (__any_past_the_end(std::make_index_sequence())) return __mapping.required_span_size(); return __mapping(__mdspan::__slice_begin(__slices)...); } template consteval size_t __static_slice_extent() { if constexpr (same_as<_Slice, full_extent_t>) return _Extent; else if constexpr (same_as<_Slice, constant_wrapper<_IndexType(0)>>) return 0; else if constexpr (__is_constant_wrapper && __is_constant_wrapper) return 1 + ((typename _Slice::extent_type{}) - 1) / (typename _Slice::stride_type{}); else return dynamic_extent; } template constexpr typename _Extents::index_type __dynamic_slice_extent(const _Extents& __exts, _Slice __slice) { if constexpr (__is_strided_slice<_Slice>) return __slice.extent == 0 ? 0 : 1 + (__slice.extent - 1) / __slice.stride; else return __exts.extent(_K); } template requires (sizeof...(_Slices) == sizeof...(_Extents)) constexpr auto __subextents(const extents<_IndexType, _Extents...>& __exts, _Slices... __slices) { constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>(); auto __impl = [&](std::index_sequence<_Indices...>) { using _SubExts = extents<_IndexType, __mdspan::__static_slice_extent<_IndexType, _Extents...[__inv_map[_Indices]], _Slices...[__inv_map[_Indices]]>()...>; if constexpr (_SubExts::rank_dynamic() == 0) return _SubExts{}; else { using _StaticSubExtents = __mdspan::_StaticExtents< __mdspan::__static_extents<_SubExts>()>; auto __create = [&](std::index_sequence<_Is...>) { constexpr auto __slice_idx = [__inv_map](size_t __i) consteval { return __inv_map[_StaticSubExtents::_S_dynamic_index_inv(__i)]; }; return _SubExts{__mdspan::__dynamic_slice_extent<__slice_idx(_Is)>( __exts, __slices...[__slice_idx(_Is)])...}; }; constexpr auto __dyn_subrank = _SubExts::rank_dynamic(); return __create(std::make_index_sequence<__dyn_subrank>()); } }; return __impl(std::make_index_sequence<__inv_map.size()>()); } enum class _LayoutSide { __left, __right, __unknown }; template consteval _LayoutSide __mapping_side() { if constexpr (__is_left_padded_mapping<_Mapping> || __mapping_of) return _LayoutSide::__left; if constexpr (__is_right_padded_mapping<_Mapping> || __mapping_of) return _LayoutSide::__right; else return _LayoutSide::__unknown; } template<_LayoutSide _Side, size_t _Rank> struct _StridesTrait { static constexpr const _LayoutSide _S_side = _Side; static constexpr size_t _S_idx(size_t __k) noexcept { if constexpr (_Side == _LayoutSide::__left) return __k; else return _Rank - 1 - __k; } // Unifies the formulas for computing strides for padded and unpadded // layouts. template static constexpr typename _Mapping::index_type _S_padded_extent(const _Mapping& __mapping, size_t __k) { if (__k == 0) return __mapping.stride(_S_idx(1)); else return __mapping.extents().extent(_S_idx(__k)); } template static consteval auto _S_inv_map() { static_assert(_Side != _LayoutSide::__unknown); auto __impl = [&](std::index_sequence<_Is...>) { return __mdspan::__inv_map_rank<_IndexType, _Slices...[_S_idx(_Is)]...>(); }; return __impl(std::make_index_sequence<_Rank>()); } }; template constexpr auto __substrides_generic(const _Mapping& __mapping, const _Slices&... __slices) { using _IndexType = typename _Mapping::index_type; if constexpr (_SubExts::rank() == 0) return array<_IndexType, _SubExts::rank()>{}; else { auto __stride = [&__mapping](size_t __k, auto __slice) -> _IndexType { if constexpr (__is_strided_slice) if (__slice.stride < __slice.extent) return __mapping.stride(__k) * __slice.stride; return __mapping.stride(__k); }; auto __impl = [&](std::index_sequence<_Is...>) { constexpr auto __inv_map = __mdspan::__inv_map_rank<_IndexType, _Slices...>(); return array<_IndexType, _SubExts::rank()>{ __stride(__inv_map[_Is], __slices...[__inv_map[_Is]])...}; }; return __impl(std::make_index_sequence<_SubExts::rank()>()); } }; template constexpr auto __substrides_standardized(const _Mapping& __mapping, const _Slices&... __slices) { using _IndexType = typename _Mapping::index_type; using _Trait = _StridesTrait<__mapping_side<_Mapping>(), _Mapping::extents_type::rank()>; using _SubTrait = _StridesTrait<__mapping_side<_Mapping>(), _SubExts::rank()>; constexpr size_t __sub_rank = _SubExts::rank(); std::array<_IndexType, __sub_rank> __ret; if constexpr (__sub_rank > 0) { constexpr auto __inv_map = _Trait::template _S_inv_map<_IndexType, _Slices...>(); auto __loop = [&](std::index_sequence<_Ks...>) { size_t __i0 = 0; size_t __stride = 1; auto __body = [&](size_t __k, auto __slice) { for (size_t __i = __i0; __i < __inv_map[__k]; ++__i) __stride *= _Trait::_S_padded_extent(__mapping, __i); size_t __krev = _SubTrait::_S_idx(__k); if constexpr (__is_strided_slice) { if (__slice.stride < __slice.extent) __ret[__krev] = __stride * __slice.stride; else __ret[__krev] = __stride; } else __ret[__krev] = __stride; __i0 = __inv_map[__k]; }; ((__body(_Ks, __slices...[_Trait::_S_idx(__inv_map[_Ks])])),...); }; __loop(std::make_index_sequence<__sub_rank>()); } return __ret; } template constexpr auto __substrides(const _Mapping& __mapping, const _Slices&... __slices) { if constexpr (__mdspan::__mapping_side<_Mapping>() == _LayoutSide::__unknown) return __mdspan::__substrides_generic<_SubExts>(__mapping, __slices...); else return __mdspan::__substrides_standardized<_SubExts>(__mapping, __slices...); } template concept __is_unit_stride_slice = (__mdspan::__is_strided_slice<_Slice> && __mdspan::__is_constant_wrapper && _Slice::stride_type::value == 1) || std::same_as<_Slice, full_extent_t>; // These are (forced) exclusive categories: // - full & collapsing: obvious, // - unit_strided_slice: strided_slice{a, b, cw<1>}, but not `full`, // - strided_slice: strided_slice{a, b, c} with c != cw<1>. enum class _SliceKind { __strided_slice, __unit_strided_slice, __full, __collapsing }; template consteval _SliceKind __make_slice_kind() { if constexpr (std::same_as<_Slice, full_extent_t>) return _SliceKind::__full; else if constexpr (__mdspan::__is_strided_slice<_Slice>) { if constexpr (__mdspan::__is_unit_stride_slice<_Slice>) return _SliceKind::__unit_strided_slice; else return _SliceKind::__strided_slice; } else return _SliceKind::__collapsing; } template consteval array<_SliceKind, sizeof...(_Slices)> __make_slice_kind_array() { return array<_SliceKind, sizeof...(_Slices)>{ __mdspan::__make_slice_kind<_Slices>()...}; } // __block_size - 1 // [full, ..., full, unit_slice , *] consteval bool __is_block(span __slice_kinds, size_t __block_size) { if (__block_size == 0) return false; if (__block_size > __slice_kinds.size()) return false; for (size_t __i = 0; __i < __block_size - 1; ++__i) if (__slice_kinds[__i] != _SliceKind::__full) return false; auto __last = __slice_kinds[__block_size - 1]; return __last == _SliceKind::__full || __last == _SliceKind::__unit_strided_slice; } // __u __u + __sub_rank-2 // [unit_slice, i, ..., k, full, ..., full, unit_slice, *] static consteval size_t __padded_block_begin_generic(span __slice_kinds, size_t __sub_rank) { if (__slice_kinds[0] != _SliceKind::__full && __slice_kinds[0] != _SliceKind::__unit_strided_slice) return dynamic_extent; else if (__slice_kinds.size() == 1) return dynamic_extent; else { size_t __u = 1; while(__u < __slice_kinds.size() && __slice_kinds[__u] == _SliceKind::__collapsing) ++__u; if (__mdspan::__is_block(__slice_kinds.subspan(__u), __sub_rank -1)) return __u; return dynamic_extent; } } template<_LayoutSide _Side, size_t _Nm> static consteval size_t __padded_block_begin(span __slice_kinds, size_t __sub_rank) { if constexpr (_Side == _LayoutSide::__left) return __mdspan::__padded_block_begin_generic(__slice_kinds, __sub_rank); else { std::array<_SliceKind, _Nm> __rev_slices; for(size_t __i = 0; __i < _Nm; ++__i) __rev_slices[__i] = __slice_kinds[_Nm - 1 - __i]; auto __rev_slice_kinds = span(__rev_slices); auto __u = __mdspan::__padded_block_begin_generic(__rev_slice_kinds, __sub_rank); return __u == dynamic_extent ? dynamic_extent : _Nm - 1 - __u; } } template<_LayoutSide _Side, bool _Padded> struct _SubMdspanMapping; template<> struct _SubMdspanMapping<_LayoutSide::__left, false> { using _Layout = layout_left; template using _PaddedLayout = layout_left_padded<_Pad>; template static consteval size_t _S_pad() { using _Extents = typename _Mapping::extents_type; constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(0, _Us); if constexpr (!__mdspan::__all_static(__sta_exts)) return dynamic_extent; else return __mdspan::__fwd_prod(__sta_exts); } template static consteval bool _S_is_unpadded_submdspan(span __slice_kinds, size_t __sub_rank) { return __mdspan::__is_block(__slice_kinds, __sub_rank); } }; template<> struct _SubMdspanMapping<_LayoutSide::__left, true> { using _Layout = layout_left; template using _PaddedLayout = layout_left_padded<_Pad>; template static consteval size_t _S_pad() { using _Extents = typename _Mapping::extents_type; constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(1, _Us); constexpr auto __sta_padstride = __mdspan::__get_static_stride<_Mapping>(); if constexpr (__sta_padstride == dynamic_extent || !__mdspan::__all_static(__sta_exts)) return dynamic_extent; else return __sta_padstride * __mdspan::__fwd_prod(__sta_exts); } template static consteval bool _S_is_unpadded_submdspan(span __slice_kinds, size_t __sub_rank) { if (__sub_rank == 1) return __slice_kinds[0] == _SliceKind::__unit_strided_slice || __slice_kinds[0] == _SliceKind::__full; else return false; } }; template<> struct _SubMdspanMapping<_LayoutSide::__right, false> { using _Layout = layout_right; template using _PaddedLayout = layout_right_padded<_Pad>; template static consteval size_t _S_pad() { using _Extents = typename _Mapping::extents_type; constexpr auto __rank = _Extents::rank(); constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(_Us + 1, __rank); if constexpr (!__mdspan::__all_static(__sta_exts)) return dynamic_extent; else return __fwd_prod(__sta_exts); } template static consteval bool _S_is_unpadded_submdspan(span __slice_kinds, size_t __sub_rank) { auto __rev_slice_kinds = array<_SliceKind, _Nm>{}; for(size_t __i = 0; __i < _Nm; ++__i) __rev_slice_kinds[__i] = __slice_kinds[_Nm - 1 - __i]; return __mdspan::__is_block(span(__rev_slice_kinds), __sub_rank); } }; template<> struct _SubMdspanMapping<_LayoutSide::__right, true> { using _Layout = layout_right; template using _PaddedLayout = layout_right_padded<_Pad>; template static consteval size_t _S_pad() { using _Extents = typename _Mapping::extents_type; constexpr auto __rank = _Extents::rank(); constexpr auto __sta_exts = __mdspan::__static_extents<_Extents>(_Us + 1, __rank - 1); constexpr auto __sta_padstride = __mdspan::__get_static_stride<_Mapping>(); if constexpr (__sta_padstride == dynamic_extent || !__mdspan::__all_static(__sta_exts)) return dynamic_extent; else return __sta_padstride * __mdspan::__fwd_prod(__sta_exts); } template static consteval bool _S_is_unpadded_submdspan(span __slice_kinds, size_t __sub_rank) { if (__sub_rank == 1) return __slice_kinds[_Nm - 1] == _SliceKind::__unit_strided_slice || __slice_kinds[_Nm - 1] == _SliceKind::__full; else return false; } }; template constexpr auto __submdspan_mapping_impl(const _Mapping& __mapping) { return submdspan_mapping_result{__mapping, 0}; } template requires (sizeof...(_Slices) > 0) constexpr auto __submdspan_mapping_impl(const _Mapping& __mapping, _Slices... __slices) { using _IndexType = typename _Mapping::index_type; static_assert((__acceptable_slice_type<_Slices, _IndexType> && ...)); constexpr auto __side = __mdspan::__mapping_side<_Mapping>(); constexpr auto __rank = sizeof...(_Slices); using _Trait = _SubMdspanMapping<__side, __is_padded_mapping<_Mapping>>; using _SliceView = span; constexpr auto __slice_kinds = __mdspan::__make_slice_kind_array<_Slices...>(); auto __offset = __mdspan::__suboffset(__mapping, __slices...); auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...); using _SubExts = decltype(__sub_exts); constexpr auto __sub_rank = _SubExts::rank(); if constexpr (__sub_rank == 0) return submdspan_mapping_result{ typename _Trait::_Layout::mapping(__sub_exts), __offset}; else if constexpr (_Trait::_S_is_unpadded_submdspan( _SliceView(__slice_kinds), __sub_rank)) return submdspan_mapping_result{ typename _Trait::_Layout::mapping(__sub_exts), __offset}; else if constexpr ( constexpr auto __u = __padded_block_begin<__side>( _SliceView(__slice_kinds), __sub_rank); __u != dynamic_extent) { constexpr auto __pad = _Trait::template _S_pad<_Mapping, __u>(); using _Layout = typename _Trait::template _PaddedLayout<__pad>; return submdspan_mapping_result{ typename _Layout::mapping(__sub_exts, __mapping.stride(__u)), __offset}; } else { auto __sub_strides = __mdspan::__substrides<_SubExts>(__mapping, __slices...); return submdspan_mapping_result{ layout_stride::mapping(__sub_exts, __sub_strides), __offset}; } } #endif // __glibcxx_submdspan } template class layout_left::mapping { public: using extents_type = _Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; using layout_type = layout_left; static_assert(__mdspan::__representable_size, "The size of extents_type must be representable as index_type"); constexpr mapping() noexcept = default; constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type& __extents) noexcept : _M_extents(__extents) { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } template requires is_constructible_v constexpr explicit(!is_convertible_v<_OExtents, extents_type>) mapping(const mapping<_OExtents>& __other) noexcept : mapping(__other.extents(), __mdspan::__internal_ctor{}) { } template requires (extents_type::rank() <= 1) && is_constructible_v constexpr explicit(!is_convertible_v<_OExtents, extents_type>) mapping(const layout_right::mapping<_OExtents>& __other) noexcept : mapping(__other.extents(), __mdspan::__internal_ctor{}) { } // noexcept for consistency with other layouts. template requires is_constructible_v constexpr explicit(!(extents_type::rank() == 0 && is_convertible_v<_OExtents, extents_type>)) mapping(const layout_stride::mapping<_OExtents>& __other) noexcept : mapping(__other.extents(), __mdspan::__internal_ctor{}) { __glibcxx_assert(*this == __other); } #if __glibcxx_padded_layouts template requires __mdspan::__is_left_padded_mapping<_LeftpadMapping> && is_constructible_v constexpr explicit(!is_convertible_v) mapping(const _LeftpadMapping& __other) noexcept : mapping(__other.extents(), __mdspan::__internal_ctor{}) { constexpr size_t __ostride_sta = __mdspan::__get_static_stride<_LeftpadMapping>(); if constexpr (extents_type::rank() > 1) { if constexpr (extents_type::static_extent(0) != dynamic_extent && __ostride_sta != dynamic_extent) static_assert(extents_type::static_extent(0) == __ostride_sta); else __glibcxx_assert(__other.stride(1) == __other.extents().extent(0)); } } #endif // __glibcxx_padded_layouts constexpr mapping& operator=(const mapping&) noexcept = default; constexpr const extents_type& extents() const noexcept { return _M_extents; } constexpr index_type required_span_size() const noexcept { return __mdspan::__size(_M_extents); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4314. Missing move in mdspan layout mapping::operator() template<__mdspan::__valid_index_type... _Indices> requires (sizeof...(_Indices) == extents_type::rank()) constexpr index_type operator()(_Indices... __indices) const noexcept { return __mdspan::__linear_index_left(_M_extents, static_cast(std::move(__indices))...); } static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept { return true; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_exhaustive() noexcept { return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type __i) const noexcept requires (extents_type::rank() > 0) { __glibcxx_assert(__i < extents_type::rank()); return __mdspan::__fwd_prod(_M_extents, __i); } template requires (extents_type::rank() == _OExtents::rank()) friend constexpr bool operator==(const mapping& __self, const mapping<_OExtents>& __other) noexcept { return __self.extents() == __other.extents(); } private: template constexpr explicit mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept : _M_extents(__oexts) { static_assert(__mdspan::__representable_size<_OExtents, index_type>, "The size of OtherExtents must be representable as index_type"); __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } #if __glibcxx_submdspan template requires (extents_type::rank() == sizeof...(_Slices)) friend constexpr auto submdspan_mapping(const mapping& __mapping, _Slices... __slices) { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } #endif // __glibcxx_submdspan [[no_unique_address]] extents_type _M_extents{}; }; namespace __mdspan { template constexpr typename _Extents::index_type __linear_index_right(const _Extents& __exts, _Indices... __indices) noexcept { using _IndexType = typename _Extents::index_type; array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...}; _IndexType __res = 0; if constexpr (sizeof...(__indices) > 0) { _IndexType __mult = 1; auto __update = [&, __pos = __exts.rank()](_IndexType) mutable { --__pos; _GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos], __exts.extent(__pos))); __res += __ind_arr[__pos] * __mult; __mult *= __exts.extent(__pos); }; (__update(__indices), ...); } return __res; } } template class layout_right::mapping { public: using extents_type = _Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; using layout_type = layout_right; static_assert(__mdspan::__representable_size, "The size of extents_type must be representable as index_type"); constexpr mapping() noexcept = default; constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type& __extents) noexcept : _M_extents(__extents) { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } template requires is_constructible_v constexpr explicit(!is_convertible_v<_OExtents, extents_type>) mapping(const mapping<_OExtents>& __other) noexcept : mapping(__other.extents(), __mdspan::__internal_ctor{}) { } template requires (extents_type::rank() <= 1) && is_constructible_v constexpr explicit(!is_convertible_v<_OExtents, extents_type>) mapping(const layout_left::mapping<_OExtents>& __other) noexcept : mapping(__other.extents(), __mdspan::__internal_ctor{}) { } template requires is_constructible_v constexpr explicit(!(extents_type::rank() == 0 && is_convertible_v<_OExtents, extents_type>)) mapping(const layout_stride::mapping<_OExtents>& __other) noexcept : mapping(__other.extents(), __mdspan::__internal_ctor{}) { __glibcxx_assert(*this == __other); } #if __glibcxx_padded_layouts template requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> && is_constructible_v constexpr explicit(!is_convertible_v) mapping(const _RightPaddedMapping& __other) noexcept : mapping(__other.extents(), __mdspan::__internal_ctor{}) { constexpr size_t __rank = extents_type::rank(); constexpr size_t __ostride_sta = __mdspan::__get_static_stride<_RightPaddedMapping>(); if constexpr (__rank > 1) { if constexpr (extents_type::static_extent(__rank - 1) != dynamic_extent && __ostride_sta != dynamic_extent) static_assert(extents_type::static_extent(__rank - 1) == __ostride_sta); else __glibcxx_assert(__other.stride(__rank - 2) == __other.extents().extent(__rank - 1)); } } #endif constexpr mapping& operator=(const mapping&) noexcept = default; constexpr const extents_type& extents() const noexcept { return _M_extents; } constexpr index_type required_span_size() const noexcept { return __mdspan::__size(_M_extents); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4314. Missing move in mdspan layout mapping::operator() template<__mdspan::__valid_index_type... _Indices> requires (sizeof...(_Indices) == extents_type::rank()) constexpr index_type operator()(_Indices... __indices) const noexcept { return __mdspan::__linear_index_right( _M_extents, static_cast(std::move(__indices))...); } static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_always_exhaustive() noexcept { return true; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_exhaustive() noexcept { return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type __i) const noexcept requires (extents_type::rank() > 0) { __glibcxx_assert(__i < extents_type::rank()); return __mdspan::__rev_prod(_M_extents, __i); } template requires (extents_type::rank() == _OExtents::rank()) friend constexpr bool operator==(const mapping& __self, const mapping<_OExtents>& __other) noexcept { return __self.extents() == __other.extents(); } private: template constexpr explicit mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept : _M_extents(__oexts) { static_assert(__mdspan::__representable_size<_OExtents, index_type>, "The size of OtherExtents must be representable as index_type"); __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } #if __glibcxx_submdspan template requires (extents_type::rank() == sizeof...(_Slices)) friend constexpr auto submdspan_mapping(const mapping& __mapping, _Slices... __slices) { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } #endif // __glibcxx_submdspan [[no_unique_address]] extents_type _M_extents{}; }; namespace __mdspan { template concept __mapping_alike = requires { requires __is_extents; { _Mp::is_always_strided() } -> same_as; { _Mp::is_always_exhaustive() } -> same_as; { _Mp::is_always_unique() } -> same_as; bool_constant<_Mp::is_always_strided()>::value; bool_constant<_Mp::is_always_exhaustive()>::value; bool_constant<_Mp::is_always_unique()>::value; }; template constexpr typename _Mapping::index_type __linear_index_strides(const _Mapping& __m, _Indices... __indices) noexcept { using _IndexType = typename _Mapping::index_type; _IndexType __res = 0; if constexpr (sizeof...(__indices) > 0) { auto __update = [&, __pos = 0u](_IndexType __idx) mutable { _GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __m.extents().extent(__pos))); __res += __idx * __m.stride(__pos++); }; (__update(__indices), ...); } return __res; } } template class layout_stride::mapping { public: using extents_type = _Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; using layout_type = layout_stride; static_assert(__mdspan::__representable_size, "The size of extents_type must be representable as index_type"); constexpr mapping() noexcept { // The precondition is either statically asserted, or automatically // satisfied because dynamic extents are zero-initialized. size_t __stride = 1; for (size_t __i = extents_type::rank(); __i > 0; --__i) { _M_strides[__i - 1] = index_type(__stride); __stride *= size_t(_M_extents.extent(__i - 1)); } } constexpr mapping(const mapping&) noexcept = default; template requires __mdspan::__valid_index_type constexpr mapping(const extents_type& __exts, span<_OIndexType, extents_type::rank()> __strides) noexcept : _M_extents(__exts) { for (size_t __i = 0; __i < extents_type::rank(); ++__i) _M_strides[__i] = index_type(as_const(__strides[__i])); } template requires __mdspan::__valid_index_type constexpr mapping(const extents_type& __exts, const array<_OIndexType, extents_type::rank()>& __strides) noexcept : mapping(__exts, span(__strides)) { } template<__mdspan::__mapping_alike _StridedMapping> requires (is_constructible_v && _StridedMapping::is_always_unique() && _StridedMapping::is_always_strided()) constexpr explicit(!( is_convertible_v && __mdspan::__standardized_mapping<_StridedMapping>)) mapping(const _StridedMapping& __other) noexcept : _M_extents(__other.extents()) { using _OIndexType = _StridedMapping::index_type; using _OExtents = _StridedMapping::extents_type; __glibcxx_assert(__mdspan::__offset(__other) == 0); static_assert(__mdspan::__representable_size<_OExtents, index_type>, "The size of StridedMapping::extents_type must be representable as" " index_type"); if constexpr (cmp_greater(__gnu_cxx::__int_traits<_OIndexType>::__max, __gnu_cxx::__int_traits::__max)) __glibcxx_assert(!cmp_less( __gnu_cxx::__int_traits::__max, __other.required_span_size()) && "other.required_span_size() must be representable" " as index_type"); if constexpr (extents_type::rank() > 0) for (size_t __i = 0; __i < extents_type::rank(); ++__i) _M_strides[__i] = index_type(__other.stride(__i)); } constexpr mapping& operator=(const mapping&) noexcept = default; constexpr const extents_type& extents() const noexcept { return _M_extents; } constexpr array strides() const noexcept { array __ret; for (size_t __i = 0; __i < extents_type::rank(); ++__i) __ret[__i] = _M_strides[__i]; return __ret; } constexpr index_type required_span_size() const noexcept { if (__mdspan::__empty(_M_extents)) return 0; index_type __ret = 1; for (size_t __i = 0; __i < extents_type::rank(); ++__i) __ret += (_M_extents.extent(__i) - 1) * _M_strides[__i]; return __ret; } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4314. Missing move in mdspan layout mapping::operator() template<__mdspan::__valid_index_type... _Indices> requires (sizeof...(_Indices) == extents_type::rank()) constexpr index_type operator()(_Indices... __indices) const noexcept { return __mdspan::__linear_index_strides(*this, static_cast(std::move(__indices))...); } static constexpr bool is_always_unique() noexcept { return true; } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4266. layout_stride::mapping should treat empty mappings as exhaustive static constexpr bool is_always_exhaustive() noexcept { return (_Extents::rank() == 0) || __mdspan::__contains_zero( __mdspan::__static_extents()); } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4266. layout_stride::mapping should treat empty mappings as exhaustive constexpr bool is_exhaustive() const noexcept { if constexpr (!is_always_exhaustive()) { auto __size = __mdspan::__size(_M_extents); if(__size > 0) return __size == required_span_size(); } return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type __r) const noexcept { return _M_strides[__r]; } template<__mdspan::__mapping_alike _OMapping> requires ((extents_type::rank() == _OMapping::extents_type::rank()) && _OMapping::is_always_strided()) friend constexpr bool operator==(const mapping& __self, const _OMapping& __other) noexcept { if (__self.extents() != __other.extents()) return false; if constexpr (extents_type::rank() > 0) for (size_t __i = 0; __i < extents_type::rank(); ++__i) if (!cmp_equal(__self.stride(__i), __other.stride(__i))) return false; return __mdspan::__offset(__other) == 0; } private: #if __glibcxx_submdspan template requires (extents_type::rank() == sizeof...(_Slices)) friend constexpr auto submdspan_mapping(const mapping& __mapping, _Slices... __slices) { if constexpr (sizeof...(_Slices) == 0) return submdspan_mapping_result{__mapping, 0}; else { auto __offset = __mdspan::__suboffset(__mapping, __slices...); auto __sub_exts = __mdspan::__subextents(__mapping.extents(), __slices...); auto __sub_strides = __mdspan::__substrides(__mapping, __slices...); return submdspan_mapping_result{ layout_stride::mapping(__sub_exts, __sub_strides), __offset}; } } #endif using _Strides = typename __array_traits::_Type; [[no_unique_address]] extents_type _M_extents; [[no_unique_address]] _Strides _M_strides; }; #ifdef __glibcxx_padded_layouts namespace __mdspan { constexpr size_t __least_multiple(size_t __x, size_t __y) { if (__x <= 1) return __y; return (__y / __x + (__y % __x != 0)) * __x ; } template constexpr bool __is_representable_least_multiple(size_t __x, size_t __y) { constexpr auto __y_max = __gnu_cxx::__int_traits<_IndexType>::__max; if(std::cmp_greater(__y, __y_max)) return false; if(__x <= 1) return true; auto __max_delta = __y_max - static_cast<_IndexType>(__y); auto __y_mod_x = __y % __x; auto __delta = (__y_mod_x == 0) ? size_t(0) : (__x - __y_mod_x); return std::cmp_less_equal(__delta, __max_delta); } template concept __valid_static_stride = (_Extents::rank() <= 1) || (_PaddingValue == dynamic_extent) || (_Extents::static_extent(_LayoutTraits::_S_ext_idx) == dynamic_extent) || (__is_representable_least_multiple( _PaddingValue, _Extents::static_extent(_LayoutTraits::_S_ext_idx))); template consteval bool __is_representable_padded_size() { using _IndexType = typename _Extents::index_type; auto __sta_exts = __static_extents<_Extents>( _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end); size_t __max = __gnu_cxx::__int_traits<_IndexType>::__max; return __static_quotient(__sta_exts, __max / _PaddedStride) != 0; } template concept __valid_padded_size = (_Rank <= 1) || (_PaddedStride == dynamic_extent) || (!__all_static(__static_extents<_Extents>())) || (__contains_zero(__static_extents<_Extents>())) || (__is_representable_padded_size<_PaddedStride, _Extents, _LayoutTraits>()); template constexpr typename _Extents::index_type __linear_index_leftpad(const _Extents& __exts, _Stride __stride, _Indices... __indices) { // i0 + stride*(i1 + extents.extent(1)*...) using _IndexType = typename _Extents::index_type; _IndexType __res = 0; if constexpr (sizeof...(__indices) > 0) { _IndexType __mult = 1; auto __update_rest = [&, __pos = 1u](_IndexType __idx) mutable { __res += __idx * __mult; __mult *= __exts.extent(__pos); ++__pos; }; auto __update = [&](_IndexType __idx, auto... __rest) { __res += __idx; __mult = __stride.extent(0); (__update_rest(__rest), ...); }; __update(__indices...); } return __res; } template constexpr typename _Extents::index_type __linear_index_rightpad(const _Extents& __exts, _Stride __stride, _Indices... __indices) { // i[n-1] + stride*(i[n-2] + extents.extent(n-2])*...) using _IndexType = typename _Extents::index_type; _IndexType __res = 0; if constexpr (sizeof...(__indices) > 0) { _IndexType __mult = 1; array<_IndexType, sizeof...(__indices)> __ind_arr{__indices...}; auto __update_rest = [&, __pos = __exts.rank()-1](_IndexType) mutable { --__pos; __res += __ind_arr[__pos] * __mult; __mult *= __exts.extent(__pos); }; auto __update = [&](_IndexType, auto... __rest) { __res += __ind_arr[__exts.rank() - 1]; __mult = __stride.extent(0); (__update_rest(__rest), ...); }; __update(__indices...); } return __res; } template struct _LeftPaddedLayoutTraits { using _LayoutSame = layout_left; using _LayoutOther = layout_right; constexpr static const size_t _S_ext_idx = 0; constexpr static const size_t _S_stride_idx = 1; constexpr static const size_t _S_unpad_begin = 1; constexpr static const size_t _S_unpad_end = _Rank; template constexpr static auto _S_make_padded_extent( extents<_IndexType, _StaticStride> __stride, const extents<_IndexType, _Extents...>& __exts) { auto __impl = [&](integer_sequence) { return extents<_IndexType, _StaticStride, (_Extents...[_Is + 1])...>{ __stride.extent(0), __exts.extent(_Is + 1)...}; }; return __impl(make_index_sequence()); } }; template struct _RightPaddedLayoutTraits { using _LayoutSame = layout_right; using _LayoutOther = layout_left; constexpr static size_t _S_ext_idx = _Rank - 1; constexpr static size_t _S_stride_idx = _Rank - 2; constexpr static size_t _S_unpad_begin = 0; constexpr static size_t _S_unpad_end = _Rank - 1; template constexpr static auto _S_make_padded_extent( extents<_IndexType, _StaticStride> __stride, const extents<_IndexType, _Extents...>& __exts) { auto __impl = [&](integer_sequence) { return extents<_IndexType, (_Extents...[_Is])..., _StaticStride>{ __exts.extent(_Is)..., __stride.extent(0)}; }; return __impl(make_index_sequence()); } }; template class _PaddedStorage { using _LayoutSame = typename _LayoutTraits::_LayoutSame; public: using _IndexType = typename _Extents::index_type; constexpr static size_t _S_rank = _Extents::rank(); // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4372. Weaken Mandates: for dynamic padding values in padded layouts static_assert((_PaddingValue == dynamic_extent) || (cmp_less_equal(_PaddingValue, __gnu_cxx::__int_traits<_IndexType>::__max)), "padding_value must be representable as index_type"); static_assert(__representable_size<_Extents, _IndexType>, "The size of extents_type must be representable as index_type"); static_assert(__valid_static_stride<_Extents, _PaddingValue, _LayoutTraits>, "The padded stride must be representable as size_t"); static constexpr size_t _S_static_stride = [] consteval { constexpr size_t __rank = _Extents::rank(); if constexpr (__rank <= 1) return 0; else { constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx; constexpr size_t __sta_ext = _Extents::static_extent(__ext_idx); if constexpr (__sta_ext == 0) return size_t(0); else if constexpr (_PaddingValue == dynamic_extent || __sta_ext == dynamic_extent) return dynamic_extent; else return __least_multiple(_PaddingValue, __sta_ext); } }(); static_assert(_S_static_stride == dynamic_extent || cmp_less_equal(_S_static_stride, __gnu_cxx::__int_traits<_IndexType>::__max), "Padded stride must be representable as index_type"); static_assert(__valid_padded_size<_Extents, _S_static_stride, _LayoutTraits>); constexpr _PaddedStorage() noexcept { if constexpr (_S_rank > 1) if constexpr (_S_static_stride == dynamic_extent && _S_static_padextent() != dynamic_extent) _M_stride = _Stride{_S_static_padextent()}; } constexpr explicit _PaddedStorage(const _Extents& __exts) : _M_extents(__exts) { if constexpr (!__all_static(__static_extents<_Extents>())) __glibcxx_assert(__is_representable_extents(_M_extents)); if constexpr (_S_rank > 1) { _IndexType __stride; if constexpr (_PaddingValue == dynamic_extent) __stride = _M_padextent(); else if constexpr (_S_static_padextent() != dynamic_extent) return; else { __glibcxx_assert( __is_representable_least_multiple<_IndexType>( _PaddingValue, _M_padextent())); __stride = static_cast<_IndexType>( __least_multiple(_PaddingValue, _M_padextent())); __glibcxx_assert(__is_representable_extents( _LayoutTraits::_S_make_padded_extent( std::dextents<_IndexType, 1>{__stride}, _M_extents))); } _M_stride = _Stride{__stride}; } } constexpr explicit _PaddedStorage(const _Extents& __exts, _IndexType __pad) : _M_extents(__exts) { if constexpr (_PaddingValue != dynamic_extent) __glibcxx_assert(cmp_equal(_PaddingValue, __pad)); if constexpr (_S_rank > 1 && _S_static_stride == dynamic_extent) { __glibcxx_assert( __is_representable_least_multiple<_IndexType>( __pad, _M_padextent())); _M_stride = _Stride{static_cast<_IndexType>( __least_multiple(__pad, _M_padextent()))}; __glibcxx_assert(__is_representable_extents( _LayoutTraits::_S_make_padded_extent( _M_stride, _M_extents))); } } template constexpr explicit _PaddedStorage( const typename _LayoutSame::template mapping<_OExtents>& __other) : _PaddedStorage(_Extents(__other.extents())) { constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx; constexpr size_t __ext_idx = _LayoutTraits::_S_ext_idx; if constexpr (_S_rank > 1 && _PaddingValue != dynamic_extent) { static_assert(_S_static_stride == dynamic_extent || _OExtents::static_extent(__ext_idx) == dynamic_extent || _S_static_stride == _OExtents::static_extent(__ext_idx), "The padded stride must be compatible with other"); if constexpr (_S_static_stride == dynamic_extent || _OExtents::static_extent(__stride_idx) == dynamic_extent) __glibcxx_assert(std::cmp_equal(_M_padstride(), _M_padextent())); } } template constexpr explicit _PaddedStorage(const typename layout_stride::mapping<_OExtents>& __other) : _M_extents(__other.extents()) { __glibcxx_assert(cmp_less_equal(__other.required_span_size(), __gnu_cxx::__int_traits<_IndexType> ::__max)); constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx; if constexpr (_S_rank > 1) { if constexpr (_PaddingValue != dynamic_extent) __glibcxx_assert(cmp_equal(__other.stride(__stride_idx), _M_calc_padstride()) && "The padded stride must be compatible with other"); if constexpr (_S_static_stride == dynamic_extent) _M_stride = _Stride{__other.stride(__stride_idx)}; } } template constexpr explicit _PaddedStorage(_LayoutTraits::_LayoutSame, const _SamePaddedMapping& __other) : _M_extents(__other.extents()) { if constexpr (_S_rank > 1) { static_assert(_PaddingValue == dynamic_extent || _SamePaddedMapping::padding_value == dynamic_extent || _PaddingValue == _SamePaddedMapping::padding_value, "If neither PaddingValue is dynamic_extent, then they must " "be equal"); constexpr size_t __stride_idx = _LayoutTraits::_S_stride_idx; if constexpr (_PaddingValue != dynamic_extent) __glibcxx_assert(cmp_equal(__other.stride(__stride_idx), _M_calc_padstride()) && "The padded stride must be compatible with other"); if constexpr (_S_static_stride == dynamic_extent) _M_stride = _Stride{__other.stride(__stride_idx)}; } __glibcxx_assert(cmp_less_equal(__other.required_span_size(), __gnu_cxx::__int_traits<_IndexType>::__max)); } template constexpr explicit _PaddedStorage(_LayoutTraits::_LayoutOther, const _OtherPaddedMapping& __other) noexcept : _M_extents(__other.extents()) { __glibcxx_assert(cmp_less_equal(__other.required_span_size(), __gnu_cxx::__int_traits<_IndexType>::__max)); } static constexpr bool _M_is_always_exhaustive() noexcept { if constexpr (_S_rank <= 1) return true; else return _S_static_padextent() != dynamic_extent && _S_static_stride != dynamic_extent && _S_static_padextent() == _S_static_stride; } constexpr bool _M_is_exhaustive() const noexcept { if constexpr (_M_is_always_exhaustive()) return true; else return cmp_equal(_M_padextent(), _M_padstride()); } constexpr static size_t _S_static_padextent() noexcept { return _Extents::static_extent(_LayoutTraits::_S_ext_idx); } constexpr _IndexType _M_padextent() const noexcept { return _M_extents.extent(_LayoutTraits::_S_ext_idx); } constexpr _IndexType _M_calc_padstride() const noexcept { if constexpr (_S_static_stride != dynamic_extent) return _S_static_stride; else if constexpr (_PaddingValue != dynamic_extent) return __least_multiple(_PaddingValue, _M_padextent()); else return _M_padextent(); } constexpr _IndexType _M_padstride() const noexcept { return _M_stride.extent(0); } constexpr _IndexType _M_required_span_size() const noexcept { if constexpr (_S_rank == 0) return 1; else if (__mdspan::__empty(_M_extents)) return 0; else { size_t __stride = static_cast(_M_padstride()); size_t __prod_rest = __mdspan::__fwd_prod(_M_extents, _LayoutTraits::_S_unpad_begin, _LayoutTraits::_S_unpad_end); size_t __delta = _M_padstride() - _M_padextent(); return static_cast<_IndexType>(__stride * __prod_rest - __delta); } } template constexpr bool _M_equal(const _SamePaddedMapping& __other) const noexcept { return _M_extents == __other.extents() && (_S_rank < 2 || cmp_equal(_M_stride.extent(0), __other.stride(_LayoutTraits::_S_stride_idx))); } using _Stride = std::extents<_IndexType, _S_static_stride>; [[no_unique_address]] _Stride _M_stride; [[no_unique_address]] _Extents _M_extents; }; } template template class layout_left_padded<_PaddingValue>::mapping { public: static constexpr size_t padding_value = _PaddingValue; using extents_type = _Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; using layout_type = layout_left_padded; private: static constexpr size_t _S_rank = extents_type::rank(); using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue, _Extents, __mdspan::_LeftPaddedLayoutTraits<_S_rank>>; [[no_unique_address]] _PaddedStorage _M_storage; consteval friend size_t __mdspan::__get_static_stride(); constexpr index_type _M_extent(size_t __r) const noexcept { return _M_storage._M_extents.extent(__r); } constexpr index_type _M_padstride() const noexcept { return _M_storage._M_stride.extent(0); } public: constexpr mapping() noexcept { } constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type& __exts) : _M_storage(__exts) { } template<__mdspan::__valid_index_type _OIndexType> constexpr mapping(const extents_type& __exts, _OIndexType __pad) : _M_storage(__exts, __mdspan::__index_type_cast(std::move(__pad))) { } template requires is_constructible_v constexpr explicit(!is_convertible_v<_OExtents, extents_type>) mapping(const layout_left::mapping<_OExtents>& __other) : _M_storage(__other) { } template requires is_constructible_v<_OExtents, extents_type> constexpr explicit(!(_OExtents::rank() == 0 && is_convertible_v<_OExtents, extents_type>)) mapping(const typename layout_stride::mapping<_OExtents>& __other) : _M_storage(__other) { __glibcxx_assert(*this == __other); } template requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping> && is_constructible_v constexpr explicit( !is_convertible_v || _S_rank > 1 && (padding_value != dynamic_extent || _LeftPaddedMapping::padding_value == dynamic_extent)) mapping(const _LeftPaddedMapping& __other) : _M_storage(layout_left{}, __other) { } template requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping> || __mdspan::__mapping_of) && (_S_rank <= 1) && is_constructible_v constexpr explicit(!is_convertible_v< typename _RightPaddedMapping::extents_type, extents_type>) mapping(const _RightPaddedMapping& __other) noexcept : _M_storage(layout_right{}, __other) { } constexpr mapping& operator=(const mapping&) noexcept = default; constexpr const extents_type& extents() const noexcept { return _M_storage._M_extents; } constexpr array strides() const noexcept { array __ret; if constexpr (_S_rank > 0) __ret[0] = 1; if constexpr (_S_rank > 1) __ret[1] = _M_padstride(); if constexpr (_S_rank > 2) for(size_t __i = 2; __i < _S_rank; ++__i) __ret[__i] = __ret[__i - 1] * _M_extent(__i - 1); return __ret; } constexpr index_type required_span_size() const noexcept { return _M_storage._M_required_span_size(); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4314. Missing move in mdspan layout mapping::operator() template<__mdspan::__valid_index_type... _Indices> requires (sizeof...(_Indices) == _S_rank) constexpr index_type operator()(_Indices... __indices) const noexcept { return __mdspan::__linear_index_leftpad( extents(), _M_storage._M_stride, static_cast(std::move(__indices))...); } static constexpr bool is_always_exhaustive() noexcept { return _PaddedStorage::_M_is_always_exhaustive(); } constexpr bool is_exhaustive() noexcept { return _M_storage._M_is_exhaustive(); } static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type __r) const noexcept { __glibcxx_assert(__r < _S_rank); if (__r == 0) return 1; else return static_cast( static_cast(_M_padstride()) * static_cast(__mdspan::__fwd_prod(extents(), 1, __r))); } template requires(__mdspan::__is_left_padded_mapping<_LeftpadMapping> && _LeftpadMapping::extents_type::rank() == _S_rank) friend constexpr bool operator==(const mapping& __self, const _LeftpadMapping& __other) noexcept { return __self._M_storage._M_equal(__other); } private: #if __glibcxx_submdspan template requires (extents_type::rank() == sizeof...(_Slices)) friend constexpr auto submdspan_mapping(const mapping& __mapping, _Slices... __slices) { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } #endif // __glibcxx_submdspan }; template template class layout_right_padded<_PaddingValue>::mapping { public: static constexpr size_t padding_value = _PaddingValue; using extents_type = _Extents; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; using layout_type = layout_right_padded<_PaddingValue>; private: static constexpr size_t _S_rank = extents_type::rank(); using _PaddedStorage = __mdspan::_PaddedStorage<_PaddingValue, _Extents, __mdspan::_RightPaddedLayoutTraits<_S_rank>>; [[no_unique_address]] _PaddedStorage _M_storage; consteval friend size_t __mdspan::__get_static_stride(); constexpr index_type _M_extent(size_t __r) const noexcept { return _M_storage._M_extents.extent(__r); } constexpr index_type _M_padstride() const noexcept { return _M_storage._M_stride.extent(0); } public: constexpr mapping() noexcept { } constexpr mapping(const mapping&) noexcept = default; constexpr mapping(const extents_type& __exts) : _M_storage(__exts) { } template<__mdspan::__valid_index_type _OIndexType> constexpr mapping(const extents_type& __exts, _OIndexType __pad) : _M_storage(__exts, __mdspan::__index_type_cast(std::move(__pad))) { } template requires is_constructible_v constexpr explicit(!is_convertible_v<_OExtents, extents_type>) mapping(const layout_right::mapping<_OExtents>& __other) : _M_storage(__other) { } template requires is_constructible_v<_OExtents, extents_type> constexpr explicit(!(_OExtents::rank() == 0 && is_convertible_v<_OExtents, extents_type>)) mapping(const typename layout_stride::mapping<_OExtents>& __other) : _M_storage(__other) { __glibcxx_assert(*this == __other); } template requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> && is_constructible_v constexpr explicit( !is_convertible_v || _S_rank > 1 && (padding_value != dynamic_extent || _RightPaddedMapping::padding_value == dynamic_extent)) mapping(const _RightPaddedMapping& __other) : _M_storage(layout_right{}, __other) { } template requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping> || __mdspan::__mapping_of) && (_S_rank <= 1) && is_constructible_v constexpr explicit(!is_convertible_v< typename _LeftPaddedMapping::extents_type, extents_type>) mapping(const _LeftPaddedMapping& __other) noexcept : _M_storage(layout_left{}, __other) { } constexpr mapping& operator=(const mapping&) noexcept = default; constexpr const extents_type& extents() const noexcept { return _M_storage._M_extents; } constexpr array strides() const noexcept { array __ret; if constexpr (_S_rank > 0) __ret[_S_rank - 1] = 1; if constexpr (_S_rank > 1) __ret[_S_rank - 2] = _M_padstride(); if constexpr (_S_rank > 2) for(size_t __i = _S_rank - 2; __i > 0; --__i) __ret[__i - 1] = __ret[__i] * _M_extent(__i); return __ret; } constexpr index_type required_span_size() const noexcept { return _M_storage._M_required_span_size(); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 4314. Missing move in mdspan layout mapping::operator() template<__mdspan::__valid_index_type... _Indices> requires (sizeof...(_Indices) == _S_rank) constexpr index_type operator()(_Indices... __indices) const noexcept { return __mdspan::__linear_index_rightpad( extents(), _M_storage._M_stride, static_cast(std::move(__indices))...); } static constexpr bool is_always_exhaustive() noexcept { return _PaddedStorage::_M_is_always_exhaustive(); } constexpr bool is_exhaustive() noexcept { return _M_storage._M_is_exhaustive(); } static constexpr bool is_always_unique() noexcept { return true; } static constexpr bool is_unique() noexcept { return true; } static constexpr bool is_always_strided() noexcept { return true; } static constexpr bool is_strided() noexcept { return true; } constexpr index_type stride(rank_type __r) const noexcept { __glibcxx_assert(__r < _S_rank); if constexpr (_S_rank <= 1) return 1; else if (__r == _S_rank - 1) return 1; else if (__r == _S_rank - 2) return _M_padstride(); else return static_cast( static_cast(_M_padstride()) * static_cast(__mdspan::__fwd_prod( extents(), __r + 1, _S_rank - 1))); } template requires(__mdspan::__is_right_padded_mapping<_RightPaddedMapping> && _RightPaddedMapping::extents_type::rank() == _S_rank) friend constexpr bool operator==(const mapping& __self, const _RightPaddedMapping& __other) noexcept { return __self._M_storage._M_equal(__other); } #if __glibcxx_submdspan private: template requires (extents_type::rank() == sizeof...(_Slices)) friend constexpr auto submdspan_mapping(const mapping& __mapping, _Slices... __slices) { return __mdspan::__submdspan_mapping_impl(__mapping, __slices...); } #endif // __glibcxx_submdspan }; #endif // __glibcxx_padded_layouts template struct default_accessor { static_assert(!is_array_v<_ElementType>, "ElementType must not be an array type"); static_assert(!is_abstract_v<_ElementType>, "ElementType must not be an abstract class type"); using offset_policy = default_accessor; using element_type = _ElementType; using reference = element_type&; using data_handle_type = element_type*; constexpr default_accessor() noexcept = default; template requires is_convertible_v<_OElementType(*)[], element_type(*)[]> constexpr default_accessor(default_accessor<_OElementType>) noexcept { } constexpr reference access(data_handle_type __p, size_t __i) const noexcept { return __p[__i]; } constexpr data_handle_type offset(data_handle_type __p, size_t __i) const noexcept { return __p + __i; } }; #ifdef __glibcxx_aligned_accessor template struct aligned_accessor { static_assert(has_single_bit(_ByteAlignment), "ByteAlignment must be a power of two"); static_assert(_ByteAlignment >= alignof(_ElementType)); using offset_policy = default_accessor<_ElementType>; using element_type = _ElementType; using reference = element_type&; using data_handle_type = element_type*; static constexpr size_t byte_alignment = _ByteAlignment; constexpr aligned_accessor() noexcept = default; template requires (_OByteAlignment >= byte_alignment) && is_convertible_v<_OElementType(*)[], element_type(*)[]> constexpr aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>) noexcept { } template requires is_convertible_v<_OElementType(*)[], element_type(*)[]> constexpr explicit aligned_accessor(default_accessor<_OElementType>) noexcept { } template requires is_convertible_v constexpr operator default_accessor<_OElementType>() const noexcept { return {}; } constexpr reference access(data_handle_type __p, size_t __i) const noexcept { return std::assume_aligned(__p)[__i]; } constexpr typename offset_policy::data_handle_type offset(data_handle_type __p, size_t __i) const noexcept { return std::assume_aligned(__p) + __i; } }; #endif namespace __mdspan { template constexpr bool __is_multi_index(const _Extents& __exts, span<_IndexType, _Nm> __indices) { static_assert(__exts.rank() == _Nm); for (size_t __i = 0; __i < __exts.rank(); ++__i) if (__indices[__i] >= __exts.extent(__i)) return false; return true; } } template> class mdspan { static_assert(!is_array_v<_ElementType>, "ElementType must not be an array type"); static_assert(!is_abstract_v<_ElementType>, "ElementType must not be an abstract class type"); static_assert(__mdspan::__is_extents<_Extents>, "Extents must be a specialization of std::extents"); static_assert(is_same_v<_ElementType, typename _AccessorPolicy::element_type>); public: using extents_type = _Extents; using layout_type = _LayoutPolicy; using accessor_type = _AccessorPolicy; using mapping_type = typename layout_type::template mapping; using element_type = _ElementType; using value_type = remove_cv_t; using index_type = typename extents_type::index_type; using size_type = typename extents_type::size_type; using rank_type = typename extents_type::rank_type; using data_handle_type = typename accessor_type::data_handle_type; using reference = typename accessor_type::reference; static constexpr rank_type rank() noexcept { return extents_type::rank(); } static constexpr rank_type rank_dynamic() noexcept { return extents_type::rank_dynamic(); } static constexpr size_t static_extent(rank_type __r) noexcept { return extents_type::static_extent(__r); } constexpr index_type extent(rank_type __r) const noexcept { return extents().extent(__r); } constexpr mdspan() requires (rank_dynamic() > 0) && is_default_constructible_v && is_default_constructible_v && is_default_constructible_v = default; constexpr mdspan(const mdspan& __other) = default; constexpr mdspan(mdspan&& __other) = default; template<__mdspan::__valid_index_type... _OIndexTypes> requires (sizeof...(_OIndexTypes) == rank() || sizeof...(_OIndexTypes) == rank_dynamic()) && is_constructible_v && is_default_constructible_v constexpr explicit mdspan(data_handle_type __handle, _OIndexTypes... __exts) : _M_accessor(), _M_mapping(_Extents(static_cast(std::move(__exts))...)), _M_handle(std::move(__handle)) { } template requires __mdspan::__valid_index_type && (_Nm == rank() || _Nm == rank_dynamic()) && is_constructible_v && is_default_constructible_v constexpr explicit(_Nm != rank_dynamic()) mdspan(data_handle_type __handle, span<_OIndexType, _Nm> __exts) : _M_accessor(), _M_mapping(extents_type(__exts)), _M_handle(std::move(__handle)) { } template requires __mdspan::__valid_index_type && (_Nm == rank() || _Nm == rank_dynamic()) && is_constructible_v && is_default_constructible_v constexpr explicit(_Nm != rank_dynamic()) mdspan(data_handle_type __handle, const array<_OIndexType, _Nm>& __exts) : _M_accessor(), _M_mapping(extents_type(__exts)), _M_handle(std::move(__handle)) { } constexpr mdspan(data_handle_type __handle, const extents_type& __exts) requires is_constructible_v && is_default_constructible_v : _M_accessor(), _M_mapping(__exts), _M_handle(std::move(__handle)) { } constexpr mdspan(data_handle_type __handle, const mapping_type& __mapping) requires is_default_constructible_v : _M_accessor(), _M_mapping(__mapping), _M_handle(std::move(__handle)) { } constexpr mdspan(data_handle_type __handle, const mapping_type& __mapping, const accessor_type& __accessor) : _M_accessor(__accessor), _M_mapping(__mapping), _M_handle(std::move(__handle)) { } template requires is_constructible_v&> && is_constructible_v constexpr explicit(!is_convertible_v< const typename _OLayout::template mapping<_OExtents>&, mapping_type> || !is_convertible_v) mdspan(const mdspan<_OElementType, _OExtents, _OLayout, _OAccessor>& __other) : _M_accessor(__other.accessor()), _M_mapping(__other.mapping()), _M_handle(__other.data_handle()) { static_assert(is_constructible_v); static_assert(is_constructible_v); } constexpr mdspan& operator=(const mdspan& __other) = default; constexpr mdspan& operator=(mdspan&& __other) = default; template<__mdspan::__valid_index_type... _OIndexTypes> requires (sizeof...(_OIndexTypes) == rank()) constexpr reference operator[](_OIndexTypes... __indices) const { auto __checked_call = [this](auto... __idxs) -> index_type { if constexpr (sizeof...(__idxs) > 0) __glibcxx_assert(__mdspan::__is_multi_index(extents(), span({__idxs...}))); return _M_mapping(__idxs...); }; auto __index = __checked_call( static_cast(std::move(__indices))...); return _M_accessor.access(_M_handle, __index); } template requires __mdspan::__valid_index_type constexpr reference operator[](span<_OIndexType, rank()> __indices) const { auto __call = [&](index_sequence<_Counts...>) -> reference { return (*this)[index_type(as_const(__indices[_Counts]))...]; }; return __call(make_index_sequence()); } template requires __mdspan::__valid_index_type constexpr reference operator[](const array<_OIndexType, rank()>& __indices) const { return (*this)[span(__indices)]; } constexpr size_type size() const noexcept { __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(), __gnu_cxx::__int_traits ::__max)); return size_type(__mdspan::__size(extents())); } [[nodiscard]] constexpr bool empty() const noexcept { return __mdspan::__empty(extents()); } friend constexpr void swap(mdspan& __x, mdspan& __y) noexcept { using std::swap; swap(__x._M_mapping, __y._M_mapping); swap(__x._M_accessor, __y._M_accessor); swap(__x._M_handle, __y._M_handle); } constexpr const extents_type& extents() const noexcept { return _M_mapping.extents(); } constexpr const data_handle_type& data_handle() const noexcept { return _M_handle; } constexpr const mapping_type& mapping() const noexcept { return _M_mapping; } constexpr const accessor_type& accessor() const noexcept { return _M_accessor; } // Strengthened noexcept for all `is_*` methods. static constexpr bool is_always_unique() noexcept(noexcept(mapping_type::is_always_unique())) { return mapping_type::is_always_unique(); } static constexpr bool is_always_exhaustive() noexcept(noexcept(mapping_type::is_always_exhaustive())) { return mapping_type::is_always_exhaustive(); } static constexpr bool is_always_strided() noexcept(noexcept(mapping_type::is_always_strided())) { return mapping_type::is_always_strided(); } constexpr bool is_unique() const noexcept(noexcept(_M_mapping.is_unique())) { return _M_mapping.is_unique(); } constexpr bool is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive())) { return _M_mapping.is_exhaustive(); } constexpr bool is_strided() const noexcept(noexcept(_M_mapping.is_strided())) { return _M_mapping.is_strided(); } constexpr index_type stride(rank_type __r) const { return _M_mapping.stride(__r); } private: [[no_unique_address]] accessor_type _M_accessor = accessor_type(); [[no_unique_address]] mapping_type _M_mapping = mapping_type(); [[no_unique_address]] data_handle_type _M_handle = data_handle_type(); }; template requires is_array_v<_CArray> && (rank_v<_CArray> == 1) mdspan(_CArray&) -> mdspan, extents>>; template requires is_pointer_v> mdspan(_Pointer&&) -> mdspan>, extents>; template requires (is_convertible_v<_Integrals, size_t> && ...) && (sizeof...(_Integrals) > 0) explicit mdspan(_ElementType*, _Integrals...) -> mdspan<_ElementType, extents...>>; template mdspan(_ElementType*, span<_OIndexType, _Nm>) -> mdspan<_ElementType, dextents>; template mdspan(_ElementType*, const array<_OIndexType, _Nm>&) -> mdspan<_ElementType, dextents>; template mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&) -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>; template mdspan(_ElementType*, const _MappingType&) -> mdspan<_ElementType, typename _MappingType::extents_type, typename _MappingType::layout_type>; template mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&, const _AccessorType&) -> mdspan; #if __glibcxx_submdspan namespace __mdspan { template constexpr auto __canonical_index(_Slice&& __slice) { if constexpr (__detail::__integral_constant_like<_Slice>) { static_assert(__is_representable_integer<_IndexType>(_Slice::value)); static_assert(_Slice::value >= 0); return std::cw<_IndexType(_Slice::value)>; } else return __mdspan::__index_type_cast<_IndexType>(std::move(__slice)); } template constexpr auto __slice_cast(_Slice&& __slice) { using _SliceType = remove_cvref_t<_Slice>; if constexpr (is_convertible_v<_SliceType, full_extent_t>) return static_cast(std::move(__slice)); else if constexpr (is_convertible_v<_SliceType, _IndexType>) return __mdspan::__canonical_index<_IndexType>(std::move(__slice)); else if constexpr (__is_strided_slice<_SliceType>) { auto __extent = __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent)); auto __offset = __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset)); if constexpr (is_same_v>) return strided_slice{ .offset = __offset, .extent = __extent, .stride = cw<_IndexType(1)> }; else return strided_slice{ .offset = __offset, .extent = __extent, .stride = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride)) }; } else { auto [__sbegin, __send] = std::move(__slice); auto __offset = __mdspan::__canonical_index<_IndexType>(std::move(__sbegin)); auto __end = __mdspan::__canonical_index<_IndexType>(std::move(__send)); return strided_slice{ .offset = __offset, .extent = __mdspan::__canonical_index<_IndexType>(__end - __offset), .stride = cw<_IndexType(1)> }; } } template constexpr void __check_valid_index(const extents<_IndexType, _Extent>& __ext, const _OIndexType& __idx) { if constexpr (__is_constant_wrapper<_OIndexType> && _Extent != dynamic_extent) { static_assert(_OIndexType::value >= 0); static_assert(std::cmp_less_equal(_OIndexType::value, _Extent)); } else __glibcxx_assert(__idx <= __ext.extent(0)); } template constexpr void __check_valid_slice(const extents<_IndexType, _Extent>& __ext, const _Slice& __slice) { if constexpr (__is_strided_slice<_Slice>) { // DEVIATION: For empty slices, P3663r3 does not allow us to check // that this is less than or equal to the k-th extent (at runtime). // We're only allowed to check if __slice.offset, __slice.extent // are constant wrappers and __ext is a static extent. __mdspan::__check_valid_index(__ext, __slice.offset); __mdspan::__check_valid_index(__ext, __slice.extent); if constexpr (__is_constant_wrapper && __is_constant_wrapper) static_assert(_Slice::stride_type::value > 0); else __glibcxx_assert(__slice.extent == 0 || __slice.stride > 0); if constexpr (__is_constant_wrapper && __is_constant_wrapper && _Extent != dynamic_extent) static_assert(std::cmp_greater_equal( _Extent - _Slice::offset_type::value, _Slice::extent_type::value)); else __glibcxx_assert(__ext.extent(0) - __slice.offset >= __slice.extent); } else if constexpr (__is_constant_wrapper<_Slice> && _Extent != dynamic_extent) static_assert(std::cmp_less(_Slice::value, _Extent)); else if constexpr (convertible_to<_Slice, _IndexType>) __glibcxx_assert(__slice < __ext.extent(0)); } template constexpr void __check_valid_slices(const _Extents& __exts, const _Slices&... __slices) { constexpr auto __rank = _Extents::rank(); auto __impl = [&](index_sequence<_Is...>) { ((__mdspan::__check_valid_slice(__extract_extent<_Is>(__exts), __slices...[_Is])),...); }; __impl(make_index_sequence<__rank>()); } template using __full_extent_t = std::full_extent_t; // Enables ADL-only calls from submdspan. void submdspan_mapping() = delete; template concept __sliceable_mapping = requires(const _Mapping __m, _Slices... __slices) { { submdspan_mapping(__m, __slices...) } -> __submdspan_mapping_result; }; template constexpr auto __submapping(const _Mapping& __mapping, _Slices... __slices) { __mdspan::__check_valid_slices(__mapping.extents(), __slices...); return submdspan_mapping(__mapping, __slices...); } } template requires (sizeof...(_RawSlices) == sizeof...(_Extents)) constexpr auto submdspan_extents(const extents<_IndexType, _Extents...>& __exts, _RawSlices... __raw_slices) { auto __impl = [&__exts](auto... __slices) { __mdspan::__check_valid_slices(__exts, __slices...); return __mdspan::__subextents(__exts, __slices...); }; return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...); } template requires (sizeof...(_Extents) == sizeof...(_RawSlices)) constexpr auto submdspan_canonicalize_slices(const extents<_IndexType, _Extents...>& __exts, _RawSlices... __raw_slices) { auto __impl = [&__exts](auto... __slices) { __mdspan::__check_valid_slices(__exts, __slices...); return std::make_tuple(__slices...); }; return __impl(__mdspan::__slice_cast<_IndexType>(__raw_slices)...); } template requires (sizeof...(_RawSlices) == _Extents::rank() && __mdspan::__sliceable_mapping, __mdspan::__full_extent_t<_RawSlices>...>) constexpr auto submdspan( const mdspan<_ElementType, _Extents, _Layout, _Accessor>& __md, _RawSlices... __raw_slices) { using _IndexType = typename _Extents::index_type; auto [__mapping, __offset] = __mdspan::__submapping( __md.mapping(), __mdspan::__slice_cast<_IndexType>(__raw_slices)...); return std::mdspan( __md.accessor().offset(__md.data_handle(), __offset), std::move(__mapping), typename _Accessor::offset_policy(__md.accessor())); } #endif // __glibcxx_submdspan _GLIBCXX_END_NAMESPACE_VERSION } #endif #endif