From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1888) id 8A9213857C44; Tue, 20 Apr 2021 13:19:13 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8A9213857C44 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Patrick Palka To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-8] libstdc++: Implement P2259R1 changes [PR95983] X-Act-Checkin: gcc X-Git-Author: Patrick Palka X-Git-Refname: refs/heads/master X-Git-Oldrev: 7f5deba1c21888aacedae93e9f324827073a1d1e X-Git-Newrev: 902b40c797a86f76791c32d537ba06dff5f1ba27 Message-Id: <20210420131913.8A9213857C44@sourceware.org> Date: Tue, 20 Apr 2021 13:19:13 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 20 Apr 2021 13:19:13 -0000 https://gcc.gnu.org/g:902b40c797a86f76791c32d537ba06dff5f1ba27 commit r12-8-g902b40c797a86f76791c32d537ba06dff5f1ba27 Author: Patrick Palka Date: Tue Apr 20 09:18:50 2021 -0400 libstdc++: Implement P2259R1 changes [PR95983] This implements the wording changes of P2259R1 "Repairing input range adaptors and counted_iterator", which resolves LWG 3283, 3289 and 3408. The wording changes are relatively straightforward, but they require some boilerplate to implement: the changes to make a type alias "conditionally present" in some iterator class are realized by defining a base class template and an appropriately constrained partial specialization thereof that contains the type alias, and having the iterator class derive from this base class. Sometimes the relevant condition depend on members from the iterator class, but because a class is incomplete when instantiating its bases, the constraints on the partial specialization can't use anything from the iterator class. This patch works around this by hoisting these members out to the enclosing scope (e.g. transform_view::_Iterator::_Base is hoisted out to transform_view::_Base so that transform_view::__iter_cat can use it). This patch also implements the proposed resolution of LWG 3291 to rename iota_view::iterator_category to iota_view::iterator_concept, which was previously problematic due to LWG 3408. libstdc++-v3/ChangeLog: PR libstdc++/95983 * include/bits/stl_iterator.h (__detail::__move_iter_cat): Define. (move_iterator): Derive from the above in C++20 in order to conditionally define iterator_category as per P2259. (move_iterator::__base_cat): No longer used, so remove. (move_iterator::iterator_category): Remove in C++20. (__detail::__common_iter_use_postfix_proxy): Define. (common_iterator::_Proxy): Rename to ... (common_iterator:__arrow_proxy): ... this. (common_iterator::__postfix_proxy): Define as per P2259. (common_iterator::operator->): Adjust. (common_iterator::operator++): Adjust as per P2259. (iterator_traits::_S_iter_cat): Define. (iterator_traits::iterator_category): Change as per P2259. (__detail::__counted_iter_value_type): Define. (__detail::__counted_iter_concept): Define. (__detail::__counted_iter_cat): Define. (counted_iterator): Derive from the above three classes in order to conditionally define value_type, iterator_concept and iterator category respectively as per P2259. (counted_iterator::operator->): Define as per P2259. (incrementable_traits): Remove as per P2259. (iterator_traits): Adjust as per P2259. * include/std/ranges (__detail::__iota_view_iter_cat): Define. (iota_view::_Iterator): Derive from the above in order to conditionally define iterator_category as per P2259. (iota_view::_S_iter_cat): Rename to ... (iota_view::_S_iter_concept): ... this. (iota_view::iterator_concept): Use it to apply LWG 3291 changes. (iota_view::iterator_category): Remove. (__detail::__filter_view_iter_cat): Define. (filter_view::_Iterator): Derive from the above in order to conditionally define iterator_category as per P2259. (filter_view::_Iterator): Move to struct __filter_view_iter_cat. (filter_view::_Iterator::iterator_category): Remove. (transform_view::_Base): Define. (transform_view::__iter_cat): Define. (transform_view::_Iterator): Derive from the above in order to conditionally define iterator_category as per P2259. (transform_view::_Iterator::_Base): Just alias transform_view::_Base. (transform_view::_Iterator::_S_iter_cat): Move to struct transform_view::__iter_cat. (transform_view::_Iterator::iterator_category): Remove. (transform_view::_Sentinel::_Base): Just alias transform_view::_Base. (join_view::_Base): Define. (join_view::_Outer_iter): Define. (join_view::_Inner_iter): Define. (join_view::_S_ref_is_glvalue): Define. (join_view::__iter_cat): Define. (join_view::_Iterator): Derive from it in order to conditionally define iterator_category as per P2259. (join_view::_Iterator::_Base): Just alias join_view::_Base. (join_view::_Iterator::_S_ref_is_glvalue): Just alias join_view::_S_ref_is_glvalue. (join_view::_Iterator::_S_iter_cat): Move to struct transform_view::__iter_cat. (join_view::_Iterator::_Outer_iter): Just alias join_view::_Outer_iter. (join_view::_Iterator::_Inner_iter): Just alias join_view::_Inner_iter. (join_view::_Iterator::iterator_category): Remove. (join_view::_Sentinel::_Base): Just alias join_view::_Base. (__detail::__split_view_outer_iter_cat): Define. (__detail::__split_view_inner_iter_cat): Define. (split_view::_Base): Define. (split_view::_Outer_iter): Derive from __split_view_outer_iter_cat in order to conditionally define iterator_category as per P2259. (split_view::_Outer_iter::iterator_category): Remove. (split_view::_Inner_iter): Derive from __split_view_inner_iter_cat in order to conditionally define iterator_category as per P2259. (split_view::_Inner_iter::_S_iter_cat): Move to __split_view_inner_iter_cat. (split_view::_Inner_iter::iterator_category): Remove. (elements_view::_Base): Define. (elements_view::__iter_cat): Define. (elements_view::_Iterator): Derive from the above in order to conditionall define iterator_category as per P2259. (elements_view::_Iterator::_Base): Just alias elements_view::_Base. (elements_view::_Iterator::_S_iter_concept) (elements_view::_Iterator::iterator_concept): Define as per P2259. (elements_view::_Iterator::iterator_category): Remove. (elements_view::_Sentinel::_Base): Just alias elements_view::_Base. * testsuite/24_iterators/headers/iterator/synopsis_c++20.cc: Adjust constraints on iterator_traits. * testsuite/std/ranges/p2259.cc: New test. Diff: --- libstdc++-v3/include/bits/stl_iterator.h | 128 +++++++-- libstdc++-v3/include/std/ranges | 299 +++++++++++++++------ .../headers/iterator/synopsis_c++20.cc | 1 + libstdc++-v3/testsuite/std/ranges/p2259.cc | 91 +++++++ 4 files changed, 412 insertions(+), 107 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index dc8b101e8f8..049f83cff90 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -1302,6 +1302,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #endif // C++20 + namespace __detail + { +#if __cplusplus > 201703L && __cpp_lib_concepts + template + struct __move_iter_cat + { }; + + template + requires requires { typename iterator_traits<_Iterator>::iterator_category; } + struct __move_iter_cat<_Iterator> + { + using iterator_category + = __clamp_iter_cat::iterator_category, + random_access_iterator_tag>; + }; +#endif + } + // 24.4.3 Move iterators /** * Class template move_iterator is an iterator adapter with the same @@ -1313,13 +1331,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template class move_iterator +#if __cplusplus > 201703L && __cpp_lib_concepts + : public __detail::__move_iter_cat<_Iterator> +#endif { _Iterator _M_current; using __traits_type = iterator_traits<_Iterator>; -#if __cplusplus > 201703L && __cpp_lib_concepts - using __base_cat = typename __traits_type::iterator_category; -#else +#if ! (__cplusplus > 201703L && __cpp_lib_concepts) using __base_ref = typename __traits_type::reference; #endif @@ -1339,8 +1358,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus > 201703L && __cpp_lib_concepts using iterator_concept = input_iterator_tag; - using iterator_category - = __detail::__clamp_iter_cat<__base_cat, random_access_iterator_tag>; + // iterator_category defined in __move_iter_cat using value_type = iter_value_t<_Iterator>; using difference_type = iter_difference_t<_Iterator>; using pointer = _Iterator; @@ -1662,6 +1680,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION || is_reference_v> || constructible_from, iter_reference_t<_It>>); + template + concept __common_iter_use_postfix_proxy + = (!requires (_It& __i) { { *__i++ } -> __can_reference; }) + && constructible_from, iter_reference_t<_It>>; } // namespace __detail /// An iterator/sentinel adaptor for representing a non-common range. @@ -1684,11 +1706,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _S_noexcept() { return _S_noexcept1<_It, _It2>() && _S_noexcept1<_Sent, _Sent2>(); } - class _Proxy + class __arrow_proxy { iter_value_t<_It> _M_keep; - _Proxy(iter_reference_t<_It>&& __x) + __arrow_proxy(iter_reference_t<_It>&& __x) : _M_keep(std::move(__x)) { } friend class common_iterator; @@ -1699,6 +1721,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return std::__addressof(_M_keep); } }; + class __postfix_proxy + { + iter_value_t<_It> _M_keep; + + __postfix_proxy(iter_reference_t<_It>&& __x) + : _M_keep(std::move(__x)) { } + + friend class common_iterator; + + public: + const iter_value_t<_It>& + operator*() const + { return _M_keep; } + }; + public: constexpr common_iterator() @@ -1855,7 +1892,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return std::__addressof(__tmp); } else - return _Proxy{*_M_it}; + return __arrow_proxy{*_M_it}; } common_iterator& @@ -1876,8 +1913,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ++*this; return __tmp; } - else + else if constexpr (!__detail::__common_iter_use_postfix_proxy<_It>) return _M_it++; + else + { + __postfix_proxy __p(**this); + ++*this; + return __p; + } } template _Sent2> @@ -2008,12 +2051,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using type = decltype(std::declval().operator->()); }; + static auto + _S_iter_cat() + { + using _Traits = iterator_traits<_It>; + if constexpr (requires { requires derived_from; }) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + public: using iterator_concept = conditional_t, forward_iterator_tag, input_iterator_tag>; - using iterator_category = __detail::__clamp_iter_cat< - typename iterator_traits<_It>::iterator_category, - forward_iterator_tag, input_iterator_tag>; + using iterator_category = decltype(_S_iter_cat()); using value_type = iter_value_t<_It>; using difference_type = iter_difference_t<_It>; using pointer = typename __ptr<_It>::type; @@ -2022,12 +2074,48 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // [iterators.counted] Counted iterators + namespace __detail + { + template + struct __counted_iter_value_type + { }; + + template + struct __counted_iter_value_type<_It> + { using value_type = iter_value_t<_It>; }; + + template + struct __counted_iter_concept + { }; + + template + requires requires { typename _It::iterator_concept; } + struct __counted_iter_concept<_It> + { using iterator_concept = typename _It::iterator_concept; }; + + template + struct __counted_iter_cat + { }; + + template + requires requires { typename _It::iterator_category; } + struct __counted_iter_cat<_It> + { using iterator_category = typename _It::iterator_category; }; + } + /// An iterator adaptor that keeps track of the distance to the end. template class counted_iterator + : public __detail::__counted_iter_value_type<_It>, + public __detail::__counted_iter_concept<_It>, + public __detail::__counted_iter_cat<_It> { public: using iterator_type = _It; + // value_type defined in __counted_iter_value_type + using difference_type = iter_difference_t<_It>; + // iterator_concept defined in __counted_iter_concept + // iterator_category defined in __counted_iter_cat constexpr counted_iterator() = default; @@ -2084,6 +2172,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *_M_current; } + constexpr auto + operator->() const noexcept + requires contiguous_iterator<_It> + { return std::to_address(_M_current); } + constexpr counted_iterator& operator++() { @@ -2232,16 +2325,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION iter_difference_t<_It> _M_length = 0; }; - template - struct incrementable_traits> - { - using difference_type = iter_difference_t<_It>; - }; - template + requires same_as<__detail::__iter_traits<_It>, iterator_traits<_It>> struct iterator_traits> : iterator_traits<_It> { - using pointer = void; + using pointer = conditional_t, + add_pointer_t>, + void>; }; #endif // C++20 diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index baec8c0efef..74075a2d6d3 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -290,6 +290,13 @@ namespace ranges { __j - __j } -> convertible_to<__iota_diff_t<_It>>; }; + template + struct __iota_view_iter_cat + { }; + + template + struct __iota_view_iter_cat<_Winc> + { using iterator_category = input_iterator_tag; }; } // namespace __detail template { private: static auto - _S_iter_cat() + _S_iter_concept() { using namespace __detail; if constexpr (__advanceable<_Winc>) @@ -319,7 +326,8 @@ namespace ranges } public: - using iterator_category = decltype(_S_iter_cat()); + using iterator_concept = decltype(_S_iter_concept()); + // iterator_category defined in __iota_view_iter_cat using value_type = _Winc; using difference_type = __detail::__iota_diff_t<_Winc>; @@ -1100,7 +1108,32 @@ namespace views::__adaptor _M_offset = __it - ranges::begin(__r); } }; + } // namespace __detail + + namespace __detail + { + template + struct __filter_view_iter_cat + { }; + template + struct __filter_view_iter_cat<_Base> + { + private: + static auto + _S_iter_cat() + { + using _Cat = typename iterator_traits>::iterator_category; + if constexpr (derived_from<_Cat, bidirectional_iterator_tag>) + return bidirectional_iterator_tag{}; + else if constexpr (derived_from<_Cat, forward_iterator_tag>) + return forward_iterator_tag{}; + else + return _Cat{}; + } + public: + using iterator_category = decltype(_S_iter_cat()); + }; } // namespace __detail template { private: static constexpr auto @@ -1125,18 +1158,6 @@ namespace views::__adaptor return input_iterator_tag{}; } - static constexpr auto - _S_iter_cat() - { - using _Cat = typename iterator_traits<_Vp_iter>::iterator_category; - if constexpr (derived_from<_Cat, bidirectional_iterator_tag>) - return bidirectional_iterator_tag{}; - else if constexpr (derived_from<_Cat, forward_iterator_tag>) - return forward_iterator_tag{}; - else - return _Cat{}; - } - friend filter_view; using _Vp_iter = iterator_t<_Vp>; @@ -1146,7 +1167,7 @@ namespace views::__adaptor public: using iterator_concept = decltype(_S_iter_concept()); - using iterator_category = decltype(_S_iter_cat()); + // iterator_category defined in __filter_view_iter_cat using value_type = range_value_t<_Vp>; using difference_type = range_difference_t<_Vp>; @@ -1344,36 +1365,26 @@ namespace views::__adaptor { private: template - struct _Sentinel; + using _Base = __detail::__maybe_const_t<_Const, _Vp>; template - struct _Iterator + struct __iter_cat + { }; + + template + requires forward_range<_Base<_Const>> + struct __iter_cat<_Const> { private: - using _Parent = __detail::__maybe_const_t<_Const, transform_view>; - using _Base = __detail::__maybe_const_t<_Const, _Vp>; - - static constexpr auto - _S_iter_concept() - { - if constexpr (random_access_range<_Vp>) - return random_access_iterator_tag{}; - else if constexpr (bidirectional_range<_Vp>) - return bidirectional_iterator_tag{}; - else if constexpr (forward_range<_Vp>) - return forward_iterator_tag{}; - else - return input_iterator_tag{}; - } - - static constexpr auto + static auto _S_iter_cat() { + using _Base = transform_view::_Base<_Const>; using _Res = invoke_result_t<_Fp&, range_reference_t<_Base>>; if constexpr (is_lvalue_reference_v<_Res>) { using _Cat - = typename iterator_traits<_Base_iter>::iterator_category; + = typename iterator_traits>::iterator_category; if constexpr (derived_from<_Cat, contiguous_iterator_tag>) return random_access_iterator_tag{}; else @@ -1382,6 +1393,32 @@ namespace views::__adaptor else return input_iterator_tag{}; } + public: + using iterator_category = decltype(_S_iter_cat()); + }; + + template + struct _Sentinel; + + template + struct _Iterator : __iter_cat<_Const> + { + private: + using _Parent = __detail::__maybe_const_t<_Const, transform_view>; + using _Base = transform_view::_Base<_Const>; + + static auto + _S_iter_concept() + { + if constexpr (random_access_range<_Vp>) + return random_access_iterator_tag{}; + else if constexpr (bidirectional_range<_Vp>) + return bidirectional_iterator_tag{}; + else if constexpr (forward_range<_Vp>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } using _Base_iter = iterator_t<_Base>; @@ -1390,7 +1427,7 @@ namespace views::__adaptor public: using iterator_concept = decltype(_S_iter_concept()); - using iterator_category = decltype(_S_iter_cat()); + // iterator_category defined in __transform_view_iter_cat using value_type = remove_cvref_t>>; using difference_type = range_difference_t<_Base>; @@ -1556,7 +1593,7 @@ namespace views::__adaptor { private: using _Parent = __detail::__maybe_const_t<_Const, transform_view>; - using _Base = __detail::__maybe_const_t<_Const, _Vp>; + using _Base = transform_view::_Base<_Const>; template constexpr auto @@ -2210,18 +2247,62 @@ namespace views::__adaptor private: using _InnerRange = range_reference_t<_Vp>; + template + using _Base = __detail::__maybe_const_t<_Const, _Vp>; + + template + using _Outer_iter = iterator_t<_Base<_Const>>; + + template + using _Inner_iter = iterator_t>>; + + template + static constexpr bool _S_ref_is_glvalue + = is_reference_v>>; + + template + struct __iter_cat + { }; + + template + requires _S_ref_is_glvalue<_Const> + && forward_range<_Base<_Const>> + && forward_range>> + struct __iter_cat<_Const> + { + private: + static constexpr auto + _S_iter_cat() + { + using _Outer_iter = join_view::_Outer_iter<_Const>; + using _Inner_iter = join_view::_Inner_iter<_Const>; + using _OuterCat = typename iterator_traits<_Outer_iter>::iterator_category; + using _InnerCat = typename iterator_traits<_Inner_iter>::iterator_category; + if constexpr (derived_from<_OuterCat, bidirectional_iterator_tag> + && derived_from<_InnerCat, bidirectional_iterator_tag>) + return bidirectional_iterator_tag{}; + else if constexpr (derived_from<_OuterCat, forward_iterator_tag> + && derived_from<_InnerCat, forward_iterator_tag>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + public: + using iterator_category = decltype(_S_iter_cat()); + }; + template struct _Sentinel; template - struct _Iterator + struct _Iterator : __iter_cat<_Const> { private: using _Parent = __detail::__maybe_const_t<_Const, join_view>; - using _Base = __detail::__maybe_const_t<_Const, _Vp>; + using _Base = join_view::_Base<_Const>; static constexpr bool _S_ref_is_glvalue - = is_reference_v>; + = join_view::_S_ref_is_glvalue<_Const>; constexpr void _M_satisfy() @@ -2261,30 +2342,8 @@ namespace views::__adaptor return input_iterator_tag{}; } - static constexpr auto - _S_iter_cat() - { - using _OuterCat - = typename iterator_traits<_Outer_iter>::iterator_category; - using _InnerCat - = typename iterator_traits<_Inner_iter>::iterator_category; - if constexpr (_S_ref_is_glvalue - && derived_from<_OuterCat, bidirectional_iterator_tag> - && derived_from<_InnerCat, bidirectional_iterator_tag>) - return bidirectional_iterator_tag{}; - else if constexpr (_S_ref_is_glvalue - && derived_from<_OuterCat, forward_iterator_tag> - && derived_from<_InnerCat, forward_iterator_tag>) - return forward_iterator_tag{}; - else if constexpr (derived_from<_OuterCat, input_iterator_tag> - && derived_from<_InnerCat, input_iterator_tag>) - return input_iterator_tag{}; - else - return output_iterator_tag{}; - } - - using _Outer_iter = iterator_t<_Base>; - using _Inner_iter = iterator_t>; + using _Outer_iter = join_view::_Outer_iter<_Const>; + using _Inner_iter = join_view::_Inner_iter<_Const>; _Outer_iter _M_outer = _Outer_iter(); _Inner_iter _M_inner = _Inner_iter(); @@ -2292,7 +2351,7 @@ namespace views::__adaptor public: using iterator_concept = decltype(_S_iter_concept()); - using iterator_category = decltype(_S_iter_cat()); + // iterator_category defined in __join_view_iter_cat using value_type = range_value_t>; using difference_type = common_type_t, @@ -2412,7 +2471,7 @@ namespace views::__adaptor { private: using _Parent = __detail::__maybe_const_t<_Const, join_view>; - using _Base = __detail::__maybe_const_t<_Const, _Vp>; + using _Base = join_view::_Base<_Const>; template constexpr bool @@ -2550,6 +2609,35 @@ namespace views::__adaptor && requires { typename __require_constant::size()>; } && (remove_reference_t<_Range>::size() <= 1); + + template + struct __split_view_outer_iter_cat + { }; + + template + struct __split_view_outer_iter_cat<_Base> + { using iterator_category = input_iterator_tag; }; + + template + struct __split_view_inner_iter_cat + { }; + + template + struct __split_view_inner_iter_cat<_Base> + { + private: + static constexpr auto + _S_iter_cat() + { + using _Cat = typename iterator_traits>::iterator_category; + if constexpr (derived_from<_Cat, forward_iterator_tag>) + return forward_iterator_tag{}; + else + return _Cat{}; + } + public: + using iterator_category = decltype(_S_iter_cat()); + }; } template @@ -2560,15 +2648,19 @@ namespace views::__adaptor class split_view : public view_interface> { private: + template + using _Base = __detail::__maybe_const_t<_Const, _Vp>; + template struct _InnerIter; template struct _OuterIter + : __detail::__split_view_outer_iter_cat<_Base<_Const>> { private: using _Parent = __detail::__maybe_const_t<_Const, split_view>; - using _Base = __detail::__maybe_const_t<_Const, _Vp>; + using _Base = split_view::_Base<_Const>; constexpr bool __at_end() const @@ -2607,7 +2699,7 @@ namespace views::__adaptor using iterator_concept = conditional_t, forward_iterator_tag, input_iterator_tag>; - using iterator_category = input_iterator_tag; + // iterator_category defined in __split_view_outer_iter_cat using difference_type = range_difference_t<_Base>; struct value_type : view_interface @@ -2723,9 +2815,10 @@ namespace views::__adaptor template struct _InnerIter + : __detail::__split_view_inner_iter_cat<_Base<_Const>> { private: - using _Base = __detail::__maybe_const_t<_Const, _Vp>; + using _Base = split_view::_Base<_Const>; constexpr bool __at_end() const @@ -2759,17 +2852,6 @@ namespace views::__adaptor } } - static constexpr auto - _S_iter_cat() - { - using _Cat - = typename iterator_traits>::iterator_category; - if constexpr (derived_from<_Cat, forward_iterator_tag>) - return forward_iterator_tag{}; - else - return _Cat{}; - } - constexpr auto& _M_i_current() noexcept { return _M_i.__current(); } @@ -2784,7 +2866,7 @@ namespace views::__adaptor public: using iterator_concept = typename _OuterIter<_Const>::iterator_concept; - using iterator_category = decltype(_S_iter_cat()); + // iterator_category defined in __split_view_inner_iter_cat using value_type = range_value_t<_Base>; using difference_type = range_difference_t<_Base>; @@ -3292,14 +3374,42 @@ namespace views::__adaptor { return ranges::size(_M_base); } private: + template + using _Base = __detail::__maybe_const_t<_Const, _Vp>; + + template + struct __iter_cat + { }; + + template + requires forward_range<_Base<_Const>> + struct __iter_cat<_Const> + { + private: + static auto _S_iter_cat() + { + using _Base = elements_view::_Base<_Const>; + using _Cat = iterator_traits>::iterator_category; + using _Res = decltype((std::get<_Nm>(*std::declval>()))); + if constexpr (!is_lvalue_reference_v<_Res>) + return input_iterator_tag{}; + else if constexpr (derived_from<_Cat, random_access_iterator_tag>) + return random_access_iterator_tag{}; + else + return _Cat{}; + } + public: + using iterator_category = decltype(_S_iter_cat()); + }; + template struct _Sentinel; template - struct _Iterator + struct _Iterator : __iter_cat<_Const> { private: - using _Base = __detail::__maybe_const_t<_Const, _Vp>; + using _Base = elements_view::_Base<_Const>; iterator_t<_Base> _M_current = iterator_t<_Base>(); @@ -3315,11 +3425,24 @@ namespace views::__adaptor } } + static auto + _S_iter_concept() + { + if constexpr (random_access_range<_Vp>) + return random_access_iterator_tag{}; + else if constexpr (bidirectional_range<_Vp>) + return bidirectional_iterator_tag{}; + else if constexpr (forward_range<_Vp>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + friend _Iterator; public: - using iterator_category - = typename iterator_traits>::iterator_category; + using iterator_concept = decltype(_S_iter_concept()); + // iterator_category defined in elements_view::__iter_cat using value_type = remove_cvref_t>>; using difference_type = range_difference_t<_Base>; @@ -3471,7 +3594,7 @@ namespace views::__adaptor _M_equal(const _Iterator<_Const>& __x) const { return __x._M_current == _M_end; } - using _Base = __detail::__maybe_const_t<_Const, _Vp>; + using _Base = elements_view::_Base<_Const>; sentinel_t<_Base> _M_end = sentinel_t<_Base>(); public: diff --git a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++20.cc b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++20.cc index 3ebb1e0e204..3103094b36c 100644 --- a/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++20.cc +++ b/libstdc++-v3/testsuite/24_iterators/headers/iterator/synopsis_c++20.cc @@ -73,6 +73,7 @@ namespace std struct incrementable_traits>; template + requires same_as<__detail::__iter_traits, iterator_traits> struct iterator_traits>; struct unreachable_sentinel_t; diff --git a/libstdc++-v3/testsuite/std/ranges/p2259.cc b/libstdc++-v3/testsuite/std/ranges/p2259.cc new file mode 100644 index 00000000000..1b422e44f16 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/p2259.cc @@ -0,0 +1,91 @@ +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +// Verify P2259 changes. + +#include +#include +#include + +namespace ranges = std::ranges; +namespace views = std::views; + +using std::__detail::__iter_without_category; + +template +concept only_cxx20_input_range = ranges::input_range<_Range> + && !ranges::forward_range<_Range> + && __iter_without_category>; + +void +test01() +{ + extern std::vector vec; + only_cxx20_input_range auto v0 + = vec + | views::transform([](int c) { return views::single(c); }) + | views::join; + + // Verify the changes to filter_view. + only_cxx20_input_range auto v1 = v0 | views::filter([](int c) { return c > 0; }); + + // Verify the changes to transform_view. + only_cxx20_input_range auto v2 = v0 | views::transform([](int& c) -> auto& { return c; }); + + // Verify the changes to split_view. + only_cxx20_input_range auto v3 = v0 | views::split(12); + static_assert(only_cxx20_input_range); + + // Verify the changes to join_view. + only_cxx20_input_range auto v4 = v0 | views::split(12) | views::join; + + // Verify the changes to elements_view. + only_cxx20_input_range auto v5 + = v0 + | views::transform([](int c) { return std::make_tuple(c, c); }) + | views::elements<0>; + + // Verify the changes to common_iterator. + only_cxx20_input_range auto v6 = v0 | views::common; + *(v6.begin()++); + + // Verify the changes to iota_view. + only_cxx20_input_range auto v8 = ranges::iota_view{v0.begin()}; + + // Verify the changes to move_iterator. + __iter_without_category auto i9 = std::make_move_iterator(v0.begin()); + + // Verify the changes to counted_iterator. + extern std::counted_iterator i10; + static_assert(std::contiguous_iterator); + static_assert(std::same_as::iterator_category, + std::random_access_iterator_tag>); + i10.operator->(); + __iter_without_category auto i11 = std::counted_iterator{v0.begin(), 5}; +} + +void +test02() +{ + // Verify LWG 3291 example. + auto v = views::iota(0); + auto i = std::counted_iterator{v.begin(), 5}; + static_assert(std::random_access_iterator); +}