Implements the remaining parts of layout_left and layout_right; and all of layout_stride.
libstdc++/ChangeLog: * include/std/mdspan(layout_stride): New class. Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> --- libstdc++-v3/include/std/mdspan | 227 ++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 583792b5269..344f89c4287 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -336,6 +336,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION class mapping; }; + struct layout_stride + { + template<typename _Extents> + class mapping; + }; + namespace __mdspan { template<typename _Tp> @@ -441,6 +447,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_extents(__other.extents()) { } + template<typename _OExtents> + requires (is_constructible_v<extents_type, _OExtents>) + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OExtents>& __other) + : _M_extents(__other.extents()) + { } + constexpr mapping& operator=(const mapping&) noexcept = default; @@ -567,6 +580,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_extents(__other.extents()) { } + template<class _OExtents> + requires (is_constructible_v<extents_type, _OExtents>) + constexpr explicit(extents_type::rank() > 0) + mapping(const layout_stride::mapping<_OExtents>& __other) noexcept + : _M_extents(__other.extents()) + { } + constexpr mapping& operator=(const mapping&) noexcept = default; @@ -630,6 +650,213 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION [[no_unique_address]] _Extents _M_extents; }; + namespace __mdspan + { + template<typename _Layout, typename _Mapping> + concept __mapping_of = + is_same_v<typename _Layout::mapping<typename _Mapping::extents_type>, + _Mapping>; + + template<typename _Mapping> + concept __standardized_mapping = __mapping_of<layout_left, _Mapping> + || __mapping_of<layout_right, _Mapping> + || __mapping_of<layout_stride, _Mapping>; + + template<typename M> + concept __mapping_like = requires + { + requires __is_extents<typename M::extents_type>; + { M::is_always_strided() } -> same_as<bool>; + { M::is_always_exhaustive() } -> same_as<bool>; + { M::is_always_unique() } -> same_as<bool>; + bool_constant<M::is_always_strided()>::value; + bool_constant<M::is_always_exhaustive()>::value; + bool_constant<M::is_always_unique()>::value; + }; + + template<typename _Mapping, size_t... _Counts> + constexpr typename _Mapping::index_type + __offset_impl(const _Mapping& __m, index_sequence<_Counts...>) noexcept + { + return __m(((void) _Counts, 0)...); + } + + template<typename _Mapping> + constexpr typename _Mapping::index_type + __offset(const _Mapping& __m) noexcept + { + return __offset_impl(__m, + make_index_sequence<_Mapping::extents_type::rank()>()); + } + + template<typename _Mapping, size_t... _Counts, typename... _Indices> + constexpr typename _Mapping::index_type + __linear_index_strides_impl(const _Mapping& __m, + index_sequence<_Counts...>, + _Indices... __indices) + { + return ((__indices * __m.stride(_Counts)) + ... + 0); + } + + template<typename _Mapping, typename... _Indices> + constexpr typename _Mapping::index_type + __linear_index_strides(const _Mapping& __m, + _Indices... __indices) + { + return __linear_index_strides_impl(__m, + make_index_sequence<_Mapping::extents_type::rank()>(), __indices...); + } + } + + template<typename _Extents> + class layout_stride::mapping + { + static_assert(__mdspan::__layout_extent<_Extents>, + "The size of extents_type is not representable as index_type."); + 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; + + constexpr + mapping() noexcept + { + auto __stride = index_type(1); + for(size_t __i = extents_type::rank(); __i > 0; --__i) + { + _M_strides[__i - 1] = __stride; + __stride *= _M_extents.extent(__i - 1); + } + } + + constexpr + mapping(const mapping&) noexcept = default; + + template<__mdspan::__valid_index_type<index_type> _OIndexType> + constexpr + mapping(const extents_type& __exts, + span<_OIndexType, extents_type::rank()> __strides) noexcept + : _M_extents(__exts) + { + for(size_t __i = 0; __i < extents_type::rank(); ++__i) + _M_strides[__i] = index_type(as_const(__strides[__i])); + } + + template<__mdspan::__valid_index_type<index_type> _OIndexType> + 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_like _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()) + { + 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 { return _M_strides; } + + constexpr index_type + required_span_size() const noexcept + { + index_type __ret = 1; + for(size_t __i = 0; __i < extents_type::rank(); ++__i) + { + index_type __ext = _M_extents.extent(__i); + if(__ext == 0) + return 0; + __ret += (__ext - 1) * _M_strides[__i]; + } + return __ret; + } + + 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>(__indices)...); + } + + static constexpr bool + is_always_unique() noexcept { return true; } + + static constexpr bool + is_always_exhaustive() noexcept { return false; } + + static constexpr bool + is_always_strided() noexcept { return true; } + + static constexpr bool + is_unique() noexcept { return true; } + + constexpr bool + is_exhaustive() const noexcept + { + if constexpr (extents_type::rank() == 0) + return true; + else + { + // Under the assumption that the mapping is unique and has positive + // size, the mapping is exhaustive, if and only if the largest value + // returned by m(i...) is within the required range. + // However, the standard requires implementing a condition that's not + // always true when the size of the mapping is zero. + auto __size = __mdspan::__fwd_prod(_M_extents, extents_type::rank()); + if (__size == 0) + return true; + return __size == required_span_size(); + } + } + + static constexpr bool + is_strided() noexcept { return true; } + + constexpr index_type + stride(rank_type __r) const noexcept { return _M_strides[__r]; } + + template<__mdspan::__mapping_like _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; + for(size_t __i = 0; __i < extents_type::rank(); ++__i) + if (__self.stride(__i) != __other.stride(__i)) + return false; + return __mdspan::__offset(__other) == 0; + } + + private: + using _S_strides_t = typename __array_traits<index_type, + extents_type::rank()>::_Type; + [[no_unique_address]] extents_type _M_extents{}; + [[no_unique_address]] _S_strides_t _M_strides; + }; + _GLIBCXX_END_NAMESPACE_VERSION } #endif -- 2.49.0