From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-lj1-x229.google.com (mail-lj1-x229.google.com [IPv6:2a00:1450:4864:20::229]) by sourceware.org (Postfix) with ESMTPS id 7E6243858D33; Wed, 16 Aug 2023 17:28:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7E6243858D33 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-lj1-x229.google.com with SMTP id 38308e7fff4ca-2b9bf52cd08so100864341fa.2; Wed, 16 Aug 2023 10:28:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20221208; t=1692206922; x=1692811722; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=CWypPFZNcFeUSgAvfCI8iKCmMJ/BcG0yG0OS/hHF+6g=; b=NMqGa/BhTzFYBUx0b79kXlSsqlW8/TUDT7US3b0qniPHkvRwCw91PhkBhBi+eUzciF t2BOKUTIFTM9KMGmvDtzD84/8UT5vvBUXjETjYTqVxPRSzkPVwHK730DouI6p2+13fCK VFD8FTr104oDxEEq1mjGqfQ3/5+hRjAcu6kVHmB24W2JKUsVSdOSNfwLiZueLVDuT62h JIRN8F3sfRYq3inz72OQiO08u6u3g7glHT9grvwvcsnCQE5wTNPLA8SjzTq/gJy5ZV30 2VxOBkAGKgiHmKJD6e7lfam1bBEr0y6GrUGRjFJ2SEVTgybwHAlwlTLu3l0z2QY73z3d 4o9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1692206922; x=1692811722; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CWypPFZNcFeUSgAvfCI8iKCmMJ/BcG0yG0OS/hHF+6g=; b=jFDO8rchigpX+gu8xfwG1XNxoMVsumPO+lq5NSPiUKKap6DU1cdnwxeiRcKj6521d+ D8imWG2p2hYt8U/GRhSbiZXjhZN6Ws5P2eVqBzEbId5gRi2a2PBWh5mA7hgWrWmeBTBt yXHnhfOMnJlaog0oQSVQuQLchZrtKaiBnPStJnQwoLvRIK+oD/WQmsbe+7syCDwdTbs4 xA5XHfCiJ2AykIOSGc1ztEXriW/9vX8K8p+X8kQC7QFtvcTzLTiciOg57eCOa2CKR3kl bR47i2AWPgHAS4DzWJ78zPyFLrKTX0iR36pgqVLta8fUt9UQdryYu8ld94WVWFaB27/e f/Dw== X-Gm-Message-State: AOJu0YwFxb90kPsiPLkANF0CzwnvIdKWdp5LUvEbrjr0mmXDAND17deP Pb8CI4AGGILIsHrFX787+z2FxE7ms9T9pAgU6PM= X-Google-Smtp-Source: AGHT+IFiUtsYTqeyjgpR4sZo3E993c76MfTwc7TzxDsIeUSW5djxYnbPgA1eDQLJVVfbnFwWRPEpK9Jn4MAV36C+UCU= X-Received: by 2002:a2e:930d:0:b0:2b6:fa3f:9230 with SMTP id e13-20020a2e930d000000b002b6fa3f9230mr1972160ljh.46.1692206921513; Wed, 16 Aug 2023 10:28:41 -0700 (PDT) MIME-Version: 1.0 References: <20230417133916.3110637-1-ppalka@redhat.com> In-Reply-To: From: Jonathan Wakely Date: Wed, 16 Aug 2023 18:28:31 +0100 Message-ID: Subject: Re: [PATCH] libstdc++: Implement P2770R0 changes to join_view / join_with_view To: Patrick Palka Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-6.0 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Wed, 16 Aug 2023 at 17:05, Patrick Palka via Libstdc++ wrote: > > On Mon, Apr 17, 2023 at 9:39=E2=80=AFAM Patrick Palka = wrote: > > > > This C++23 paper fixes a bug in these views when adapting a certain kin= d > > of non-forward range, and we treat it as a DR against C++20. > > > > Tested on x86_64-pc-linux-gnu, does this look OK for GCC 13? This > > is an ABI change for join_view so it'd be unsuitable for backporting > > later I think :( > > Ping, does this look OK for trunk? Looks like I completely missed this one, sorry. OK for trunk. > > > > > libstdc++-v3/ChangeLog: > > > > * include/bits/regex.h (regex_iterator::iterator_concept): > > Define for C++20 as per P2770R0. > > (regex_token_iterator::iterator_concept): Likewise. > > * include/std/ranges (__detail::__as_lvalue): Define. > > (join_view::_Iterator): Befriend join_view. > > (join_view::_Iterator::_M_satisfy): Use _M_get_outer > > instead of _M_outer. > > (join_view::_Iterator::_M_get_outer): Define. > > (join_view::_Iterator::_Iterator): Split constructor taking > > _Parent argument into two as per P2770R0. Remove constraint on > > default constructor. > > (join_view::_Iterator::_M_outer): Make this data member present > > only when the underlying range is forward. > > (join_view::_Iterator::operator++): Use _M_get_outer instead of > > _M_outer. > > (join_view::_Iterator::operator--): Use __as_lvalue helper. > > (join_view::_Iterator::operator=3D=3D): Adjust constraints as p= er > > P2770R0. > > (join_view::_Sentinel::__equal): Use _M_get_outer instead of > > _M_outer. > > (join_view::_M_outer): New data member when the underlying rang= e > > is non-forward. > > (join_view::begin): Adjust definition as per P2770R0. > > (join_view::end): Likewise. > > (join_with_view::_M_outer_it): New data member when the > > underlying range is non-forward. > > (join_with_view::begin): Adjust definition as per P2770R0. > > (join_with_view::end): Likewise. > > (join_with_view::_Iterator::_M_outer_it): Make this data member > > present only when the underlying range is forward. > > (join_with_view::_Iterator::_M_get_outer): Define. > > (join_with_view::_Iterator::_Iterator): Split constructor > > taking _Parent argument into two as per P2770R0. Remove > > constraint on default constructor. > > (join_with_view::_Iterator::_M_update_inner): Adjust definition > > as per P2770R0. > > (join_with_view::_Iterator::_M_get_inner): Likewise. > > (join_with_view::_Iterator::_M_satisfy): Adjust calls to > > _M_get_inner. Use _M_get_outer instead of _M_outer_it. > > (join_with_view::_Iterator::operator=3D=3D): Adjust constraints > > as per P2770R0. > > (join_with_view::_Sentinel::operator=3D=3D): Use _M_get_outer > > instead of _M_outer_it. > > * testsuite/std/ranges/adaptors/p2770r0.cc: New test. > > --- > > libstdc++-v3/include/bits/regex.h | 6 + > > libstdc++-v3/include/std/ranges | 190 +++++++++++++----- > > .../testsuite/std/ranges/adaptors/p2770r0.cc | 110 ++++++++++ > > 3 files changed, 257 insertions(+), 49 deletions(-) > > create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.= cc > > > > diff --git a/libstdc++-v3/include/bits/regex.h b/libstdc++-v3/include/b= its/regex.h > > index 26ac6a21c31..2d306868721 100644 > > --- a/libstdc++-v3/include/bits/regex.h > > +++ b/libstdc++-v3/include/bits/regex.h > > @@ -2740,6 +2740,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > > typedef const value_type* pointer; > > typedef const value_type& reference; > > typedef std::forward_iterator_tag iterator_category; > > +#if __cplusplus > 201703L > > + typedef std::input_iterator_tag iterator_concept; > > +#endif > > > > /** > > * @brief Provides a singular iterator, useful for indicating > > @@ -2869,6 +2872,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 > > typedef const value_type* pointer; > > typedef const value_type& reference; > > typedef std::forward_iterator_tag iterator_catego= ry; > > +#if __cplusplus > 201703L > > + typedef std::input_iterator_tag iterator_concept; > > +#endif > > > > public: > > /** > > diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std= /ranges > > index 283d757faa4..ddcf50cc93e 100644 > > --- a/libstdc++-v3/include/std/ranges > > +++ b/libstdc++-v3/include/std/ranges > > @@ -2705,6 +2705,14 @@ namespace views::__adaptor > > inline constexpr _DropWhile drop_while; > > } // namespace views > > > > + namespace __detail > > + { > > + template > > + constexpr _Tp& > > + __as_lvalue(_Tp&& __t) > > + { return static_cast<_Tp&>(__t); } > > + } // namespace __detail > > + > > template > > requires view<_Vp> && input_range> > > class join_view : public view_interface> > > @@ -2767,6 +2775,8 @@ namespace views::__adaptor > > using _Parent =3D __detail::__maybe_const_t<_Const, join_view= >; > > using _Base =3D join_view::_Base<_Const>; > > > > + friend join_view; > > + > > static constexpr bool _S_ref_is_glvalue > > =3D join_view::_S_ref_is_glvalue<_Const>; > > > > @@ -2780,9 +2790,10 @@ namespace views::__adaptor > > return _M_parent->_M_inner._M_emplace_deref(__x); > > }; > > > > - for (; _M_outer !=3D ranges::end(_M_parent->_M_base); ++_M_= outer) > > + _Outer_iter& __outer =3D _M_get_outer(); > > + for (; __outer !=3D ranges::end(_M_parent->_M_base); ++__ou= ter) > > { > > - auto&& __inner =3D __update_inner(_M_outer); > > + auto&& __inner =3D __update_inner(__outer); > > _M_inner =3D ranges::begin(__inner); > > if (_M_inner !=3D ranges::end(__inner)) > > return; > > @@ -2811,7 +2822,36 @@ namespace views::__adaptor > > using _Outer_iter =3D join_view::_Outer_iter<_Const>; > > using _Inner_iter =3D join_view::_Inner_iter<_Const>; > > > > - _Outer_iter _M_outer =3D _Outer_iter(); > > + constexpr _Outer_iter& > > + _M_get_outer() > > + { > > + if constexpr (forward_range<_Base>) > > + return _M_outer; > > + else > > + return *_M_parent->_M_outer; > > + } > > + > > + constexpr const _Outer_iter& > > + _M_get_outer() const > > + { > > + if constexpr (forward_range<_Base>) > > + return _M_outer; > > + else > > + return *_M_parent->_M_outer; > > + } > > + > > + constexpr > > + _Iterator(_Parent* __parent, _Outer_iter __outer) requires fo= rward_range<_Base> > > + : _M_outer(std::move(__outer)), _M_parent(__parent) > > + { _M_satisfy(); } > > + > > + constexpr explicit > > + _Iterator(_Parent* __parent) requires (!forward_range<_Base>) > > + : _M_parent(__parent) > > + { _M_satisfy(); } > > + > > + [[no_unique_address]] > > + __detail::__maybe_present_t, _Outer_it= er> _M_outer; > > optional<_Inner_iter> _M_inner; > > _Parent* _M_parent =3D nullptr; > > > > @@ -2823,13 +2863,7 @@ namespace views::__adaptor > > =3D common_type_t, > > range_difference_t= >>; > > > > - _Iterator() requires default_initializable<_Outer_iter> =3D d= efault; > > - > > - constexpr > > - _Iterator(_Parent* __parent, _Outer_iter __outer) > > - : _M_outer(std::move(__outer)), > > - _M_parent(__parent) > > - { _M_satisfy(); } > > + _Iterator() =3D default; > > > > constexpr > > _Iterator(_Iterator __i) > > @@ -2857,13 +2891,13 @@ namespace views::__adaptor > > { > > auto&& __inner_range =3D [this] () -> auto&& { > > if constexpr (_S_ref_is_glvalue) > > - return *_M_outer; > > + return *_M_get_outer(); > > else > > return *_M_parent->_M_inner; > > }(); > > if (++*_M_inner =3D=3D ranges::end(__inner_range)) > > { > > - ++_M_outer; > > + ++_M_get_outer(); > > _M_satisfy(); > > } > > return *this; > > @@ -2890,9 +2924,9 @@ namespace views::__adaptor > > && common_range> > > { > > if (_M_outer =3D=3D ranges::end(_M_parent->_M_base)) > > - _M_inner =3D ranges::end(*--_M_outer); > > - while (*_M_inner =3D=3D ranges::begin(*_M_outer)) > > - *_M_inner =3D ranges::end(*--_M_outer); > > + _M_inner =3D ranges::end(__detail::__as_lvalue(*--_M_oute= r)); > > + while (*_M_inner =3D=3D ranges::begin(__detail::__as_lvalue= (*_M_outer))) > > + *_M_inner =3D ranges::end(__detail::__as_lvalue(*--_M_out= er)); > > --*_M_inner; > > return *this; > > } > > @@ -2911,7 +2945,7 @@ namespace views::__adaptor > > friend constexpr bool > > operator=3D=3D(const _Iterator& __x, const _Iterator& __y) > > requires _S_ref_is_glvalue > > - && equality_comparable<_Outer_iter> > > + && forward_range<_Base> > > && equality_comparable<_Inner_iter> > > { > > return (__x._M_outer =3D=3D __y._M_outer > > @@ -2943,7 +2977,7 @@ namespace views::__adaptor > > template > > constexpr bool > > __equal(const _Iterator<_Const2>& __i) const > > - { return __i._M_outer =3D=3D _M_end; } > > + { return __i._M_get_outer() =3D=3D _M_end; } > > > > sentinel_t<_Base> _M_end =3D sentinel_t<_Base>(); > > > > @@ -2972,6 +3006,9 @@ namespace views::__adaptor > > }; > > > > _Vp _M_base =3D _Vp(); > > + [[no_unique_address]] > > + __detail::__maybe_present_t, > > + __detail::__non_propagating_cache>> _M_outer; > > [[no_unique_address]] > > __detail::__non_propagating_cache> _M_= inner; > > > > @@ -2994,16 +3031,25 @@ namespace views::__adaptor > > constexpr auto > > begin() > > { > > - constexpr bool __use_const > > - =3D (__detail::__simple_view<_Vp> > > - && is_reference_v>); > > - return _Iterator<__use_const>{this, ranges::begin(_M_base)}; > > + if constexpr (forward_range<_Vp>) > > + { > > + constexpr bool __use_const > > + =3D (__detail::__simple_view<_Vp> > > + && is_reference_v>); > > + return _Iterator<__use_const>{this, ranges::begin(_M_base)}= ; > > + } > > + else > > + { > > + _M_outer =3D ranges::begin(_M_base); > > + return _Iterator{this}; > > + } > > } > > > > constexpr auto > > begin() const > > - requires input_range > > + requires forward_range > > && is_reference_v> > > + && input_range> > > { > > return _Iterator{this, ranges::begin(_M_base)}; > > } > > @@ -3022,11 +3068,11 @@ namespace views::__adaptor > > > > constexpr auto > > end() const > > - requires input_range > > + requires forward_range > > && is_reference_v> > > + && input_range> > > { > > - if constexpr (forward_range > > - && is_reference_v> > > + if constexpr (is_reference_v> > > && forward_range> > > && common_range > > && common_range>) > > @@ -6948,6 +6994,9 @@ namespace views::__adaptor > > using _InnerRange =3D range_reference_t<_Vp>; > > > > _Vp _M_base =3D _Vp(); > > + [[no_unique_address]] > > + __detail::__maybe_present_t, > > + __detail::__non_propagating_cache>> _M_outer_it= ; > > __detail::__non_propagating_cache> _M_inn= er; > > _Pattern _M_pattern =3D _Pattern(); > > > > @@ -7035,16 +7084,25 @@ namespace views::__adaptor > > constexpr auto > > begin() > > { > > - constexpr bool __use_const =3D is_reference_v<_InnerRange> > > - && __detail::__simple_view<_Vp> && __detail::__simple_view<_Pat= tern>; > > - return _Iterator<__use_const>{*this, ranges::begin(_M_base)}; > > + if constexpr (forward_range<_Vp>) > > + { > > + constexpr bool __use_const =3D is_reference_v<_InnerRange> > > + && __detail::__simple_view<_Vp> && __detail::__simple_view<= _Pattern>; > > + return _Iterator<__use_const>{*this, ranges::begin(_M_base)}; > > + } > > + else > > + { > > + _M_outer_it =3D ranges::begin(_M_base); > > + return _Iterator{*this}; > > + } > > } > > > > constexpr auto > > begin() const > > - requires input_range > > + requires forward_range > > && forward_range > > && is_reference_v> > > + && input_range> > > { return _Iterator{*this, ranges::begin(_M_base)}; } > > > > constexpr auto > > @@ -7062,13 +7120,13 @@ namespace views::__adaptor > > > > constexpr auto > > end() const > > - requires input_range > > + requires forward_range > > && forward_range > > && is_reference_v> > > + && input_range> > > { > > using _InnerConstRange =3D range_reference_t; > > - if constexpr (forward_range > > - && forward_range<_InnerConstRange> > > + if constexpr (forward_range<_InnerConstRange> > > && common_range > > && common_range<_InnerConstRange>) > > return _Iterator{*this, ranges::end(_M_base)}; > > @@ -7105,35 +7163,69 @@ namespace views::__adaptor > > static constexpr bool _S_ref_is_glvalue =3D join_with_view::_S_ref= _is_glvalue<_Const>; > > > > _Parent* _M_parent =3D nullptr; > > - _OuterIter _M_outer_it =3D _OuterIter(); > > + [[no_unique_address]] > > + __detail::__maybe_present_t, _OuterIter> _M= _outer_it; > > variant<_PatternIter, _InnerIter> _M_inner_it; > > > > + constexpr _OuterIter& > > + _M_get_outer() > > + { > > + if constexpr (forward_range<_Base>) > > + return _M_outer_it; > > + else > > + return *_M_parent->_M_outer_it; > > + } > > + > > + constexpr const _OuterIter& > > + _M_get_outer() const > > + { > > + if constexpr (forward_range<_Base>) > > + return _M_outer_it; > > + else > > + return *_M_parent->_M_outer_it; > > + } > > + > > constexpr > > - _Iterator(_Parent& __parent, iterator_t<_Base> __outer) > > + _Iterator(_Parent& __parent, _OuterIter __outer) > > + requires forward_range<_Base> > > : _M_parent(std::__addressof(__parent)), _M_outer_it(std::move(__o= uter)) > > { > > - if (_M_outer_it !=3D ranges::end(_M_parent->_M_base)) > > + if (_M_get_outer() !=3D ranges::end(_M_parent->_M_base)) > > + { > > + auto&& __inner =3D _M_update_inner(); > > + _M_inner_it.template emplace<1>(ranges::begin(__inner)); > > + _M_satisfy(); > > + } > > + } > > + > > + constexpr > > + _Iterator(_Parent& __parent) > > + requires (!forward_range<_Base>) > > + : _M_parent(std::__addressof(__parent)) > > + { > > + if (_M_get_outer() !=3D ranges::end(_M_parent->_M_base)) > > { > > - auto&& __inner =3D _M_update_inner(_M_outer_it); > > + auto&& __inner =3D _M_update_inner(); > > _M_inner_it.template emplace<1>(ranges::begin(__inner)); > > _M_satisfy(); > > } > > } > > > > - constexpr auto&& > > - _M_update_inner(const _OuterIter& __x) > > + constexpr auto& > > + _M_update_inner() > > { > > + _OuterIter& __outer =3D _M_get_outer(); > > if constexpr (_S_ref_is_glvalue) > > - return *__x; > > + return __detail::__as_lvalue(*__outer); > > else > > - return _M_parent->_M_inner._M_emplace_deref(__x); > > + return _M_parent->_M_inner._M_emplace_deref(__outer); > > } > > > > - constexpr auto&& > > - _M_get_inner(const _OuterIter& __x) > > + constexpr auto& > > + _M_get_inner() > > { > > if constexpr (_S_ref_is_glvalue) > > - return *__x; > > + return __detail::__as_lvalue(*_M_get_outer()); > > else > > return *_M_parent->_M_inner; > > } > > @@ -7148,16 +7240,16 @@ namespace views::__adaptor > > if (std::get<0>(_M_inner_it) !=3D ranges::end(_M_parent->= _M_pattern)) > > break; > > > > - auto&& __inner =3D _M_update_inner(_M_outer_it); > > + auto&& __inner =3D _M_update_inner(); > > _M_inner_it.template emplace<1>(ranges::begin(__inner)); > > } > > else > > { > > - auto&& __inner =3D _M_get_inner(_M_outer_it); > > + auto&& __inner =3D _M_get_inner(); > > if (std::get<1>(_M_inner_it) !=3D ranges::end(__inner)) > > break; > > > > - if (++_M_outer_it =3D=3D ranges::end(_M_parent->_M_base)) > > + if (++_M_get_outer() =3D=3D ranges::end(_M_parent->_M_bas= e)) > > { > > if constexpr (_S_ref_is_glvalue) > > _M_inner_it.template emplace<0>(); > > @@ -7196,7 +7288,7 @@ namespace views::__adaptor > > iter_difference_t<_InnerIter>= , > > iter_difference_t<_PatternIte= r>>; > > > > - _Iterator() requires default_initializable<_OuterIter> =3D default= ; > > + _Iterator() =3D default; > > > > constexpr > > _Iterator(_Iterator __i) > > @@ -7306,7 +7398,7 @@ namespace views::__adaptor > > friend constexpr bool > > operator=3D=3D(const _Iterator& __x, const _Iterator& __y) > > requires _S_ref_is_glvalue > > - && equality_comparable<_OuterIter> && equality_comparable<_Inne= rIter> > > + && forward_range<_Base> && equality_comparable<_InnerIter> > > { return __x._M_outer_it =3D=3D __y._M_outer_it && __x._M_inner_it= =3D=3D__y._M_inner_it; } > > > > friend constexpr common_reference_t, > > @@ -7373,7 +7465,7 @@ namespace views::__adaptor > > iterator_t<__detail::__maybe_const_t<_Other= Const, _Vp>>> > > friend constexpr bool > > operator=3D=3D(const _Iterator<_OtherConst>& __x, const _Sentinel&= __y) > > - { return __x._M_outer_it =3D=3D __y._M_end; } > > + { return __x._M_get_outer() =3D=3D __y._M_end; } > > }; > > > > namespace views > > diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.cc b/li= bstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.cc > > new file mode 100644 > > index 00000000000..15d71b2faa9 > > --- /dev/null > > +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/p2770r0.cc > > @@ -0,0 +1,110 @@ > > +// { dg-options "-std=3Dgnu++20" } > > +// { dg-do run { target c++20 } } > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +namespace ranges =3D std::ranges; > > +namespace views =3D std::views; > > + > > +void > > +test01() > > +{ > > + // Test case from LWG 3698 > > + char const text[] =3D "Hello"; > > + std::regex regex{"[a-z]"}; > > + > > + auto lower > > + =3D ranges::subrange(std::cregex_iterator(ranges::begin(text), > > + ranges::end(text), > > + regex), > > + std::cregex_iterator{}) > > + | views::join > > + | views::transform([](auto const& sm) { > > + return std::string_view(sm.first, sm.second); > > + }); > > + > > + VERIFY( ranges::equal(lower, (std::string_view[]){"e", "l", "l", "o"= })); > > +} > > + > > +void > > +test02() > > +{ > > +#if __cpp_lib_ranges_join_with > > + // Analogous test case from LWG 3698 for join_with_view > > + char const text[] =3D "Hello"; > > + std::regex regex{"[a-z]"}; > > + > > + auto lower > > + =3D ranges::subrange(std::cregex_iterator(ranges::begin(text), > > + ranges::end(text), > > + regex), > > + std::cregex_iterator{}) > > + | views::join_with(views::empty>) > > + | views::transform([](auto const& sm) { > > + return std::string_view(sm.first, sm.second); > > + }); > > + > > + VERIFY( ranges::equal(lower, (std::string_view[]){"e", "l", "l", "o"= })); > > +#endif > > +} > > + > > +void > > +test03() > > +{ > > + // Test case from LWG 3700 > > + auto r =3D views::iota(0, 5) | views::split(1); > > + auto s =3D views::single(r); > > + auto j =3D s | views::join; > > + auto f =3D j.front(); > > +} > > + > > +void > > +test04() > > +{ > > +#if __cpp_lib_ranges_join_with > > + // Analogous test case from LWG 3700 for join_with_view > > + auto r =3D views::iota(0, 5) | views::split(1); > > + auto s =3D views::single(r); > > + auto j =3D s | views::join_with(views::empty>); > > + auto f =3D j.front(); > > +#endif > > +} > > + > > +void > > +test05() > > +{ > > + // Test case from LWG 3791 > > + std::vector> v =3D {{1}}; > > + auto r =3D v > > + | views::transform([](auto& x) -> auto&& { return std::move(x); }) > > + | views::join; > > + auto e =3D --r.end(); > > +} > > + > > +void > > +test06() > > +{ > > +#if __cpp_lib_ranges_join_with > > + // Analogous test case from LWG 3791 for join_with_view > > + std::vector> v =3D {{1}}; > > + auto r =3D v > > + | views::transform([](auto& x) -> auto&& { return std::move(x); }) > > + | views::join_with(views::empty); > > + auto e =3D --r.end(); > > +#endif > > +} > > + > > +int > > +main() > > +{ > > + test01(); > > + test02(); > > + test03(); > > + test04(); > > + test05(); > > + test06(); > > +} > > -- > > 2.40.0.335.g9857273be0 > > >