From patchwork Thu Jun 17 15:22:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1493635 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=CrkdutG6; dkim-atps=neutral Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G5RMR55Mpz9s24 for ; Fri, 18 Jun 2021 01:49:55 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 703E839730F9 for ; Thu, 17 Jun 2021 15:49:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 703E839730F9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1623944993; bh=eclKvtb3ofscL4DG/2Z9/piGn7/MgjKPnz+FlBd9ks8=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=CrkdutG6MVyyfhln+4Jlr4VjbCDH+iXjfVIqKftFOlfncqTfDTAHt2DJqFrekfQtB pKF37Z9FwU4ylkSgKLpmzWQn4tAhBhS1hku5WdQZdvsv4W2PF4rJRmuKhCHPfaW2OL gE8gS0Vhc1POYIO+EwNzs1l0d+WtQvTs8uqgZufk= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 8747C396AC27 for ; Thu, 17 Jun 2021 15:22:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8747C396AC27 Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-41-I_A6n34uPXqbdN_Y2tu23g-1; Thu, 17 Jun 2021 11:22:11 -0400 X-MC-Unique: I_A6n34uPXqbdN_Y2tu23g-1 Received: by mail-qk1-f200.google.com with SMTP id b125-20020a3799830000b02903ad1e638ccaso2352829qke.4 for ; Thu, 17 Jun 2021 08:22:11 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=eclKvtb3ofscL4DG/2Z9/piGn7/MgjKPnz+FlBd9ks8=; b=P2jm3AXl7qQBPYIv9TfUInodw3o4wNhKxdYg3m+UY+qpOcGS0yf/kgDCVJ1yn/Qk2W qJO68X6VeNVyac+/R1/kAMg5Q+KkD93VCygAcLcQw4w0l6DAiuIXFI8DwbrzYGLx+XTJ CzDNdPPXGZXYtZcA9NJxv3HG8HxNKCiqpMvNI2F3Sp7mG/IeOrglWIp/TEiBfxdMQQe4 AWm+w3FJcJVZ91o7OezUS8nDpmmO7s/mbSUC1K2IeR4MUZEDQUOiG6D12KukomKB849q Q6IdqwqVNiY/rzoxMnag4XtCHH/MXvTcDY4WqOYFcR+f+dKOeok77tzkiQujN9RmTT14 fjNA== X-Gm-Message-State: AOAM530wf4mu4nS7z0qd3bRokSHBS8xWWXhSqZkDd9t4+kvN28Lppur6 xvHiYfe9JG93xfOMXOrWw79WVdpmk2QgDHzehLKxNAyF0Rv/QL4i+LDkIdHFrcP22sqno4I+Uxy Y1zdHX7mCY5o++ytcJn81MdciO+4aYkvhSq0ac5DeWH+299agwTP+EwsqC/kT2pSEz18= X-Received: by 2002:a05:620a:22ab:: with SMTP id p11mr4365565qkh.250.1623943330151; Thu, 17 Jun 2021 08:22:10 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyzC5vRvOAIS4QkNLn5aVIkFJpsgT5xelBU20fCJVJjknLweeoZ6Qxg+itl9hcWf+2mMf6EyQ== X-Received: by 2002:a05:620a:22ab:: with SMTP id p11mr4365484qkh.250.1623943329202; Thu, 17 Jun 2021 08:22:09 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id 5sm1933230qkj.99.2021.06.17.08.22.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Jun 2021 08:22:08 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 1/5] libstdc++: Implement P2325 changes to default-constructibilty of views Date: Thu, 17 Jun 2021 11:22:02 -0400 Message-Id: <20210617152206.1408001-1-ppalka@redhat.com> X-Mailer: git-send-email 2.32.0.93.g670b81a890 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-16.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FILL_THIS_FORM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Cc: libstdc++@gcc.gnu.org Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This implements the wording changes of P2325R3 "Views should not be required to be default constructible". Changes are relatively straightforward, besides perhaps those to __box (which now stands for copyable-box instead of semiregular-box) and __non_propagating_cache. For __box, this patch implements the recommended practice to also avoid std::optional when the boxed type is nothrow_move/copy_constructible. For __non_propagating_cache, now that it's used by split_view::_M_current, we need to add assignment from a value of the underlying type to the subset of the std::optional API implemented for the cache (needed by split_view::begin()). Hence the new __non_propagating_cache::operator= overload. While we're changing __box, this fixes the undesirable list-init in the constuctors of the partial specialization as reported in PR100475 comment #7. libstdc++-v3/ChangeLog: * include/bits/iterator_concepts.h (weakly_incrementable): Remove default_initializable requirement. * include/bits/ranges_base.h (ranges::view): Likewise. * include/bits/ranges_util.h (subrange): Constrain the default ctor. * include/bits/stl_iterator.h (back_insert_iterator): Remove the default ctor. (front_insert_iterator): Likewise. (insert_iterator): Likewise. Remove NSDMIs. (common_iterator): Constrain the default ctor. (counted_iterator): Likewise. * include/bits/stream_iterator.h (ostream_iterator): Remove the default ctor. * include/std/ranges (__detail::__box::operator=): Handle self-assignment in the primary template. (__detail::__box): In the partial specialization: adjust constraints as per P2325. Add specialized operator= for the case when the wrapped type is not copyable. Constrain the default ctor. Avoid list-initialization. (single_view): Constraint the default ctor. (iota_view): Relax semiregular constraint to copyable. Constrain the default ctor. (iota_view::_Iterator): Constraint the default ctor. (basic_istream_view): Remove the default ctor. Remove NSDMIs. Remove redundant checks for empty _M_stream. (basic_istream_view::_Iterator): Likewise. (ref_view): Remove the default ctor. Remove NSDMIs. (ref_view::_Iterator): Constrain the default ctor. (__detail::__non_propagating_cache::operator=): Define overload for assigning from a value of the underlying type. (filter_view): Likewise. (filter_view::_Iterator): Likewise. (transform_view): Likewise. (transform_view::_Iterator): Likewise. (take_view): Likewise. (take_view::_Iterator): Likewise. (take_while_view): Likewise. (take_while_view::_Iterator): Likewise. (drop_while_view): Likewise. (drop_while_view::_Iterator): Likewise. (join_view): Likewise. (split_view::_OuterIter::__current): Adjust after changing the type of _M_current. (split_view::_M_current): Wrap it in a __non_propagating_cache. (split_view::split_view): Constrain the default ctor. (common_view): Constrain the default ctor. (reverse_view): Likewise. (elements_view): Likewise. * include/std/span (enable_view>): Define this partial specialization to true unconditionally. * include/std/version (__cpp_lib_ranges): Adjust value. * testsuite/24_iterators/back_insert_iterator/constexpr.cc: Don't attempt to default construct a back_insert_iterator. * testsuite/24_iterators/front_insert_iterator/constexpr.cc: Don't attempt to default construct a front_insert_iterator. * testsuite/24_iterators/insert_iterator/constexpr.cc: Don't attempt to default construct an insert_iterator. * testsuite/24_iterators/ostream_iterator/requirements/constexpr.cc: Remove this test for default constructibility of ostream_iterator. * testsuite/std/ranges/97600.cc: Don't attempt to default construct a basic_istream_view. * testsuite/std/ranges/adaptors/detail/semiregular_box.cc: Rename to ... * testsuite/std/ranges/adaptors/detail/copyable_box.cc: ... this. (test02): Adjust now that __box is copyable-box not semiregular-box. (test03): New test. * testsuite/std/ranges/p2325.cc: New test. * testsuite/std/ranges/single_view.cc (test06): New test. * testsuite/std/ranges/view.cc: Adjust now that view doesn't require default_initializable. --- libstdc++-v3/include/bits/iterator_concepts.h | 3 +- libstdc++-v3/include/bits/ranges_base.h | 3 +- libstdc++-v3/include/bits/ranges_util.h | 2 +- libstdc++-v3/include/bits/stl_iterator.h | 16 +- libstdc++-v3/include/bits/stream_iterator.h | 5 - libstdc++-v3/include/std/ranges | 160 ++++++++++++------ libstdc++-v3/include/std/span | 3 +- libstdc++-v3/include/std/version | 2 +- .../back_insert_iterator/constexpr.cc | 3 +- .../front_insert_iterator/constexpr.cc | 3 +- .../24_iterators/insert_iterator/constexpr.cc | 3 +- .../requirements/constexpr.cc | 24 --- libstdc++-v3/testsuite/std/ranges/97600.cc | 3 +- .../{semiregular_box.cc => copyable_box.cc} | 51 +++++- libstdc++-v3/testsuite/std/ranges/p2325.cc | 155 +++++++++++++++++ .../testsuite/std/ranges/single_view.cc | 15 ++ libstdc++-v3/testsuite/std/ranges/view.cc | 2 +- 17 files changed, 335 insertions(+), 118 deletions(-) delete mode 100644 libstdc++-v3/testsuite/24_iterators/ostream_iterator/requirements/constexpr.cc rename libstdc++-v3/testsuite/std/ranges/adaptors/detail/{semiregular_box.cc => copyable_box.cc} (70%) create mode 100644 libstdc++-v3/testsuite/std/ranges/p2325.cc diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index 11748e5ed7b..c273056c204 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -594,8 +594,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Requirements on types that can be incremented with ++. template - concept weakly_incrementable = default_initializable<_Iter> - && movable<_Iter> + concept weakly_incrementable = movable<_Iter> && requires(_Iter __i) { typename iter_difference_t<_Iter>; diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 25af4b742a6..9d749c8d9b7 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -619,8 +619,7 @@ namespace ranges /// [range.view] The ranges::view concept. template concept view - = range<_Tp> && movable<_Tp> && default_initializable<_Tp> - && enable_view<_Tp>; + = range<_Tp> && movable<_Tp> && enable_view<_Tp>; // [range.refinements] diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index dd829ed957f..d7b12b3d985 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -241,7 +241,7 @@ namespace ranges [[no_unique_address]] _Size<__size_type> _M_size = {}; public: - subrange() = default; + subrange() requires default_initializable<_It> = default; constexpr subrange(__detail::__convertible_to_non_slicing<_It> auto __i, _Sent __s) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 8768624b7d1..6ec046b597b 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -639,8 +639,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef _Container container_type; #if __cplusplus > 201703L using difference_type = ptrdiff_t; - - constexpr back_insert_iterator() noexcept : container(nullptr) { } #endif /// The only way to create this %iterator is with a container. @@ -742,8 +740,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef _Container container_type; #if __cplusplus > 201703L using difference_type = ptrdiff_t; - - constexpr front_insert_iterator() noexcept : container(nullptr) { } #endif /// The only way to create this %iterator is with a container. @@ -843,17 +839,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { #if __cplusplus > 201703L && defined __cpp_lib_concepts using _Iter = std::__detail::__range_iter_t<_Container>; - - protected: - _Container* container = nullptr; - _Iter iter = _Iter(); #else typedef typename _Container::iterator _Iter; - +#endif protected: _Container* container; _Iter iter; -#endif public: /// A nested typedef for the type of whatever container you used. @@ -861,8 +852,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus > 201703L && defined __cpp_lib_concepts using difference_type = ptrdiff_t; - - insert_iterator() = default; #endif /** @@ -1740,6 +1729,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr common_iterator() noexcept(is_nothrow_default_constructible_v<_It>) + requires default_initializable<_It> : _M_it(), _M_index(0) { } @@ -2117,7 +2107,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // iterator_concept defined in __counted_iter_concept // iterator_category defined in __counted_iter_cat - constexpr counted_iterator() = default; + constexpr counted_iterator() requires default_initializable<_It> = default; constexpr counted_iterator(_It __i, iter_difference_t<_It> __n) diff --git a/libstdc++-v3/include/bits/stream_iterator.h b/libstdc++-v3/include/bits/stream_iterator.h index fd8920b8d01..d07474d4996 100644 --- a/libstdc++-v3/include/bits/stream_iterator.h +++ b/libstdc++-v3/include/bits/stream_iterator.h @@ -192,11 +192,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION const _CharT* _M_string; public: -#if __cplusplus > 201703L - constexpr ostream_iterator() noexcept - : _M_stream(nullptr), _M_string(nullptr) { } -#endif - /// Construct from an ostream. ostream_iterator(ostream_type& __s) : _M_stream(std::__addressof(__s)), _M_string(0) {} diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 73c35dafd29..f96adf63d10 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -113,10 +113,13 @@ namespace ranges noexcept(is_nothrow_copy_constructible_v<_Tp>) requires (!copyable<_Tp>) { - if ((bool)__that) - this->emplace(*__that); - else - this->reset(); + if (this != std::__addressof(__that)) + { + if ((bool)__that) + this->emplace(*__that); + else + this->reset(); + } return *this; } @@ -125,37 +128,42 @@ namespace ranges noexcept(is_nothrow_move_constructible_v<_Tp>) requires (!movable<_Tp>) { - if ((bool)__that) - this->emplace(std::move(*__that)); - else - this->reset(); + if (this != std::__addressof(__that)) + { + if ((bool)__that) + this->emplace(std::move(*__that)); + else + this->reset(); + } return *this; } }; - // For types which are already semiregular, this specialization of the - // semiregular wrapper stores the object directly without going through + // For types which are already copyable, this specialization of the + // copyable wrapper stores the object directly without going through // std::optional. It provides just the subset of the primary template's // API that we currently use. - template<__boxable _Tp> requires semiregular<_Tp> + template<__boxable _Tp> + requires copyable<_Tp> || (is_nothrow_move_constructible_v<_Tp> + && is_nothrow_copy_constructible_v<_Tp>) struct __box<_Tp> { private: [[no_unique_address]] _Tp _M_value = _Tp(); public: - __box() = default; + __box() requires default_initializable<_Tp> = default; constexpr explicit __box(const _Tp& __t) noexcept(is_nothrow_copy_constructible_v<_Tp>) - : _M_value{__t} + : _M_value(__t) { } constexpr explicit __box(_Tp&& __t) noexcept(is_nothrow_move_constructible_v<_Tp>) - : _M_value{std::move(__t)} + : _M_value(std::move(__t)) { } template @@ -166,6 +174,38 @@ namespace ranges : _M_value(std::forward<_Args>(__args)...) { } + __box(const __box&) = default; + __box(__box&&) = default; + __box& operator=(const __box&) requires copyable<_Tp> = default; + __box& operator=(__box&&) requires copyable<_Tp> = default; + + // When _Tp is nothrow_copy_constructible but not copy_assignable, + // copy assignment is implemented via destroy-then-copy-construct. + constexpr __box& + operator=(const __box& __that) noexcept + { + static_assert(is_nothrow_copy_constructible_v<_Tp>); + if (this != std::__addressof(__that)) + { + _M_value.~_Tp(); + std::construct_at(std::__addressof(_M_value), *__that); + } + return *this; + } + + // Likewise for move assignment. + constexpr __box& + operator=(__box&& __that) noexcept + { + static_assert(is_nothrow_move_constructible_v<_Tp>); + if (this != std::__addressof(__that)) + { + _M_value.~_Tp(); + std::construct_at(std::__addressof(_M_value), std::move(*__that)); + } + return *this; + } + constexpr bool has_value() const noexcept { return true; }; @@ -193,7 +233,7 @@ namespace ranges class single_view : public view_interface> { public: - single_view() = default; + single_view() requires default_initializable<_Tp> = default; constexpr explicit single_view(const _Tp& __t) @@ -308,7 +348,7 @@ namespace ranges template requires std::__detail::__weakly_eq_cmp_with<_Winc, _Bound> - && semiregular<_Winc> + && copyable<_Winc> class iota_view : public view_interface> { private: @@ -337,7 +377,7 @@ namespace ranges using value_type = _Winc; using difference_type = __detail::__iota_diff_t<_Winc>; - _Iterator() = default; + _Iterator() requires default_initializable<_Winc> = default; constexpr explicit _Iterator(_Winc __value) @@ -534,7 +574,7 @@ namespace ranges [[no_unique_address]] _Bound _M_bound = _Bound(); public: - iota_view() = default; + iota_view() requires default_initializable<_Winc> = default; constexpr explicit iota_view(_Winc __value) @@ -643,8 +683,6 @@ namespace views : public view_interface> { public: - basic_istream_view() = default; - constexpr explicit basic_istream_view(basic_istream<_CharT, _Traits>& __stream) : _M_stream(std::__addressof(__stream)) @@ -653,8 +691,7 @@ namespace views constexpr auto begin() { - if (_M_stream != nullptr) - *_M_stream >> _M_object; + *_M_stream >> _M_object; return _Iterator{this}; } @@ -663,8 +700,8 @@ namespace views { return default_sentinel; } private: - basic_istream<_CharT, _Traits>* _M_stream = nullptr; - _Val _M_object = _Val(); + basic_istream<_CharT, _Traits>* _M_stream; + _Val _M_object; struct _Iterator { @@ -673,8 +710,6 @@ namespace views using difference_type = ptrdiff_t; using value_type = _Val; - _Iterator() = default; - constexpr explicit _Iterator(basic_istream_view* __parent) noexcept : _M_parent(__parent) @@ -688,7 +723,6 @@ namespace views _Iterator& operator++() { - __glibcxx_assert(_M_parent->_M_stream != nullptr); *_M_parent->_M_stream >> _M_parent->_M_object; return *this; } @@ -699,21 +733,18 @@ namespace views _Val& operator*() const - { - __glibcxx_assert(_M_parent->_M_stream != nullptr); - return _M_parent->_M_object; - } + { return _M_parent->_M_object; } friend bool operator==(const _Iterator& __x, default_sentinel_t) { return __x._M_at_end(); } private: - basic_istream_view* _M_parent = nullptr; + basic_istream_view* _M_parent; bool _M_at_end() const - { return _M_parent == nullptr || !*_M_parent->_M_stream; } + { return !*_M_parent->_M_stream; } }; friend _Iterator; @@ -1017,15 +1048,12 @@ namespace views::__adaptor class ref_view : public view_interface> { private: - _Range* _M_r = nullptr; + _Range* _M_r; static void _S_fun(_Range&); // not defined static void _S_fun(_Range&&) = delete; public: - constexpr - ref_view() noexcept = default; - template<__detail::__not_same_as _Tp> requires convertible_to<_Tp, _Range&> && requires { _S_fun(declval<_Tp>()); } @@ -1205,6 +1233,16 @@ namespace views::__adaptor return *this; } + constexpr __non_propagating_cache& + operator=(_Tp __val) + { + this->_M_reset(); + std::construct_at(std::__addressof(this->_M_payload._M_payload), + std::in_place, std::move(__val)); + this->_M_payload._M_engaged = true; + return *this; + } + constexpr _Tp& operator*() noexcept { return this->_M_get(); } @@ -1382,7 +1420,7 @@ namespace views::__adaptor using value_type = range_value_t<_Vp>; using difference_type = range_difference_t<_Vp>; - _Iterator() = default; + _Iterator() requires default_initializable<_Vp_iter> = default; constexpr _Iterator(filter_view* __parent, _Vp_iter __current) @@ -1494,7 +1532,9 @@ namespace views::__adaptor _Vp _M_base = _Vp(); public: - filter_view() = default; + filter_view() requires (default_initializable<_Vp> + && default_initializable<_Pred>) + = default; constexpr filter_view(_Vp __base, _Pred __pred) @@ -1643,7 +1683,7 @@ namespace views::__adaptor = remove_cvref_t>>; using difference_type = range_difference_t<_Base>; - _Iterator() = default; + _Iterator() requires default_initializable<_Base_iter> = default; constexpr _Iterator(_Parent* __parent, _Base_iter __current) @@ -1858,7 +1898,9 @@ namespace views::__adaptor _Vp _M_base = _Vp(); public: - transform_view() = default; + transform_view() requires (default_initializable<_Vp> + && default_initializable<_Fp>) + = default; constexpr transform_view(_Vp __base, _Fp __fun) @@ -1993,7 +2035,7 @@ namespace views::__adaptor _Vp _M_base = _Vp(); public: - take_view() = default; + take_view() requires default_initializable<_Vp> = default; constexpr take_view(_Vp base, range_difference_t<_Vp> __count) @@ -2177,7 +2219,9 @@ namespace views::__adaptor _Vp _M_base = _Vp(); public: - take_while_view() = default; + take_while_view() requires (default_initializable<_Vp> + && default_initializable<_Pred>) + = default; constexpr take_while_view(_Vp base, _Pred __pred) @@ -2265,7 +2309,7 @@ namespace views::__adaptor _M_cached_begin; public: - drop_view() = default; + drop_view() requires default_initializable<_Vp> = default; constexpr drop_view(_Vp __base, range_difference_t<_Vp> __count) @@ -2381,7 +2425,9 @@ namespace views::__adaptor _Vp _M_base = _Vp(); public: - drop_while_view() = default; + drop_while_view() requires (default_initializable<_Vp> + && default_initializable<_Pred>) + = default; constexpr drop_while_view(_Vp __base, _Pred __pred) @@ -2571,7 +2617,9 @@ namespace views::__adaptor = common_type_t, range_difference_t>>; - _Iterator() = default; + _Iterator() requires (default_initializable<_Outer_iter> + && default_initializable<_Inner_iter>) + = default; constexpr _Iterator(_Parent* __parent, _Outer_iter __outer) @@ -2724,7 +2772,7 @@ namespace views::__adaptor _Vp _M_base = _Vp(); public: - join_view() = default; + join_view() requires default_initializable<_Vp> = default; constexpr explicit join_view(_Vp __base) @@ -2891,7 +2939,7 @@ namespace views::__adaptor if constexpr (forward_range<_Vp>) return _M_current; else - return _M_parent->_M_current; + return *_M_parent->_M_current; } constexpr auto& @@ -2900,7 +2948,7 @@ namespace views::__adaptor if constexpr (forward_range<_Vp>) return _M_current; else - return _M_parent->_M_current; + return *_M_parent->_M_current; } _Parent* _M_parent = nullptr; @@ -3146,12 +3194,14 @@ namespace views::__adaptor // XXX: _M_current is "present only if !forward_range" [[no_unique_address]] __detail::__maybe_present_t, - iterator_t<_Vp>> _M_current; + __detail::__non_propagating_cache>> _M_current; _Vp _M_base = _Vp(); public: - split_view() = default; + split_view() requires (default_initializable<_Vp> + && default_initializable<_Pattern>) + = default; constexpr split_view(_Vp __base, _Pattern __pattern) @@ -3282,7 +3332,7 @@ namespace views::__adaptor _Vp _M_base = _Vp(); public: - common_view() = default; + common_view() requires default_initializable<_Vp> = default; constexpr explicit common_view(_Vp __r) @@ -3413,7 +3463,7 @@ namespace views::__adaptor _Vp _M_base = _Vp(); public: - reverse_view() = default; + reverse_view() requires default_initializable<_Vp> = default; constexpr explicit reverse_view(_Vp __r) @@ -3555,7 +3605,7 @@ namespace views::__adaptor class elements_view : public view_interface> { public: - elements_view() = default; + elements_view() requires default_initializable<_Vp> = default; constexpr explicit elements_view(_Vp base) @@ -3676,7 +3726,7 @@ namespace views::__adaptor = remove_cvref_t>>; using difference_type = range_difference_t<_Base>; - _Iterator() = default; + _Iterator() requires default_initializable> = default; constexpr explicit _Iterator(iterator_t<_Base> current) diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 09bdcd69afb..63f0a8f6279 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -447,8 +447,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Opt-in to view concept template inline constexpr bool - enable_view> - = _Extent == 0 || _Extent == dynamic_extent; + enable_view> = true; } _GLIBCXX_END_NAMESPACE_VERSION } // namespace std diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index 8d0b2b95f34..e3ab9b4c7c0 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -240,7 +240,7 @@ #define __cpp_lib_math_constants 201907L #define __cpp_lib_polymorphic_allocator 201902L #if __cpp_lib_concepts -# define __cpp_lib_ranges 201911L +# define __cpp_lib_ranges 202106L #endif #if __cpp_lib_atomic_wait || _GLIBCXX_HAVE_POSIX_SEMAPHORE # define __cpp_lib_semaphore 201907L diff --git a/libstdc++-v3/testsuite/24_iterators/back_insert_iterator/constexpr.cc b/libstdc++-v3/testsuite/24_iterators/back_insert_iterator/constexpr.cc index bef2289ba79..27acd071df1 100644 --- a/libstdc++-v3/testsuite/24_iterators/back_insert_iterator/constexpr.cc +++ b/libstdc++-v3/testsuite/24_iterators/back_insert_iterator/constexpr.cc @@ -42,8 +42,7 @@ constexpr bool test01() { container c; - std::back_insert_iterator iter; - iter = std::back_inserter(c); + std::back_insert_iterator iter = std::back_inserter(c); *iter++ = 1; int i = 2; *iter = i; diff --git a/libstdc++-v3/testsuite/24_iterators/front_insert_iterator/constexpr.cc b/libstdc++-v3/testsuite/24_iterators/front_insert_iterator/constexpr.cc index 7b4c990b107..cff7f6a4524 100644 --- a/libstdc++-v3/testsuite/24_iterators/front_insert_iterator/constexpr.cc +++ b/libstdc++-v3/testsuite/24_iterators/front_insert_iterator/constexpr.cc @@ -42,8 +42,7 @@ constexpr bool test01() { container c; - std::front_insert_iterator iter; - iter = std::front_inserter(c); + std::front_insert_iterator iter = std::front_inserter(c); *iter++ = 1; int i = 2; *iter = i; diff --git a/libstdc++-v3/testsuite/24_iterators/insert_iterator/constexpr.cc b/libstdc++-v3/testsuite/24_iterators/insert_iterator/constexpr.cc index e74df3eb5d5..e326b01d534 100644 --- a/libstdc++-v3/testsuite/24_iterators/insert_iterator/constexpr.cc +++ b/libstdc++-v3/testsuite/24_iterators/insert_iterator/constexpr.cc @@ -51,8 +51,7 @@ constexpr bool test01() { container c; - std::insert_iterator iter; - iter = std::inserter(c, c.begin()); + std::insert_iterator iter = std::inserter(c, c.begin()); *iter++ = 1; int i = 2; *iter = i; diff --git a/libstdc++-v3/testsuite/24_iterators/ostream_iterator/requirements/constexpr.cc b/libstdc++-v3/testsuite/24_iterators/ostream_iterator/requirements/constexpr.cc deleted file mode 100644 index 4edaaa8aebb..00000000000 --- a/libstdc++-v3/testsuite/24_iterators/ostream_iterator/requirements/constexpr.cc +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2019-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 } } - -#include - -constexpr std::ostream_iterator iter1; -constexpr std::ostream_iterator iter2{}; diff --git a/libstdc++-v3/testsuite/std/ranges/97600.cc b/libstdc++-v3/testsuite/std/ranges/97600.cc index 7435de022cd..c642b9d22d0 100644 --- a/libstdc++-v3/testsuite/std/ranges/97600.cc +++ b/libstdc++-v3/testsuite/std/ranges/97600.cc @@ -24,9 +24,8 @@ #include void -test01() +test01(std::ranges::basic_istream_view> v) { - std::ranges::basic_istream_view> v; v.begin(); static_assert(std::ranges::range); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/detail/semiregular_box.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/detail/copyable_box.cc similarity index 70% rename from libstdc++-v3/testsuite/std/ranges/adaptors/detail/semiregular_box.cc rename to libstdc++-v3/testsuite/std/ranges/adaptors/detail/copyable_box.cc index ed694e04fd1..fa6d4d56816 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/detail/semiregular_box.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/detail/copyable_box.cc @@ -82,9 +82,10 @@ test01() } static_assert(test01()); -template +template struct A { - A() requires make_semiregular; + A(const A&) = default; + A& operator=(const A&) requires make_copyable; A(int, int); A(std::initializer_list) = delete; }; @@ -93,9 +94,51 @@ void test02() { // PR libstdc++/100475 - static_assert(std::semiregular>); + static_assert(std::copyable>); __box> x2(std::in_place, 0, 0); - static_assert(!std::semiregular>); + static_assert(!std::copyable>); __box> x1(std::in_place, 0, 0); } + +constexpr bool +test03() +{ + // Verify correctness of the non-defaulted operator= for the partial + // specialization of __box. + struct B { + constexpr B(int* p) : p(p) { } + constexpr ~B() { ++*p; }; + B(const B&) = default; + B& operator=(const B&) = delete; + int* p; + }; + static_assert(!std::copyable); + static_assert(std::is_nothrow_copy_constructible_v); + static_assert(sizeof(__box) == sizeof(B)); + + int m = 0; + __box x(std::in_place, &m); + __glibcxx_assert(m == 0); + x = x; + __glibcxx_assert(m == 0); + x = std::move(x); + __glibcxx_assert(m == 0); + + int n = 0; + __box y(std::in_place, &n); + auto z = x; + x = y; + __glibcxx_assert(m == 1); + __glibcxx_assert(n == 0); + __glibcxx_assert(x->p == &n); + __glibcxx_assert(y->p == &n); + y = std::move(z); + __glibcxx_assert(m == 1); + __glibcxx_assert(n == 1); + __glibcxx_assert(y->p == &m); + __glibcxx_assert(z->p == &m); + + return true; +} +static_assert(test03()); diff --git a/libstdc++-v3/testsuite/std/ranges/p2325.cc b/libstdc++-v3/testsuite/std/ranges/p2325.cc new file mode 100644 index 00000000000..df6cde29e4d --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/p2325.cc @@ -0,0 +1,155 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// P2325R3 "Views should not be required to be default constructible" + +#include +#include +#include +#include +#include +#include + +using namespace std; + +template void f(); +template requires weakly_incrementable || ranges::view void f(); + +void +test01() +{ + // Verify neither std::weakly_incrementable nor ranges::view require + // default_initializable. + f(); // { dg-error "ambiguous" } +} + +void +test02() +{ + // Verify these iterators are not default constructible. + static_assert(!default_initializable>>); + static_assert(!default_initializable>>); + static_assert(!default_initializable>>); + static_assert(!default_initializable>); + + using iter = ostream_iterator; + + // Verify common_iterator is conditionally default constructible. + static_assert(!default_initializable>); + static_assert(default_initializable>); + + // Verify counted_iterator is conditionally default constructible. + static_assert(!default_initializable>); + static_assert(default_initializable>); +} + +void +test03() +{ + using iter = ostream_iterator; + + // Verify iota_view is conditionally default constructible. + static_assert(!default_initializable>); + static_assert(!default_initializable>().begin())>); + static_assert(default_initializable>); + static_assert(default_initializable>().begin())>); + + // Verify subrange is conditionally default constructible. + static_assert(!default_initializable>); + static_assert(default_initializable>); + + // Verify single_view is conditionally default constructible. + static_assert(!default_initializable>); + static_assert(default_initializable>); +} + +void +test04() +{ + // Verify basic_istream_view is not default constructible. + using type = ranges::basic_istream_view>; + static_assert(!default_initializable); + static_assert(!default_initializable().begin())>); +} + +void +test05() +{ + // Verify ref_view is not default constructible. + static_assert(!default_initializable>); +} + +template +void +test06() +{ + auto f1 = [] (auto) { return true; }; + auto f2 = [i=0] (auto) { return true; }; + static_assert(default_initializable); + static_assert(!default_initializable); + + struct S { S() = delete; }; + static_assert(!default_initializable()) | adaptor(f1))>); + static_assert(!default_initializable()) | adaptor(f2))>); +} + +// Verify filter_view, transform_view, take_while_view and drop_while_view are +// conditionally default constructible. +template void test06(); +template void test06(); +template void test06(); +template void test06(); + +void +test07() +{ + // Verify join_view is conditionally default constructible. + struct S { S() = delete; }; + using type1 = ranges::join_view>>; + static_assert(!default_initializable); + using type2 = ranges::join_view>>; + static_assert(default_initializable); +} + +void +test08() +{ + // Verify split_view is conditionally default constructible. + using type1 = ranges::split_view, ranges::single_view>; + static_assert(!default_initializable); + using type2 = ranges::split_view, ranges::ref_view>; + static_assert(!default_initializable); + using type3 = ranges::split_view, ranges::ref_view>; + static_assert(!default_initializable); + using type4 = ranges::split_view, ranges::single_view>; + static_assert(default_initializable); +} + +void +test09() +{ + // Verify common_view is conditionally default constructible. + using type1 = ranges::common_view>>; + static_assert(!default_initializable); + using type2 = ranges::common_view>; + static_assert(default_initializable); +} + +void +test10() +{ + // Verify reverse_view is conditionally default constructible. + using type1 = ranges::reverse_view>; + static_assert(!default_initializable); + using type2 = ranges::reverse_view>; + static_assert(default_initializable); +} + +void +test11() +{ + // Verify elements_view is conditionally default constructible. + using type1 = ranges::elements_view[2]>, 0>; + static_assert(!default_initializable); + using type2 = ranges::elements_view>, 0>; + static_assert(default_initializable); +} diff --git a/libstdc++-v3/testsuite/std/ranges/single_view.cc b/libstdc++-v3/testsuite/std/ranges/single_view.cc index c036fc8976a..f1d8e103715 100644 --- a/libstdc++-v3/testsuite/std/ranges/single_view.cc +++ b/libstdc++-v3/testsuite/std/ranges/single_view.cc @@ -96,6 +96,20 @@ test05() static_assert(noexcept(cs.empty())); // view_interface::empty() } +void +test06() +{ + // PR libstdc++/100475 comment #7 + struct S { + S() = default; + S(std::initializer_list) = delete; + S(const S&) {} + }; + S obj; + auto x = std::views::single(obj); + auto y = std::views::single(std::move(obj)); +} + int main() { test01(); @@ -103,4 +117,5 @@ int main() test03(); test04(); test05(); + test06(); } diff --git a/libstdc++-v3/testsuite/std/ranges/view.cc b/libstdc++-v3/testsuite/std/ranges/view.cc index d8972ab3e46..dd8258220ed 100644 --- a/libstdc++-v3/testsuite/std/ranges/view.cc +++ b/libstdc++-v3/testsuite/std/ranges/view.cc @@ -31,7 +31,7 @@ static_assert(std::ranges::view>); static_assert(std::ranges::view>); -static_assert(!std::ranges::view>); +static_assert(std::ranges::view>); // Changed with P2325R3 static_assert(std::ranges::view); static_assert(std::ranges::view); From patchwork Thu Jun 17 15:22:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1493632 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=CNm/zjyf; dkim-atps=neutral Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G5RKR5976z9sSn for ; Fri, 18 Jun 2021 01:48:10 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 84467395541E for ; Thu, 17 Jun 2021 15:48:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 84467395541E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1623944887; bh=i2KED7FFtAg0ysw8XUH8A+IblkVu6/mVHBzgh38OA5s=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=CNm/zjyfNcfr5nvgALjoyJ1ncL0uV3YlMvAjwfZnajs6xehhs8iobGfn4GGKsrg+K OyRCCApAne1QopChBXkETCApSPSyBl4Tc8j0+Ckd/IZoc8E/2BFcPdCQM6ykY8/uuB pCuOGsLkoM0leVk9JK1qnYSGGcPJZDOyS4B+cWcw= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 9EAC1396BC04 for ; Thu, 17 Jun 2021 15:22:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9EAC1396BC04 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-63-4HYzmJJpNoSEvjG8XRSzug-1; Thu, 17 Jun 2021 11:22:12 -0400 X-MC-Unique: 4HYzmJJpNoSEvjG8XRSzug-1 Received: by mail-qt1-f199.google.com with SMTP id z17-20020ac86b910000b0290244cba55754so420374qts.19 for ; Thu, 17 Jun 2021 08:22:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=i2KED7FFtAg0ysw8XUH8A+IblkVu6/mVHBzgh38OA5s=; b=Oa3JDUdGfFLqfvECasaXM3PGFlgYYNJkUwUocaaZ0YjLSEl1Q2nsE/qFRaWtVIHf3Z 5nWfIIaEH61cyyd9SUnMsaz1CV4payS6htZbgbwtZnQnKtkaS0WGn9DgBhmE5o4w6xGH mlJ8No1RFkFZx0S5xuzy1QXcyFGLZSbm7k6dWuOXu0SRCWb9un7ZXfBnEWYbbTkLYkEb cCeXf518iS1NYyRz8yC93Q8qYKK9pwkRDB5QwL/QLwFAgSajRYznYUA8weOvYjkSJk0s 75P9MRJvuD1YB7uhtQzTFFhC+fq9rGv1F4Jp4UjHtwPMcK2G+kvivs1FLF34nIabwOEH DPxg== X-Gm-Message-State: AOAM530FGE/3eBbnw4c5JZvbkZX9ttUS5RpFCu2x8cCr6ibJ5rCYtI/Q ONmkhickPFrRhpVytvv3bpjlGvFT9Bfyo5TXH3LbQyfDvQNAfOPUXfViMtFMlryGyW2Fv+79JJn KCVj5FlYXvQUoPBXHUr1XHfT5ecS9gZLx0bNmEtHuC8AVxElFIz3rVqO5vMIOBxsbaSw= X-Received: by 2002:a37:6cd:: with SMTP id 196mr4243558qkg.442.1623943331116; Thu, 17 Jun 2021 08:22:11 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx0DfXYngQ0kG3rcbxcvjZEYPNr2+p5UUQDk40O8Ml4VKUzpfdXnWL+yKbnIlegS2WQcgk18w== X-Received: by 2002:a37:6cd:: with SMTP id 196mr4243509qkg.442.1623943330551; Thu, 17 Jun 2021 08:22:10 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id 5sm1933230qkj.99.2021.06.17.08.22.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Jun 2021 08:22:10 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 2/5] libstdc++: Move ranges algos used by into ranges_util.h Date: Thu, 17 Jun 2021 11:22:03 -0400 Message-Id: <20210617152206.1408001-2-ppalka@redhat.com> X-Mailer: git-send-email 2.32.0.93.g670b81a890 In-Reply-To: <20210617152206.1408001-1-ppalka@redhat.com> References: <20210617152206.1408001-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-15.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Cc: libstdc++@gcc.gnu.org Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" The header defines simplified copies of some ranges algorithms in order to avoid including the entirety of ranges_algo.h. A subsequent patch is going to want to use ranges::search in as well, but that algorithm is more complicated compared to the other copied ones. So rather than additionally copying ranges::search into , this patch splits out all the ranges algos used by (including ranges::search) from ranges_algo.h to ranges_util.h, and deletes the simplified copies in . This seems like the best place for these algorithms, as ranges_util.h is included only from and ranges_algo.h. libstdc++-v3/ChangeLog: * include/bits/ranges_algo.h (__find_fn, find, __find_if_fn) (find_if, __find_if_not_fn, find_if_not, _in_in_result) (__mismatch_fn, mismatch, __search_fn, search): Move to ... * include/bits/ranges_util.h: ... here. * include/std/ranges (__detail::find, __detail::find_if) (__detail::find_if_not, __detail::mismatch): Remove. (filter_view): Use ranges::find_if instead. (drop_while_view): Use ranges::find_if_not instead. (split_view): Use ranges::find and ranges::mismatch instead. --- libstdc++-v3/include/bits/ranges_algo.h | 215 +---------------------- libstdc++-v3/include/bits/ranges_util.h | 219 ++++++++++++++++++++++++ libstdc++-v3/include/std/ranges | 72 ++------ 3 files changed, 233 insertions(+), 273 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index ecf1378742d..9eeebff6525 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -234,91 +234,7 @@ namespace ranges inline constexpr __for_each_n_fn for_each_n{}; - struct __find_fn - { - template _Sent, typename _Tp, - typename _Proj = identity> - requires indirect_binary_predicate, const _Tp*> - constexpr _Iter - operator()(_Iter __first, _Sent __last, - const _Tp& __value, _Proj __proj = {}) const - { - while (__first != __last - && !(std::__invoke(__proj, *__first) == __value)) - ++__first; - return __first; - } - - template - requires indirect_binary_predicate, _Proj>, - const _Tp*> - constexpr borrowed_iterator_t<_Range> - operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const - { - return (*this)(ranges::begin(__r), ranges::end(__r), - __value, std::move(__proj)); - } - }; - - inline constexpr __find_fn find{}; - - struct __find_if_fn - { - template _Sent, - typename _Proj = identity, - indirect_unary_predicate> _Pred> - constexpr _Iter - operator()(_Iter __first, _Sent __last, - _Pred __pred, _Proj __proj = {}) const - { - while (__first != __last - && !(bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) - ++__first; - return __first; - } - - template, _Proj>> - _Pred> - constexpr borrowed_iterator_t<_Range> - operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const - { - return (*this)(ranges::begin(__r), ranges::end(__r), - std::move(__pred), std::move(__proj)); - } - }; - - inline constexpr __find_if_fn find_if{}; - - struct __find_if_not_fn - { - template _Sent, - typename _Proj = identity, - indirect_unary_predicate> _Pred> - constexpr _Iter - operator()(_Iter __first, _Sent __last, - _Pred __pred, _Proj __proj = {}) const - { - while (__first != __last - && (bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) - ++__first; - return __first; - } - - template, _Proj>> - _Pred> - constexpr borrowed_iterator_t<_Range> - operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const - { - return (*this)(ranges::begin(__r), ranges::end(__r), - std::move(__pred), std::move(__proj)); - } - }; - - inline constexpr __find_if_not_fn find_if_not{}; + // find, find_if and find_if_not are defined in . struct __find_first_of_fn { @@ -421,134 +337,7 @@ namespace ranges inline constexpr __count_if_fn count_if{}; - template - struct in_in_result - { - [[no_unique_address]] _Iter1 in1; - [[no_unique_address]] _Iter2 in2; - - template - requires convertible_to - && convertible_to - constexpr - operator in_in_result<_IIter1, _IIter2>() const & - { return {in1, in2}; } - - template - requires convertible_to<_Iter1, _IIter1> - && convertible_to<_Iter2, _IIter2> - constexpr - operator in_in_result<_IIter1, _IIter2>() && - { return {std::move(in1), std::move(in2)}; } - }; - - template - using mismatch_result = in_in_result<_Iter1, _Iter2>; - - struct __mismatch_fn - { - template _Sent1, - input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, - typename _Pred = ranges::equal_to, - typename _Proj1 = identity, typename _Proj2 = identity> - requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> - constexpr mismatch_result<_Iter1, _Iter2> - operator()(_Iter1 __first1, _Sent1 __last1, - _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, - _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const - { - while (__first1 != __last1 && __first2 != __last2 - && (bool)std::__invoke(__pred, - std::__invoke(__proj1, *__first1), - std::__invoke(__proj2, *__first2))) - { - ++__first1; - ++__first2; - } - return { std::move(__first1), std::move(__first2) }; - } - - template - requires indirectly_comparable, iterator_t<_Range2>, - _Pred, _Proj1, _Proj2> - constexpr mismatch_result, iterator_t<_Range2>> - operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, - _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const - { - return (*this)(ranges::begin(__r1), ranges::end(__r1), - ranges::begin(__r2), ranges::end(__r2), - std::move(__pred), - std::move(__proj1), std::move(__proj2)); - } - }; - - inline constexpr __mismatch_fn mismatch{}; - - struct __search_fn - { - template _Sent1, - forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, - typename _Pred = ranges::equal_to, - typename _Proj1 = identity, typename _Proj2 = identity> - requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> - constexpr subrange<_Iter1> - operator()(_Iter1 __first1, _Sent1 __last1, - _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, - _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const - { - if (__first1 == __last1 || __first2 == __last2) - return {__first1, __first1}; - - for (;;) - { - for (;;) - { - if (__first1 == __last1) - return {__first1, __first1}; - if (std::__invoke(__pred, - std::__invoke(__proj1, *__first1), - std::__invoke(__proj2, *__first2))) - break; - ++__first1; - } - auto __cur1 = __first1; - auto __cur2 = __first2; - for (;;) - { - if (++__cur2 == __last2) - return {__first1, ++__cur1}; - if (++__cur1 == __last1) - return {__cur1, __cur1}; - if (!(bool)std::__invoke(__pred, - std::__invoke(__proj1, *__cur1), - std::__invoke(__proj2, *__cur2))) - { - ++__first1; - break; - } - } - } - } - - template - requires indirectly_comparable, iterator_t<_Range2>, - _Pred, _Proj1, _Proj2> - constexpr borrowed_subrange_t<_Range1> - operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, - _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const - { - return (*this)(ranges::begin(__r1), ranges::end(__r1), - ranges::begin(__r2), ranges::end(__r2), - std::move(__pred), - std::move(__proj1), std::move(__proj2)); - } - }; - - inline constexpr __search_fn search{}; + // in_in_result, mismatch and search are defined in . struct __search_n_fn { diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index d7b12b3d985..9a07079ac13 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -420,7 +420,226 @@ namespace ranges using borrowed_subrange_t = conditional_t, subrange>, dangling>; +} // namespace ranges + +// The following ranges algorithms are used by , and are defined here +// so that can avoid including all of . +namespace ranges +{ + struct __find_fn + { + template _Sent, typename _Tp, + typename _Proj = identity> + requires indirect_binary_predicate, const _Tp*> + constexpr _Iter + operator()(_Iter __first, _Sent __last, + const _Tp& __value, _Proj __proj = {}) const + { + while (__first != __last + && !(std::__invoke(__proj, *__first) == __value)) + ++__first; + return __first; + } + + template + requires indirect_binary_predicate, _Proj>, + const _Tp*> + constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, const _Tp& __value, _Proj __proj = {}) const + { + return (*this)(ranges::begin(__r), ranges::end(__r), + __value, std::move(__proj)); + } + }; + + inline constexpr __find_fn find{}; + + struct __find_if_fn + { + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr _Iter + operator()(_Iter __first, _Sent __last, + _Pred __pred, _Proj __proj = {}) const + { + while (__first != __last + && !(bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + ++__first; + return __first; + } + + template, _Proj>> + _Pred> + constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const + { + return (*this)(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + }; + + inline constexpr __find_if_fn find_if{}; + + struct __find_if_not_fn + { + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr _Iter + operator()(_Iter __first, _Sent __last, + _Pred __pred, _Proj __proj = {}) const + { + while (__first != __last + && (bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + ++__first; + return __first; + } + + template, _Proj>> + _Pred> + constexpr borrowed_iterator_t<_Range> + operator()(_Range&& __r, _Pred __pred, _Proj __proj = {}) const + { + return (*this)(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + }; + + inline constexpr __find_if_not_fn find_if_not{}; + + template + struct in_in_result + { + [[no_unique_address]] _Iter1 in1; + [[no_unique_address]] _Iter2 in2; + + template + requires convertible_to + && convertible_to + constexpr + operator in_in_result<_IIter1, _IIter2>() const & + { return {in1, in2}; } + + template + requires convertible_to<_Iter1, _IIter1> + && convertible_to<_Iter2, _IIter2> + constexpr + operator in_in_result<_IIter1, _IIter2>() && + { return {std::move(in1), std::move(in2)}; } + }; + + template + using mismatch_result = in_in_result<_Iter1, _Iter2>; + + struct __mismatch_fn + { + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr mismatch_result<_Iter1, _Iter2> + operator()(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const + { + while (__first1 != __last1 && __first2 != __last2 + && (bool)std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + { + ++__first1; + ++__first2; + } + return { std::move(__first1), std::move(__first2) }; + } + + template + requires indirectly_comparable, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr mismatch_result, iterator_t<_Range2>> + operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const + { + return (*this)(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + }; + + inline constexpr __mismatch_fn mismatch{}; + + struct __search_fn + { + template _Sent1, + forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr subrange<_Iter1> + operator()(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const + { + if (__first1 == __last1 || __first2 == __last2) + return {__first1, __first1}; + + for (;;) + { + for (;;) + { + if (__first1 == __last1) + return {__first1, __first1}; + if (std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + break; + ++__first1; + } + auto __cur1 = __first1; + auto __cur2 = __first2; + for (;;) + { + if (++__cur2 == __last2) + return {__first1, ++__cur1}; + if (++__cur1 == __last1) + return {__cur1, __cur1}; + if (!(bool)std::__invoke(__pred, + std::__invoke(__proj1, *__cur1), + std::__invoke(__proj2, *__cur2))) + { + ++__first1; + break; + } + } + } + } + + template + requires indirectly_comparable, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr borrowed_subrange_t<_Range1> + operator()(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const + { + return (*this)(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + }; + inline constexpr __search_fn search{}; } // namespace ranges using ranges::get; diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index f96adf63d10..f93a880ff8a 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -1144,54 +1144,6 @@ namespace views::__adaptor using all_t = decltype(all(std::declval<_Range>())); } // namespace views - // The following simple algos are transcribed from ranges_algo.h to avoid - // having to include that entire header. - namespace __detail - { - template - constexpr _Iter - find(_Iter __first, _Sent __last, const _Tp& __value) - { - while (__first != __last - && !(bool)(*__first == __value)) - ++__first; - return __first; - } - - template - constexpr _Iter - find_if(_Iter __first, _Sent __last, _Pred __pred) - { - while (__first != __last - && !(bool)std::__invoke(__pred, *__first)) - ++__first; - return __first; - } - - template - constexpr _Iter - find_if_not(_Iter __first, _Sent __last, _Pred __pred) - { - while (__first != __last - && (bool)std::__invoke(__pred, *__first)) - ++__first; - return __first; - } - - template - constexpr pair<_Iter1, _Iter2> - mismatch(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2) - { - while (__first1 != __last1 && __first2 != __last2 - && (bool)ranges::equal_to{}(*__first1, *__first2)) - { - ++__first1; - ++__first2; - } - return { std::move(__first1), std::move(__first2) }; - } - } // namespace __detail - namespace __detail { template @@ -1449,9 +1401,9 @@ namespace views::__adaptor constexpr _Iterator& operator++() { - _M_current = __detail::find_if(std::move(++_M_current), - ranges::end(_M_parent->_M_base), - std::ref(*_M_parent->_M_pred)); + _M_current = ranges::find_if(std::move(++_M_current), + ranges::end(_M_parent->_M_base), + std::ref(*_M_parent->_M_pred)); return *this; } @@ -1560,9 +1512,9 @@ namespace views::__adaptor return {this, _M_cached_begin._M_get(_M_base)}; __glibcxx_assert(_M_pred.has_value()); - auto __it = __detail::find_if(ranges::begin(_M_base), - ranges::end(_M_base), - std::ref(*_M_pred)); + auto __it = ranges::find_if(ranges::begin(_M_base), + ranges::end(_M_base), + std::ref(*_M_pred)); _M_cached_begin._M_set(_M_base, __it); return {this, std::move(__it)}; } @@ -2453,9 +2405,9 @@ namespace views::__adaptor return _M_cached_begin._M_get(_M_base); __glibcxx_assert(_M_pred.has_value()); - auto __it = __detail::find_if_not(ranges::begin(_M_base), - ranges::end(_M_base), - std::cref(*_M_pred)); + auto __it = ranges::find_if_not(ranges::begin(_M_base), + ranges::end(_M_base), + std::cref(*_M_pred)); _M_cached_begin._M_set(_M_base, __it); return __it; } @@ -3031,8 +2983,8 @@ namespace views::__adaptor ++__current(); else if constexpr (__detail::__tiny_range<_Pattern>) { - __current() = __detail::find(std::move(__current()), __end, - *__pbegin); + __current() = ranges::find(std::move(__current()), __end, + *__pbegin); if (__current() != __end) ++__current(); } @@ -3040,7 +2992,7 @@ namespace views::__adaptor do { auto [__b, __p] - = __detail::mismatch(__current(), __end, __pbegin, __pend); + = ranges::mismatch(__current(), __end, __pbegin, __pend); if (__p == __pend) { __current() = __b; From patchwork Thu Jun 17 15:22:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1493660 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=KgiUN5mM; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G5RWt6cXCz9s24 for ; Fri, 18 Jun 2021 01:57:14 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B92D8397F41A for ; Thu, 17 Jun 2021 15:57:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B92D8397F41A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1623945432; bh=NKyBOsYzy+eBIl27Acdj1Z9YvYbuo1G2lHNGxPcchyo=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=KgiUN5mMIyg6MxMAirP/lJGAynOk+2lA0Gh2QZR2TKFbecH1dzv9R2QsWKdkegseI c4fP2y/BSha4MWjbQ8fsckpl75kgAgDPak88tPuBX3/24JolsONVGsAWA//j7AdL6v Ym+GCodkVNT+auKbOeeRGIs9dgLs7ibTvgfz0iu8= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 788BE395B462 for ; Thu, 17 Jun 2021 15:22:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 788BE395B462 Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-563-V7nNCTS1O4-N0nj1EmOxOA-1; Thu, 17 Jun 2021 11:22:14 -0400 X-MC-Unique: V7nNCTS1O4-N0nj1EmOxOA-1 Received: by mail-qv1-f70.google.com with SMTP id jm5-20020ad45ec50000b0290219dc9a1ab8so2477962qvb.21 for ; Thu, 17 Jun 2021 08:22:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=NKyBOsYzy+eBIl27Acdj1Z9YvYbuo1G2lHNGxPcchyo=; b=fDxiOas/3gWvlR8KPhunxh3E9uQFw6BpGw+Xbq+ClxcKIo6FjxJ/x41o1JNzuTDeGv epDhuiyGvPIMpiOb2F2eBXw1/p366ciwWDrygZCAyUTM9TZT3k6CcqC24aehW1PgOtnY FBacVHqLNBb3s2RMpjH53jjW1mf7v4Z8EXHMLJeYSnLezQsB7nsBvUO0cy1uKAPlUGQS RF1eDlgYdNKa187CfbPrlYF28R38AXEjC6QQqjRfuv4btj5ed9B7cpiSV2s1kRPbBn9F OP4nZMCI3xs5+cHvQL3fPNrkPHw9qLW71NjYFmklidqPJNnzCT9L9vEbH69e0PNoUVdF sb0w== X-Gm-Message-State: AOAM5332m9pU7asyPJWh+zOZfsVik9w7bA8GIDm56WXexSLbjbuuzQTN F+jLuFxy/DJqWkqQNqMT7UQFVeVu7239wdFB2WrXrnfleuhf/ezQSsfIjLPDPPeEjkB60zPUJsB exEnAKBpGek9Av6eVYomUj8/92vmgfe+lc9IpCMDm/L7QyjdlcI3fzmysH4dFmqEJGoc= X-Received: by 2002:a37:4096:: with SMTP id n144mr4265965qka.271.1623943333191; Thu, 17 Jun 2021 08:22:13 -0700 (PDT) X-Google-Smtp-Source: ABdhPJy1y7GjjVZNuz02+o7UWoX4B30V7zKdauEmG9PIpIIqixYEB/i6PDv5SokTwno858XTTWkp5A== X-Received: by 2002:a37:4096:: with SMTP id n144mr4265909qka.271.1623943332466; Thu, 17 Jun 2021 08:22:12 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id 5sm1933230qkj.99.2021.06.17.08.22.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Jun 2021 08:22:11 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 3/5] libstdc++: Rename views::split to views::lazy_split as per P2210 Date: Thu, 17 Jun 2021 11:22:04 -0400 Message-Id: <20210617152206.1408001-3-ppalka@redhat.com> X-Mailer: git-send-email 2.32.0.93.g670b81a890 In-Reply-To: <20210617152206.1408001-1-ppalka@redhat.com> References: <20210617152206.1408001-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-15.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_FILL_THIS_FORM_SHORT, URI_HEX autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Cc: libstdc++@gcc.gnu.org Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This mostly mechanical patch performs the renaming part of P2210R3 "Superior string splitting". It also defines _InnerIter::base() overloads. libstdc++-v3/ChangeLog: * include/std/ranges: Rename views::split to views::lazy_split, split_view to lazy_split_view, etc. throughout. (lazy_split_view::_InnerIter::base): Define as per P2210. * testsuite/std/ranges/*: Likewise. --- libstdc++-v3/include/std/ranges | 68 +++++++++++-------- .../testsuite/std/ranges/adaptors/100479.cc | 2 +- .../testsuite/std/ranges/adaptors/100577.cc | 20 +++--- .../testsuite/std/ranges/adaptors/join.cc | 2 +- .../adaptors/{split.cc => lazy_split.cc} | 54 +++++++-------- .../{split_neg.cc => lazy_split_neg.cc} | 6 +- .../testsuite/std/ranges/adaptors/p2281.cc | 18 ++--- .../testsuite/std/ranges/adaptors/sizeof.cc | 2 +- libstdc++-v3/testsuite/std/ranges/p2259.cc | 6 +- libstdc++-v3/testsuite/std/ranges/p2325.cc | 10 +-- libstdc++-v3/testsuite/std/ranges/p2367.cc | 4 +- 11 files changed, 100 insertions(+), 92 deletions(-) rename libstdc++-v3/testsuite/std/ranges/adaptors/{split.cc => lazy_split.cc} (76%) rename libstdc++-v3/testsuite/std/ranges/adaptors/{split_neg.cc => lazy_split_neg.cc} (79%) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index f93a880ff8a..cc1ef112ff1 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -2826,19 +2826,19 @@ namespace views::__adaptor && (remove_reference_t<_Range>::size() <= 1); template - struct __split_view_outer_iter_cat + struct __lazy_split_view_outer_iter_cat { }; template - struct __split_view_outer_iter_cat<_Base> + struct __lazy_split_view_outer_iter_cat<_Base> { using iterator_category = input_iterator_tag; }; template - struct __split_view_inner_iter_cat + struct __lazy_split_view_inner_iter_cat { }; template - struct __split_view_inner_iter_cat<_Base> + struct __lazy_split_view_inner_iter_cat<_Base> { private: static constexpr auto @@ -2860,7 +2860,7 @@ namespace views::__adaptor && indirectly_comparable, iterator_t<_Pattern>, ranges::equal_to> && (forward_range<_Vp> || __detail::__tiny_range<_Pattern>) - class split_view : public view_interface> + class lazy_split_view : public view_interface> { private: template @@ -2871,17 +2871,17 @@ namespace views::__adaptor template struct _OuterIter - : __detail::__split_view_outer_iter_cat<_Base<_Const>> + : __detail::__lazy_split_view_outer_iter_cat<_Base<_Const>> { private: - using _Parent = __detail::__maybe_const_t<_Const, split_view>; - using _Base = split_view::_Base<_Const>; + using _Parent = __detail::__maybe_const_t<_Const, lazy_split_view>; + using _Base = lazy_split_view::_Base<_Const>; constexpr bool __at_end() const { return __current() == ranges::end(_M_parent->_M_base); } - // [range.split.outer] p1 + // [range.lazy.split.outer] p1 // Many of the following specifications refer to the notional member // current of outer-iterator. current is equivalent to current_ if // V models forward_range, and parent_->current_ otherwise. @@ -2914,7 +2914,7 @@ namespace views::__adaptor using iterator_concept = conditional_t, forward_iterator_tag, input_iterator_tag>; - // iterator_category defined in __split_view_outer_iter_cat + // iterator_category defined in __lazy_split_view_outer_iter_cat using difference_type = range_difference_t<_Base>; struct value_type : view_interface @@ -2974,7 +2974,7 @@ namespace views::__adaptor operator++() { // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 3505. split_view::outer-iterator::operator++ misspecified + // 3505. lazy_split_view::outer-iterator::operator++ misspecified const auto __end = ranges::end(_M_parent->_M_base); if (__current() == __end) return *this; @@ -3030,10 +3030,10 @@ namespace views::__adaptor template struct _InnerIter - : __detail::__split_view_inner_iter_cat<_Base<_Const>> + : __detail::__lazy_split_view_inner_iter_cat<_Base<_Const>> { private: - using _Base = split_view::_Base<_Const>; + using _Base = lazy_split_view::_Base<_Const>; constexpr bool __at_end() const @@ -3081,7 +3081,7 @@ namespace views::__adaptor public: using iterator_concept = typename _OuterIter<_Const>::iterator_concept; - // iterator_category defined in __split_view_inner_iter_cat + // iterator_category defined in __lazy_split_view_inner_iter_cat using value_type = range_value_t<_Base>; using difference_type = range_difference_t<_Base>; @@ -3092,6 +3092,14 @@ namespace views::__adaptor : _M_i(std::move(__i)) { } + constexpr iterator_t<_Base> + base() const& requires copyable> + { return _M_i_current(); } + + constexpr iterator_t<_Base> + base() && + { return std::move(_M_i_current()); } + constexpr decltype(auto) operator*() const { return *_M_i_current(); } @@ -3151,12 +3159,12 @@ namespace views::__adaptor public: - split_view() requires (default_initializable<_Vp> - && default_initializable<_Pattern>) + lazy_split_view() requires (default_initializable<_Vp> + && default_initializable<_Pattern>) = default; constexpr - split_view(_Vp __base, _Pattern __pattern) + lazy_split_view(_Vp __base, _Pattern __pattern) : _M_pattern(std::move(__pattern)), _M_base(std::move(__base)) { } @@ -3164,7 +3172,7 @@ namespace views::__adaptor requires constructible_from<_Vp, views::all_t<_Range>> && constructible_from<_Pattern, single_view>> constexpr - split_view(_Range&& __r, range_value_t<_Range> __e) + lazy_split_view(_Range&& __r, range_value_t<_Range> __e) : _M_pattern(views::single(std::move(__e))), _M_base(views::all(std::forward<_Range>(__r))) { } @@ -3216,35 +3224,35 @@ namespace views::__adaptor }; template - split_view(_Range&&, _Pattern&&) - -> split_view, views::all_t<_Pattern>>; + lazy_split_view(_Range&&, _Pattern&&) + -> lazy_split_view, views::all_t<_Pattern>>; template - split_view(_Range&&, range_value_t<_Range>) - -> split_view, single_view>>; + lazy_split_view(_Range&&, range_value_t<_Range>) + -> lazy_split_view, single_view>>; namespace views { namespace __detail { template - concept __can_split_view - = requires { split_view(std::declval<_Range>(), std::declval<_Pattern>()); }; + concept __can_lazy_split_view + = requires { lazy_split_view(std::declval<_Range>(), std::declval<_Pattern>()); }; } // namespace __detail - struct _Split : __adaptor::_RangeAdaptor<_Split> + struct _LazySplit : __adaptor::_RangeAdaptor<_LazySplit> { template - requires __detail::__can_split_view<_Range, _Pattern> + requires __detail::__can_lazy_split_view<_Range, _Pattern> constexpr auto operator()(_Range&& __r, _Pattern&& __f) const { - return split_view(std::forward<_Range>(__r), std::forward<_Pattern>(__f)); + return lazy_split_view(std::forward<_Range>(__r), std::forward<_Pattern>(__f)); } - using _RangeAdaptor<_Split>::operator(); + using _RangeAdaptor<_LazySplit>::operator(); static constexpr int _S_arity = 2; - // The pattern argument of views::split is not always simple -- it can be + // The pattern argument of views::lazy_split is not always simple -- it can be // a non-view range, the value category of which affects whether the call // is well-formed. But a scalar or a view pattern argument is surely // simple. @@ -3254,7 +3262,7 @@ namespace views::__adaptor && copy_constructible<_Pattern>); }; - inline constexpr _Split split; + inline constexpr _LazySplit lazy_split; } // namespace views namespace views diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc index ba10b7baf3f..9899ff92c0b 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc @@ -90,7 +90,7 @@ test03() // Propagating cached iterators during copy/move would cause these asserts // to fail here. auto v = views::single(1) - | views::split(1) + | views::lazy_split(1) | views::drop(0) | views::drop_while([](auto) { return false; }) | views::filter([](auto) { return true; }); diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc index 06be4980ddb..5ef7f3f59a7 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc @@ -38,11 +38,11 @@ test01() static_assert(__adaptor_has_simple_extra_args); static_assert(__adaptor_has_simple_extra_args); static_assert(__adaptor_has_simple_extra_args); - static_assert(__adaptor_has_simple_extra_args); - static_assert(__adaptor_has_simple_extra_args); - static_assert(!__adaptor_has_simple_extra_args); + static_assert(__adaptor_has_simple_extra_args); + static_assert(__adaptor_has_simple_extra_args); + static_assert(!__adaptor_has_simple_extra_args); - // Verify all adaptor closures except for views::split(pattern) have a simple + // Verify all adaptor closures except for views::lazy_split(pattern) have a simple // operator(). using views::__adaptor::__closure_has_simple_call_op; __closure_has_simple_call_op auto a00 = views::all; @@ -56,14 +56,14 @@ test01() __closure_has_simple_call_op auto a08 = views::common; __closure_has_simple_call_op auto a09 = views::reverse; __closure_has_simple_call_op auto a10 = views::keys; - __closure_has_simple_call_op auto a11 = views::split(' '); + __closure_has_simple_call_op auto a11 = views::lazy_split(' '); // Verify composition of simple closures is simple. __closure_has_simple_call_op auto b = (a00 | a01) | (a02 | a03) | (a04 | a05 | a06) | (a07 | a08 | a09 | a10) | a11; - // Verify views::split(non_view_range) is an exception. + // Verify views::lazy_split(non_view_range) is an exception. extern std::string s; - auto a12 = views::split(s); + auto a12 = views::lazy_split(s); static_assert(!__closure_has_simple_call_op); static_assert(!__closure_has_simple_call_op); static_assert(!__closure_has_simple_call_op); @@ -91,9 +91,9 @@ test02() // implemented using a fallback deleted overload, so when a call is // ill-formed overload resolution succeeds but selects the deleted overload // (but only when the closure is invoked as an rvalue). - views::split(badarg)(x); // { dg-error "deleted function" } - (views::split(badarg) | views::all)(x); // { dg-error "deleted function" } - auto a0 = views::split(badarg); + views::lazy_split(badarg)(x); // { dg-error "deleted function" } + (views::lazy_split(badarg) | views::all)(x); // { dg-error "deleted function" } + auto a0 = views::lazy_split(badarg); a0(x); // { dg-error "no match" }; auto a1 = a0 | views::all; a1(x); // { dg-error "no match" } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc index d774e8d9385..50af3fdf729 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc @@ -93,7 +93,7 @@ test05() { using namespace std::literals; std::vector x = {"the", " ", "quick", " ", "brown", " ", "fox"}; - auto v = x | views::join | views::split(' '); + auto v = x | views::join | views::lazy_split(' '); auto i = v.begin(); VERIFY( ranges::equal(*i++, "the"sv) ); VERIFY( ranges::equal(*i++, "quick"sv) ); diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc similarity index 76% rename from libstdc++-v3/testsuite/std/ranges/adaptors/split.cc rename to libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc index 9d2cfa8632a..12844525d86 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc @@ -39,7 +39,7 @@ test01() { auto x = "the quick brown fox"sv; auto p = std::string{" "}; - auto v = x | views::split(views::all(p)); // views::all is needed here after P2281. + auto v = x | views::lazy_split(views::all(p)); // views::all is needed here after P2281. auto i = v.begin(); VERIFY( ranges::equal(*i++, "the"sv) ); VERIFY( ranges::equal(*i++, "quick"sv) ); @@ -52,7 +52,7 @@ void test02() { auto x = "the quick brown fox"sv; - auto v = x | views::split(' '); + auto v = x | views::lazy_split(' '); auto i = v.begin(); VERIFY( ranges::equal(*i++, "the"sv) ); VERIFY( ranges::equal(*i++, "quick"sv) ); @@ -66,7 +66,7 @@ test03() { char x[] = "the quick brown fox"; test_range rx(x, x+sizeof(x)-1); - auto v = rx | views::split(' '); + auto v = rx | views::lazy_split(' '); auto i = v.begin(); VERIFY( ranges::equal(*i++, "the"sv) ); VERIFY( ranges::equal(*i++, "quick"sv) ); @@ -83,7 +83,7 @@ test04() static_assert(!ranges::view); static_assert(std::same_as>); - auto v = x | views::split(views::all(p)); // views::all is needed here after P2281. + auto v = x | views::lazy_split(views::all(p)); // views::all is needed here after P2281. auto i = v.begin(); VERIFY( ranges::equal(*i++, "the"sv) ); VERIFY( ranges::equal(*i++, "quick"sv) ); @@ -102,7 +102,7 @@ test05() std::string str = "Now is the time for all good men to come to the aid of their county."; auto rng - = str | views::split(' ') | views::transform(as_string) | views::common; + = str | views::lazy_split(' ') | views::transform(as_string) | views::common; std::vector words(rng.begin(), rng.end()); auto not_space_p = [](char c) { return c != ' '; }; VERIFY( ranges::equal(words | views::join, @@ -113,7 +113,7 @@ void test06() { std::string str = "hello world"; - auto v = str | views::transform(std::identity{}) | views::split(' '); + auto v = str | views::transform(std::identity{}) | views::lazy_split(' '); // Verify that _Iterator is implicitly convertible to _Iterator. static_assert(!std::same_as rx(x, x+sizeof(x)-1); - auto v = rx | views::split(' '); + auto v = rx | views::lazy_split(' '); auto i = v.begin(); VERIFY( ranges::equal(*i, "the"sv) ); ++i; @@ -152,32 +152,32 @@ test08() VERIFY( i == v.end() ); } -template +template void test09() { // Verify SFINAE behavior. std::string s, p; - static_assert(!requires { split(); }); - static_assert(!requires { split(s, p, 0); }); - static_assert(!requires { split(p)(); }); - static_assert(!requires { s | split; }); - - static_assert(!requires { s | split(p); }); - static_assert(!requires { split(p)(s); }); - static_assert(!requires { s | (split(p) | views::all); }); - static_assert(!requires { (split(p) | views::all)(s); }); - - static_assert(requires { s | split(views::all(p)); }); - static_assert(requires { split(views::all(p))(s); }); - static_assert(requires { s | (split(views::all(p)) | views::all); }); - static_assert(requires { (split(views::all(p)) | views::all)(s); }); - - auto adapt = split(p); + static_assert(!requires { lazy_split(); }); + static_assert(!requires { lazy_split(s, p, 0); }); + static_assert(!requires { lazy_split(p)(); }); + static_assert(!requires { s | lazy_split; }); + + static_assert(!requires { s | lazy_split(p); }); + static_assert(!requires { lazy_split(p)(s); }); + static_assert(!requires { s | (lazy_split(p) | views::all); }); + static_assert(!requires { (lazy_split(p) | views::all)(s); }); + + static_assert(requires { s | lazy_split(views::all(p)); }); + static_assert(requires { lazy_split(views::all(p))(s); }); + static_assert(requires { s | (lazy_split(views::all(p)) | views::all); }); + static_assert(requires { (lazy_split(views::all(p)) | views::all)(s); }); + + auto adapt = lazy_split(p); static_assert(requires { s | adapt; }); static_assert(requires { adapt(s); }); - auto adapt2 = split(p) | views::all; + auto adapt2 = lazy_split(p) | views::all; static_assert(requires { s | adapt2; }); static_assert(requires { adapt2(s); }); } @@ -189,7 +189,7 @@ test10() auto to_string = [] (auto r) { return std::string(r.begin(), ranges::next(r.begin(), r.end())); }; - auto v = "xxyx"sv | views::split("xy"sv) | views::transform(to_string); + auto v = "xxyx"sv | views::lazy_split("xy"sv) | views::transform(to_string); VERIFY( ranges::equal(v, (std::string_view[]){"x", "x"}) ); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split_neg.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split_neg.cc similarity index 79% rename from libstdc++-v3/testsuite/std/ranges/adaptors/split_neg.cc rename to libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split_neg.cc index 4229314a9dc..c59f828ee56 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/split_neg.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split_neg.cc @@ -30,7 +30,7 @@ test01() { using namespace std::literals; auto x = "the quick brown fox"sv; - auto v = views::split(x, std::initializer_list{' ', ' '}); // { dg-error "no match" } + auto v = views::lazy_split(x, std::initializer_list{' ', ' '}); // { dg-error "no match" } } void @@ -38,8 +38,8 @@ test02() { using namespace std::literals; auto x = "the quick brown fox"sv; - auto v1 = views::split(std::initializer_list{' ', ' '})(x); // { dg-error "deleted" } - auto v2 = x | views::split(std::initializer_list{' ', ' '}); // { dg-error "no match" } + auto v1 = views::lazy_split(std::initializer_list{' ', ' '})(x); // { dg-error "deleted" } + auto v2 = x | views::lazy_split(std::initializer_list{' ', ' '}); // { dg-error "no match" } } // { dg-prune-output "in requirements" } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/p2281.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/p2281.cc index c916a5ea8b7..7950c43576d 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/p2281.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/p2281.cc @@ -34,7 +34,7 @@ void test01() { auto split_into_strings = [] (auto p) { - return views::split(p) | views::transform([](auto r){ + return views::lazy_split(p) | views::transform([](auto r){ return std::string(r.begin(), ranges::next(r.begin(), r.end())); }); }; @@ -60,19 +60,19 @@ struct move_only_range template<> inline constexpr bool std::ranges::enable_view = true; -template +template void test02() { std::string_view s; move_only_range p; - static_assert(requires { s | split(std::move(p)); }); - static_assert(requires { split(std::move(p))(s); }); - static_assert(requires { split(std::move(p)) | views::all; }); - static_assert(requires { views::all | split(std::move(p)); }); - static_assert(!requires { split(p); }); - static_assert(!requires { split(p) | views::all; }); - static_assert(!requires { views::all | split(p); }); + static_assert(requires { s | lazy_split(std::move(p)); }); + static_assert(requires { lazy_split(std::move(p))(s); }); + static_assert(requires { lazy_split(std::move(p)) | views::all; }); + static_assert(requires { views::all | lazy_split(std::move(p)); }); + static_assert(!requires { lazy_split(p); }); + static_assert(!requires { lazy_split(p) | views::all; }); + static_assert(!requires { views::all | lazy_split(p); }); } int diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc index 80326f8bf21..219e2a61f07 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/sizeof.cc @@ -46,7 +46,7 @@ static_assert(sizeof(ranges::take_while_view) == 3*ptr); static_assert(sizeof(ranges::drop_while_view) == 3*ptr); static_assert(sizeof(ranges::transform_view) == 3*ptr); -static_assert(sizeof(ranges::split_view) == 4*ptr); +static_assert(sizeof(ranges::lazy_split_view) == 4*ptr); static_assert (sizeof(ranges::reverse_view>) == 4*ptr); diff --git a/libstdc++-v3/testsuite/std/ranges/p2259.cc b/libstdc++-v3/testsuite/std/ranges/p2259.cc index 1b422e44f16..0ec7e21f657 100644 --- a/libstdc++-v3/testsuite/std/ranges/p2259.cc +++ b/libstdc++-v3/testsuite/std/ranges/p2259.cc @@ -49,12 +49,12 @@ test01() // 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); + // Verify the changes to lazy_split_view. + only_cxx20_input_range auto v3 = v0 | views::lazy_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; + only_cxx20_input_range auto v4 = v0 | views::lazy_split(12) | views::join; // Verify the changes to elements_view. only_cxx20_input_range auto v5 diff --git a/libstdc++-v3/testsuite/std/ranges/p2325.cc b/libstdc++-v3/testsuite/std/ranges/p2325.cc index df6cde29e4d..4d075409026 100644 --- a/libstdc++-v3/testsuite/std/ranges/p2325.cc +++ b/libstdc++-v3/testsuite/std/ranges/p2325.cc @@ -113,14 +113,14 @@ test07() void test08() { - // Verify split_view is conditionally default constructible. - using type1 = ranges::split_view, ranges::single_view>; + // Verify lazy_split_view is conditionally default constructible. + using type1 = ranges::lazy_split_view, ranges::single_view>; static_assert(!default_initializable); - using type2 = ranges::split_view, ranges::ref_view>; + using type2 = ranges::lazy_split_view, ranges::ref_view>; static_assert(!default_initializable); - using type3 = ranges::split_view, ranges::ref_view>; + using type3 = ranges::lazy_split_view, ranges::ref_view>; static_assert(!default_initializable); - using type4 = ranges::split_view, ranges::single_view>; + using type4 = ranges::lazy_split_view, ranges::single_view>; static_assert(default_initializable); } diff --git a/libstdc++-v3/testsuite/std/ranges/p2367.cc b/libstdc++-v3/testsuite/std/ranges/p2367.cc index 40875233d88..5228b021602 100644 --- a/libstdc++-v3/testsuite/std/ranges/p2367.cc +++ b/libstdc++-v3/testsuite/std/ranges/p2367.cc @@ -43,6 +43,6 @@ test01() // Verify changes to views::drop. auto v5 = views::drop(x, 0ull); - // Verify changes to views::split. - auto v6 = views::split(x, 5u); + // Verify changes to views::lazy_split. + auto v6 = views::lazy_split(x, 5u); } From patchwork Thu Jun 17 15:22:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1493638 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=R8AudFk3; dkim-atps=neutral Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G5RQJ4P55z9s24 for ; Fri, 18 Jun 2021 01:52:24 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5449C39730F9 for ; Thu, 17 Jun 2021 15:52:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5449C39730F9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1623945142; bh=tXk7F1ywk3Tc4JV86AhH7ZY7xpYa7MYRtWA/gbNLxZE=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=R8AudFk3Ewgpm9SCC7DqzfCsUq1EBRLztjwcjFcihFb2fMS+FhUF2hrBNYqbBoM0g 2kdrEtZjctiZOeDMIpsLCRxc4OAMTWXFbBOO+w584CtObFLqL/UG47Ffuz8IX6ibYm H64aTi7l3TxEm6ACDhMPL9mWGe57p7aVa2jLYS9g= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 2E143396AC1A for ; Thu, 17 Jun 2021 15:22:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2E143396AC1A Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-577-8_EJ87seMBCwC7s_1cWzgw-1; Thu, 17 Jun 2021 11:22:15 -0400 X-MC-Unique: 8_EJ87seMBCwC7s_1cWzgw-1 Received: by mail-qk1-f199.google.com with SMTP id 14-20020a37060e0000b02903aad32851d2so2345854qkg.1 for ; Thu, 17 Jun 2021 08:22:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=tXk7F1ywk3Tc4JV86AhH7ZY7xpYa7MYRtWA/gbNLxZE=; b=XjPCUyCRps/QtzOA1F0aI1zAgodKm+VSpDQGi8oNfwr6TsQxqOmsZo8HyYy0SeROS0 D/uDFIkJFg/figiRtIWBOuWahJcgHz5TeLF1wGmwEeHBlccSGSbzBX5nodz3d83rVvJB q5mturvEtBi8arjKmG2Lwt9+diuVkx5GuxPKR7Vmx6gN+1Zq0zbEJb1wFXBtGdGTUHKs geSHrmxrXjDJE2QAbMGsIDiWE83U/0Tz6zHrFRm6f5YXaSBRR8h/9w1cED+NDjVelAOE 6g3X1NTeacS1pDq/gVV4eeW04R87ibcuBYpQIl8jt2jRbivyiIMGq61LlZsdF4QbyOf7 p/dQ== X-Gm-Message-State: AOAM5325vK44RIJr7HLIey8taBot2CGxhkuymWLMQYuo79UiCPxE5aRl dMg3WtsePRbH//pgCaP41vtSXIH+jp1oEE8ZXJ3i/hGEIkZYSSL4PANLGVAFV+//a6mUGZCjKCX LqFk5Mcv1nsGLPOL5RTJf8zJ2E9kcJwgckagfHJPsSp7jdo1ohA1Idj9i2vHph4fQBQs= X-Received: by 2002:a37:bf81:: with SMTP id p123mr4521568qkf.40.1623943333885; Thu, 17 Jun 2021 08:22:13 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwmXLnvjCrMJKXPnUDfkr6u/xruPx7q/iNkDf7ktAuBl7Vis25hJAJdLwUVYzk7vUsGcM3tMw== X-Received: by 2002:a37:bf81:: with SMTP id p123mr4521541qkf.40.1623943333588; Thu, 17 Jun 2021 08:22:13 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id 5sm1933230qkj.99.2021.06.17.08.22.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Jun 2021 08:22:13 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 4/5] libstdc++: Implement resolution of LWG 3478 as per P2210 Date: Thu, 17 Jun 2021 11:22:05 -0400 Message-Id: <20210617152206.1408001-4-ppalka@redhat.com> X-Mailer: git-send-email 2.32.0.93.g670b81a890 In-Reply-To: <20210617152206.1408001-1-ppalka@redhat.com> References: <20210617152206.1408001-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-14.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, URI_HEX autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Cc: libstdc++@gcc.gnu.org Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This implements the part of P2210R2 "Superior String Splitting" that resolves LWG 3478 for split_view (now named lazy_split_view). libstdc++-v3/ChangeLog: * include/std/ranges (lazy_split_view::_OuterIter::__at_end): Check _M_trailing_empty. (lazy_split_view::_OuterIter::_M_trailing_empty): Define this data member. (lazy_split_view::_OuterIter::operator++): Set _M_trailing_empty appropriately. (lazy_split_view::_OuterIter::operator==): Compare _M_trailing_empty. * testsuite/std/ranges/adaptors/100479.cc (test03): Expect two split parts instead of one. * testsuite/std/ranges/adaptors/lazy_split.cc (test11): New test. --- libstdc++-v3/include/std/ranges | 21 +++++++++++++++---- .../testsuite/std/ranges/adaptors/100479.cc | 6 +++--- .../std/ranges/adaptors/lazy_split.cc | 15 +++++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index cc1ef112ff1..78562924bee 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -2879,7 +2879,7 @@ namespace views::__adaptor constexpr bool __at_end() const - { return __current() == ranges::end(_M_parent->_M_base); } + { return __current() == ranges::end(_M_parent->_M_base) && !_M_trailing_empty; } // [range.lazy.split.outer] p1 // Many of the following specifications refer to the notional member @@ -2909,6 +2909,7 @@ namespace views::__adaptor [[no_unique_address]] __detail::__maybe_present_t, iterator_t<_Base>> _M_current; + bool _M_trailing_empty = false; public: using iterator_concept = conditional_t, @@ -2977,7 +2978,10 @@ namespace views::__adaptor // 3505. lazy_split_view::outer-iterator::operator++ misspecified const auto __end = ranges::end(_M_parent->_M_base); if (__current() == __end) - return *this; + { + _M_trailing_empty = false; + return *this; + } const auto [__pbegin, __pend] = subrange{_M_parent->_M_pattern}; if (__pbegin == __pend) ++__current(); @@ -2986,7 +2990,11 @@ namespace views::__adaptor __current() = ranges::find(std::move(__current()), __end, *__pbegin); if (__current() != __end) - ++__current(); + { + ++__current(); + if (__current() == __end) + _M_trailing_empty = true; + } } else do @@ -2996,6 +3004,8 @@ namespace views::__adaptor if (__p == __pend) { __current() = __b; + if (__current() == __end) + _M_trailing_empty = true; break; } } while (++__current() != __end); @@ -3018,7 +3028,10 @@ namespace views::__adaptor friend constexpr bool operator==(const _OuterIter& __x, const _OuterIter& __y) requires forward_range<_Base> - { return __x._M_current == __y._M_current; } + { + return __x._M_current == __y._M_current + && __x._M_trailing_empty == __y._M_trailing_empty; + } friend constexpr bool operator==(const _OuterIter& __x, default_sentinel_t) diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc index 9899ff92c0b..b8c1e6f4f57 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/100479.cc @@ -95,11 +95,11 @@ test03() | views::drop_while([](auto) { return false; }) | views::filter([](auto) { return true; }); static_assert(ranges::forward_range); - VERIFY( ranges::next(v.begin()) == v.end() ); + VERIFY( ranges::distance(v) == 2 ); auto w = v; - VERIFY( ranges::next(w.begin()) == w.end() ); + VERIFY( ranges::distance(v) == 2 ); auto z = std::move(w); - VERIFY( ranges::next(z.begin()) == z.end() ); + VERIFY( ranges::distance(v) == 2 ); return true; } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc index 12844525d86..133e9a7025b 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/lazy_split.cc @@ -193,6 +193,20 @@ test10() VERIFY( ranges::equal(v, (std::string_view[]){"x", "x"}) ); } +void +test11() +{ + // LWG 3478 + static_assert(ranges::distance(views::lazy_split("text"sv, "text"sv)) == 2); + static_assert(ranges::distance(views::lazy_split(" text "sv, ' ')) == 3); + static_assert(ranges::distance(views::lazy_split(" t e x t "sv, ' ')) == 6); + static_assert(ranges::distance(views::lazy_split(" text "sv, " "sv)) == 3); + static_assert(ranges::distance(views::lazy_split(" text "sv, " "sv)) == 4); + static_assert(ranges::distance(views::lazy_split(" text "sv, " "sv)) == 4); + static_assert(ranges::distance(views::lazy_split("t"sv, 't')) == 2); + static_assert(ranges::distance(views::lazy_split("text"sv, ""sv)) == 4); +} + int main() { @@ -206,4 +220,5 @@ main() test08(); test09(); test10(); + test11(); } From patchwork Thu Jun 17 15:22:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1493644 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=FaDRIMY4; dkim-atps=neutral Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4G5RRs3PKqz9sSn for ; Fri, 18 Jun 2021 01:53:44 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 39FCC397EC06 for ; Thu, 17 Jun 2021 15:53:42 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 39FCC397EC06 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1623945222; bh=eZi0WIu7grbv5WOBsk6nL6IVg5SQxHEhwfvZL6wqL8M=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=FaDRIMY42bkhpdOyNlCCpwFgwf5Adm2cnJXxsRk6XPhmxMlZNnQgimg7Tv0X1A1rX JPC8jg0q18MlemhOJsxGHrKbD91dYeCmMruZNCdV2S7pIky/yC+1uRL5/HZPlbQPtE +CqO6cl7Stq3l/l7jk+CUxtCP+zBkd8WzoepFwJ4= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id B4AAD3951883 for ; Thu, 17 Jun 2021 15:22:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B4AAD3951883 Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-71-510nPTB0OkiRkt-kPKxh8A-1; Thu, 17 Jun 2021 11:22:17 -0400 X-MC-Unique: 510nPTB0OkiRkt-kPKxh8A-1 Received: by mail-qt1-f197.google.com with SMTP id z5-20020ac86c450000b029024e9a87714dso4146549qtu.2 for ; Thu, 17 Jun 2021 08:22:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=eZi0WIu7grbv5WOBsk6nL6IVg5SQxHEhwfvZL6wqL8M=; b=eaZdJ1fkn8RUitZamLnZ3xo2NjC1NH0rOok4gnrVAT/VP0OF1NhXqCegjrhVw7vZyj h5EwfgTFmpI31ihZocanPZIr8LMj5EtUvSklRuP60i2mrcBC/Pi47FIpMTRzzWUlkr5G 6gD+3IJxkqV2qRK+ME1bpzWYhGF1xmadbCWw1PnnA8r9lG46PRxYy5mJvnUq7LuUpENV IQCAomT71Ng31C6zPGAKMa3LEMq2OVGiQj729EHebtDSr5u6hSKf3ZZKOE7IUJk+Kx4p qcYWedfbmeVsrGzS+9gSaf28KdeCUX0lCmlPwiP2yJVBP8eeYuQpJzT9TMxXB9HObl9M 41qQ== X-Gm-Message-State: AOAM53079BVPHDZ4dOof5Zm0TOR61PrQBFbRXejtRYyNeAg+PS8BnfXE 4E9l0L1F9nyBhAavmLN3ls9FGmKsmVlYt2e3PENePoCsRDsHqC1l3Ukv9BDnGvhSiUO0GwJ7Hgp vx+hE9R7UpHz3fW6mETp2clEfob7Y9QIJiysufBha8ZZcWp2AApcOnACpzs3Ix35zMXo= X-Received: by 2002:a05:6214:2aa1:: with SMTP id js1mr438616qvb.11.1623943335832; Thu, 17 Jun 2021 08:22:15 -0700 (PDT) X-Google-Smtp-Source: ABdhPJz6IhVH0+cmrILYsmPhbEIdkWaQ31rkuqy+fnx4bTrF7KFvmziTj8KpPmklBosa+mMRFqgzVw== X-Received: by 2002:a05:6214:2aa1:: with SMTP id js1mr438565qvb.11.1623943335325; Thu, 17 Jun 2021 08:22:15 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id 5sm1933230qkj.99.2021.06.17.08.22.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Jun 2021 08:22:14 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 5/5] libstdc++: Implement new views::split as per P2210 Date: Thu, 17 Jun 2021 11:22:06 -0400 Message-Id: <20210617152206.1408001-5-ppalka@redhat.com> X-Mailer: git-send-email 2.32.0.93.g670b81a890 In-Reply-To: <20210617152206.1408001-1-ppalka@redhat.com> References: <20210617152206.1408001-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-15.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, URI_HEX autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Cc: libstdc++@gcc.gnu.org Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This implements the new views::split as specified by P2210R2 "Superior string splitting". libstdc++-v3/ChangeLog: * include/std/ranges (__non_propagating_cache::operator bool): Define. (split_view): Define as per P2210. (views::__detail::__can_split_view): Define. (views::_Split, views::Split): Define. * testsuite/std/ranges/adaptors/100577.cc (test01, test02): Test views::split. * testsuite/std/ranges/adaptors/split.cc: New test. * testsuite/std/ranges/p2325.cc (test08a): New test. * testsuite/std/ranges/p2367.cc (test01): Test views::split. --- libstdc++-v3/include/std/ranges | 205 ++++++++++++++++++ .../testsuite/std/ranges/adaptors/100577.cc | 16 +- .../testsuite/std/ranges/adaptors/split.cc | 196 +++++++++++++++++ libstdc++-v3/testsuite/std/ranges/p2325.cc | 14 ++ libstdc++-v3/testsuite/std/ranges/p2367.cc | 1 + 5 files changed, 430 insertions(+), 2 deletions(-) create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/split.cc diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 78562924bee..42278f128b8 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -1195,6 +1195,10 @@ namespace views::__adaptor return *this; } + constexpr explicit + operator bool() const noexcept + { return this->_M_is_engaged(); } + constexpr _Tp& operator*() noexcept { return this->_M_get(); } @@ -3278,6 +3282,207 @@ namespace views::__adaptor inline constexpr _LazySplit lazy_split; } // namespace views + template + requires view<_Vp> && view<_Pattern> + && indirectly_comparable, iterator_t<_Pattern>, + ranges::equal_to> + class split_view : public view_interface> + { + private: + _Pattern _M_pattern = _Pattern(); + __detail::__non_propagating_cache>> _M_cached_begin; + _Vp _M_base = _Vp(); + + struct _Iterator; + struct _Sentinel; + + public: + split_view() requires (default_initializable<_Vp> + && default_initializable<_Pattern>) + = default; + + constexpr + split_view(_Vp __base, _Pattern __pattern) + : _M_pattern(std::move(__pattern)), + _M_base(std::move(__base)) + { } + + template + requires constructible_from<_Vp, views::all_t<_Range>> + && constructible_from<_Pattern, single_view>> + constexpr + split_view(_Range&& __r, range_value_t<_Range> __e) + : _M_pattern(views::single(__e)), + _M_base(views::all(std::forward<_Range>(__r))) + { } + + constexpr _Vp + base() const& requires copyable<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr _Iterator + begin() + { + if (!_M_cached_begin) + _M_cached_begin = _M_find_next(ranges::begin(_M_base)); + return {this, ranges::begin(_M_base), *_M_cached_begin}; + } + + constexpr auto + end() + { + if constexpr (common_range<_Vp>) + return _Iterator{this, ranges::end(_M_base), {}}; + else + return _Sentinel{this}; + } + + constexpr subrange> + _M_find_next(iterator_t<_Vp> __it) + { + auto [__b, __e] = ranges::search(subrange(__it, ranges::end(_M_base)), _M_pattern); + if (__b != ranges::end(_M_base) && ranges::empty(_M_pattern)) + { + ++__b; + ++__e; + } + return {__b, __e}; + } + + private: + struct _Iterator + { + private: + split_view* _M_parent = nullptr; + iterator_t<_Vp> _M_cur = iterator_t<_Vp>(); + subrange> _M_next = subrange>(); + bool _M_trailing_empty = false; + + public: + using iterator_concept = forward_iterator_tag; + using iterator_category = input_iterator_tag; + using value_type = subrange>; + using difference_type = range_difference_t<_Vp>; + + _Iterator() requires default_initializable> = default; + + constexpr + _Iterator(split_view* __parent, + iterator_t<_Vp> __current, + subrange> __next) + : _M_parent(__parent), + _M_cur(std::move(__current)), + _M_next(std::move(__next)) + { } + + constexpr iterator_t<_Vp> + base() const + { return _M_cur; } + + constexpr value_type + operator*() const + { return {_M_cur, _M_next.begin()}; } + + constexpr _Iterator& + operator++() + { + _M_cur = _M_next.begin(); + if (_M_cur != ranges::end(_M_parent->_M_base)) + { + _M_cur = _M_next.end(); + if (_M_cur == ranges::end(_M_parent->_M_base)) + { + _M_trailing_empty = true; + _M_next = {_M_cur, _M_cur}; + } + else + _M_next = _M_parent->_M_find_next(_M_cur); + } + else + _M_trailing_empty = false; + return *this; + } + + constexpr _Iterator + operator++(int) + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + friend constexpr bool + operator==(const _Iterator& __x, const _Iterator& __y) + { + return __x._M_cur == __y._M_cur + && __x._M_trailing_empty == __y._M_trailing_empty; + } + + friend struct _Sentinel; + }; + + struct _Sentinel + { + private: + sentinel_t<_Vp> _M_end = sentinel_t<_Vp>(); + + constexpr bool + _M_equal(const _Iterator& __x) const + { return __x._M_cur == _M_end && !__x._M_trailing_empty; } + + public: + constexpr explicit + _Sentinel(split_view* __parent) + : _M_end(ranges::end(__parent->_M_base)) + { } + + friend constexpr bool + operator==(const _Iterator& __x, const _Sentinel& __y) + { return __y._M_equal(__x); } + }; + }; + + template + split_view(_Range&&, _Pattern&&) + -> split_view, views::all_t<_Pattern>>; + + template + split_view(_Range&&, range_value_t<_Range>) + -> split_view, single_view>>; + + namespace views + { + namespace __detail + { + template + concept __can_split_view + = requires { split_view(std::declval<_Range>(), std::declval<_Pattern>()); }; + } // namespace __detail + + struct _Split : __adaptor::_RangeAdaptor<_Split> + { + template + requires __detail::__can_split_view<_Range, _Pattern> + constexpr auto + operator()(_Range&& __r, _Pattern&& __f) const + { + return split_view(std::forward<_Range>(__r), std::forward<_Pattern>(__f)); + } + + using _RangeAdaptor<_Split>::operator(); + static constexpr int _S_arity = 2; + template + static constexpr bool _S_has_simple_extra_args + = _LazySplit::_S_has_simple_extra_args<_Pattern>; + }; + + inline constexpr _Split split; + } // namespace views + namespace views { struct _Counted diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc index 5ef7f3f59a7..81f2a62cfaa 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/100577.cc @@ -42,8 +42,6 @@ test01() static_assert(__adaptor_has_simple_extra_args); static_assert(!__adaptor_has_simple_extra_args); - // Verify all adaptor closures except for views::lazy_split(pattern) have a simple - // operator(). using views::__adaptor::__closure_has_simple_call_op; __closure_has_simple_call_op auto a00 = views::all; __closure_has_simple_call_op auto a01 = views::transform(std::identity{}); @@ -57,6 +55,7 @@ test01() __closure_has_simple_call_op auto a09 = views::reverse; __closure_has_simple_call_op auto a10 = views::keys; __closure_has_simple_call_op auto a11 = views::lazy_split(' '); + __closure_has_simple_call_op auto a11a = views::split(' '); // Verify composition of simple closures is simple. __closure_has_simple_call_op auto b = (a00 | a01) | (a02 | a03) | (a04 | a05 | a06) | (a07 | a08 | a09 | a10) | a11; @@ -67,6 +66,12 @@ test01() static_assert(!__closure_has_simple_call_op); static_assert(!__closure_has_simple_call_op); static_assert(!__closure_has_simple_call_op); + + // Likewise views::split(non_view_range). + auto a12a = views::split(s); + static_assert(!__closure_has_simple_call_op); + static_assert(!__closure_has_simple_call_op); + static_assert(!__closure_has_simple_call_op); } void @@ -98,6 +103,13 @@ test02() auto a1 = a0 | views::all; a1(x); // { dg-error "no match" } + views::lazy_split(badarg)(x); // { dg-error "deleted function" } + (views::lazy_split(badarg) | views::all)(x); // { dg-error "deleted function" } + auto a0a = views::split(badarg); + a0a(x); // { dg-error "no match" }; + auto a1a = a0a | views::all; + a1a(x); // { dg-error "no match" } + views::take(badarg)(x); // { dg-error "deleted" } views::drop(badarg)(x); // { dg-error "deleted" } (views::take(badarg) | views::all)(x); // { dg-error "deleted" } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc new file mode 100644 index 00000000000..9e6726cd07f --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc @@ -0,0 +1,196 @@ +// Copyright (C) 2020-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 run { target c++2a } } + +#include +#include +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::input_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +using namespace std::literals; + +void +test01() +{ + auto from_chars = [] (auto v) { + return std::stoi(std::string(v.data(), v.data() + v.size())); + }; + auto ints = "1.2.3.4"sv + | views::split('.') + | views::transform(from_chars); + VERIFY( ranges::equal(ints, (int[]){1,2,3,4}) ); +} + +// The following testcases were adapted from lazy_split.cc. +namespace from_lazy_split_cc +{ +void +test01() +{ + auto x = "the quick brown fox"sv; + auto p = std::string{" "}; + auto v = x | views::split(views::all(p)); // views::all is needed here after P2281. + auto i = v.begin(); + VERIFY( ranges::equal(*i++, "the"sv) ); + VERIFY( ranges::equal(*i++, "quick"sv) ); + VERIFY( ranges::equal(*i++, "brown"sv) ); + VERIFY( ranges::equal(*i++, "fox"sv) ); + VERIFY( i == v.end() ); +} + +void +test02() +{ + auto x = "the quick brown fox"sv; + auto v = x | views::split(' '); + auto i = v.begin(); + VERIFY( ranges::equal(*i++, "the"sv) ); + VERIFY( ranges::equal(*i++, "quick"sv) ); + VERIFY( ranges::equal(*i++, "brown"sv) ); + VERIFY( ranges::equal(*i++, "fox"sv) ); + VERIFY( i == v.end() ); +} + +void +test03() +{ + char x[] = "the quick brown fox"; + test_range rx(x, x+sizeof(x)-1); + auto v = rx | views::split(' '); + auto i = v.begin(); + VERIFY( ranges::equal(*i++, "the"sv) ); + VERIFY( ranges::equal(*i++, "quick"sv) ); + VERIFY( ranges::equal(*i++, "brown"sv) ); + VERIFY( ranges::equal(*i++, "fox"sv) ); + VERIFY( i == v.end() ); +} + +void +test04() +{ + auto x = "the quick brown fox"sv; + std::initializer_list p = {' ', ' '}; + static_assert(!ranges::view); + static_assert(std::same_as>); + auto v = x | views::split(views::all(p)); // views::all is needed here after P2281. + auto i = v.begin(); + VERIFY( ranges::equal(*i++, "the"sv) ); + VERIFY( ranges::equal(*i++, "quick"sv) ); + VERIFY( ranges::equal(*i++, "brown"sv) ); + VERIFY( ranges::equal(*i++, "fox"sv) ); + VERIFY( i == v.end() ); +} + +void +test05() +{ + auto as_string = [](ranges::view auto rng) { + auto in = rng | views::common; + return std::string(in.begin(), in.end()); + }; + std::string str + = "Now is the time for all good men to come to the aid of their county."; + auto rng + = str | views::split(' ') | views::transform(as_string) | views::common; + std::vector words(rng.begin(), rng.end()); + auto not_space_p = [](char c) { return c != ' '; }; + VERIFY( ranges::equal(words | views::join, + str | views::filter(not_space_p)) ); +} + +template +void +test06() +{ + // Verify SFINAE behavior. + std::string s, p; + static_assert(!requires { split(); }); + static_assert(!requires { split(s, p, 0); }); + static_assert(!requires { split(p)(); }); + static_assert(!requires { s | split; }); + + static_assert(!requires { s | split(p); }); + static_assert(!requires { split(p)(s); }); + static_assert(!requires { s | (split(p) | views::all); }); + static_assert(!requires { (split(p) | views::all)(s); }); + + static_assert(requires { s | split(views::all(p)); }); + static_assert(requires { split(views::all(p))(s); }); + static_assert(requires { s | (split(views::all(p)) | views::all); }); + static_assert(requires { (split(views::all(p)) | views::all)(s); }); + + auto adapt = split(p); + static_assert(requires { s | adapt; }); + static_assert(requires { adapt(s); }); + + auto adapt2 = split(p) | views::all; + static_assert(requires { s | adapt2; }); + static_assert(requires { adapt2(s); }); +} + +void +test10() +{ + // LWG 3505 + auto to_string = [] (auto r) { + return std::string(r.begin(), ranges::next(r.begin(), r.end())); + }; + auto v = "xxyx"sv | views::split("xy"sv) | views::transform(to_string); + VERIFY( ranges::equal(v, (std::string_view[]){"x", "x"}) ); +} + +void +test11() +{ + // LWG 3478 + static_assert(ranges::distance(views::split("text"sv, "text"sv)) == 2); + static_assert(ranges::distance(views::split(" text "sv, ' ')) == 3); + static_assert(ranges::distance(views::split(" t e x t "sv, ' ')) == 6); + static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 3); + static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 4); + static_assert(ranges::distance(views::split(" text "sv, " "sv)) == 4); + static_assert(ranges::distance(views::split("t"sv, 't')) == 2); + static_assert(ranges::distance(views::split("text"sv, ""sv)) == 4); +} +} // namespace from_lazy_split_cc + +int +main() +{ + test01(); + + from_lazy_split_cc::test01(); + from_lazy_split_cc::test02(); + from_lazy_split_cc::test03(); + from_lazy_split_cc::test04(); + from_lazy_split_cc::test05(); + from_lazy_split_cc::test06(); + from_lazy_split_cc::test10(); + from_lazy_split_cc::test11(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/p2325.cc b/libstdc++-v3/testsuite/std/ranges/p2325.cc index 4d075409026..d2ebe9af863 100644 --- a/libstdc++-v3/testsuite/std/ranges/p2325.cc +++ b/libstdc++-v3/testsuite/std/ranges/p2325.cc @@ -124,6 +124,20 @@ test08() static_assert(default_initializable); } +void +test08a() +{ + // Verify split_view is conditionally default constructible. + using type1 = ranges::split_view, ranges::single_view>; + static_assert(!default_initializable); + using type2 = ranges::split_view, ranges::ref_view>; + static_assert(!default_initializable); + using type3 = ranges::split_view, ranges::ref_view>; + static_assert(!default_initializable); + using type4 = ranges::split_view, ranges::single_view>; + static_assert(default_initializable); +} + void test09() { diff --git a/libstdc++-v3/testsuite/std/ranges/p2367.cc b/libstdc++-v3/testsuite/std/ranges/p2367.cc index 5228b021602..70a0304593f 100644 --- a/libstdc++-v3/testsuite/std/ranges/p2367.cc +++ b/libstdc++-v3/testsuite/std/ranges/p2367.cc @@ -45,4 +45,5 @@ test01() // Verify changes to views::lazy_split. auto v6 = views::lazy_split(x, 5u); + auto v7 = views::split(x, 5u); }