| // <mdspan> -*- 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 | |
| // <http://www.gnu.org/licenses/>. | |
| /** @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 <span> | |
| #include <array> | |
| #include <type_traits> | |
| #include <utility> | |
| #define __glibcxx_want_mdspan | |
| #define __glibcxx_want_aligned_accessor | |
| #define __glibcxx_want_hardened_mdspan | |
| #define __glibcxx_want_submdspan | |
| #include <bits/version.h> | |
| #if __glibcxx_aligned_accessor | |
| #include <bits/align.h> | |
| #endif | |
| #if __glibcxx_submdspan | |
| #include <tuple> | |
| #endif | |
| #if __cplusplus > 202302L | |
| #include <bits/stdexcept_throw.h> | |
| #endif | |
| #ifdef __glibcxx_mdspan | |
| namespace std _GLIBCXX_VISIBILITY(default) | |
| { | |
| _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
| namespace __mdspan | |
| { | |
| consteval bool | |
| __all_static(std::span<const size_t> __extents) | |
| { | |
| for(auto __ext : __extents) | |
| if (__ext == dynamic_extent) | |
| return false; | |
| return true; | |
| } | |
| consteval bool | |
| __all_dynamic(std::span<const size_t> __extents) | |
| { | |
| for(auto __ext : __extents) | |
| if (__ext != dynamic_extent) | |
| return false; | |
| return true; | |
| } | |
| template<typename _IndexType, typename _OIndexTypeRef> | |
| constexpr _IndexType | |
| __index_type_cast(_OIndexTypeRef&& __other) | |
| { | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 4020. extents::index-cast weirdness | |
| using _OIndexType = std::remove_cvref_t<_OIndexTypeRef>; | |
| 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 | |
| { | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 4314. Missing move in mdspan layout mapping::operator() | |
| auto __ret = static_cast<_IndexType>(std::forward<_OIndexTypeRef>(__other)); | |
| if constexpr (std::is_signed_v<_IndexType>) | |
| __glibcxx_assert(__ret >= 0); | |
| return __ret; | |
| } | |
| } | |
| template<array _Extents> | |
| 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<size_t, _S_rank+1> __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<size_t, _S_rank_dynamic> __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<array _Extents> | |
| 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<typename _IndexType, array _Extents> | |
| 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<typename _OIndexType> | |
| 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<size_t _OtherRank, typename _GetOtherExtent> | |
| 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<size_t _OtherRank, typename _GetOtherExtent> | |
| 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<typename _OIndexType, array _OExtents> | |
| constexpr | |
| _ExtentsStorage(const _ExtentsStorage<_OIndexType, _OExtents>& | |
| __other) noexcept | |
| { | |
| _M_init_dynamic_extents<_S_rank>([&__other](size_t __i) | |
| { return __other._M_extent(__i); }); | |
| } | |
| template<typename _OIndexType, size_t _Nm> | |
| constexpr | |
| _ExtentsStorage(span<const _OIndexType, _Nm> __exts) noexcept | |
| { | |
| _M_init_dynamic_extents<_Nm>( | |
| [&__exts](size_t __i) -> const _OIndexType& | |
| { return __exts[__i]; }); | |
| } | |
| static constexpr const array<size_t, _S_rank>& | |
| _S_static_extents() noexcept | |
| { return _Extents; } | |
| constexpr span<const _IndexType> | |
| _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<typename _OIndexType, typename _SIndexType> | |
| concept __valid_index_type = | |
| is_convertible_v<_OIndexType, _SIndexType> && | |
| is_nothrow_constructible_v<_SIndexType, _OIndexType>; | |
| template<size_t _Extent, typename _IndexType> | |
| concept | |
| __valid_static_extent = _Extent == dynamic_extent | |
| || _Extent <= __gnu_cxx::__int_traits<_IndexType>::__max; | |
| template<typename _Extents> | |
| constexpr const array<size_t, _Extents::rank()>& | |
| __static_extents() noexcept | |
| { return _Extents::_Storage::_S_static_extents(); } | |
| template<typename _Extents> | |
| constexpr span<const size_t> | |
| __static_extents(size_t __begin, size_t __end) noexcept | |
| { | |
| const auto& __sta_exts = __static_extents<_Extents>(); | |
| return span<const size_t>(__sta_exts.data() + __begin, __end - __begin); | |
| } | |
| // Pre-compute: \prod_{i = 0}^r _Extents[i], for r = 0,..., n (exclusive) | |
| template<array _Extents> | |
| constexpr auto __fwd_partial_prods = [] consteval | |
| { | |
| constexpr size_t __rank = _Extents.size(); | |
| std::array<size_t, __rank> __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<array _Extents> | |
| constexpr auto __rev_partial_prods = [] consteval | |
| { | |
| constexpr size_t __rank = _Extents.size(); | |
| std::array<size_t, __rank> __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<typename _Extents> | |
| constexpr span<const typename _Extents::index_type> | |
| __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<typename _OffsetType, typename _ExtentType, typename _StrideType> | |
| struct extent_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<typename _FirstType, typename _LastType, typename _StrideType = constant_wrapper<1zu>> | |
| struct range_slice | |
| { | |
| static_assert(__is_signed_or_unsigned_integer<_FirstType>::value | |
| || __detail::__integral_constant_like<_FirstType>); | |
| static_assert(__is_signed_or_unsigned_integer<_LastType>::value | |
| || __detail::__integral_constant_like<_LastType>); | |
| static_assert(__is_signed_or_unsigned_integer<_StrideType>::value | |
| || __detail::__integral_constant_like<_StrideType>); | |
| [[no_unique_address]] _FirstType first{}; | |
| [[no_unique_address]] _LastType last{}; | |
| [[no_unique_address]] _StrideType stride{}; | |
| }; | |
| template<typename _Mapping> | |
| struct submdspan_mapping_result | |
| { | |
| [[no_unique_address]] _Mapping mapping = _Mapping(); | |
| size_t offset{}; | |
| }; | |
| template<typename _Tp> | |
| constexpr bool __is_submdspan_mapping_result = false; | |
| template<typename _Mapping> | |
| constexpr bool __is_submdspan_mapping_result<submdspan_mapping_result<_Mapping>> = true; | |
| template<typename _Mapping> | |
| concept __submdspan_mapping_result = __is_submdspan_mapping_result<_Mapping>; | |
| #endif // __glibcxx_submdspan | |
| template<typename _IndexType, size_t... _Extents> | |
| 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<size_t, sizeof...(_Extents)>{_Extents...}>; | |
| [[no_unique_address]] _Storage _M_exts; | |
| public: | |
| using index_type = _IndexType; | |
| using size_type = make_unsigned_t<index_type>; | |
| 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<typename _OIndexType, size_t... _OExtents> | |
| static consteval bool | |
| _S_ctor_explicit() | |
| { | |
| return (_S_is_less_dynamic(_Extents, _OExtents) || ...) | |
| || (__gnu_cxx::__int_traits<index_type>::__max | |
| < __gnu_cxx::__int_traits<_OIndexType>::__max); | |
| } | |
| template<size_t... _OExtents> | |
| 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<typename _OIndexType, size_t... _OExtents> | |
| 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<index_type>... _OIndexTypes> | |
| requires (sizeof...(_OIndexTypes) == rank() | |
| || sizeof...(_OIndexTypes) == rank_dynamic()) | |
| constexpr explicit extents(_OIndexTypes... __exts) noexcept | |
| : _M_exts(span<const _IndexType, sizeof...(_OIndexTypes)>( | |
| initializer_list{static_cast<_IndexType>(std::move(__exts))...})) | |
| { } | |
| template<typename _OIndexType, size_t _Nm> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| && (_Nm == rank() || _Nm == rank_dynamic()) | |
| constexpr explicit(_Nm != rank_dynamic()) | |
| extents(span<_OIndexType, _Nm> __exts) noexcept | |
| : _M_exts(span<const _OIndexType, _Nm>(__exts)) | |
| { } | |
| template<typename _OIndexType, size_t _Nm> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| && (_Nm == rank() || _Nm == rank_dynamic()) | |
| constexpr explicit(_Nm != rank_dynamic()) | |
| extents(const array<_OIndexType, _Nm>& __exts) noexcept | |
| : _M_exts(span<const _OIndexType, _Nm>(__exts)) | |
| { } | |
| template<typename _OIndexType, size_t... _OExtents> | |
| 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]<size_t... _Counts>( | |
| index_sequence<_Counts...>) | |
| { return (cmp_equal(__self.extent(_Counts), | |
| __other.extent(_Counts)) && ...); }; | |
| return __impl(make_index_sequence<__self.rank()>()); | |
| } | |
| } | |
| private: | |
| friend constexpr const array<size_t, rank()>& | |
| __mdspan::__static_extents<extents>() noexcept; | |
| friend constexpr span<const index_type> | |
| __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t) | |
| noexcept; | |
| template<typename _OIndexType, size_t... _OExtents> | |
| friend class extents; | |
| }; | |
| namespace __mdspan | |
| { | |
| template<typename _Tp, size_t _Nm> | |
| 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<typename _Tp, size_t _Nm> | |
| consteval bool | |
| __contains_zero(const array<_Tp, _Nm>& __exts) noexcept | |
| { return __contains_zero(span<const _Tp>(__exts)); } | |
| template<typename _Extents> | |
| 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<typename _Extents> | |
| 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<typename _Extents::index_type>(__ret); | |
| } | |
| // Preconditions: _r < _Extents::rank() | |
| template<typename _Extents> | |
| constexpr typename _Extents::index_type | |
| __fwd_prod(const _Extents& __exts, size_t __begin, size_t __end) noexcept | |
| { | |
| size_t __sta_prod = [__begin, __end] { | |
| span<const size_t> __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<typename _Extents> | |
| 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<typename _IndexType, size_t _Nm> | |
| consteval _IndexType | |
| __fwd_prod(span<const _IndexType, _Nm> __values) | |
| { | |
| _IndexType __ret = 1; | |
| for(auto __value : __values) | |
| __ret *= __value; | |
| return __ret; | |
| } | |
| // Preconditions: _r < _Extents::rank() | |
| template<typename _Extents> | |
| 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<typename _Extents> | |
| constexpr typename _Extents::index_type | |
| __size(const _Extents& __exts) noexcept | |
| { | |
| constexpr size_t __sta_prod = [] { | |
| span<const size_t> __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<typename _IndexType, size_t... _Counts> | |
| auto __build_dextents_type(integer_sequence<size_t, _Counts...>) | |
| -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>; | |
| } | |
| template<typename _IndexType, size_t _Rank> | |
| using dextents = decltype(__mdspan::__build_dextents_type<_IndexType>( | |
| make_index_sequence<_Rank>())); | |
| #if __glibcxx_mdspan >= 202406L | |
| template<size_t _Rank, typename _IndexType = size_t> | |
| using dims = dextents<_IndexType, _Rank>; | |
| #endif | |
| template<typename... _Integrals> | |
| requires (is_convertible_v<_Integrals, size_t> && ...) | |
| explicit extents(_Integrals...) -> | |
| extents<size_t, __detail::__maybe_static_ext<_Integrals>...>; | |
| struct layout_left | |
| { | |
| template<typename _Extents> | |
| class mapping; | |
| }; | |
| struct layout_right | |
| { | |
| template<typename _Extents> | |
| class mapping; | |
| }; | |
| struct layout_stride | |
| { | |
| template<typename _Extents> | |
| class mapping; | |
| }; | |
| #ifdef __glibcxx_padded_layouts | |
| template<size_t _PaddingValue> | |
| struct layout_left_padded | |
| { | |
| template<typename _Extents> | |
| class mapping; | |
| }; | |
| template<size_t _PaddingValue> | |
| struct layout_right_padded | |
| { | |
| template<typename _Extents> | |
| class mapping; | |
| }; | |
| #endif | |
| namespace __mdspan | |
| { | |
| template<typename _Tp> | |
| constexpr bool __is_extents = false; | |
| template<typename _IndexType, size_t... _Extents> | |
| constexpr bool __is_extents<extents<_IndexType, _Extents...>> = true; | |
| template<typename _Extents, typename... _Indices> | |
| 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<typename _IndexType> | |
| consteval _IndexType | |
| __static_quotient(std::span<const size_t> __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<typename _Extents, | |
| typename _IndexType = typename _Extents::index_type> | |
| requires __is_extents<_Extents> | |
| consteval _IndexType | |
| __static_quotient(_IndexType __nom | |
| = __gnu_cxx::__int_traits<_IndexType>::__max) | |
| { | |
| std::span<const size_t> __sta_exts = __static_extents<_Extents>(); | |
| return __static_quotient<_IndexType>(__sta_exts, __nom); | |
| } | |
| template<typename _Extents> | |
| 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<typename _Extents, typename _IndexType> | |
| concept __representable_size = _Extents::rank_dynamic() != 0 | |
| || __contains_zero(__static_extents<_Extents>()) | |
| || (__static_quotient<_Extents, _IndexType>() != 0); | |
| template<typename _Layout, typename _Mapping> | |
| concept __mapping_of = | |
| is_same_v<typename _Layout::template mapping< | |
| typename _Mapping::extents_type>, | |
| _Mapping>; | |
| template<template<size_t> typename _Layout, typename _Mapping> | |
| concept __padded_mapping_of = __mapping_of< | |
| _Layout<_Mapping::padding_value>, _Mapping>; | |
| #ifdef __glibcxx_padded_layouts | |
| template<typename _Mapping> | |
| constexpr bool __is_left_padded_mapping = __padded_mapping_of< | |
| layout_left_padded, _Mapping>; | |
| template<typename _Mapping> | |
| constexpr bool __is_right_padded_mapping = __padded_mapping_of< | |
| layout_right_padded, _Mapping>; | |
| template<typename _Mapping> | |
| constexpr bool __is_padded_mapping = __is_left_padded_mapping<_Mapping> | |
| || __is_right_padded_mapping<_Mapping>; | |
| #endif | |
| template<typename _PaddedMapping> | |
| consteval size_t | |
| __get_static_stride() | |
| { return _PaddedMapping::_PaddedStorage::_S_static_stride; } | |
| template<typename _Mapping> | |
| concept __standardized_mapping = __mapping_of<layout_left, _Mapping> | |
| || __mapping_of<layout_right, _Mapping> | |
| || __mapping_of<layout_stride, _Mapping> | |
| #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<typename _Mapping> | |
| 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]<size_t... _Counts>(index_sequence<_Counts...>) | |
| { return __m(((void) _Counts, _IndexType(0))...); }; | |
| return __impl(make_index_sequence<__rank>()); | |
| } | |
| } | |
| #ifdef __glibcxx_submdspan | |
| template<typename _Tp> | |
| constexpr bool __is_extent_slice = false; | |
| template<typename _OffsetType, typename _ExtentType, typename _StrideType> | |
| constexpr bool __is_extent_slice<extent_slice<_OffsetType, | |
| _ExtentType, _StrideType>> = true; | |
| template<typename _Tp> | |
| constexpr bool __is_range_slice = false; | |
| template<typename _FirstType, typename _LastType, typename _StrideType> | |
| constexpr bool __is_range_slice<range_slice<_FirstType, | |
| _LastType, _StrideType>> = true; | |
| template<typename _IndexType, typename _OIndexType> | |
| 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<size_t _Index, typename _Extents> | |
| constexpr auto | |
| __extract_extent(const _Extents& __exts) | |
| { | |
| using _IndexType = typename _Extents::index_type; | |
| return extents<_IndexType, _Extents::static_extent(_Index)>{ | |
| __exts.extent(_Index)}; | |
| } | |
| template<typename _Slice, typename _IndexType> | |
| concept __acceptable_slice_type = same_as<_Slice, full_extent_t> | |
| || same_as<_Slice, _IndexType> || __is_constant_wrapper_v<_Slice> | |
| || __is_extent_slice<_Slice>; | |
| template<typename _IndexType, typename... _Slices> | |
| consteval auto | |
| __subrank() | |
| { | |
| return (static_cast<size_t>(!convertible_to<_Slices, _IndexType>) | |
| + ... + 0); | |
| } | |
| template<typename _IndexType, typename... _Slices> | |
| consteval auto | |
| __inv_map_rank() | |
| { | |
| constexpr auto __rank = sizeof...(_Slices); | |
| constexpr auto __sub_rank = __subrank<_IndexType, _Slices...>(); | |
| auto __map = std::array<size_t, __sub_rank>{}; | |
| auto __is_int_like = std::array<bool, __rank>{ | |
| 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<typename _Slice> | |
| constexpr auto | |
| __slice_begin(_Slice __slice) | |
| { | |
| if constexpr (same_as<_Slice, full_extent_t>) | |
| return 0; | |
| else if constexpr (__is_extent_slice<_Slice>) | |
| return __slice.offset; | |
| else | |
| return __slice; // collapsing slice | |
| } | |
| template<typename _Mapping, typename... _Slices> | |
| constexpr size_t | |
| __suboffset(const _Mapping& __mapping, const _Slices&... __slices) | |
| { | |
| using _IndexType = typename _Mapping::index_type; | |
| auto __any_past_the_end = [&]<size_t... _Is>(index_sequence<_Is...>) | |
| { | |
| auto __is_past_the_end = [](const auto& __slice, const auto& __ext) | |
| { | |
| using _Slice = remove_cvref_t<decltype(__slice)>; | |
| 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<sizeof...(__slices)>())) | |
| return __mapping.required_span_size(); | |
| return __mapping(__mdspan::__slice_begin(__slices)...); | |
| } | |
| template<typename _IndexType, size_t _Extent, typename _Slice> | |
| 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_v<typename _Slice::extent_type>) | |
| return _Slice::extent_type::value; | |
| else | |
| return dynamic_extent; | |
| } | |
| template<size_t _K, typename _Extents, typename _Slice> | |
| constexpr typename _Extents::index_type | |
| __dynamic_slice_extent(const _Extents& __exts, _Slice __slice) | |
| { | |
| if constexpr (__is_extent_slice<_Slice>) | |
| return __slice.extent; | |
| else | |
| return __exts.extent(_K); | |
| } | |
| template<typename _IndexType, size_t... _Extents, typename... _Slices> | |
| 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 = [&]<size_t... _Indices>(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 = [&]<size_t... _Is>(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<typename _Mapping> | |
| consteval _LayoutSide | |
| __mapping_side() | |
| { | |
| if constexpr (__is_left_padded_mapping<_Mapping> | |
| || __mapping_of<layout_left, _Mapping>) | |
| return _LayoutSide::__left; | |
| if constexpr (__is_right_padded_mapping<_Mapping> | |
| || __mapping_of<layout_right, _Mapping>) | |
| 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<typename _Mapping> | |
| 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<typename _IndexType, typename... _Slices> | |
| static consteval auto | |
| _S_inv_map() | |
| { | |
| static_assert(_Side != _LayoutSide::__unknown); | |
| auto __impl = [&]<size_t... _Is>(std::index_sequence<_Is...>) | |
| { | |
| return __mdspan::__inv_map_rank<_IndexType, _Slices...[_S_idx(_Is)]...>(); | |
| }; | |
| return __impl(std::make_index_sequence<_Rank>()); | |
| } | |
| }; | |
| template<typename _SubExts, typename _Mapping, typename... _Slices> | |
| 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_extent_slice<decltype(__slice)>) | |
| if (__slice.extent > 1) | |
| return __mapping.stride(__k) * __slice.stride; | |
| return __mapping.stride(__k); | |
| }; | |
| auto __impl = [&]<size_t... _Is>(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<typename _SubExts, typename _Mapping, typename... _Slices> | |
| 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 = [&]<size_t... _Ks>(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_extent_slice<decltype(__slice)>) | |
| { | |
| if (__slice.extent > 1) | |
| __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<typename _SubExts, typename _Mapping, typename... _Slices> | |
| 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<typename _Slice> | |
| concept __is_unit_stride_slice = (__mdspan::__is_extent_slice<_Slice> | |
| && __is_constant_wrapper_v<typename _Slice::stride_type> | |
| && _Slice::stride_type::value == 1) | |
| || std::same_as<_Slice, full_extent_t>; | |
| // These are (forced) exclusive categories: | |
| // - full & collapsing: obvious, | |
| // - unit_extent_slice: extent_slice{a, b, cw<1>}, but not `full`, | |
| // - extent_slice: extent_slice{a, b, c} with c != cw<1>. | |
| enum class _SliceKind | |
| { | |
| __extent_slice, | |
| __unit_stride_slice, | |
| __full, | |
| __collapsing | |
| }; | |
| template<typename _Slice> | |
| consteval _SliceKind | |
| __make_slice_kind() | |
| { | |
| if constexpr (std::same_as<_Slice, full_extent_t>) | |
| return _SliceKind::__full; | |
| else if constexpr (__mdspan::__is_extent_slice<_Slice>) | |
| { | |
| if constexpr (__mdspan::__is_unit_stride_slice<_Slice>) | |
| return _SliceKind::__unit_stride_slice; | |
| else | |
| return _SliceKind::__extent_slice; | |
| } | |
| else | |
| return _SliceKind::__collapsing; | |
| } | |
| template<typename... _Slices> | |
| 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<const _SliceKind> __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_stride_slice; | |
| } | |
| // __u __u + __sub_rank-2 | |
| // [unit_slice, i, ..., k, full, ..., full, unit_slice, *] | |
| static consteval size_t | |
| __padded_block_begin_generic(span<const _SliceKind> __slice_kinds, | |
| size_t __sub_rank) | |
| { | |
| if (__slice_kinds[0] != _SliceKind::__full | |
| && __slice_kinds[0] != _SliceKind::__unit_stride_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<const _SliceKind, _Nm> __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<const _SliceKind>(__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<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>; | |
| template<typename _Mapping, size_t _Us> | |
| 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<size_t _Nm> | |
| static consteval bool | |
| _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __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<size_t _Pad> using _PaddedLayout = layout_left_padded<_Pad>; | |
| template<typename _Mapping, size_t _Us> | |
| 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<size_t _Nm> | |
| static consteval bool | |
| _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, | |
| size_t __sub_rank) | |
| { | |
| if (__sub_rank == 1) | |
| return __slice_kinds[0] == _SliceKind::__unit_stride_slice | |
| || __slice_kinds[0] == _SliceKind::__full; | |
| else | |
| return false; | |
| } | |
| }; | |
| template<> | |
| struct _SubMdspanMapping<_LayoutSide::__right, false> | |
| { | |
| using _Layout = layout_right; | |
| template<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>; | |
| template<typename _Mapping, size_t _Us> | |
| 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<size_t _Nm> | |
| static consteval bool | |
| _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __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<size_t _Pad> using _PaddedLayout = layout_right_padded<_Pad>; | |
| template<typename _Mapping, size_t _Us> | |
| 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<size_t _Nm> | |
| static consteval bool | |
| _S_is_unpadded_submdspan(span<const _SliceKind, _Nm> __slice_kinds, | |
| size_t __sub_rank) | |
| { | |
| if (__sub_rank == 1) | |
| return __slice_kinds[_Nm - 1] == _SliceKind::__unit_stride_slice | |
| || __slice_kinds[_Nm - 1] == _SliceKind::__full; | |
| else | |
| return false; | |
| } | |
| }; | |
| template<typename _Mapping> | |
| constexpr auto | |
| __submdspan_mapping_impl(const _Mapping& __mapping) | |
| { return submdspan_mapping_result{__mapping, 0}; } | |
| template<typename _Mapping, typename... _Slices> | |
| 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<const _SliceKind, __rank>; | |
| 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<typename _Extents> | |
| 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<extents_type, index_type>, | |
| "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<typename _OExtents> | |
| requires is_constructible_v<extents_type, _OExtents> | |
| constexpr explicit(!is_convertible_v<_OExtents, extents_type>) | |
| mapping(const mapping<_OExtents>& __other) noexcept | |
| : mapping(__other.extents(), __mdspan::__internal_ctor{}) | |
| { } | |
| template<typename _OExtents> | |
| requires (extents_type::rank() <= 1) | |
| && is_constructible_v<extents_type, _OExtents> | |
| 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<typename _OExtents> | |
| requires is_constructible_v<extents_type, _OExtents> | |
| 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<typename _LeftpadMapping> | |
| requires __mdspan::__is_left_padded_mapping<_LeftpadMapping> | |
| && is_constructible_v<extents_type, | |
| typename _LeftpadMapping::extents_type> | |
| constexpr | |
| explicit(!is_convertible_v<typename _LeftpadMapping::extents_type, | |
| extents_type>) | |
| 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<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<index_type>(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<typename _OExtents> | |
| 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<typename _OExtents> | |
| 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<typename... _Slices> | |
| 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<typename _Extents, typename... _Indices> | |
| 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<typename _Extents> | |
| 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<extents_type, index_type>, | |
| "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<typename _OExtents> | |
| requires is_constructible_v<extents_type, _OExtents> | |
| constexpr explicit(!is_convertible_v<_OExtents, extents_type>) | |
| mapping(const mapping<_OExtents>& __other) noexcept | |
| : mapping(__other.extents(), __mdspan::__internal_ctor{}) | |
| { } | |
| template<typename _OExtents> | |
| requires (extents_type::rank() <= 1) | |
| && is_constructible_v<extents_type, _OExtents> | |
| constexpr explicit(!is_convertible_v<_OExtents, extents_type>) | |
| mapping(const layout_left::mapping<_OExtents>& __other) noexcept | |
| : mapping(__other.extents(), __mdspan::__internal_ctor{}) | |
| { } | |
| template<typename _OExtents> | |
| requires is_constructible_v<extents_type, _OExtents> | |
| 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<typename _RightPaddedMapping> | |
| requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> | |
| && is_constructible_v<extents_type, | |
| typename _RightPaddedMapping::extents_type> | |
| constexpr | |
| explicit(!is_convertible_v<typename _RightPaddedMapping::extents_type, | |
| extents_type>) | |
| 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<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<index_type>(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<typename _OExtents> | |
| 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<typename _OExtents> | |
| 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<typename... _Slices> | |
| 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<typename _Mp> | |
| concept __mapping_alike = requires | |
| { | |
| requires __is_extents<typename _Mp::extents_type>; | |
| { _Mp::is_always_strided() } -> same_as<bool>; | |
| { _Mp::is_always_exhaustive() } -> same_as<bool>; | |
| { _Mp::is_always_unique() } -> same_as<bool>; | |
| bool_constant<_Mp::is_always_strided()>::value; | |
| bool_constant<_Mp::is_always_exhaustive()>::value; | |
| bool_constant<_Mp::is_always_unique()>::value; | |
| }; | |
| template<typename _Mapping, typename... _Indices> | |
| 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<typename _Extents> | |
| 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<extents_type, index_type>, | |
| "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<typename _OIndexType> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, 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] = | |
| __mdspan::__index_type_cast<index_type>(as_const(__strides[__i])); | |
| if constexpr (extents_type::rank() > 0) | |
| __glibcxx_assert(_M_check_unique()); | |
| } | |
| template<typename _OIndexType> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| constexpr | |
| mapping(const extents_type& __exts, | |
| const array<_OIndexType, extents_type::rank()>& __strides) | |
| noexcept | |
| : mapping(__exts, | |
| span<const _OIndexType, extents_type::rank()>(__strides)) | |
| { } | |
| template<__mdspan::__mapping_alike _StridedMapping> | |
| requires (is_constructible_v<extents_type, | |
| typename _StridedMapping::extents_type> | |
| && _StridedMapping::is_always_unique() | |
| && _StridedMapping::is_always_strided()) | |
| constexpr explicit(!( | |
| is_convertible_v<typename _StridedMapping::extents_type, extents_type> | |
| && __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<index_type>::__max)) | |
| __glibcxx_assert(!cmp_less( | |
| __gnu_cxx::__int_traits<index_type>::__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<index_type, extents_type::rank()> | |
| strides() const noexcept | |
| { | |
| array<index_type, extents_type::rank()> __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<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<index_type>(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<extents_type>()); | |
| } | |
| 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: | |
| using _Strides = typename __array_traits<index_type, | |
| extents_type::rank()>::_Type; | |
| constexpr bool | |
| _M_check_unique() const | |
| { | |
| constexpr size_t __rank = extents_type::rank(); | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 4603. `layout_stride` should accept zero strides for empty `extents` | |
| // 4606. Bullet (4.3) preconditions are too strict to implement submdspan | |
| if (__mdspan::__empty(_M_extents)) | |
| return true; | |
| auto __stride_nonzero = [&](size_t __idx) | |
| { return (_M_strides[__idx] > 0) || (_M_extents.extent(__idx) == 1); }; | |
| if constexpr (__rank == 1) | |
| return __stride_nonzero(0); | |
| else if constexpr (__rank == 2) | |
| { | |
| if (_M_extents.extent(0) == 1) | |
| return __stride_nonzero(1); | |
| if (_M_extents.extent(1) == 1) | |
| return __stride_nonzero(0); | |
| if (!_M_strides[0] || !_M_strides[1]) | |
| return false; | |
| return (_M_strides[1] > _M_strides[0] * (_M_extents.extent(0) - 1)) | |
| || (_M_strides[0] > _M_strides[1] * (_M_extents.extent(1) - 1)); | |
| } | |
| else | |
| { | |
| // This is necessary, but not sufficient condition for uniqueness. | |
| // It requires computation in range of call of operator(), so check | |
| // if first, also in non-debug mode. | |
| if (required_span_size() < __mdspan::__size(_M_extents)) | |
| return false; | |
| // Checking for a valid permutation of strides is O(rank^2) so | |
| // so enabled only in debug mode. | |
| #ifdef _GLIBCXX_DEBUG | |
| size_t __perm[__rank]; | |
| for (size_t __i = 0; __i < __rank; ++__i) | |
| __perm[__i] = __i; | |
| auto __getstride = [&](size_t __idx) { return _M_strides[__idx]; }; | |
| auto __getextent = [&](size_t __idx) { return _M_extents.extent(__idx); }; | |
| auto __popmin = [&](size_t __from, auto __getter) | |
| { | |
| size_t __min = __perm[__rank - 1]; | |
| for (size_t __i = __rank - 1; __i > __from; --__i) | |
| { | |
| const size_t __cur = __perm[__i - 1]; | |
| if (__getter(__cur) < __getter(__min)) | |
| { | |
| __perm[__i] = __min; | |
| __min = __cur; | |
| } | |
| else | |
| __perm[__i] = __cur; | |
| } | |
| __perm[__from] = __min; | |
| return __getter(__min); | |
| }; | |
| // We use eager insertion-sort based algorithm to permute the __perm. | |
| size_t __idx = 0; | |
| // Stride values are not relevant for dimension with single element | |
| while (__popmin(__idx, __getextent) == 1) | |
| if (++__idx == __rank) | |
| return true; | |
| size_t __prev_span = 1; | |
| for (; __idx < __rank; ++__idx) | |
| { | |
| const size_t __stride = __popmin(__idx, __getstride); | |
| if (__stride < __prev_span) | |
| return false; | |
| __prev_span += __stride * (__getextent(__perm[__idx]) - 1); | |
| } | |
| #else | |
| // Otherwise check obvious cases where stride is zero. | |
| for (size_t __idx = 0; __idx < __rank; ++__idx) | |
| if (!__stride_nonzero(__idx)) | |
| return false; | |
| #endif | |
| return true; | |
| } | |
| } | |
| #if __glibcxx_submdspan | |
| template<typename... _Slices> | |
| 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<decltype(__sub_exts)>(__mapping, __slices...); | |
| return submdspan_mapping_result{ | |
| layout_stride::mapping(__sub_exts, __sub_strides), __offset}; | |
| } | |
| } | |
| #endif | |
| [[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<typename _IndexType> | |
| 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<typename _Extents, size_t _PaddingValue, typename _LayoutTraits, | |
| size_t _Rank = _Extents::rank()> | |
| concept __valid_static_stride = (_Extents::rank() <= 1) | |
| || (_PaddingValue == dynamic_extent) | |
| || (_Extents::static_extent(_LayoutTraits::_S_ext_idx) == dynamic_extent) | |
| || (__is_representable_least_multiple<size_t>( | |
| _PaddingValue, _Extents::static_extent(_LayoutTraits::_S_ext_idx))); | |
| template<size_t _PaddedStride, typename _Extents, | |
| typename _LayoutTraits> | |
| 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<typename _Extents, size_t _PaddedStride, typename _LayoutTraits, | |
| size_t _Rank = _Extents::rank()> | |
| 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<typename _Extents, typename _Stride, typename... _Indices> | |
| 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<typename _Extents, typename _Stride, typename... _Indices> | |
| 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<size_t _Rank> | |
| 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<typename _IndexType, size_t _StaticStride, size_t..._Extents> | |
| constexpr static auto | |
| _S_make_padded_extent( | |
| extents<_IndexType, _StaticStride> __stride, | |
| const extents<_IndexType, _Extents...>& __exts) | |
| { | |
| auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>) | |
| { | |
| return extents<_IndexType, _StaticStride, | |
| (_Extents...[_Is + 1])...>{ | |
| __stride.extent(0), __exts.extent(_Is + 1)...}; | |
| }; | |
| return __impl(make_index_sequence<sizeof...(_Extents) - 1>()); | |
| } | |
| }; | |
| template<size_t _Rank> | |
| 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<typename _IndexType, size_t _StaticStride, size_t..._Extents> | |
| constexpr static auto | |
| _S_make_padded_extent( | |
| extents<_IndexType, _StaticStride> __stride, | |
| const extents<_IndexType, _Extents...>& __exts) | |
| { | |
| auto __impl = [&]<size_t... _Is>(integer_sequence<size_t, _Is...>) | |
| { | |
| return extents<_IndexType, (_Extents...[_Is])..., _StaticStride>{ | |
| __exts.extent(_Is)..., __stride.extent(0)}; | |
| }; | |
| return __impl(make_index_sequence<sizeof...(_Extents) - 1>()); | |
| } | |
| }; | |
| template<size_t _PaddingValue, typename _Extents, typename _LayoutTraits> | |
| 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<typename _OExtents> | |
| 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<typename _OExtents> | |
| 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<typename _SamePaddedMapping> | |
| 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<typename _OtherPaddedMapping> | |
| 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<size_t>(_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<typename _SamePaddedMapping> | |
| 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<size_t _PaddingValue> | |
| template<typename _Extents> | |
| 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<padding_value>; | |
| 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<mapping>(); | |
| 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<index_type> _OIndexType> | |
| constexpr | |
| mapping(const extents_type& __exts, _OIndexType __pad) | |
| : _M_storage(__exts, | |
| __mdspan::__index_type_cast<index_type>(std::move(__pad))) | |
| { } | |
| template<typename _OExtents> | |
| requires is_constructible_v<extents_type, _OExtents> | |
| constexpr explicit(!is_convertible_v<_OExtents, extents_type>) | |
| mapping(const layout_left::mapping<_OExtents>& __other) | |
| : _M_storage(__other) | |
| { } | |
| template<typename _OExtents> | |
| 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<typename _LeftPaddedMapping> | |
| requires __mdspan::__is_left_padded_mapping<_LeftPaddedMapping> | |
| && is_constructible_v<extents_type, | |
| typename _LeftPaddedMapping::extents_type> | |
| constexpr explicit( | |
| !is_convertible_v<typename _LeftPaddedMapping::extents_type, | |
| extents_type> | |
| || _S_rank > 1 && (padding_value != dynamic_extent | |
| || _LeftPaddedMapping::padding_value == dynamic_extent)) | |
| mapping(const _LeftPaddedMapping& __other) | |
| : _M_storage(layout_left{}, __other) | |
| { } | |
| template<typename _RightPaddedMapping> | |
| requires (__mdspan::__is_right_padded_mapping<_RightPaddedMapping> | |
| || __mdspan::__mapping_of<layout_right, _RightPaddedMapping>) | |
| && (_S_rank <= 1) | |
| && is_constructible_v<extents_type, | |
| typename _RightPaddedMapping::extents_type> | |
| 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<index_type, _S_rank> | |
| strides() const noexcept | |
| { | |
| array<index_type, _S_rank> __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<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<index_type>(std::move(__indices))...); | |
| } | |
| static constexpr bool | |
| is_always_exhaustive() noexcept | |
| { return _PaddedStorage::_M_is_always_exhaustive(); } | |
| constexpr bool | |
| is_exhaustive() const 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<index_type>( | |
| static_cast<size_t>(_M_padstride()) * | |
| static_cast<size_t>(__mdspan::__fwd_prod(extents(), 1, __r))); | |
| } | |
| template<typename _LeftpadMapping> | |
| 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<typename... _Slices> | |
| 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<size_t _PaddingValue> | |
| template<typename _Extents> | |
| 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<mapping>(); | |
| 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<index_type> _OIndexType> | |
| constexpr | |
| mapping(const extents_type& __exts, _OIndexType __pad) | |
| : _M_storage(__exts, | |
| __mdspan::__index_type_cast<index_type>(std::move(__pad))) | |
| { } | |
| template<typename _OExtents> | |
| requires is_constructible_v<extents_type, _OExtents> | |
| constexpr explicit(!is_convertible_v<_OExtents, extents_type>) | |
| mapping(const layout_right::mapping<_OExtents>& __other) | |
| : _M_storage(__other) | |
| { } | |
| template<typename _OExtents> | |
| 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<typename _RightPaddedMapping> | |
| requires __mdspan::__is_right_padded_mapping<_RightPaddedMapping> | |
| && is_constructible_v<extents_type, | |
| typename _RightPaddedMapping::extents_type> | |
| constexpr explicit( | |
| !is_convertible_v<typename _RightPaddedMapping::extents_type, | |
| extents_type> | |
| || _S_rank > 1 && (padding_value != dynamic_extent | |
| || _RightPaddedMapping::padding_value == dynamic_extent)) | |
| mapping(const _RightPaddedMapping& __other) | |
| : _M_storage(layout_right{}, __other) | |
| { } | |
| template<typename _LeftPaddedMapping> | |
| requires (__mdspan::__is_left_padded_mapping<_LeftPaddedMapping> | |
| || __mdspan::__mapping_of<layout_left, _LeftPaddedMapping>) | |
| && (_S_rank <= 1) | |
| && is_constructible_v<extents_type, | |
| typename _LeftPaddedMapping::extents_type> | |
| 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<index_type, _S_rank> | |
| strides() const noexcept | |
| { | |
| array<index_type, _S_rank> __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<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<index_type>(std::move(__indices))...); | |
| } | |
| static constexpr bool | |
| is_always_exhaustive() noexcept | |
| { return _PaddedStorage::_M_is_always_exhaustive(); } | |
| constexpr bool | |
| is_exhaustive() const 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<index_type>( | |
| static_cast<size_t>(_M_padstride()) * | |
| static_cast<size_t>(__mdspan::__fwd_prod( | |
| extents(), __r + 1, _S_rank - 1))); | |
| } | |
| template<typename _RightPaddedMapping> | |
| 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<typename... _Slices> | |
| 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<typename _ElementType> | |
| 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<typename _OElementType> | |
| 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<typename _ElementType, size_t _ByteAlignment> | |
| 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<typename _OElementType, size_t _OByteAlignment> | |
| requires (_OByteAlignment >= byte_alignment) | |
| && is_convertible_v<_OElementType(*)[], element_type(*)[]> | |
| constexpr | |
| aligned_accessor(aligned_accessor<_OElementType, _OByteAlignment>) | |
| noexcept | |
| { } | |
| template<typename _OElementType> | |
| requires is_convertible_v<_OElementType(*)[], element_type(*)[]> | |
| constexpr explicit | |
| aligned_accessor(default_accessor<_OElementType>) noexcept | |
| { } | |
| template<typename _OElementType> | |
| requires is_convertible_v<element_type(*)[], _OElementType(*)[]> | |
| constexpr | |
| operator default_accessor<_OElementType>() const noexcept | |
| { return {}; } | |
| constexpr reference | |
| access(data_handle_type __p, size_t __i) const noexcept | |
| { return std::assume_aligned<byte_alignment>(__p)[__i]; } | |
| constexpr typename offset_policy::data_handle_type | |
| offset(data_handle_type __p, size_t __i) const noexcept | |
| { return std::assume_aligned<byte_alignment>(__p) + __i; } | |
| }; | |
| #endif | |
| template<typename _ElementType, typename _Extents, | |
| typename _LayoutPolicy = layout_right, | |
| typename _AccessorPolicy = default_accessor<_ElementType>> | |
| 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<extents_type>; | |
| using element_type = _ElementType; | |
| using value_type = remove_cv_t<element_type>; | |
| 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<data_handle_type> | |
| && is_default_constructible_v<mapping_type> | |
| && is_default_constructible_v<accessor_type> = default; | |
| constexpr | |
| mdspan(const mdspan& __other) = default; | |
| constexpr | |
| mdspan(mdspan&& __other) = default; | |
| template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> | |
| requires (sizeof...(_OIndexTypes) == rank() | |
| || sizeof...(_OIndexTypes) == rank_dynamic()) | |
| && is_constructible_v<mapping_type, extents_type> | |
| && is_default_constructible_v<accessor_type> | |
| constexpr explicit | |
| mdspan(data_handle_type __handle, _OIndexTypes... __exts) | |
| : _M_accessor(), | |
| _M_mapping(_Extents(static_cast<index_type>(std::move(__exts))...)), | |
| _M_handle(std::move(__handle)) | |
| { } | |
| template<typename _OIndexType, size_t _Nm> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| && (_Nm == rank() || _Nm == rank_dynamic()) | |
| && is_constructible_v<mapping_type, extents_type> | |
| && is_default_constructible_v<accessor_type> | |
| 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<typename _OIndexType, size_t _Nm> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| && (_Nm == rank() || _Nm == rank_dynamic()) | |
| && is_constructible_v<mapping_type, extents_type> | |
| && is_default_constructible_v<accessor_type> | |
| 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<mapping_type, const extents_type&> | |
| && is_default_constructible_v<accessor_type> | |
| : _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<accessor_type> | |
| : _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<typename _OElementType, typename _OExtents, typename _OLayout, | |
| typename _OAccessor> | |
| requires is_constructible_v<mapping_type, | |
| const typename _OLayout::template mapping<_OExtents>&> | |
| && is_constructible_v<accessor_type, const _OAccessor&> | |
| constexpr explicit(!is_convertible_v< | |
| const typename _OLayout::template mapping<_OExtents>&, mapping_type> | |
| || !is_convertible_v<const _OAccessor&, accessor_type>) | |
| 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<data_handle_type, | |
| const typename _OAccessor::data_handle_type&>); | |
| static_assert(is_constructible_v<extents_type, _OExtents>); | |
| } | |
| constexpr mdspan& | |
| operator=(const mdspan& __other) = default; | |
| constexpr mdspan& | |
| operator=(mdspan&& __other) = default; | |
| template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> | |
| requires (sizeof...(_OIndexTypes) == rank()) | |
| constexpr reference | |
| operator[](_OIndexTypes... __indices) const | |
| { | |
| if constexpr (rank() == 0) | |
| return _M_accessor.access(_M_handle, _M_mapping()); | |
| else if constexpr (!(is_integral_v<_OIndexTypes> && ...)) | |
| return operator[](__index_int_t<_OIndexTypes>(std::move(__indices))...); | |
| else | |
| { | |
| auto __is_valid_index = [&]<typename _OIntType>(size_t __dim, _OIntType __index) | |
| { | |
| if constexpr (is_signed_v<_OIntType>) | |
| if (__index < 0) | |
| return false; | |
| return std::cmp_less(__index, extents().extent(__dim)); | |
| }; | |
| auto __is_multi_index = [&]<size_t... _Counts>(index_sequence<_Counts...>) | |
| { return (__is_valid_index(_Counts, __indices) && ...); }; | |
| __glibcxx_assert(__is_multi_index(make_index_sequence<rank()>())); | |
| auto __index = _M_mapping(static_cast<index_type>(__indices)...); | |
| return _M_accessor.access(_M_handle, __index); | |
| } | |
| } | |
| template<typename _OIndexType> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| constexpr reference | |
| operator[](span<_OIndexType, rank()> __indices) const | |
| { | |
| auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>) | |
| -> reference | |
| { | |
| return operator[]( | |
| __index_int_t<_OIndexType>(as_const(__indices[_Counts]))...); | |
| }; | |
| return __call(make_index_sequence<rank()>()); | |
| } | |
| template<typename _OIndexType> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| constexpr reference | |
| operator[](const array<_OIndexType, rank()>& __indices) const | |
| { return operator[](span<const _OIndexType, rank()>(__indices)); } | |
| #if __cplusplus > 202302L | |
| template<__mdspan::__valid_index_type<index_type>... _OIndexTypes> | |
| requires (sizeof...(_OIndexTypes) == rank()) | |
| constexpr reference | |
| at(_OIndexTypes... __indices) const | |
| { | |
| if constexpr (rank() == 0) | |
| return _M_accessor.access(_M_handle, _M_mapping()); | |
| else if constexpr (!(is_integral_v<_OIndexTypes> && ...)) | |
| return at(__index_int_t<_OIndexTypes>(std::move(__indices))...); | |
| else | |
| { | |
| auto __check_bound = [&]<typename _OIntType>(size_t __dim, _OIntType __index) | |
| { | |
| if constexpr (is_signed_v<_OIntType>) | |
| if (__index < 0) | |
| std::__throw_out_of_range_fmt( | |
| __N("mdspan::at: %zuth index is negative"), __dim); | |
| const auto __ext = extents().extent(__dim); | |
| if (std::cmp_greater_equal(__index, __ext)) | |
| std::__throw_out_of_range_fmt( | |
| __N("mdspan::at: %zuth index (which is %zu)" | |
| " >= extent(%zu) (which is %zu)"), | |
| __dim, size_t(__index), __dim, size_t(__ext)); | |
| }; | |
| auto __check_bounds = [&]<size_t... _Counts>(index_sequence<_Counts...>) | |
| { (__check_bound(_Counts, __indices), ...); }; | |
| __check_bounds(make_index_sequence<rank()>()); | |
| auto __index = _M_mapping(static_cast<index_type>(__indices)...); | |
| return _M_accessor.access(_M_handle, __index); | |
| } | |
| } | |
| template<typename _OIndexType> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| constexpr reference | |
| at(span<_OIndexType, rank()> __indices) const | |
| { | |
| auto __call = [&]<size_t... _Counts>(index_sequence<_Counts...>) | |
| -> reference | |
| { | |
| return at( | |
| __index_int_t<_OIndexType>(as_const(__indices[_Counts]))...); | |
| }; | |
| return __call(make_index_sequence<rank()>()); | |
| } | |
| template<typename _OIndexType> | |
| requires __mdspan::__valid_index_type<const _OIndexType&, index_type> | |
| constexpr reference | |
| at(const array<_OIndexType, rank()>& __indices) const | |
| { return at(span<const _OIndexType, rank()>(__indices)); } | |
| #endif // C++26 | |
| constexpr size_type | |
| size() const noexcept | |
| { | |
| __glibcxx_assert(cmp_less_equal(_M_mapping.required_span_size(), | |
| __gnu_cxx::__int_traits<size_t> | |
| ::__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: | |
| template<typename _OIndexType> | |
| using __index_int_t = std::__conditional_t< | |
| is_integral_v<_OIndexType>, _OIndexType, index_type>; | |
| [[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<typename _CArray> | |
| requires is_array_v<_CArray> && (rank_v<_CArray> == 1) | |
| mdspan(_CArray&) | |
| -> mdspan<remove_all_extents_t<_CArray>, | |
| extents<size_t, extent_v<_CArray, 0>>>; | |
| template<typename _Pointer> | |
| requires is_pointer_v<remove_reference_t<_Pointer>> | |
| mdspan(_Pointer&&) | |
| -> mdspan<remove_pointer_t<remove_reference_t<_Pointer>>, extents<size_t>>; | |
| template<typename _ElementType, typename... _Integrals> | |
| requires (is_convertible_v<_Integrals, size_t> && ...) | |
| && (sizeof...(_Integrals) > 0) | |
| explicit mdspan(_ElementType*, _Integrals...) | |
| -> mdspan<_ElementType, | |
| extents<size_t, __detail::__maybe_static_ext<_Integrals>...>>; | |
| template<typename _ElementType, typename _OIndexType, size_t _Nm> | |
| mdspan(_ElementType*, span<_OIndexType, _Nm>) | |
| -> mdspan<_ElementType, dextents<size_t, _Nm>>; | |
| template<typename _ElementType, typename _OIndexType, size_t _Nm> | |
| mdspan(_ElementType*, const array<_OIndexType, _Nm>&) | |
| -> mdspan<_ElementType, dextents<size_t, _Nm>>; | |
| template<typename _ElementType, typename _IndexType, size_t... _ExtentsPack> | |
| mdspan(_ElementType*, const extents<_IndexType, _ExtentsPack...>&) | |
| -> mdspan<_ElementType, extents<_IndexType, _ExtentsPack...>>; | |
| template<typename _ElementType, typename _MappingType> | |
| mdspan(_ElementType*, const _MappingType&) | |
| -> mdspan<_ElementType, typename _MappingType::extents_type, | |
| typename _MappingType::layout_type>; | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 4511. Inconsistency between the deduction guide of std::mdspan taking... | |
| template<typename _MappingType, typename _AccessorType> | |
| mdspan(typename _AccessorType::data_handle_type, const _MappingType&, | |
| const _AccessorType&) | |
| -> mdspan<typename _AccessorType::element_type, | |
| typename _MappingType::extents_type, | |
| typename _MappingType::layout_type, _AccessorType>; | |
| #if __glibcxx_submdspan | |
| namespace __mdspan | |
| { | |
| template<typename _IndexType, typename _Slice> | |
| 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<typename _IndexType, | |
| typename _OffsetType, typename _SpanType, typename _StrideType> | |
| constexpr auto | |
| __canonical_range_slice(_OffsetType __offset, _SpanType __span, | |
| _StrideType __stride) | |
| { | |
| if constexpr (is_same_v<_SpanType, constant_wrapper<_IndexType(0)>> | |
| || is_same_v<_StrideType, constant_wrapper<_IndexType(1)>>) | |
| return extent_slice{ | |
| .offset = __offset, | |
| .extent = __span, | |
| .stride = cw<_IndexType(1)> | |
| }; | |
| else if constexpr (__is_constant_wrapper_v<_StrideType>) | |
| { | |
| static_assert(_StrideType::value > 0); | |
| if constexpr (__is_constant_wrapper_v<_SpanType>) | |
| return extent_slice{ | |
| .offset = __offset, | |
| .extent = cw<_IndexType(1 + (_SpanType::value - 1) / _StrideType::value)>, | |
| .stride = __stride | |
| }; | |
| else | |
| return extent_slice{ | |
| .offset = __offset, | |
| .extent = _IndexType(__span > 0 ? 1 + (__span - 1) / _StrideType::value : 0), | |
| .stride = __stride | |
| }; | |
| } | |
| else if (__span == 0 || __stride == 1) | |
| return extent_slice{ | |
| .offset = __offset, | |
| .extent = _IndexType(__span), | |
| .stride = _IndexType(1) | |
| }; | |
| else | |
| { | |
| __glibcxx_assert(__stride > 0); | |
| return extent_slice{ | |
| .offset = __offset, | |
| .extent = _IndexType(1 + (__span - 1) / __stride), | |
| .stride = __stride | |
| }; | |
| } | |
| } | |
| template<typename _IndexType, typename _Slice> | |
| constexpr auto | |
| __slice_cast(_Slice&& __slice) | |
| { | |
| using _SliceType = remove_cvref_t<_Slice>; | |
| if constexpr (is_convertible_v<_SliceType, full_extent_t>) | |
| return static_cast<full_extent_t>(std::move(__slice)); | |
| else if constexpr (is_convertible_v<_SliceType, _IndexType>) | |
| return __mdspan::__canonical_index<_IndexType>(std::move(__slice)); | |
| else if constexpr (__is_extent_slice<_SliceType>) | |
| return extent_slice{ | |
| .offset = __mdspan::__canonical_index<_IndexType>(std::move(__slice.offset)), | |
| .extent = __mdspan::__canonical_index<_IndexType>(std::move(__slice.extent)), | |
| .stride = __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride)) | |
| }; | |
| else if constexpr (__is_range_slice<_SliceType>) | |
| { | |
| auto __first | |
| = __mdspan::__canonical_index<_IndexType>(std::move(__slice.first)); | |
| auto __last | |
| = __mdspan::__canonical_index<_IndexType>(std::move(__slice.last)); | |
| return __mdspan::__canonical_range_slice<_IndexType>( | |
| __first, | |
| __mdspan::__canonical_index<_IndexType>(__last - __first), | |
| __mdspan::__canonical_index<_IndexType>(std::move(__slice.stride))); | |
| } | |
| else | |
| { | |
| auto [__sbegin, __send] = std::move(__slice); | |
| auto __cbegin | |
| = __mdspan::__canonical_index<_IndexType>(std::move(__sbegin)); | |
| auto __cend | |
| = __mdspan::__canonical_index<_IndexType>(std::move(__send)); | |
| auto __cspan | |
| = __mdspan::__canonical_index<_IndexType>(__cend - __cbegin); | |
| return __mdspan::__canonical_range_slice<_IndexType>( | |
| __cbegin, __cspan, cw<_IndexType(1)>); | |
| } | |
| } | |
| template<typename _IndexType, size_t _Extent, typename _OIndexType> | |
| constexpr void | |
| __check_inrange_index(const extents<_IndexType, _Extent>& __ext, | |
| const _OIndexType& __idx) | |
| { | |
| if constexpr (__is_constant_wrapper_v<_OIndexType> | |
| && _Extent != dynamic_extent) | |
| { | |
| static_assert(_OIndexType::value >= 0); | |
| static_assert(std::cmp_less(_OIndexType::value, _Extent)); | |
| } | |
| else | |
| __glibcxx_assert(__idx < __ext.extent(0)); | |
| } | |
| template<typename _IndexType, size_t _Extent, typename _OIndexType> | |
| constexpr void | |
| __check_valid_index(const extents<_IndexType, _Extent>& __ext, | |
| const _OIndexType& __idx) | |
| { | |
| if constexpr (__is_constant_wrapper_v<_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<typename _IndexType, size_t _Extent, typename _Slice> | |
| constexpr void | |
| __check_valid_slice(const extents<_IndexType, _Extent>& __ext, | |
| const _Slice& __slice) | |
| { | |
| if constexpr (__is_extent_slice<_Slice>) | |
| { | |
| __mdspan::__check_valid_index(__ext, __slice.extent); | |
| // 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. | |
| if constexpr (is_same_v<typename _Slice::extent_type, | |
| constant_wrapper<_IndexType(0)>>) | |
| __mdspan::__check_valid_index(__ext, __slice.offset); | |
| else if constexpr (is_same_v<typename _Slice::extent_type, | |
| constant_wrapper<_IndexType(1)>>) | |
| __mdspan::__check_inrange_index(__ext, __slice.offset); | |
| else if constexpr (__is_constant_wrapper_v<typename _Slice::extent_type>) | |
| { | |
| __mdspan::__check_inrange_index(__ext, __slice.offset); | |
| if constexpr (__is_constant_wrapper_v<typename _Slice::stride_type>) | |
| static_assert(_Slice::stride_type::value > 0); | |
| else | |
| __glibcxx_assert(__slice.stride > 0); | |
| if constexpr (_Extent != dynamic_extent | |
| && __is_constant_wrapper_v<typename _Slice::offset_type>) | |
| static_assert(std::cmp_greater_equal( | |
| _Extent - _Slice::offset_type::value, | |
| _Slice::extent_type::value)); | |
| if constexpr (_Extent != dynamic_extent | |
| && __is_constant_wrapper_v<typename _Slice::stride_type>) | |
| static_assert(std::cmp_greater( | |
| _Extent, | |
| (_Slice::extent_type::value - 1) * _Slice::stride_type::value)); | |
| if constexpr (_Extent != dynamic_extent | |
| && __is_constant_wrapper_v<typename _Slice::offset_type> | |
| && __is_constant_wrapper_v<typename _Slice::stride_type>) | |
| static_assert(std::cmp_greater( | |
| _Extent - _Slice::offset_type::value, | |
| (_Slice::extent_type::value - 1) * _Slice::stride_type::value)); | |
| else | |
| __glibcxx_assert(std::cmp_greater( | |
| __ext.extent(0) - __slice.offset, | |
| (_Slice::extent_type::value - 1) * __slice.stride)); | |
| } | |
| else if constexpr (is_same_v<typename _Slice::stride_type, | |
| constant_wrapper<_IndexType(1)>>) | |
| { | |
| __mdspan::__check_valid_index(__ext, __slice.offset); | |
| __glibcxx_assert(std::cmp_greater_equal( | |
| __ext.extent(0) - __slice.offset, | |
| __slice.extent)); | |
| } | |
| else if (__slice.extent == 0) | |
| __mdspan::__check_valid_index(__ext, __slice.offset); | |
| else | |
| { | |
| __glibcxx_assert(__slice.offset < __ext.extent(0)); | |
| __glibcxx_assert(__slice.extent == 1 || __slice.stride > 0); | |
| __glibcxx_assert(__slice.extent == 1 || std::cmp_greater( | |
| __ext.extent(0) - __slice.offset, | |
| (__slice.extent - 1) * __slice.stride)); | |
| } | |
| } | |
| else if constexpr (!is_same_v<_Slice, full_extent_t>) | |
| __mdspan::__check_inrange_index(__ext, __slice); | |
| } | |
| template<typename _Extents, typename... _Slices> | |
| constexpr void | |
| __check_valid_slices(const _Extents& __exts, const _Slices&... __slices) | |
| { | |
| constexpr auto __rank = _Extents::rank(); | |
| auto __impl = [&]<size_t... _Is>(index_sequence<_Is...>) | |
| { | |
| ((__mdspan::__check_valid_slice(__extract_extent<_Is>(__exts), | |
| __slices...[_Is])),...); | |
| }; | |
| __impl(make_index_sequence<__rank>()); | |
| } | |
| template<typename _Slice> | |
| using __full_extent_t = std::full_extent_t; | |
| // Enables ADL-only calls from submdspan. | |
| void submdspan_mapping() = delete; | |
| template<typename _Mapping, typename... _Slices> | |
| concept __sliceable_mapping = requires(const _Mapping __m, _Slices... __slices) | |
| { | |
| { submdspan_mapping(__m, __slices...) } -> __submdspan_mapping_result; | |
| }; | |
| template<typename _Mapping, typename... _Slices> | |
| constexpr auto | |
| __submapping(const _Mapping& __mapping, _Slices... __slices) | |
| { | |
| __mdspan::__check_valid_slices(__mapping.extents(), __slices...); | |
| return submdspan_mapping(__mapping, __slices...); | |
| } | |
| } | |
| template<typename _IndexType, size_t... _Extents, typename... _RawSlices> | |
| requires (sizeof...(_RawSlices) == sizeof...(_Extents)) | |
| constexpr auto | |
| subextents(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<typename _IndexType, size_t... _Extents, typename... _RawSlices> | |
| requires (sizeof...(_Extents) == sizeof...(_RawSlices)) | |
| constexpr auto | |
| canonical_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<typename _ElementType, typename _Extents, typename _Layout, | |
| typename _Accessor, typename... _RawSlices> | |
| requires (sizeof...(_RawSlices) == _Extents::rank() | |
| && __mdspan::__sliceable_mapping<typename _Layout::template mapping<_Extents>, | |
| __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 |