From 2a12d44e44e89f98b12ef7dd999f609ce8245f58 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 4 Jul 2023 01:02:54 +0200 Subject: [PATCH] ``: Make `extents` truly empty when `rank_dynamic() == 0` (#3825) --- stl/inc/mdspan | 38 +++++++++++-------- .../tests/P0009R18_mdspan_extents/test.cpp | 6 +++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 332cf5ff9d..c8a1669c2b 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -25,9 +25,19 @@ _STL_DISABLE_CLANG_WARNINGS #undef new _STD_BEGIN +template +struct _Maybe_empty_array { + array<_IndexType, _Size> _Array{}; +}; + +template +struct _Maybe_empty_array<_IndexType, 0> {}; + +template +inline constexpr size_t _Calculate_rank_dynamic = ((_Extents == dynamic_extent) + ... + 0); _EXPORT_STD template -class extents { +class extents : private _Maybe_empty_array<_IndexType, _Calculate_rank_dynamic<_Extents...>> { public: using index_type = _IndexType; using size_type = make_unsigned_t; @@ -39,8 +49,8 @@ public: "Each element of Extents must be either equal to dynamic_extent, or must be representable as a value of type " "IndexType (N4950 [mdspan.extents.overview]/1.2)."); - static constexpr rank_type _Rank = sizeof...(_Extents); - static constexpr rank_type _Rank_dynamic = (static_cast(_Extents == dynamic_extent) + ... + 0); + static constexpr rank_type _Rank = sizeof...(_Extents); + static constexpr rank_type _Rank_dynamic = _Calculate_rank_dynamic<_Extents...>; static constexpr array _Static_extents = {_Extents...}; static constexpr bool _Multidim_index_space_size_is_always_zero = ((_Extents == 0) || ...); @@ -76,14 +86,10 @@ private: static constexpr array _Dynamic_indices_inv = _Make_dynamic_indices_inv(); struct _Construct_from_tuple { - constexpr explicit _Construct_from_tuple() noexcept = default; - }; - - struct _Static_extents_only { - constexpr explicit _Static_extents_only() noexcept = default; + explicit _Construct_from_tuple() = default; }; - conditional_t<_Rank_dynamic != 0, array, _Static_extents_only> _Dynamic_extents{}; + using _Base = _Maybe_empty_array<_IndexType, _Rank_dynamic>; public: _NODISCARD static constexpr rank_type rank() noexcept { @@ -108,10 +114,10 @@ public: if constexpr (rank_dynamic() == 0) { return static_cast(_Static_extents[_Idx]); } else if constexpr (rank_dynamic() == rank()) { - return _Dynamic_extents[_Idx]; + return this->_Array[_Idx]; } else { if (_Static_extents[_Idx] == dynamic_extent) { - return _Dynamic_extents[_Dynamic_indices[_Idx]]; + return this->_Array[_Dynamic_indices[_Idx]]; } else { return static_cast(_Static_extents[_Idx]); } @@ -125,7 +131,7 @@ public: && ((_OtherExtents == dynamic_extent || _Extents == dynamic_extent || _OtherExtents == _Extents) && ...) constexpr explicit extents( const extents<_OtherIndexType, _OtherExtents...>& _Other, index_sequence<_Indices...>) noexcept - : _Dynamic_extents{static_cast(_Other.extent(_Dynamic_indices_inv[_Indices]))...} { + : _Base{static_cast(_Other.extent(_Dynamic_indices_inv[_Indices]))...} { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (rank() > 0) { for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { @@ -154,12 +160,12 @@ public: template requires (tuple_size_v<_ExtsTuple> == rank_dynamic()) constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_Indices...>) noexcept - : _Dynamic_extents{static_cast(_STD move(_STD get<_Indices>(_Tpl)))...} {} + : _Base{static_cast(_STD move(_STD get<_Indices>(_Tpl)))...} {} template requires (tuple_size_v<_ExtsTuple> != rank_dynamic()) constexpr explicit extents(_Construct_from_tuple, _ExtsTuple _Tpl, index_sequence<_DynIndices...>) noexcept - : _Dynamic_extents{static_cast(_STD move(_STD get<_Dynamic_indices_inv[_DynIndices]>(_Tpl)))...} { + : _Base{static_cast(_STD move(_STD get<_Dynamic_indices_inv[_DynIndices]>(_Tpl)))...} { #if _CONTAINER_DEBUG_LEVEL > 0 [&](index_sequence<_MixedIndices...>) { _STL_VERIFY(((_Static_extents[_MixedIndices] == dynamic_extent @@ -199,7 +205,7 @@ public: requires is_convertible_v && is_nothrow_constructible_v && (_Size == rank_dynamic()) constexpr explicit extents(span<_OtherIndexType, _Size> _Dynamic_exts, index_sequence<_Indices...>) noexcept - : _Dynamic_extents{static_cast(_STD as_const(_Dynamic_exts[_Indices]))...} { + : _Base{static_cast(_STD as_const(_Dynamic_exts[_Indices]))...} { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (_Is_standard_integer<_OtherIndexType> && _Size != 0) { _STL_VERIFY(((_Dynamic_exts[_Indices] >= 0 && _STD in_range(_Dynamic_exts[_Indices])) && ...), @@ -213,7 +219,7 @@ public: requires is_convertible_v && is_nothrow_constructible_v && (_Size != rank_dynamic()) constexpr explicit extents(span<_OtherIndexType, _Size> _Mixed_exts, index_sequence<_Indices...>) noexcept - : _Dynamic_extents{static_cast(_STD as_const(_Mixed_exts[_Dynamic_indices_inv[_Indices]]))...} { + : _Base{static_cast(_STD as_const(_Mixed_exts[_Dynamic_indices_inv[_Indices]]))...} { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (_Is_standard_integer<_OtherIndexType>) { for (rank_type _Idx = 0; _Idx < _Rank; ++_Idx) { diff --git a/tests/std/tests/P0009R18_mdspan_extents/test.cpp b/tests/std/tests/P0009R18_mdspan_extents/test.cpp index 3ff5424078..58fd6ff5ac 100644 --- a/tests/std/tests/P0009R18_mdspan_extents/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_extents/test.cpp @@ -546,6 +546,12 @@ static_assert(all_extents_dynamic, 7>); static_assert(all_extents_dynamic, 8>); static_assert(all_extents_dynamic, 9>); +// When 'E::rank_dynamic()' is equal to 0 then 'is_empty_v' should be true (MSVC STL specific behavior) +static_assert(!is_empty_v>); +static_assert(!is_empty_v>); +static_assert(is_empty_v>); +static_assert(is_empty_v>); + int main() { static_assert(test()); test();