From 99fabc9efbaa07212c81b286ce107fc1dd667d34 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 14:35:57 -0700 Subject: [PATCH 01/12] Unconditionally strengthen `mdspan::is_always_MEOW()`. They return `mapping_type::is_always_MEOW()` which is required to be a constant expression of type `bool` (N4950 \[mdspan.mdspan.overview\]/3, \[mdspan.layout.policy.reqmts\]/1, \[mdspan.layout.reqmts\]/22,24,26). The Standard should simply be enhanced to say `noexcept` here. Also introduce `constexpr bool _Result` to make this extra clear and improve debug codegen. --- stl/inc/mdspan | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index e06ca1a4d2b..1e2386bf49f 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1359,19 +1359,19 @@ public: return this->_Acc; } - _NODISCARD static constexpr bool is_always_unique() noexcept( - noexcept(mapping_type::is_always_unique())) /* strengthened */ { - return mapping_type::is_always_unique(); + _NODISCARD static constexpr bool is_always_unique() noexcept /* strengthened */ { + constexpr bool _Result = mapping_type::is_always_unique(); + return _Result; } - _NODISCARD static constexpr bool is_always_exhaustive() noexcept( - noexcept(mapping_type::is_always_exhaustive())) /* strengthened */ { - return mapping_type::is_always_exhaustive(); + _NODISCARD static constexpr bool is_always_exhaustive() noexcept /* strengthened */ { + constexpr bool _Result = mapping_type::is_always_exhaustive(); + return _Result; } - _NODISCARD static constexpr bool is_always_strided() noexcept( - noexcept(mapping_type::is_always_strided())) /* strengthened */ { - return mapping_type::is_always_strided(); + _NODISCARD static constexpr bool is_always_strided() noexcept /* strengthened */ { + constexpr bool _Result = mapping_type::is_always_strided(); + return _Result; } _NODISCARD constexpr bool is_unique() const noexcept(noexcept(this->_Map.is_unique())) /* strengthened */ { From 2f40cf7dcecc6dd4ee781af1af9f04c307090b62 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 14:41:15 -0700 Subject: [PATCH 02/12] Drop strengthened comment; `_Access_impl()` is `_Ugly` --- stl/inc/mdspan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 1e2386bf49f..75bab90abb0 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1401,7 +1401,7 @@ private: template _NODISCARD constexpr reference _Access_impl(_OtherIndexTypes... _Indices) const - noexcept(noexcept(this->_Acc.access(_Ptr, static_cast(this->_Map(_Indices...))))) /* strengthened */ { + noexcept(noexcept(this->_Acc.access(_Ptr, static_cast(this->_Map(_Indices...))))) { _STL_INTERNAL_STATIC_ASSERT((same_as<_OtherIndexTypes, index_type> && ...)); #if _CONTAINER_DEBUG_LEVEL > 0 _STL_VERIFY(this->_Map.extents()._Contains_multidimensional_index(make_index_sequence{}, _Indices...), From 5529f162ebc67e035d7e1b8c6c9822a63f1bcea0 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 14:50:19 -0700 Subject: [PATCH 03/12] Follow N4950 \[mdspan.mdspan.cons\]/8.1 by saying `const _OtherIndexType&` in this constraint. --- stl/inc/mdspan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 75bab90abb0..b8de551bbb8 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1200,7 +1200,7 @@ public: _Ptr(_STD move(_Ptr_)) {} template - requires is_convertible_v<_OtherIndexType, index_type> + requires is_convertible_v && is_nothrow_constructible_v && (_Size == rank() || _Size == rank_dynamic()) && is_constructible_v && is_default_constructible_v From 364622e4dc4467607c28fa088f7627f32f576e47 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 14:52:22 -0700 Subject: [PATCH 04/12] In `default_accessor`, define `access()` before `offset()` to follow the order of N4950 \[mdspan.accessor.default.overview\]. --- stl/inc/mdspan | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index b8de551bbb8..2879ccbb320 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1045,13 +1045,13 @@ struct default_accessor { requires is_convertible_v<_OtherElementType (*)[], element_type (*)[]> constexpr default_accessor(default_accessor<_OtherElementType>) noexcept {} - _NODISCARD constexpr data_handle_type offset(data_handle_type _Ptr, size_t _Idx) const noexcept { - return _Ptr + _Idx; - } - _NODISCARD constexpr reference access(data_handle_type _Ptr, size_t _Idx) const noexcept { return _Ptr[_Idx]; } + + _NODISCARD constexpr data_handle_type offset(data_handle_type _Ptr, size_t _Idx) const noexcept { + return _Ptr + _Idx; + } }; template From 49d335e782c464970060bbda007c2ac4518a1b06 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 14:57:46 -0700 Subject: [PATCH 05/12] `layout_stride::template mapping` is unnecessary; `layout_stride` is not a template. --- stl/inc/mdspan | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 2879ccbb320..ed4699029bd 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -532,7 +532,7 @@ public: template requires is_constructible_v constexpr explicit(extents_type::rank() > 0) - mapping(const layout_stride::template mapping<_OtherExtents>& _Other) noexcept // strengthened + mapping(const layout_stride::mapping<_OtherExtents>& _Other) noexcept // strengthened : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank() > 0) { @@ -684,8 +684,7 @@ public: template requires is_constructible_v - constexpr explicit(extents_type::rank() > 0) - mapping(const layout_stride::template mapping<_OtherExtents>& _Other) noexcept + constexpr explicit(extents_type::rank() > 0) mapping(const layout_stride::mapping<_OtherExtents>& _Other) noexcept : _Base(_Other.extents()) { #if _CONTAINER_DEBUG_LEVEL > 0 if constexpr (extents_type::rank() > 0) { From 4ce75ee8d9bdcfde5683fad88c3b2331090e5537 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 14:59:12 -0700 Subject: [PATCH 06/12] Add `explicit` to the deduction guide `extents(_Integrals...)`, depicted by N4950 \[mdspan.extents.overview\] and \[mdspan.extents.cons\]/12. --- stl/inc/mdspan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index ed4699029bd..787063a2bd4 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -321,7 +321,7 @@ inline constexpr size_t _Repeat_dynamic_extent = dynamic_extent; template requires (is_convertible_v<_Integrals, size_t> && ...) -extents(_Integrals...) -> extents...>; +explicit extents(_Integrals...) -> extents...>; template struct _Dextents_impl; From b328d13eb7e0fe50af046736eb54da187682d56c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 15:01:08 -0700 Subject: [PATCH 07/12] Style: Reorder the template parameters for `_Contains_multidimensional_index()` to match its function parameters; it's always called with template argument deduction. --- stl/inc/mdspan | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 787063a2bd4..935b0c106d6 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -304,7 +304,7 @@ public: } } - template + template _NODISCARD constexpr bool _Contains_multidimensional_index( index_sequence<_Seq...>, _IndexTypes... _Indices) const noexcept { _STL_INTERNAL_STATIC_ASSERT((same_as<_IndexTypes, index_type> && ...)); From 72141974e9635125efd3d2d802f85e532e4ab5d2 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 15:44:06 -0700 Subject: [PATCH 08/12] Step 1: Move `_Multidimensional_access()` up. --- stl/inc/mdspan | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 935b0c106d6..cd746c2a685 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1276,7 +1276,15 @@ public: noexcept(noexcept(_Access_impl(static_cast(_STD move(_Indices))...))) /* strengthened */ { return _Access_impl(static_cast(_STD move(_Indices))...); } -#endif // __cpp_multidimensional_subscript +#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv +private: + template + _NODISCARD constexpr reference _Multidimensional_access(_OtherIndexTypes... _Indices) const { + return _Access_impl(static_cast(_STD move(_Indices))...); + } + +public: +#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ template requires is_convertible_v @@ -1391,13 +1399,6 @@ public: } private: -#ifndef __cpp_multidimensional_subscript // TRANSITION, P2128R6 - template - _NODISCARD constexpr reference _Multidimensional_access(_OtherIndexTypes... _Indices) const { - return _Access_impl(static_cast(_STD move(_Indices))...); - } -#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ - template _NODISCARD constexpr reference _Access_impl(_OtherIndexTypes... _Indices) const noexcept(noexcept(this->_Acc.access(_Ptr, static_cast(this->_Map(_Indices...))))) { From 41c438fe89323baa824a444ed9beb320f58d92b5 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 15:45:37 -0700 Subject: [PATCH 09/12] Step 2: Add conditional `noexcept` to `_Multidimensional_access()`, not commented as strengthened because it's `_Ugly`. It's now identical to the real multidimensional subscript operator except for the name, the comment, and the intentional lack of constraints. --- stl/inc/mdspan | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index cd746c2a685..6ea0cc0933d 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1279,7 +1279,8 @@ public: #else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv private: template - _NODISCARD constexpr reference _Multidimensional_access(_OtherIndexTypes... _Indices) const { + _NODISCARD constexpr reference _Multidimensional_access(_OtherIndexTypes... _Indices) const + noexcept(noexcept(_Access_impl(static_cast(_STD move(_Indices))...))) { return _Access_impl(static_cast(_STD move(_Indices))...); } From ef8c8c2c034a6eda2e0bd824960c85843775826c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 15:51:32 -0700 Subject: [PATCH 10/12] Step 3: Add `as_const()` to the `array` overload, so it exactly matches the `span` overload. This is what N4950 \[mdspan.mdspan.members\]/6 depicts. It was being implicitly skipped before (`const array&` has the same effect), but adding this will make the following unification clearer. --- stl/inc/mdspan | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index 6ea0cc0933d..c95d4b885b7 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1306,9 +1306,9 @@ public: _NODISCARD constexpr reference operator[](const array<_OtherIndexType, rank()>& _Indices) const { return [&](index_sequence<_Seq...>) -> reference { #ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 - return operator[](_Indices[_Seq]...); + return operator[](_STD as_const(_Indices[_Seq])...); #else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv - return _Multidimensional_access(_Indices[_Seq]...); + return _Multidimensional_access(_STD as_const(_Indices[_Seq])...); #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ }(make_index_sequence{}); } From c193bce99c728b310f14000b833f619fcdca9417 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 16:07:57 -0700 Subject: [PATCH 11/12] Step 4: Replace lambdas with `_Multidimensional_subscript()`. This unifies them by wrapping the `array` in a `span`. --- stl/inc/mdspan | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index c95d4b885b7..e33eed5dce6 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1276,6 +1276,13 @@ public: noexcept(noexcept(_Access_impl(static_cast(_STD move(_Indices))...))) /* strengthened */ { return _Access_impl(static_cast(_STD move(_Indices))...); } + +private: + template + _NODISCARD constexpr reference _Multidimensional_subscript( + span<_OtherIndexType, rank()> _Indices, index_sequence<_Seq...>) const { + return operator[](_STD as_const(_Indices[_Seq])...); + } #else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv private: template @@ -1284,33 +1291,26 @@ private: return _Access_impl(static_cast(_STD move(_Indices))...); } -public: + template + _NODISCARD constexpr reference _Multidimensional_subscript( + span<_OtherIndexType, rank()> _Indices, index_sequence<_Seq...>) const { + return _Multidimensional_access(_STD as_const(_Indices[_Seq])...); + } #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ +public: template requires is_convertible_v && is_nothrow_constructible_v _NODISCARD constexpr reference operator[](span<_OtherIndexType, rank()> _Indices) const { - return [&](index_sequence<_Seq...>) -> reference { -#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 - return operator[](_STD as_const(_Indices[_Seq])...); -#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv - return _Multidimensional_access(_STD as_const(_Indices[_Seq])...); -#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ - }(make_index_sequence{}); + return _Multidimensional_subscript(_Indices, make_index_sequence{}); } template requires is_convertible_v && is_nothrow_constructible_v _NODISCARD constexpr reference operator[](const array<_OtherIndexType, rank()>& _Indices) const { - return [&](index_sequence<_Seq...>) -> reference { -#ifdef __cpp_multidimensional_subscript // TRANSITION, P2128R6 - return operator[](_STD as_const(_Indices[_Seq])...); -#else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv - return _Multidimensional_access(_STD as_const(_Indices[_Seq])...); -#endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ - }(make_index_sequence{}); + return _Multidimensional_subscript(span{_Indices}, make_index_sequence{}); } _NODISCARD constexpr size_type size() const noexcept { From 1c92a8e339fcc7f652c66b4267b07d14ea73948c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 15 Aug 2023 16:11:01 -0700 Subject: [PATCH 12/12] Step 5: Add conditional `noexcept` to `_Multidimensional_subscript` (not commented, it's `_Ugly`), then strengthen `operator[]` for `span`/`array`. This brings the `span`/`array` subscript operators up to parity with the multidimensional subscript operator. --- stl/inc/mdspan | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/stl/inc/mdspan b/stl/inc/mdspan index e33eed5dce6..18bfbd32420 100644 --- a/stl/inc/mdspan +++ b/stl/inc/mdspan @@ -1279,8 +1279,8 @@ public: private: template - _NODISCARD constexpr reference _Multidimensional_subscript( - span<_OtherIndexType, rank()> _Indices, index_sequence<_Seq...>) const { + _NODISCARD constexpr reference _Multidimensional_subscript(span<_OtherIndexType, rank()> _Indices, + index_sequence<_Seq...>) const noexcept(noexcept(operator[](_STD as_const(_Indices[_Seq])...))) { return operator[](_STD as_const(_Indices[_Seq])...); } #else // ^^^ defined(__cpp_multidimensional_subscript) / !defined(__cpp_multidimensional_subscript) vvv @@ -1292,8 +1292,8 @@ private: } template - _NODISCARD constexpr reference _Multidimensional_subscript( - span<_OtherIndexType, rank()> _Indices, index_sequence<_Seq...>) const { + _NODISCARD constexpr reference _Multidimensional_subscript(span<_OtherIndexType, rank()> _Indices, + index_sequence<_Seq...>) const noexcept(noexcept(_Multidimensional_access(_STD as_const(_Indices[_Seq])...))) { return _Multidimensional_access(_STD as_const(_Indices[_Seq])...); } #endif // ^^^ !defined(__cpp_multidimensional_subscript) ^^^ @@ -1302,14 +1302,18 @@ public: template requires is_convertible_v && is_nothrow_constructible_v - _NODISCARD constexpr reference operator[](span<_OtherIndexType, rank()> _Indices) const { + _NODISCARD constexpr reference operator[](span<_OtherIndexType, rank()> _Indices) const + noexcept(noexcept(_Multidimensional_subscript(_Indices, make_index_sequence{}))) /* strengthened */ + { return _Multidimensional_subscript(_Indices, make_index_sequence{}); } template requires is_convertible_v && is_nothrow_constructible_v - _NODISCARD constexpr reference operator[](const array<_OtherIndexType, rank()>& _Indices) const { + _NODISCARD constexpr reference operator[](const array<_OtherIndexType, rank()>& _Indices) const noexcept( + noexcept(_Multidimensional_subscript(span{_Indices}, make_index_sequence{}))) /* strengthened */ + { return _Multidimensional_subscript(span{_Indices}, make_index_sequence{}); }