In mdspan related code involving static extents, often the IndexType is part of the template parameters, even though it's not needed.
This commit extracts the parts of _ExtentsStorage not related to IndexType into a separate class _StaticExtents. It also prefers passing the array of static extents, instead of the whole extents object where possible. These changes don't effect the compilation time, i.e. the difference was (much) less than 10%. However, the size of the object file is noticeably impacted. Consider an extreme example that computes required_span_size and stride for all combinations of: - all three layouts, - three choices of static extents Indices... - eight choices of IndexType. In this case the size of the object file reduced by 45% (22.3kB -> 12.1kB) when compiling with -O2. Using objdump -h we see that the size of .text is unchanged, but .rodata decreases. This is plausible, because: - the deduplicated code is short and is always inlined, - the static storage for _FwdProd, _RevProd, the NTTP _Extents and _StaticExtents::_S_dynamic_index is not deduplicated before this commit. libstdc++-v3/ChangeLog: * include/std/mdspan (__mdspan::_StaticExtents): New class. (__mdspan::_ExtentsStorage): Inherit non-IndexType related methods from _StaticExtents. (__mdspan::_ExtentsStorage::_S_static_extents): Return reference to NTTP _Extents. (__mdspan::__static_extents): Ditto. (__mdspan::__static_prod): Use NTTP for static extents. (__mdspan::_FwdProd): Ditto. (__mdspan::_RevProd): Ditto. (__mdspan::__contains_zero): New overload for const array&. Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> --- libstdc++-v3/include/std/mdspan | 70 +++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan index 5b47c95d2c6..2cf572f1410 100644 --- a/libstdc++-v3/include/std/mdspan +++ b/libstdc++-v3/include/std/mdspan @@ -49,19 +49,14 @@ namespace std _GLIBCXX_VISIBILITY(default) _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace __mdspan { - template<typename _IndexType, array _Extents> - class _ExtentsStorage + template<array _Extents> + class _StaticExtents { public: static consteval bool _S_is_dyn(size_t __ext) noexcept { return __ext == dynamic_extent; } - template<typename _OIndexType> - static constexpr _IndexType - _S_int_cast(const _OIndexType& __other) noexcept - { return _IndexType(__other); } - static constexpr size_t _S_rank = _Extents.size(); // For __r in [0, _S_rank], _S_dynamic_index[__r] is the number @@ -99,6 +94,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static constexpr size_t _S_static_extent(size_t __r) noexcept { return _Extents[__r]; } + }; + + template<typename _IndexType, array _Extents> + class _ExtentsStorage : public _StaticExtents<_Extents> + { + private: + using _S_base = _StaticExtents<_Extents>; + + public: + using _S_base::_S_rank; + using _S_base::_S_rank_dynamic; + using _S_base::_S_dynamic_index; + using _S_base::_S_dynamic_index_inv; + + 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 @@ -157,9 +170,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __exts[__i]; }); } - static constexpr span<const size_t> - _S_static_extents(size_t __begin, size_t __end) noexcept - { return {_Extents.data() + __begin, _Extents.data() + __end}; } + 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 @@ -184,27 +197,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __valid_static_extent = _Extent == dynamic_extent || _Extent <= numeric_limits<_IndexType>::max(); - template<typename _Extents> + template<array _Extents> consteval size_t __static_prod(size_t __begin, size_t __end) { size_t __prod = 1; for(size_t __i = __begin; __i < __end; ++__i) { - auto __ext = _Extents::static_extent(__i); + auto __ext = _Extents[__i]; __prod *= __ext == dynamic_extent ? size_t(1) : __ext; } return __prod; } // Pre-compute: \prod_{i = 0}^r _Extents[i] - template<typename _Extents> + template<array _Extents> struct _FwdProd { - constexpr static std::array<size_t, _Extents::rank() + 1> _S_value = + constexpr static std::array<size_t, _Extents.size() + 1> _S_value = [] consteval { - constexpr size_t __rank = _Extents::rank(); + constexpr size_t __rank = _Extents.size(); std::array<size_t, __rank + 1> __ret; for(size_t __r = 0; __r < __rank + 1; ++__r) __ret[__r] = __static_prod<_Extents>(0, __r); @@ -213,13 +226,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; // Pre-compute: \prod_{i = r+1}^n _Extents[i] - template<typename _Extents> + template<array _Extents> struct _RevProd { - constexpr static std::array<size_t, _Extents::rank()> _S_value = + constexpr static std::array<size_t, _Extents.size()> _S_value = [] consteval { - constexpr size_t __rank = _Extents::rank(); + constexpr size_t __rank = _Extents.size(); std::array<size_t, __rank> __ret; for(size_t __r = 0; __r < __rank; ++__r) __ret[__r] = __static_prod<_Extents>(__r + 1, __rank); @@ -228,10 +241,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; template<typename _Extents> - constexpr span<const size_t> - __static_extents(size_t __begin = 0, size_t __end = _Extents::rank()) + constexpr const array<size_t, _Extents::rank()>& + __static_extents() noexcept - { return _Extents::_S_storage::_S_static_extents(__begin, __end); } + { return _Extents::_S_storage::_S_static_extents(); } template<typename _Extents> constexpr span<const typename _Extents::index_type> @@ -358,8 +371,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } private: - friend span<const size_t> - __mdspan::__static_extents<extents>(size_t, size_t); + friend const array<size_t, rank()>& + __mdspan::__static_extents<extents>(); friend span<const index_type> __mdspan::__dynamic_extents<extents>(const extents&, size_t, size_t); @@ -384,6 +397,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return false; } + template<typename _Tp, size_t _Nm> + consteval bool + __contains_zero(const array<_Tp, _Nm>& __exts) noexcept + { return __contains_zero(span<const _Tp, _Nm>{__exts}); } + template<typename _Extents> constexpr bool __empty(const _Extents& __exts) noexcept @@ -412,7 +430,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr typename _Extents::index_type __fwd_prod(const _Extents& __exts, size_t __r) noexcept { - size_t __sta_prod = _FwdProd<_Extents>::_S_value[__r]; + constexpr auto __sta_exts = __static_extents<_Extents>(); + size_t __sta_prod = _FwdProd<__sta_exts>::_S_value[__r]; return __extents_prod(__exts, __sta_prod, 0, __r); } @@ -420,8 +439,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr typename _Extents::index_type __rev_prod(const _Extents& __exts, size_t __r) noexcept { + constexpr auto __sta_exts = __static_extents<_Extents>(); constexpr size_t __rank = _Extents::rank(); - size_t __sta_prod = _RevProd<_Extents>::_S_value[__r]; + size_t __sta_prod = _RevProd<__sta_exts>::_S_value[__r]; return __extents_prod(__exts, __sta_prod, __r + 1, __rank); } -- 2.50.0