[PATCH] libstdc++: Implement P2328 changes to join_view

Jonathan Wakely jwakely@redhat.com
Fri Apr 30 16:59:33 GMT 2021


On 30/04/21 10:38 -0400, Patrick Palka via Libstdc++ wrote:
>This implements the wording changes of "join_view should join all views
>of ranges".
>
>Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

OK, thanks.

>libstdc++-v3/ChangeLog:
>
>	* include/std/ranges (__detail::__non_propating_cache): Define
>	as per P2328.
>	(join_view): Remove constraints on the value and reference types
>	of the wrapped iterator type as per P2328.
>	(join_view::_Iterator::_M_satisfy): Adjust as per P2328.
>	(join_view::_Iterator::operator++): Likewise.
>	(join_view::_M_inner): Use __non_propating_cache as per P2328.
>	Remove now-redundant use of __maybe_present_t.
>	* testsuite/std/ranges/adaptors/join.cc (test10): New test.
>---
> libstdc++-v3/include/std/ranges               | 70 ++++++++++++++++---
> .../testsuite/std/ranges/adaptors/join.cc     | 12 ++++
> 2 files changed, 71 insertions(+), 11 deletions(-)
>
>diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
>index 4be643baeaa..b43f9b337a4 100644
>--- a/libstdc++-v3/include/std/ranges
>+++ b/libstdc++-v3/include/std/ranges
>@@ -2258,10 +2258,61 @@ namespace views::__adaptor
>     inline constexpr _DropWhile drop_while;
>   } // namespace views
>
>+  namespace __detail
>+  {
>+    template<typename _Tp>
>+      struct __non_propagating_cache
>+      {
>+	// When _Tp is not an object type (e.g. is a reference type), we make
>+	// __non_propagating_cache<_Tp> empty rather than an invalid type so
>+	// that users can easily conditionally declare data members with this
>+	// type (such as join_view::_M_inner).
>+      };
>+
>+    template<typename _Tp>
>+      requires is_object_v<_Tp>
>+      struct __non_propagating_cache<_Tp> : private optional<_Tp>
>+      {
>+	__non_propagating_cache() = default;
>+
>+	constexpr
>+	__non_propagating_cache(const __non_propagating_cache&) noexcept
>+	{ }
>+
>+	constexpr
>+	__non_propagating_cache(__non_propagating_cache&& __other) noexcept
>+	{ __other.reset(); }
>+
>+	constexpr __non_propagating_cache&
>+	operator=(const __non_propagating_cache& __other) noexcept
>+	{
>+	  if (std::__addressof(__other) != this)
>+	    this->reset();
>+	  return *this;
>+	}
>+
>+	constexpr __non_propagating_cache&
>+	operator=(__non_propagating_cache&& __other) noexcept
>+	{
>+	  this->reset();
>+	  __other.reset();
>+	  return *this;
>+	}
>+
>+	using optional<_Tp>::operator*;
>+
>+	template<typename _Iter>
>+	  _Tp&
>+	  _M_emplace_deref(const _Iter& __i)
>+	  {
>+	    this->reset();
>+	    return this->emplace(*__i);
>+	  }
>+      };
>+  }
>+
>   template<input_range _Vp>
>     requires view<_Vp> && input_range<range_reference_t<_Vp>>
>-      && (is_reference_v<range_reference_t<_Vp>>
>-	  || view<range_value_t<_Vp>>)
>     class join_view : public view_interface<join_view<_Vp>>
>     {
>     private:
>@@ -2327,17 +2378,16 @@ namespace views::__adaptor
> 	  constexpr void
> 	  _M_satisfy()
> 	  {
>-	    auto __update_inner = [this] (range_reference_t<_Base> __x) -> auto&
>-	    {
>+	    auto __update_inner = [this] (const iterator_t<_Base>& __x) -> auto&& {
> 	      if constexpr (_S_ref_is_glvalue)
>-		return __x;
>+		return *__x;
> 	      else
>-		return (_M_parent->_M_inner = views::all(std::move(__x)));
>+		return _M_parent->_M_inner._M_emplace_deref(__x);
> 	    };
>
> 	    for (; _M_outer != ranges::end(_M_parent->_M_base); ++_M_outer)
> 	      {
>-		auto& __inner = __update_inner(*_M_outer);
>+		auto&& __inner = __update_inner(_M_outer);
> 		_M_inner = ranges::begin(__inner);
> 		if (_M_inner != ranges::end(__inner))
> 		  return;
>@@ -2413,7 +2463,7 @@ namespace views::__adaptor
> 	      if constexpr (_S_ref_is_glvalue)
> 		return *_M_outer;
> 	      else
>-		return _M_parent->_M_inner;
>+		return *_M_parent->_M_inner;
> 	    }();
> 	    if (++_M_inner == ranges::end(__inner_range))
> 	      {
>@@ -2524,10 +2574,8 @@ namespace views::__adaptor
> 	  friend _Sentinel<!_Const>;
> 	};
>
>-      // XXX: _M_inner is "present only when !is_reference_v<_InnerRange>"
>       [[no_unique_address]]
>-	__detail::__maybe_present_t<!is_reference_v<_InnerRange>,
>-				    views::all_t<_InnerRange>> _M_inner;
>+	__detail::__non_propagating_cache<remove_cv_t<_InnerRange>> _M_inner;
>       _Vp _M_base = _Vp();
>
>     public:
>diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
>index fb06a7698af..6890b105eab 100644
>--- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
>+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc
>@@ -160,6 +160,17 @@ test09()
>   static_assert(!requires { 0 | join; });
> }
>
>+void
>+test10()
>+{
>+// Verify P2328 changes.
>+  int r[] = {1, 2, 3};
>+  auto v = r
>+    | views::transform([] (int n) { return std::vector{{n, -n}}; })
>+    | views::join;
>+  VERIFY( ranges::equal(v, (int[]){1, -1, 2, -2, 3, -3}) );
>+}
>+
> int
> main()
> {
>@@ -172,4 +183,5 @@ main()
>   test07();
>   test08();
>   test09();
>+  test10();
> }
>-- 
>2.31.1.362.g311531c9de
>



More information about the Libstdc++ mailing list