Implements the parts of layout_left that don't depend on any of the other layouts.
libstdc++-v3/ChangeLog: * include/std/mdspan (layout_left): New class. Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> --- libstdc++-v3/include/std/mdspan | 240 ++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 47cfa405e44..3c1c33d9e9a 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -144,6 +144,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __exts[__i]; }); } + static constexpr size_t + _M_static_extents_prod(size_t __begin, size_t __end) noexcept + { + size_t __ret = 1; + if constexpr (_S_rank > 0) + for(size_t __i = __begin; __i < __end; ++__i) + __ret *= (_Extents[__i] == dynamic_extent ? 1 : _Extents[__i]); + return __ret; + } + + constexpr _IndexType + _M_dynamic_extents_prod(size_t __begin, size_t __end) const noexcept + { + _IndexType __ret = 1; + if constexpr (_S_rank_dynamic > 0) + { + size_t __dyn_begin = _S_dynamic_index[__begin]; + size_t __dyn_end = _S_dynamic_index[__end]; + + for(size_t __i = __dyn_begin; __i < __dyn_end; ++__i) + __ret *= _M_dynamic_extents[__i]; + } + return __ret; + } + + constexpr _IndexType + _M_extents_prod(size_t __begin, size_t __end) const noexcept + { + return _IndexType(_M_static_extents_prod(__begin, __end)) + * _M_dynamic_extents_prod(__begin, __end); + } + private: using _S_storage = __array_traits<_IndexType, _S_rank_dynamic>::_Type; [[no_unique_address]] _S_storage _M_dynamic_extents; @@ -190,6 +222,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return _S_storage::_S_static_extent(__r); } + constexpr index_type + _M_fwd_prod(rank_type __r) const noexcept + { return _M_dynamic_extents._M_extents_prod(0, __r); } + + constexpr index_type + _M_rev_prod(rank_type __r) const noexcept + { return _M_dynamic_extents._M_extents_prod(__r + 1, rank()); } + constexpr index_type extent(rank_type __r) const noexcept { @@ -286,6 +326,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace __mdspan { + template<typename _Extents> + constexpr typename _Extents::index_type + __fwd_prod(const _Extents& __exts, size_t __r) noexcept + { return __exts._M_fwd_prod(__r); } + + template<typename _Extents> + constexpr typename _Extents::index_type + __rev_prod(const _Extents& __exts, size_t __r) noexcept + { return __exts._M_rev_prod(__r); } + template<typename _IndexType, size_t... _Counts> auto __build_dextents_type(integer_sequence<size_t, _Counts...>) -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>; @@ -304,6 +354,196 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit extents(_Integrals...) -> extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>; + struct layout_left + { + template<typename _Extents> + class mapping; + }; + + 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) + { + using _IndexType = typename _Extents::index_type; + _IndexType __res = 0; + if constexpr (sizeof...(__indices) > 0) + { + _IndexType __mult = 1; + auto __update = [&, __pos = 0u](_IndexType __idx) mutable + { + __res += __idx * __mult; + __mult *= __exts.extent(__pos); + ++__pos; + }; + (__update(__indices), ...); + } + return __res; + } + + template<typename _IndexType, size_t _Nm, typename _GetFactor> + constexpr bool + __is_representable_product(_GetFactor __get_factor) + { + size_t __rest = numeric_limits<_IndexType>::max(); + for(size_t __i = 0; __i < _Nm; ++__i) + { + auto __factor = _IndexType(__get_factor(__i)); + if (__factor == 0) + return true; + __rest /= __factor; + } + return __rest > 0; + } + + template<typename _Extents> + constexpr bool + __is_representable_extents(const _Extents& __exts) + { + using _IndexType = typename _Extents::index_type; + return __is_representable_product<_IndexType, _Extents::rank()>( + [&](size_t __i) { return __exts.extent(__i); }); + } + + template<typename _Extents, typename _IndexType> + concept __representable_size = _Extents::rank_dynamic() != 0 + || __is_representable_product<_IndexType, _Extents::rank()>( + [](size_t __i) { return _Extents::static_extent(__i); }); + + template<typename _Extents> + concept __layout_extent = + __representable_size<_Extents, typename _Extents::index_type>; + + 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>; + + 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; + }; + + // A tag type to create internal ctors. + class __internal_ctor + { }; + } + + template<typename _Extents> + class layout_left::mapping + { + static_assert(__mdspan::__layout_extent<_Extents>, + "The size of extents_type must be 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_left; + + constexpr + mapping() noexcept = default; + + constexpr + mapping(const mapping&) noexcept = default; + + constexpr + mapping(const _Extents& __extents) noexcept + : _M_extents(__extents) + { __glibcxx_assert(__mdspan::__is_representable_extents(_M_extents)); } + + private: + template<typename _OExtents> + constexpr explicit + mapping(const _OExtents& __oexts, __mdspan::__internal_ctor) noexcept + : mapping(extents_type(__oexts)) + { + static_assert(__mdspan::__representable_size<_OExtents, index_type>, + "The size of OtherExtents must be representable as index_type"); + } + + public: + 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{}) + { } + + constexpr mapping& + operator=(const mapping&) noexcept = default; + + constexpr const _Extents& + extents() const noexcept { return _M_extents; } + + constexpr index_type + required_span_size() const noexcept + { return __mdspan::__fwd_prod(_M_extents, extents_type::rank()); } + + 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( + this->extents(), static_cast<index_type>(__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: + [[no_unique_address]] _Extents _M_extents; + }; + _GLIBCXX_END_NAMESPACE_VERSION } #endif -- 2.49.0