From 02980fd8036126ae9832e0a7d9bf2b1b14828620 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 4 Jul 2023 02:19:52 +0200 Subject: [PATCH 01/16] Address https://github.com/microsoft/STL/pull/3825#discussion_r1251316931 --- stl/inc/mdspan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index c8a1669c2b..9724e33f66 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -34,7 +34,7 @@ template struct _Maybe_empty_array<_IndexType, 0> {}; template -inline constexpr size_t _Calculate_rank_dynamic = ((_Extents == dynamic_extent) + ... + 0); +inline constexpr size_t _Calculate_rank_dynamic = (static_cast(_Extents == dynamic_extent) + ... + 0); _EXPORT_STD template class extents : private _Maybe_empty_array<_IndexType, _Calculate_rank_dynamic<_Extents...>> { From 8153309512a1b6094faab87674fffab3d7303b06 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Tue, 4 Jul 2023 17:06:40 +0200 Subject: [PATCH 02/16] Check if `default_accessor` is empty --- tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp index 9036a910c7..0c9d507abf 100644 --- a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp @@ -27,6 +27,9 @@ constexpr void test_one(array elems) { static_assert(is_trivially_copyable_v); static_assert(semiregular); + // Check if default_accessor is emtpy + static_assert(std::is_empty_v); + // Check nested types static_assert(same_as); static_assert(same_as); From 6a4d0478073f371a6af2882b2ba8c9745e9935a7 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 02:04:48 +0200 Subject: [PATCH 03/16] EBO for `layout_left` --- stl/inc/mdspan | 53 ++++++++++++++----- .../P0009R18_mdspan_layout_left/test.cpp | 13 +++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 9724e33f66..739c5d5972 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -437,7 +437,32 @@ _EXPORT_STD struct layout_stride { }; template -class layout_left::mapping { +struct _Maybe_fully_static_extents { + _Extents _Exts{}; + + constexpr _Maybe_fully_static_extents() noexcept = default; + + template + constexpr explicit _Maybe_fully_static_extents(const _OtherExtents& _Exts_) : _Exts(_Exts_) {} +}; + +template + requires (_Extents::rank_dynamic() == 0) +struct _Maybe_fully_static_extents<_Extents> { + static constexpr _Extents _Exts{}; + + constexpr _Maybe_fully_static_extents() noexcept = default; + + template + constexpr explicit _Maybe_fully_static_extents([[maybe_unused]] const _OtherExtents& _Exts_) { +#if _CONTAINER_DEBUG_LEVEL > 0 + (void) _Extents(_Exts_); // NB: temporary created for preconditions check +#endif // _CONTAINER_DEBUG_LEVEL > 0 + } +}; + +template +class layout_left::mapping : private _Maybe_fully_static_extents<_Extents> { public: using extents_type = _Extents; using index_type = extents_type::index_type; @@ -445,6 +470,9 @@ public: using rank_type = extents_type::rank_type; using layout_type = layout_left; +private: + using _Base = _Maybe_fully_static_extents<_Extents>; + static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.left.overview]/2)."); static_assert( @@ -452,10 +480,11 @@ public: "If Extents::rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents() must be " "representable as a value of type typename Extents::index_type (N4950 [mdspan.layout.left.overview]/4)."); +public: constexpr mapping() noexcept = default; constexpr mapping(const mapping&) noexcept = default; - constexpr mapping(const extents_type& _Exts_) noexcept : _Exts(_Exts_) { + constexpr mapping(const extents_type& _Exts_) noexcept : _Base(_Exts_) { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank_dynamic() != 0) { _STL_VERIFY(_Exts_._Is_dynamic_multidim_index_space_size_representable(), @@ -469,7 +498,7 @@ public: requires is_constructible_v constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& _Other) noexcept - : _Exts(_Other.extents()) { + : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -481,7 +510,7 @@ public: requires (extents_type::rank() <= 1) && is_constructible_v constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_right::mapping<_OtherExtents>& _Other) noexcept - : _Exts(_Other.extents()) { + : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -492,7 +521,7 @@ public: template requires is_constructible_v constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::template mapping<_OtherExtents>& _Other) - : _Exts(_Other.extents()) { + : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank() > 0) { index_type _Prod = 1; @@ -500,7 +529,7 @@ public: _STL_VERIFY(_Other.stride(_Idx) == _Prod, "For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to " "extents().fwd-prod-of-extents(r) (N4950 [mdspan.layout.left.cons]/10.1)."); - _Prod = static_cast(_Prod * _Exts.extent(_Idx)); + _Prod = static_cast(_Prod * this->_Exts.extent(_Idx)); } _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -512,11 +541,11 @@ public: constexpr mapping& operator=(const mapping&) noexcept = default; _NODISCARD constexpr const extents_type& extents() const noexcept { - return _Exts; + return this->_Exts; } _NODISCARD constexpr index_type required_span_size() const noexcept { - return _Fwd_prod_of_extents::_Calculate(_Exts, extents_type::_Rank); + return _Fwd_prod_of_extents::_Calculate(this->_Exts, extents_type::_Rank); } template @@ -557,7 +586,7 @@ public: _STL_VERIFY(_Idx < extents_type::_Rank, "Value of i must be less than extents_type::rank() (N4950 [mdspan.layout.left.obs]/6)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _Fwd_prod_of_extents::_Calculate(_Exts, _Idx); + return _Fwd_prod_of_extents::_Calculate(this->_Exts, _Idx); } template @@ -567,21 +596,19 @@ public: } private: - extents_type _Exts{}; - template _NODISCARD constexpr index_type _Index_impl( [[maybe_unused]] index_sequence<_Seq...> _Index_seq, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), + _STL_VERIFY(this->_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), "Value of extents_type::index-cast(i) must be a multidimensional index in extents_ (N4950 " "[mdspan.layout.left.obs]/3)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 index_type _Stride = 1; index_type _Result = 0; - (((_Result += _Indices * _Stride), (_Stride *= _Exts.extent(_Seq))), ...); + (((_Result += _Indices * _Stride), (_Stride *= this->_Exts.extent(_Seq))), ...); return _Result; } }; diff --git a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp index be1ae79656..4c53b23742 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_left/test.cpp @@ -423,6 +423,10 @@ constexpr void check_correctness() { #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ } + +#ifdef __clang__ + if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here +#endif { // 3x2 matrix with column-major order const array values{0, 1, 2, 3, 4, 5}; mdspan, layout_left> matrix{values.data()}; @@ -444,6 +448,9 @@ constexpr void check_correctness() { #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ } +#ifdef __clang__ + if (!is_constant_evaluated()) // FIXME clang hits constexpr limit here +#endif { // 3x2x4 tensor const array values{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}; mdspan, layout_left> tensor{values.data(), 3, 2, 4}; @@ -493,6 +500,12 @@ constexpr void check_correctness() { } } +// When 'M::extents_type::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>>); + constexpr bool test() { check_members_with_various_extents([](const E& e) { check_members(e, make_index_sequence{}); }); if (!is_constant_evaluated()) { // too heavy for compile time From f69946dca8387842fb897e4930f68847649201be Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 02:13:26 +0200 Subject: [PATCH 04/16] EBO for `layout_right` --- stl/inc/mdspan | 30 ++++++++++--------- .../P0009R18_mdspan_layout_right/test.cpp | 6 ++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 739c5d5972..bcca7f9056 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -614,7 +614,7 @@ private: }; template -class layout_right::mapping { +class layout_right::mapping : private _Maybe_fully_static_extents<_Extents> { public: using extents_type = _Extents; using index_type = extents_type::index_type; @@ -622,6 +622,9 @@ public: using rank_type = extents_type::rank_type; using layout_type = layout_right; +private: + using _Base = _Maybe_fully_static_extents<_Extents>; + static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.right.overview]/2)."); static_assert( @@ -629,10 +632,11 @@ public: "If Extents::rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents() must be " "representable as a value of type typename Extents::index_type (N4950 [mdspan.layout.right.overview]/4)."); +public: constexpr mapping() noexcept = default; constexpr mapping(const mapping&) noexcept = default; - constexpr mapping(const extents_type& _Exts_) noexcept : _Exts(_Exts_) { + constexpr mapping(const extents_type& _Exts_) noexcept : _Base(_Exts_) { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank_dynamic() != 0) { _STL_VERIFY(_Exts_._Is_dynamic_multidim_index_space_size_representable(), @@ -646,7 +650,7 @@ public: requires is_constructible_v constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const mapping<_OtherExtents>& _Other) noexcept - : _Exts(_Other.extents()) { + : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -658,7 +662,7 @@ public: requires (extents_type::rank() <= 1) && is_constructible_v constexpr explicit(!is_convertible_v<_OtherExtents, extents_type>) mapping(const layout_left::mapping<_OtherExtents>& _Other) noexcept - : _Exts(_Other.extents()) { + : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -670,7 +674,7 @@ public: requires is_constructible_v constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::template mapping<_OtherExtents>& _Other) noexcept - : _Exts(_Other.extents()) { + : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank() > 0) { index_type _Prod = 1; @@ -678,7 +682,7 @@ public: _STL_VERIFY(_Prod == _Other.stride(_Idx), "For all r in the range [0, extents_type::rank()), other.stride(r) must be equal to " "extents().rev-prod-of-extents(r) (N4950 [mdspan.layout.right.cons]/10.1)."); - _Prod = static_cast(_Prod * _Exts.extent(_Idx)); + _Prod = static_cast(_Prod * this->_Exts.extent(_Idx)); } _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -690,11 +694,11 @@ public: constexpr mapping& operator=(const mapping&) noexcept = default; _NODISCARD constexpr const extents_type& extents() const noexcept { - return _Exts; + return this->_Exts; } _NODISCARD constexpr index_type required_span_size() const noexcept { - return _Fwd_prod_of_extents::_Calculate(_Exts, extents_type::_Rank); + return _Fwd_prod_of_extents::_Calculate(this->_Exts, extents_type::_Rank); } template @@ -735,30 +739,28 @@ public: _STL_VERIFY(_Idx < extents_type::_Rank, "Value of i must be less than extents_type::rank() (N4950 [mdspan.layout.right.obs]/6)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _Rev_prod_of_extents::_Calculate(_Exts, _Idx); + return _Rev_prod_of_extents::_Calculate(this->_Exts, _Idx); } template requires (extents_type::rank() == _OtherExtents::rank()) _NODISCARD_FRIEND constexpr bool operator==(const mapping& _Left, const mapping<_OtherExtents>& _Right) noexcept { - return _Left.extents() == _Right.extents(); + return _Left._Exts == _Right.extents(); } private: - extents_type _Exts{}; - template _NODISCARD constexpr index_type _Index_impl( [[maybe_unused]] index_sequence<_Seq...> _Index_seq, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), + _STL_VERIFY(this->_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), "Value of extents_type::index-cast(i) must be a multidimensional index in extents_ (N4950 " "[mdspan.layout.right.obs]/3)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 index_type _Result = 0; - ((_Result = static_cast(_Indices + _Exts.extent(_Seq) * _Result)), ...); + ((_Result = static_cast(_Indices + this->_Exts.extent(_Seq) * _Result)), ...); return _Result; } }; diff --git a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp index f7d9f80137..273a461ecf 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_right/test.cpp @@ -516,6 +516,12 @@ constexpr void check_correctness() { } } +// When 'M::extents_type::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>>); + constexpr bool test() { check_members_with_various_extents([](const E& e) { check_members(e, make_index_sequence{}); }); if (!is_constant_evaluated()) { // too heavy for compile time From 731ff981c9448e6716390af86b1b61852f92c375 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 03:20:31 +0200 Subject: [PATCH 05/16] EBO for `layout_stride` --- stl/inc/mdspan | 53 ++++++++++--------- .../P0009R18_mdspan_layout_stride/test.cpp | 6 +++ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index bcca7f9056..b9df1952c8 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -456,7 +456,7 @@ struct _Maybe_fully_static_extents<_Extents> { template constexpr explicit _Maybe_fully_static_extents([[maybe_unused]] const _OtherExtents& _Exts_) { #if _CONTAINER_DEBUG_LEVEL > 0 - (void) _Extents(_Exts_); // NB: temporary created for preconditions check + (void) _Extents{_Exts_}; // NB: temporary created for preconditions check #endif // _CONTAINER_DEBUG_LEVEL > 0 } }; @@ -471,7 +471,7 @@ public: using layout_type = layout_left; private: - using _Base = _Maybe_fully_static_extents<_Extents>; + using _Base = _Maybe_fully_static_extents; static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.left.overview]/2)."); @@ -623,7 +623,7 @@ public: using layout_type = layout_right; private: - using _Base = _Maybe_fully_static_extents<_Extents>; + using _Base = _Maybe_fully_static_extents; static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.right.overview]/2)."); @@ -777,7 +777,8 @@ concept _Layout_mapping_alike = requires { }; template -class layout_stride::mapping { +class layout_stride::mapping : private _Maybe_fully_static_extents<_Extents>, + private _Maybe_empty_array { public: using extents_type = _Extents; using index_type = extents_type::index_type; @@ -785,6 +786,10 @@ public: using rank_type = extents_type::rank_type; using layout_type = layout_stride; +private: + using _Extents_base = _Maybe_fully_static_extents; + using _Strides_base = _Maybe_empty_array; + static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.stride.overview]/2)."); static_assert( @@ -792,12 +797,14 @@ public: "If Extents::rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents() must be " "representable as a value of type typename Extents::index_type (N4950 [mdspan.layout.stride.overview]/4)."); - constexpr mapping() noexcept : _Exts(extents_type{}) { +public: + constexpr mapping() noexcept : _Extents_base(extents_type{}) { if constexpr (extents_type::rank() != 0) { - _Strides.back() = 1; + this->_Array.back() = 1; for (rank_type _Idx = extents_type::_Rank - 1; _Idx-- > 0;) { #if _CONTAINER_DEBUG_LEVEL > 0 - const bool _Overflow = _Mul_overflow(_Strides[_Idx + 1], _Exts.extent(_Idx + 1), _Strides[_Idx]); + const bool _Overflow = + _Mul_overflow(this->_Array[_Idx + 1], this->_Exts.extent(_Idx + 1), this->_Array[_Idx]); // NB: N4950 requires value of 'layout_right::mapping().required_span_size()' to be // representable as value of type 'index_type', but this is not enough. We need to require every single // stride to be representable as value of type 'index_type', so we can get desired effects. @@ -805,7 +812,7 @@ public: "Value of layout_right::mapping().required_span_size() must be " "representable as a value of type index_type (N4950 [mdspan.layout.stride.cons]/1)."); #else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL == 0 vvv - _Strides[_Idx] = static_cast(_Strides[_Idx + 1] * _Exts.extent(_Idx + 1)); + this->_Array[_Idx] = static_cast(this->_Array[_Idx + 1] * this->_Exts.extent(_Idx + 1)); #endif // _CONTAINER_DEBUG_LEVEL > 0 } } @@ -818,17 +825,17 @@ public: && is_nothrow_constructible_v constexpr mapping(const extents_type& _Exts_, span<_OtherIndexType, extents_type::rank()> _Strides_, index_sequence<_Indices...>) noexcept - : _Exts(_Exts_), _Strides{static_cast(_STD as_const(_Strides_[_Indices]))...} { + : _Extents_base(_Exts_), _Strides_base{static_cast(_STD as_const(_Strides_[_Indices]))...} { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank() != 0) { bool _Found_zero = false; bool _Overflow = false; index_type _Req_span_size = 0; for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { - const index_type _Stride = _Strides[_Idx]; + const index_type _Stride = this->_Array[_Idx]; _STL_VERIFY(_Stride > 0, "Value of s[i] must be greater than 0 for all i in the range [0, rank_) " "(N4950 [mdspan.layout.stride.cons]/4.1)."); - const index_type _Ext = _Exts.extent(_Idx); + const index_type _Ext = this->_Exts.extent(_Idx); if (_Ext == 0) { _Found_zero = true; } @@ -881,7 +888,7 @@ public: && (_Is_mapping_of || _Is_mapping_of || _Is_mapping_of) )) mapping(const _StridedLayoutMapping& _Other) noexcept - : _Exts(_Other.extents()) { + : _Extents_base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -895,18 +902,18 @@ public: _STL_VERIFY(_Stride > 0, "Value of other.stride(r) must be greater than 0 for every rank index r of " "extents() (N4950 [mdspan.layout.stride.cons]/7.2)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - _Strides[_Idx] = static_cast(_Stride); + this->_Array[_Idx] = static_cast(_Stride); } } constexpr mapping& operator=(const mapping&) noexcept = default; _NODISCARD constexpr const extents_type& extents() const noexcept { - return _Exts; + return this->_Exts; } _NODISCARD constexpr array strides() const noexcept { - return _Strides; + return this->_Array; } _NODISCARD constexpr index_type required_span_size() const noexcept { @@ -915,12 +922,12 @@ public: } else { index_type _Result = 1; for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { - const index_type _Ext = _Exts.extent(_Idx); + const index_type _Ext = this->_Exts.extent(_Idx); if (_Ext == 0) { return 0; } - _Result += (_Ext - 1) * _Strides[_Idx]; + _Result += (_Ext - 1) * this->_Array[_Idx]; } return _Result; @@ -954,7 +961,8 @@ public: if constexpr (extents_type::rank() == 0) { return true; } else { - return required_span_size() == _Fwd_prod_of_extents::_Calculate(_Exts, extents_type::_Rank); + return required_span_size() + == _Fwd_prod_of_extents::_Calculate(this->_Exts, extents_type::_Rank); } } @@ -963,7 +971,7 @@ public: } _NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept { - return _Strides[_Idx]; + return this->_Array[_Idx]; } template @@ -986,9 +994,6 @@ public: } private: - extents_type _Exts{}; - array _Strides{}; - template _NODISCARD static constexpr _OtherMapping::index_type _Offset(_OtherMapping& _Mapping) noexcept { if constexpr (extents_type::rank() == 0) { @@ -1010,12 +1015,12 @@ private: [[maybe_unused]] index_sequence<_Seq...> _Index_seq, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), + _STL_VERIFY(this->_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), "Value of extents_type::index-cast(i) must be a multidimensional index in extents_ (N4950 " "[mdspan.layout.stride.obs]/3)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return static_cast(((_Indices * _Strides[_Seq]) + ... + 0)); + return static_cast(((_Indices * this->_Array[_Seq]) + ... + 0)); } }; diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index ab20ad5c87..13f6ea3032 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -821,6 +821,12 @@ constexpr void check_correctness() { } } +// When 'M::extents_type::rank()' 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>>); + constexpr bool test() { // Check signed integers check_members(extents{5}, array{1}); From 73e7ba457285e6ecef744e6555c9f8bcf71a37cf Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 12:47:08 +0200 Subject: [PATCH 06/16] Revert "EBO for `layout_stride`" This reverts commit 731ff981c9448e6716390af86b1b61852f92c375. --- stl/inc/mdspan | 53 +++++++++---------- .../P0009R18_mdspan_layout_stride/test.cpp | 6 --- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index b9df1952c8..bcca7f9056 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -456,7 +456,7 @@ struct _Maybe_fully_static_extents<_Extents> { template constexpr explicit _Maybe_fully_static_extents([[maybe_unused]] const _OtherExtents& _Exts_) { #if _CONTAINER_DEBUG_LEVEL > 0 - (void) _Extents{_Exts_}; // NB: temporary created for preconditions check + (void) _Extents(_Exts_); // NB: temporary created for preconditions check #endif // _CONTAINER_DEBUG_LEVEL > 0 } }; @@ -471,7 +471,7 @@ public: using layout_type = layout_left; private: - using _Base = _Maybe_fully_static_extents; + using _Base = _Maybe_fully_static_extents<_Extents>; static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.left.overview]/2)."); @@ -623,7 +623,7 @@ public: using layout_type = layout_right; private: - using _Base = _Maybe_fully_static_extents; + using _Base = _Maybe_fully_static_extents<_Extents>; static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.right.overview]/2)."); @@ -777,8 +777,7 @@ concept _Layout_mapping_alike = requires { }; template -class layout_stride::mapping : private _Maybe_fully_static_extents<_Extents>, - private _Maybe_empty_array { +class layout_stride::mapping { public: using extents_type = _Extents; using index_type = extents_type::index_type; @@ -786,10 +785,6 @@ public: using rank_type = extents_type::rank_type; using layout_type = layout_stride; -private: - using _Extents_base = _Maybe_fully_static_extents; - using _Strides_base = _Maybe_empty_array; - static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.stride.overview]/2)."); static_assert( @@ -797,14 +792,12 @@ private: "If Extents::rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents() must be " "representable as a value of type typename Extents::index_type (N4950 [mdspan.layout.stride.overview]/4)."); -public: - constexpr mapping() noexcept : _Extents_base(extents_type{}) { + constexpr mapping() noexcept : _Exts(extents_type{}) { if constexpr (extents_type::rank() != 0) { - this->_Array.back() = 1; + _Strides.back() = 1; for (rank_type _Idx = extents_type::_Rank - 1; _Idx-- > 0;) { #if _CONTAINER_DEBUG_LEVEL > 0 - const bool _Overflow = - _Mul_overflow(this->_Array[_Idx + 1], this->_Exts.extent(_Idx + 1), this->_Array[_Idx]); + const bool _Overflow = _Mul_overflow(_Strides[_Idx + 1], _Exts.extent(_Idx + 1), _Strides[_Idx]); // NB: N4950 requires value of 'layout_right::mapping().required_span_size()' to be // representable as value of type 'index_type', but this is not enough. We need to require every single // stride to be representable as value of type 'index_type', so we can get desired effects. @@ -812,7 +805,7 @@ public: "Value of layout_right::mapping().required_span_size() must be " "representable as a value of type index_type (N4950 [mdspan.layout.stride.cons]/1)."); #else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL == 0 vvv - this->_Array[_Idx] = static_cast(this->_Array[_Idx + 1] * this->_Exts.extent(_Idx + 1)); + _Strides[_Idx] = static_cast(_Strides[_Idx + 1] * _Exts.extent(_Idx + 1)); #endif // _CONTAINER_DEBUG_LEVEL > 0 } } @@ -825,17 +818,17 @@ public: && is_nothrow_constructible_v constexpr mapping(const extents_type& _Exts_, span<_OtherIndexType, extents_type::rank()> _Strides_, index_sequence<_Indices...>) noexcept - : _Extents_base(_Exts_), _Strides_base{static_cast(_STD as_const(_Strides_[_Indices]))...} { + : _Exts(_Exts_), _Strides{static_cast(_STD as_const(_Strides_[_Indices]))...} { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank() != 0) { bool _Found_zero = false; bool _Overflow = false; index_type _Req_span_size = 0; for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { - const index_type _Stride = this->_Array[_Idx]; + const index_type _Stride = _Strides[_Idx]; _STL_VERIFY(_Stride > 0, "Value of s[i] must be greater than 0 for all i in the range [0, rank_) " "(N4950 [mdspan.layout.stride.cons]/4.1)."); - const index_type _Ext = this->_Exts.extent(_Idx); + const index_type _Ext = _Exts.extent(_Idx); if (_Ext == 0) { _Found_zero = true; } @@ -888,7 +881,7 @@ public: && (_Is_mapping_of || _Is_mapping_of || _Is_mapping_of) )) mapping(const _StridedLayoutMapping& _Other) noexcept - : _Extents_base(_Other.extents()) { + : _Exts(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -902,18 +895,18 @@ public: _STL_VERIFY(_Stride > 0, "Value of other.stride(r) must be greater than 0 for every rank index r of " "extents() (N4950 [mdspan.layout.stride.cons]/7.2)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - this->_Array[_Idx] = static_cast(_Stride); + _Strides[_Idx] = static_cast(_Stride); } } constexpr mapping& operator=(const mapping&) noexcept = default; _NODISCARD constexpr const extents_type& extents() const noexcept { - return this->_Exts; + return _Exts; } _NODISCARD constexpr array strides() const noexcept { - return this->_Array; + return _Strides; } _NODISCARD constexpr index_type required_span_size() const noexcept { @@ -922,12 +915,12 @@ public: } else { index_type _Result = 1; for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { - const index_type _Ext = this->_Exts.extent(_Idx); + const index_type _Ext = _Exts.extent(_Idx); if (_Ext == 0) { return 0; } - _Result += (_Ext - 1) * this->_Array[_Idx]; + _Result += (_Ext - 1) * _Strides[_Idx]; } return _Result; @@ -961,8 +954,7 @@ public: if constexpr (extents_type::rank() == 0) { return true; } else { - return required_span_size() - == _Fwd_prod_of_extents::_Calculate(this->_Exts, extents_type::_Rank); + return required_span_size() == _Fwd_prod_of_extents::_Calculate(_Exts, extents_type::_Rank); } } @@ -971,7 +963,7 @@ public: } _NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept { - return this->_Array[_Idx]; + return _Strides[_Idx]; } template @@ -994,6 +986,9 @@ public: } private: + extents_type _Exts{}; + array _Strides{}; + template _NODISCARD static constexpr _OtherMapping::index_type _Offset(_OtherMapping& _Mapping) noexcept { if constexpr (extents_type::rank() == 0) { @@ -1015,12 +1010,12 @@ private: [[maybe_unused]] index_sequence<_Seq...> _Index_seq, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(this->_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), + _STL_VERIFY(_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), "Value of extents_type::index-cast(i) must be a multidimensional index in extents_ (N4950 " "[mdspan.layout.stride.obs]/3)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return static_cast(((_Indices * this->_Array[_Seq]) + ... + 0)); + return static_cast(((_Indices * _Strides[_Seq]) + ... + 0)); } }; diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index 13f6ea3032..ab20ad5c87 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -821,12 +821,6 @@ constexpr void check_correctness() { } } -// When 'M::extents_type::rank()' 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>>); - constexpr bool test() { // Check signed integers check_members(extents{5}, array{1}); From 2d3f8886be74c9a8fd173a4a4fc6326ef6307edc Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 12:48:14 +0200 Subject: [PATCH 07/16] layouts: `_Extents` -> `extents_type` --- stl/inc/mdspan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index bcca7f9056..34f4b34e0e 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -471,7 +471,7 @@ public: using layout_type = layout_left; private: - using _Base = _Maybe_fully_static_extents<_Extents>; + using _Base = _Maybe_fully_static_extents; static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.left.overview]/2)."); @@ -623,7 +623,7 @@ public: using layout_type = layout_right; private: - using _Base = _Maybe_fully_static_extents<_Extents>; + using _Base = _Maybe_fully_static_extents; static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.right.overview]/2)."); From 48ee2aac9797e0b592ef98643f4ac7359232a652 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 12:48:45 +0200 Subject: [PATCH 08/16] `_Maybe_fully_static_extents`: Use `{}` instead of `()` --- stl/inc/mdspan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 34f4b34e0e..1e607e3866 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -456,7 +456,7 @@ struct _Maybe_fully_static_extents<_Extents> { template constexpr explicit _Maybe_fully_static_extents([[maybe_unused]] const _OtherExtents& _Exts_) { #if _CONTAINER_DEBUG_LEVEL > 0 - (void) _Extents(_Exts_); // NB: temporary created for preconditions check + (void) _Extents{_Exts_}; // NB: temporary created for preconditions check #endif // _CONTAINER_DEBUG_LEVEL > 0 } }; From 9f89bd55937a78a7cc7e5c250a85bfd8a621ae7f Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 12:57:03 +0200 Subject: [PATCH 09/16] Add `/* [[no_unique_address]] */` comments in `layout_stride` --- stl/inc/mdspan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 1e607e3866..a93ea6b2e5 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -986,8 +986,8 @@ public: } private: - extents_type _Exts{}; - array _Strides{}; + /* [[no_unique_address]] */ extents_type _Exts{}; + /* [[no_unique_address]] */ array _Strides{}; template _NODISCARD static constexpr _OtherMapping::index_type _Offset(_OtherMapping& _Mapping) noexcept { From 607ef74c591fcaba43959a290004b5c2b641b7d2 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 14:00:35 +0200 Subject: [PATCH 10/16] EBO for `mdspan` --- stl/inc/mdspan | 150 ++++++++++++++---- .../test.compile.pass.cpp | 5 + .../std/tests/P0009R18_mdspan_mdspan/test.cpp | 87 ++++++---- 3 files changed, 182 insertions(+), 60 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index a93ea6b2e5..1155ff6d65 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -24,6 +24,10 @@ _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new +// TRANSITION, non-_Ugly attribute tokens +#pragma push_macro("empty_bases") +#undef empty_bases + _STD_BEGIN template struct _Maybe_empty_array { @@ -1048,9 +1052,80 @@ struct default_accessor { } }; +template +concept _Elidable_layout_mapping = + _Is_any_of_v<_LayoutPolicy, layout_left, layout_right> && (_Extents::rank_dynamic() == 0); + +template +struct _Mdspan_mapping_base { + using _Mapping = _LayoutPolicy::template mapping<_Extents>; + + constexpr _Mdspan_mapping_base() noexcept = default; + + constexpr explicit _Mdspan_mapping_base(const _Extents& _Exts) : _Map(_Exts) {} + + constexpr explicit _Mdspan_mapping_base(const _Mapping& _Map_) : _Map(_Map_) {} + + template + constexpr explicit _Mdspan_mapping_base(const _OtherMapping& _Map_) : _Map(_Map_) {} + + _Mapping _Map{}; +}; + +template _LayoutPolicy> +struct _Mdspan_mapping_base<_Extents, _LayoutPolicy> { + using _Mapping = _LayoutPolicy::template mapping<_Extents>; + + constexpr _Mdspan_mapping_base() noexcept = default; + + constexpr explicit _Mdspan_mapping_base(const _Extents&) noexcept {} + + constexpr explicit _Mdspan_mapping_base(const _Mapping&) noexcept {} + + template + constexpr explicit _Mdspan_mapping_base(const _OtherMapping& _Map_) { + // NB: Constructing _Mapping from _OtherMapping may have side effects - we should create a temporary. + if constexpr (!_Elidable_layout_mapping) { + (void) _Mapping{_Map_}; + } + } + + static constexpr _Mapping _Map{}; +}; + +template +concept _Elidable_accessor_policy = _Is_specialization_v<_AccessorPolicy, default_accessor>; + +template +struct _Mdspan_accessor_base { + constexpr _Mdspan_accessor_base() noexcept = default; + + template + constexpr explicit _Mdspan_accessor_base(const _OtherAccessorPolicy& _Acc_) : _Acc(_Acc_) {} + + _AccessorPolicy _Acc{}; +}; + +template <_Elidable_accessor_policy _AccessorPolicy> +struct _Mdspan_accessor_base<_AccessorPolicy> { + constexpr _Mdspan_accessor_base() noexcept = default; + + template + constexpr explicit _Mdspan_accessor_base(const _OtherAccessorPolicy& _Acc_) { + // NB: Constructing _AccessorPolicy from _OtherAccessorPolicy may have side effects - we should create a + // temporary. + if constexpr (!_Elidable_accessor_policy<_OtherAccessorPolicy>) { + (void) _AccessorPolicy{_Acc_}; + } + } + + static constexpr _AccessorPolicy _Acc{}; +}; + _EXPORT_STD template > -class mdspan { +class __declspec(empty_bases) mdspan : private _Mdspan_mapping_base<_Extents, _LayoutPolicy>, + private _Mdspan_accessor_base<_AccessorPolicy> { public: using extents_type = _Extents; using layout_type = _LayoutPolicy; @@ -1064,6 +1139,10 @@ public: using data_handle_type = accessor_type::data_handle_type; using reference = accessor_type::reference; +private: + using _Mapping_base = _Mdspan_mapping_base; + using _Accessor_base = _Mdspan_accessor_base; + static_assert( sizeof(element_type) > 0, "ElementType must be a complete type (N4950 [mdspan.mdspan.overview]/2.1)."); static_assert( @@ -1076,6 +1155,7 @@ public: "ElementType and typename AccessorPolicy::element_type must be the same type (N4950 " "[mdspan.mdspan.overview]/2.3)."); +public: _NODISCARD static constexpr rank_type rank() noexcept { return extents_type::_Rank; } @@ -1092,7 +1172,7 @@ public: } _NODISCARD constexpr index_type extent(const rank_type _Idx) const noexcept { - return _Map.extents().extent(_Idx); + return this->_Map.extents().extent(_Idx); } constexpr mdspan() @@ -1109,7 +1189,8 @@ public: && (sizeof...(_OtherIndexTypes) == rank() || sizeof...(_OtherIndexTypes) == rank_dynamic()) && is_constructible_v && is_default_constructible_v constexpr explicit mdspan(data_handle_type _Ptr_, _OtherIndexTypes... _Exts) - : _Ptr(_STD move(_Ptr_)), _Map(extents_type{static_cast(_STD move(_Exts))...}), _Acc() {} + : _Mapping_base(extents_type{static_cast(_STD move(_Exts))...}), _Accessor_base(), + _Ptr(_STD move(_Ptr_)) {} template requires is_convertible_v<_OtherIndexType, index_type> @@ -1117,7 +1198,7 @@ public: && (_Size == rank() || _Size == rank_dynamic()) && is_constructible_v && is_default_constructible_v constexpr explicit(_Size != rank_dynamic()) mdspan(data_handle_type _Ptr_, span<_OtherIndexType, _Size> _Exts) - : _Ptr(_STD move(_Ptr_)), _Map(extents_type{_Exts}), _Acc() {} + : _Mapping_base(extents_type{_Exts}), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} template requires is_convertible_v @@ -1126,18 +1207,18 @@ public: && is_constructible_v && is_default_constructible_v constexpr explicit(_Size != rank_dynamic()) mdspan(data_handle_type _Ptr_, const array<_OtherIndexType, _Size>& _Exts) - : _Ptr(_STD move(_Ptr_)), _Map(extents_type{_Exts}), _Acc() {} + : _Mapping_base(extents_type{_Exts}), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} - constexpr mdspan(data_handle_type _Ptr_, const extents_type& _Ext) + constexpr mdspan(data_handle_type _Ptr_, const extents_type& _Exts) requires is_constructible_v && is_default_constructible_v - : _Ptr(_STD move(_Ptr_)), _Map(_Ext), _Acc() {} + : _Mapping_base(_Exts), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} constexpr mdspan(data_handle_type _Ptr_, const mapping_type& _Map_) requires is_default_constructible_v - : _Ptr(_STD move(_Ptr_)), _Map(_Map_), _Acc() {} + : _Mapping_base(_Map_), _Accessor_base(), _Ptr(_STD move(_Ptr_)) {} constexpr mdspan(data_handle_type _Ptr_, const mapping_type& _Map_, const accessor_type& _Acc_) - : _Ptr(_STD move(_Ptr_)), _Map(_Map_), _Acc(_Acc_) {} + : _Mapping_base(_Map_), _Accessor_base(_Acc_), _Ptr(_STD move(_Ptr_)) {} template requires is_constructible_v&> @@ -1146,7 +1227,7 @@ public: !is_convertible_v&, mapping_type> || !is_convertible_v) mdspan(const mdspan<_OtherElementType, _OtherExtents, _OtherLayoutPolicy, _OtherAccessor>& _Other) - : _Ptr(_Other.data_handle()), _Map(_Other.mapping()), _Acc(_Other.accessor()) { + : _Mapping_base(_Other.mapping()), _Accessor_base(_Other.accessor()), _Ptr(_Other.data_handle()) { static_assert(is_constructible_v, "The data_handle_type must be constructible from const typename OtherAccessor::data_handle_type& (N4950 " "[mdspan.mdspan.cons]/20.1)."); @@ -1204,20 +1285,20 @@ public: _NODISCARD constexpr size_type size() const noexcept { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (rank_dynamic() != 0) { - _STL_VERIFY(_Map.extents().template _Is_dynamic_multidim_index_space_size_representable(), + _STL_VERIFY(this->_Map.extents().template _Is_dynamic_multidim_index_space_size_representable(), "The size of the multidimensional index space extents() must be representable as a value of type " "size_type (N4950 [mdspan.mdspan.members]/7)."); } #endif // _CONTAINER_DEBUG_LEVEL > 0 return static_cast( - _Fwd_prod_of_extents::_Calculate(_Map.extents(), extents_type::_Rank)); + _Fwd_prod_of_extents::_Calculate(this->_Map.extents(), extents_type::_Rank)); } _NODISCARD constexpr bool empty() const noexcept { if constexpr (extents_type::_Multidim_index_space_size_is_always_zero) { return true; } else { - const extents_type& _Exts = _Map.extents(); + const extents_type& _Exts = this->_Map.extents(); for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { if (_Exts.extent(_Idx) == 0) { return true; @@ -1229,12 +1310,18 @@ public: friend constexpr void swap(mdspan& _Left, mdspan& _Right) noexcept { swap(_Left._Ptr, _Right._Ptr); // intentional ADL - swap(_Left._Map, _Right._Map); // intentional ADL - swap(_Left._Acc, _Right._Acc); // intentional ADL + + if constexpr (!_Elidable_layout_mapping) { + swap(_Left._Map, _Right._Map); // intentional ADL + } + + if constexpr (!_Elidable_accessor_policy) { + swap(_Left._Acc, _Right._Acc); // intentional ADL + } } _NODISCARD constexpr const extents_type& extents() const noexcept { - return _Map.extents(); + return this->_Map.extents(); } _NODISCARD constexpr const data_handle_type& data_handle() const noexcept { @@ -1242,11 +1329,11 @@ public: } _NODISCARD constexpr const mapping_type& mapping() const noexcept { - return _Map; + return this->_Map; } _NODISCARD constexpr const accessor_type& accessor() const noexcept { - return _Acc; + return this->_Acc; } _NODISCARD static constexpr bool is_always_unique() noexcept( @@ -1264,21 +1351,21 @@ public: return mapping_type::is_always_strided(); } - _NODISCARD constexpr bool is_unique() const noexcept(noexcept(_Map.is_unique())) /* strengthened */ { - return _Map.is_unique(); + _NODISCARD constexpr bool is_unique() const noexcept(noexcept(this->_Map.is_unique())) /* strengthened */ { + return this->_Map.is_unique(); } - _NODISCARD constexpr bool is_exhaustive() const noexcept(noexcept(_Map.is_exhaustive())) /* strengthened */ { - return _Map.is_exhaustive(); + _NODISCARD constexpr bool is_exhaustive() const noexcept(noexcept(this->_Map.is_exhaustive())) /* strengthened */ { + return this->_Map.is_exhaustive(); } - _NODISCARD constexpr bool is_strided() const noexcept(noexcept(_Map.is_strided())) /* strengthened */ { - return _Map.is_strided(); + _NODISCARD constexpr bool is_strided() const noexcept(noexcept(this->_Map.is_strided())) /* strengthened */ { + return this->_Map.is_strided(); } _NODISCARD constexpr index_type stride(const rank_type _Idx) const - noexcept(noexcept(_Map.stride(_Idx))) /* strengthened */ { - return _Map.stride(_Idx); + noexcept(noexcept(this->_Map.stride(_Idx))) /* strengthened */ { + return this->_Map.stride(_Idx); } private: @@ -1293,16 +1380,14 @@ private: _NODISCARD constexpr reference _Access_impl(_OtherIndexTypes... _Indices) const { _STL_INTERNAL_STATIC_ASSERT((same_as<_OtherIndexTypes, index_type> && ...)); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Map.extents()._Contains_multidimensional_index(make_index_sequence{}, _Indices...), + _STL_VERIFY(this->_Map.extents()._Contains_multidimensional_index(make_index_sequence{}, _Indices...), "I must be a multidimensional index in extents() (N4950 [mdspan.mdspan.members]/3)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return _Acc.access(_Ptr, static_cast(_Map(_Indices...))); + return this->_Acc.access(_Ptr, static_cast(this->_Map(_Indices...))); } - data_handle_type _Ptr{}; - mapping_type _Map{}; - accessor_type _Acc{}; + /* [[no_unique_address]] */ data_handle_type _Ptr{}; }; template @@ -1338,6 +1423,9 @@ mdspan(const typename _AccessorType::data_handle_type&, const _MappingType&, con _STD_END +// TRANSITION, non-_Ugly attribute tokens +#pragma pop_macro("empty_bases") + #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) diff --git a/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp b/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp index d5534e2234..7bed2d659c 100644 --- a/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp +++ b/tests/std/tests/GH_002206_unreserved_names/test.compile.pass.cpp @@ -13,6 +13,7 @@ #define intrinsic 3 #define lifetimebound 4 #define noop_dtor 5 +#define empty_bases 6 #include <__msvc_all_public_headers.hpp> @@ -35,3 +36,7 @@ #if noop_dtor != 5 #error bad macro expansion #endif // noop_dtor != 5 + +#if empty_bases != 6 +#error bad macro expansion +#endif // noop_dtor != 6 diff --git a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp index 44580c94dd..8701991b64 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp @@ -1095,35 +1095,52 @@ constexpr void check_empty() { } constexpr void check_swap() { - using E = extents; - using Mds = mdspan, TrackingAccessor>; - static_assert(is_nothrow_swappable_v); - static_assert(!is_swappable_v); - - int a1[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; - Mds mds1{TrackingDataHandle{1, a1}, TrackingLayout<>::mapping(1), TrackingAccessor{1}}; - int a2[9] = {3, 0, 0, 0, 3, 0, 0, 0, 3}; - Mds mds2{TrackingDataHandle{3, a2}, TrackingLayout<>::mapping(3), TrackingAccessor{3}}; - swap(mds1, mds2); - static_assert(is_void_v); - - assert(mds1.data_handle().get_id() == 3); - assert(mds1.data_handle().is_swapped()); - assert(mds1.mapping().get_id() == 3); - assert(mds1.mapping().is_swapped()); - assert(mds1.accessor().get_id() == 3); - assert(mds1.accessor().is_swapped()); - assert((mds1[array{1, 1}] == 3)); - assert((mds1[array{0, 1}] == 0)); - - assert(mds2.data_handle().get_id() == 1); - assert(mds2.data_handle().is_swapped()); - assert(mds2.mapping().get_id() == 1); - assert(mds2.mapping().is_swapped()); - assert(mds2.accessor().get_id() == 1); - assert(mds2.accessor().is_swapped()); - assert((mds2[array{1, 1}] == 1)); - assert((mds2[array{0, 1}] == 0)); + { // Check swapping with tracking types + using E = extents; + using Mds = mdspan, TrackingAccessor>; + static_assert(is_nothrow_swappable_v); + static_assert(!is_swappable_v); + + int a1[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; + Mds mds1{TrackingDataHandle{1, a1}, TrackingLayout<>::mapping(1), TrackingAccessor{1}}; + int a2[9] = {3, 0, 0, 0, 3, 0, 0, 0, 3}; + Mds mds2{TrackingDataHandle{3, a2}, TrackingLayout<>::mapping(3), TrackingAccessor{3}}; + swap(mds1, mds2); + static_assert(is_void_v); + + assert(mds1.data_handle().get_id() == 3); + assert(mds1.data_handle().is_swapped()); + assert(mds1.mapping().get_id() == 3); + assert(mds1.mapping().is_swapped()); + assert(mds1.accessor().get_id() == 3); + assert(mds1.accessor().is_swapped()); + assert((mds1[array{1, 1}] == 3)); + assert((mds1[array{0, 1}] == 0)); + + assert(mds2.data_handle().get_id() == 1); + assert(mds2.data_handle().is_swapped()); + assert(mds2.mapping().get_id() == 1); + assert(mds2.mapping().is_swapped()); + assert(mds2.accessor().get_id() == 1); + assert(mds2.accessor().is_swapped()); + assert((mds2[array{1, 1}] == 1)); + assert((mds2[array{0, 1}] == 0)); + } + + { // Check swapping with standard layout and accessor + using Mds = mdspan>; + static_assert(is_nothrow_swappable_v); + static_assert(!is_swappable_v); + + int diag[] = {1, 0, 0, 1}; + Mds mds1{diag}; + int revdiag[] = {0, 1, 1, 0}; + Mds mds2{revdiag}; + + swap(mds1, mds2); + assert(mds1.data_handle() == revdiag); + assert(mds2.data_handle() == diag); + } } constexpr void check_getters() { @@ -1316,6 +1333,18 @@ constexpr void check_deduction_guides() { } } +// When +// * 'Mds::accessor_type' is specialization of 'default_accesor', and +// * 'Mds::layout_type' is layout_left or layout_right and 'Mds::extents_type::rank_dynamic() == 0', +// then 'sizeof(Mds) == sizeof(void*)' (MSVC STL specific behavior). +static_assert(sizeof(mdspan, layout_left>) == sizeof(void*)); +static_assert(sizeof(mdspan, layout_left>) > sizeof(void*)); +static_assert(sizeof(mdspan, layout_left, TrivialAccessor>) > sizeof(void*)); + +static_assert(sizeof(mdspan, layout_right>) == sizeof(void*)); +static_assert(sizeof(mdspan, layout_right>) > sizeof(void*)); +static_assert(sizeof(mdspan, layout_right, TrivialAccessor>) > sizeof(void*)); + constexpr bool test() { check_modeled_concepts_and_member_types, layout_stride, TrivialAccessor>(); check_modeled_concepts_and_member_types, TrackingLayout<>, From ae4f4a0fad3d18b151229be962d8a8565c5e0ea1 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 14:06:14 +0200 Subject: [PATCH 11/16] Remove extra constructors from mapping base --- stl/inc/mdspan | 4 ---- 1 file changed, 4 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 1155ff6d65..a9ea50e6d2 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1064,8 +1064,6 @@ struct _Mdspan_mapping_base { constexpr explicit _Mdspan_mapping_base(const _Extents& _Exts) : _Map(_Exts) {} - constexpr explicit _Mdspan_mapping_base(const _Mapping& _Map_) : _Map(_Map_) {} - template constexpr explicit _Mdspan_mapping_base(const _OtherMapping& _Map_) : _Map(_Map_) {} @@ -1080,8 +1078,6 @@ struct _Mdspan_mapping_base<_Extents, _LayoutPolicy> { constexpr explicit _Mdspan_mapping_base(const _Extents&) noexcept {} - constexpr explicit _Mdspan_mapping_base(const _Mapping&) noexcept {} - template constexpr explicit _Mdspan_mapping_base(const _OtherMapping& _Map_) { // NB: Constructing _Mapping from _OtherMapping may have side effects - we should create a temporary. From 2c935035c1e23898a150f57c702a633f37d69d8d Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 14:23:32 +0200 Subject: [PATCH 12/16] Revert "Revert "EBO for `layout_stride`"" This reverts commit 73e7ba457285e6ecef744e6555c9f8bcf71a37cf. --- stl/inc/mdspan | 47 ++++++++++--------- .../P0009R18_mdspan_layout_stride/test.cpp | 6 +++ 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index a9ea50e6d2..220bfde647 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -781,7 +781,8 @@ concept _Layout_mapping_alike = requires { }; template -class layout_stride::mapping { +class layout_stride::mapping : private _Maybe_fully_static_extents<_Extents>, + private _Maybe_empty_array { public: using extents_type = _Extents; using index_type = extents_type::index_type; @@ -789,6 +790,10 @@ public: using rank_type = extents_type::rank_type; using layout_type = layout_stride; +private: + using _Extents_base = _Maybe_fully_static_extents; + using _Strides_base = _Maybe_empty_array; + static_assert(_Is_extents, "Extents must be a specialization of std::extents (N4950 [mdspan.layout.stride.overview]/2)."); static_assert( @@ -796,12 +801,14 @@ public: "If Extents::rank_dynamic() == 0 is true, then the size of the multidimensional index space Extents() must be " "representable as a value of type typename Extents::index_type (N4950 [mdspan.layout.stride.overview]/4)."); - constexpr mapping() noexcept : _Exts(extents_type{}) { +public: + constexpr mapping() noexcept : _Extents_base(extents_type{}) { if constexpr (extents_type::rank() != 0) { - _Strides.back() = 1; + this->_Array.back() = 1; for (rank_type _Idx = extents_type::_Rank - 1; _Idx-- > 0;) { #if _CONTAINER_DEBUG_LEVEL > 0 - const bool _Overflow = _Mul_overflow(_Strides[_Idx + 1], _Exts.extent(_Idx + 1), _Strides[_Idx]); + const bool _Overflow = + _Mul_overflow(this->_Array[_Idx + 1], this->_Exts.extent(_Idx + 1), this->_Array[_Idx]); // NB: N4950 requires value of 'layout_right::mapping().required_span_size()' to be // representable as value of type 'index_type', but this is not enough. We need to require every single // stride to be representable as value of type 'index_type', so we can get desired effects. @@ -809,7 +816,7 @@ public: "Value of layout_right::mapping().required_span_size() must be " "representable as a value of type index_type (N4950 [mdspan.layout.stride.cons]/1)."); #else // ^^^ _CONTAINER_DEBUG_LEVEL > 0 / _CONTAINER_DEBUG_LEVEL == 0 vvv - _Strides[_Idx] = static_cast(_Strides[_Idx + 1] * _Exts.extent(_Idx + 1)); + this->_Array[_Idx] = static_cast(this->_Array[_Idx + 1] * this->_Exts.extent(_Idx + 1)); #endif // _CONTAINER_DEBUG_LEVEL > 0 } } @@ -822,17 +829,17 @@ public: && is_nothrow_constructible_v constexpr mapping(const extents_type& _Exts_, span<_OtherIndexType, extents_type::rank()> _Strides_, index_sequence<_Indices...>) noexcept - : _Exts(_Exts_), _Strides{static_cast(_STD as_const(_Strides_[_Indices]))...} { + : _Extents_base(_Exts_), _Strides_base{static_cast(_STD as_const(_Strides_[_Indices]))...} { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank() != 0) { bool _Found_zero = false; bool _Overflow = false; index_type _Req_span_size = 0; for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { - const index_type _Stride = _Strides[_Idx]; + const index_type _Stride = this->_Array[_Idx]; _STL_VERIFY(_Stride > 0, "Value of s[i] must be greater than 0 for all i in the range [0, rank_) " "(N4950 [mdspan.layout.stride.cons]/4.1)."); - const index_type _Ext = _Exts.extent(_Idx); + const index_type _Ext = this->_Exts.extent(_Idx); if (_Ext == 0) { _Found_zero = true; } @@ -885,7 +892,7 @@ public: && (_Is_mapping_of || _Is_mapping_of || _Is_mapping_of) )) mapping(const _StridedLayoutMapping& _Other) noexcept - : _Exts(_Other.extents()) { + : _Extents_base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(_STD in_range(_Other.required_span_size()), "Value of other.required_span_size() must be representable as a value of type index_type (N4950 " @@ -899,18 +906,18 @@ public: _STL_VERIFY(_Stride > 0, "Value of other.stride(r) must be greater than 0 for every rank index r of " "extents() (N4950 [mdspan.layout.stride.cons]/7.2)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - _Strides[_Idx] = static_cast(_Stride); + this->_Array[_Idx] = static_cast(_Stride); } } constexpr mapping& operator=(const mapping&) noexcept = default; _NODISCARD constexpr const extents_type& extents() const noexcept { - return _Exts; + return this->_Exts; } _NODISCARD constexpr array strides() const noexcept { - return _Strides; + return this->_Array; } _NODISCARD constexpr index_type required_span_size() const noexcept { @@ -919,12 +926,12 @@ public: } else { index_type _Result = 1; for (rank_type _Idx = 0; _Idx < extents_type::_Rank; ++_Idx) { - const index_type _Ext = _Exts.extent(_Idx); + const index_type _Ext = this->_Exts.extent(_Idx); if (_Ext == 0) { return 0; } - _Result += (_Ext - 1) * _Strides[_Idx]; + _Result += (_Ext - 1) * this->_Array[_Idx]; } return _Result; @@ -958,7 +965,8 @@ public: if constexpr (extents_type::rank() == 0) { return true; } else { - return required_span_size() == _Fwd_prod_of_extents::_Calculate(_Exts, extents_type::_Rank); + return required_span_size() + == _Fwd_prod_of_extents::_Calculate(this->_Exts, extents_type::_Rank); } } @@ -967,7 +975,7 @@ public: } _NODISCARD constexpr index_type stride(const rank_type _Idx) const noexcept { - return _Strides[_Idx]; + return this->_Array[_Idx]; } template @@ -990,9 +998,6 @@ public: } private: - /* [[no_unique_address]] */ extents_type _Exts{}; - /* [[no_unique_address]] */ array _Strides{}; - template _NODISCARD static constexpr _OtherMapping::index_type _Offset(_OtherMapping& _Mapping) noexcept { if constexpr (extents_type::rank() == 0) { @@ -1014,12 +1019,12 @@ private: [[maybe_unused]] index_sequence<_Seq...> _Index_seq, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); #if _CONTAINER_DEBUG_LEVEL > 0 - _STL_VERIFY(_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), + _STL_VERIFY(this->_Exts._Contains_multidimensional_index(_Index_seq, _Indices...), "Value of extents_type::index-cast(i) must be a multidimensional index in extents_ (N4950 " "[mdspan.layout.stride.obs]/3)."); #endif // _CONTAINER_DEBUG_LEVEL > 0 - return static_cast(((_Indices * _Strides[_Seq]) + ... + 0)); + return static_cast(((_Indices * this->_Array[_Seq]) + ... + 0)); } }; diff --git a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp index ab20ad5c87..13f6ea3032 100644 --- a/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_layout_stride/test.cpp @@ -821,6 +821,12 @@ constexpr void check_correctness() { } } +// When 'M::extents_type::rank()' 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>>); + constexpr bool test() { // Check signed integers check_members(extents{5}, array{1}); From cddcdde4e86d4acbf83f222223d465fd72498d14 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 14:28:13 +0200 Subject: [PATCH 13/16] EBO for `mdspan` when layout type is `layout_stride` --- stl/inc/mdspan | 3 ++- tests/std/tests/P0009R18_mdspan_mdspan/test.cpp | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 220bfde647..9d8cad3e08 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1059,7 +1059,8 @@ struct default_accessor { template concept _Elidable_layout_mapping = - _Is_any_of_v<_LayoutPolicy, layout_left, layout_right> && (_Extents::rank_dynamic() == 0); + (_Is_any_of_v<_LayoutPolicy, layout_left, layout_right> && _Extents::rank_dynamic() == 0) + || (same_as<_LayoutPolicy, layout_stride> && _Extents::rank() == 0); template struct _Mdspan_mapping_base { diff --git a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp index 8701991b64..aa4915c84c 100644 --- a/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_mdspan/test.cpp @@ -1335,7 +1335,9 @@ constexpr void check_deduction_guides() { // When // * 'Mds::accessor_type' is specialization of 'default_accesor', and -// * 'Mds::layout_type' is layout_left or layout_right and 'Mds::extents_type::rank_dynamic() == 0', +// * 'Mds::layout_type' is +// * 'layout_left' or 'layout_right' and 'Mds::extents_type::rank_dynamic() == 0', or +// * 'layout_stride' and 'Mds::extents_type::rank() == 0' // then 'sizeof(Mds) == sizeof(void*)' (MSVC STL specific behavior). static_assert(sizeof(mdspan, layout_left>) == sizeof(void*)); static_assert(sizeof(mdspan, layout_left>) > sizeof(void*)); @@ -1345,11 +1347,19 @@ static_assert(sizeof(mdspan, layout_right>) == size static_assert(sizeof(mdspan, layout_right>) > sizeof(void*)); static_assert(sizeof(mdspan, layout_right, TrivialAccessor>) > sizeof(void*)); +static_assert(sizeof(mdspan, layout_stride>) == sizeof(void*)); +static_assert(sizeof(mdspan, layout_stride>) > sizeof(void*)); +static_assert(sizeof(mdspan, layout_stride>) > sizeof(void*)); +static_assert(sizeof(mdspan, layout_stride, TrivialAccessor>) > sizeof(void*)); + constexpr bool test() { + check_modeled_concepts_and_member_types, layout_left, default_accessor>(); + check_modeled_concepts_and_member_types, layout_right, default_accessor>(); + check_modeled_concepts_and_member_types, layout_stride, default_accessor>(); + check_modeled_concepts_and_member_types, layout_left, TrackingAccessor>(); check_modeled_concepts_and_member_types, layout_stride, TrivialAccessor>(); check_modeled_concepts_and_member_types, TrackingLayout<>, AccessorWithTrackingDataHandle>(); - check_modeled_concepts_and_member_types, layout_left, TrackingAccessor>(); check_observers(); check_default_constructor(); check_defaulted_copy_and_move_constructors(); From bd2b058e3f8fe7f85c2534bb527dc31a762913c2 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 14:38:21 +0200 Subject: [PATCH 14/16] Fix double space --- stl/inc/mdspan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 9d8cad3e08..aed5c322d1 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1114,7 +1114,7 @@ struct _Mdspan_accessor_base<_AccessorPolicy> { template constexpr explicit _Mdspan_accessor_base(const _OtherAccessorPolicy& _Acc_) { - // NB: Constructing _AccessorPolicy from _OtherAccessorPolicy may have side effects - we should create a + // NB: Constructing _AccessorPolicy from _OtherAccessorPolicy may have side effects - we should create a // temporary. if constexpr (!_Elidable_accessor_policy<_OtherAccessorPolicy>) { (void) _AccessorPolicy{_Acc_}; From b8108d993c8684aff57db2de0c0e1f7d3fa84ad7 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 14:40:22 +0200 Subject: [PATCH 15/16] Typo: `emtpy` -> `empty` --- tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp index 0c9d507abf..5402186a9f 100644 --- a/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp +++ b/tests/std/tests/P0009R18_mdspan_default_accessor/test.cpp @@ -27,7 +27,7 @@ constexpr void test_one(array elems) { static_assert(is_trivially_copyable_v); static_assert(semiregular); - // Check if default_accessor is emtpy + // Check if default_accessor is empty static_assert(std::is_empty_v); // Check nested types From 30f7630496fe7d18a286dfe59d87905d1657dd32 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Wed, 5 Jul 2023 18:47:06 +0200 Subject: [PATCH 16/16] Cleanups --- stl/inc/mdspan | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index aed5c322d1..2fad249ec3 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -442,18 +442,20 @@ _EXPORT_STD struct layout_stride { template struct _Maybe_fully_static_extents { - _Extents _Exts{}; + _STL_INTERNAL_STATIC_ASSERT(_Is_extents<_Extents>); constexpr _Maybe_fully_static_extents() noexcept = default; template constexpr explicit _Maybe_fully_static_extents(const _OtherExtents& _Exts_) : _Exts(_Exts_) {} + + _Extents _Exts{}; }; template requires (_Extents::rank_dynamic() == 0) struct _Maybe_fully_static_extents<_Extents> { - static constexpr _Extents _Exts{}; + _STL_INTERNAL_STATIC_ASSERT(_Is_extents<_Extents>); constexpr _Maybe_fully_static_extents() noexcept = default; @@ -463,6 +465,8 @@ struct _Maybe_fully_static_extents<_Extents> { (void) _Extents{_Exts_}; // NB: temporary created for preconditions check #endif // _CONTAINER_DEBUG_LEVEL > 0 } + + static constexpr _Extents _Exts{}; }; template @@ -1064,6 +1068,8 @@ concept _Elidable_layout_mapping = template struct _Mdspan_mapping_base { + _STL_INTERNAL_STATIC_ASSERT(_Is_extents<_Extents>); + using _Mapping = _LayoutPolicy::template mapping<_Extents>; constexpr _Mdspan_mapping_base() noexcept = default; @@ -1078,6 +1084,8 @@ struct _Mdspan_mapping_base { template _LayoutPolicy> struct _Mdspan_mapping_base<_Extents, _LayoutPolicy> { + _STL_INTERNAL_STATIC_ASSERT(_Is_extents<_Extents>); + using _Mapping = _LayoutPolicy::template mapping<_Extents>; constexpr _Mdspan_mapping_base() noexcept = default;