Re: [PATCH 2/2] libstdc++: Implement ranges::adjacent_transform_view from P2321R2

2022-09-01 Thread Jonathan Wakely via Gcc-patches
On Tue, 30 Aug 2022 at 18:14, Patrick Palka via Libstdc++
 wrote:
>
> Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

OK


>
> libstdc++-v3/ChangeLog:
>
> * include/std/ranges (__detail::__unarize): Define.
> (adjacent_view::_Iterator): Befriend adjacent_transform_view.
> (adjacent_transform_view): Define.
> (adjacent_transform_view::_Iterator): Define.
> (adjacent_transform_view::_Sentinel): Define.
> (views::__detail::__can_adjacent_transform_view): Define.
> (views::_AdjacentTransform): Define.
> (views::adjacent_transform): Define.
> (views::pairwise): Define.
> * testsuite/std/ranges/adaptors/adjacent_transform/1.cc: New test.
> ---
>  libstdc++-v3/include/std/ranges   | 342 ++
>  .../ranges/adaptors/adjacent_transform/1.cc   | 106 ++
>  2 files changed, 448 insertions(+)
>  create mode 100644 
> libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc
>
> diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
> index 4fb879a088c..3a7f0545030 100644
> --- a/libstdc++-v3/include/std/ranges
> +++ b/libstdc++-v3/include/std/ranges
> @@ -5158,6 +5158,20 @@ namespace views::__adaptor
>  // Yields tuple<_Tp, ..., _Tp> with _Nm elements.
>  template
>using __repeated_tuple = 
> decltype(std::tuple_cat(std::declval>()));
> +
> +// For a functor F that takes N arguments, the expression 
> declval<__unarize>(x)
> +// is equivalent to declval(x, ..., x).
> +template
> +  struct __unarize
> +  {
> +   template
> + static invoke_result_t<_Fp, _Ts...>
> + __tuple_apply(const tuple<_Ts...>&); // not defined
> +
> +   template
> + decltype(__tuple_apply(std::declval<__repeated_tuple<_Tp, _Nm>>()))
> + operator()(_Tp&&); // not defined
> +  };
>}
>
>template
> @@ -5205,6 +5219,13 @@ namespace views::__adaptor
>
>  friend class adjacent_view;
>
> +template
> +  requires view<_Wp> && (_Mm > 0) && is_object_v<_Fp>
> +&& regular_invocable<__detail::__unarize<_Fp&, _Mm>, 
> range_reference_t<_Wp>>
> +&& 
> std::__detail::__can_reference,
> +
> range_reference_t<_Wp>>>
> +  friend class adjacent_transform_view;
> +
>public:
>  using iterator_category = input_iterator_tag;
>  using iterator_concept = decltype(_S_iter_concept());
> @@ -5440,6 +5461,327 @@ namespace views::__adaptor
>
>  inline constexpr auto pairwise = adjacent<2>;
>}
> +
> +  template
> +   requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
> + && regular_invocable<__detail::__unarize<_Fp&, _Nm>, 
> range_reference_t<_Vp>>
> + && 
> std::__detail::__can_reference,
> +  
> range_reference_t<_Vp>>>
> +  class adjacent_transform_view : public 
> view_interface>
> +  {
> +[[no_unique_address]] __detail::__box<_Fp> _M_fun;
> +adjacent_view<_Vp, _Nm> _M_inner;
> +
> +using _InnerView = adjacent_view<_Vp, _Nm>;
> +
> +template
> +  using _InnerIter = iterator_t<__detail::__maybe_const_t<_Const, 
> _InnerView>>;
> +
> +template
> +  using _InnerSent = sentinel_t<__detail::__maybe_const_t<_Const, 
> _InnerView>>;
> +
> +template class _Iterator;
> +template class _Sentinel;
> +
> +  public:
> +adjacent_transform_view() = default;
> +
> +constexpr explicit
> +adjacent_transform_view(_Vp __base, _Fp __fun)
> +  : _M_fun(std::move(__fun)), _M_inner(std::move(__base))
> +{ }
> +
> +constexpr auto
> +begin()
> +{ return _Iterator(*this, _M_inner.begin()); }
> +
> +constexpr auto
> +begin() const
> +  requires range
> +   && regular_invocable<__detail::__unarize,
> +range_reference_t>
> +{ return _Iterator(*this, _M_inner.begin()); }
> +
> +constexpr auto
> +end()
> +{
> +  if constexpr (common_range<_InnerView>)
> +return _Iterator(*this, _M_inner.end());
> +  else
> +return _Sentinel(_M_inner.end());
> +}
> +
> +constexpr auto
> +end() const
> +  requires range
> +   && regular_invocable<__detail::__unarize,
> +range_reference_t>
> +{
> +  if constexpr (common_range)
> +return _Iterator(*this, _M_inner.end());
> +  else
> +return _Sentinel(_M_inner.end());
> +}
> +
> +constexpr auto
> +size() requires sized_range<_InnerView>
> +{ return _M_inner.size(); }
> +
> +constexpr auto
> +size() const requires sized_range
> +{ return _M_inner.size(); }
> +  };
> +
> +  template
> +   requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
> + && regular_invocable<__detail::__unarize<_Fp&, _Nm>, 
> range_reference_t<_Vp>>
> + && 
> std::__detail::__can_reference,
> +

[PATCH 2/2] libstdc++: Implement ranges::adjacent_transform_view from P2321R2

2022-08-30 Thread Patrick Palka via Gcc-patches
Tested on x86_64-pc-linux-gnu, does this look OK for trunk?

libstdc++-v3/ChangeLog:

* include/std/ranges (__detail::__unarize): Define.
(adjacent_view::_Iterator): Befriend adjacent_transform_view.
(adjacent_transform_view): Define.
(adjacent_transform_view::_Iterator): Define.
(adjacent_transform_view::_Sentinel): Define.
(views::__detail::__can_adjacent_transform_view): Define.
(views::_AdjacentTransform): Define.
(views::adjacent_transform): Define.
(views::pairwise): Define.
* testsuite/std/ranges/adaptors/adjacent_transform/1.cc: New test.
---
 libstdc++-v3/include/std/ranges   | 342 ++
 .../ranges/adaptors/adjacent_transform/1.cc   | 106 ++
 2 files changed, 448 insertions(+)
 create mode 100644 
libstdc++-v3/testsuite/std/ranges/adaptors/adjacent_transform/1.cc

diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 4fb879a088c..3a7f0545030 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -5158,6 +5158,20 @@ namespace views::__adaptor
 // Yields tuple<_Tp, ..., _Tp> with _Nm elements.
 template
   using __repeated_tuple = decltype(std::tuple_cat(std::declval>()));
+
+// For a functor F that takes N arguments, the expression 
declval<__unarize>(x)
+// is equivalent to declval(x, ..., x).
+template
+  struct __unarize
+  {
+   template
+ static invoke_result_t<_Fp, _Ts...>
+ __tuple_apply(const tuple<_Ts...>&); // not defined
+
+   template
+ decltype(__tuple_apply(std::declval<__repeated_tuple<_Tp, _Nm>>()))
+ operator()(_Tp&&); // not defined
+  };
   }
 
   template
@@ -5205,6 +5219,13 @@ namespace views::__adaptor
 
 friend class adjacent_view;
 
+template
+  requires view<_Wp> && (_Mm > 0) && is_object_v<_Fp>
+&& regular_invocable<__detail::__unarize<_Fp&, _Mm>, 
range_reference_t<_Wp>>
+&& 
std::__detail::__can_reference,
+
range_reference_t<_Wp>>>
+  friend class adjacent_transform_view;
+
   public:
 using iterator_category = input_iterator_tag;
 using iterator_concept = decltype(_S_iter_concept());
@@ -5440,6 +5461,327 @@ namespace views::__adaptor
 
 inline constexpr auto pairwise = adjacent<2>;
   }
+
+  template
+   requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
+ && regular_invocable<__detail::__unarize<_Fp&, _Nm>, 
range_reference_t<_Vp>>
+ && 
std::__detail::__can_reference,
+  range_reference_t<_Vp>>>
+  class adjacent_transform_view : public 
view_interface>
+  {
+[[no_unique_address]] __detail::__box<_Fp> _M_fun;
+adjacent_view<_Vp, _Nm> _M_inner;
+
+using _InnerView = adjacent_view<_Vp, _Nm>;
+
+template
+  using _InnerIter = iterator_t<__detail::__maybe_const_t<_Const, 
_InnerView>>;
+
+template
+  using _InnerSent = sentinel_t<__detail::__maybe_const_t<_Const, 
_InnerView>>;
+
+template class _Iterator;
+template class _Sentinel;
+
+  public:
+adjacent_transform_view() = default;
+
+constexpr explicit
+adjacent_transform_view(_Vp __base, _Fp __fun)
+  : _M_fun(std::move(__fun)), _M_inner(std::move(__base))
+{ }
+
+constexpr auto
+begin()
+{ return _Iterator(*this, _M_inner.begin()); }
+
+constexpr auto
+begin() const
+  requires range
+   && regular_invocable<__detail::__unarize,
+range_reference_t>
+{ return _Iterator(*this, _M_inner.begin()); }
+
+constexpr auto
+end()
+{
+  if constexpr (common_range<_InnerView>)
+return _Iterator(*this, _M_inner.end());
+  else
+return _Sentinel(_M_inner.end());
+}
+
+constexpr auto
+end() const
+  requires range
+   && regular_invocable<__detail::__unarize,
+range_reference_t>
+{
+  if constexpr (common_range)
+return _Iterator(*this, _M_inner.end());
+  else
+return _Sentinel(_M_inner.end());
+}
+
+constexpr auto
+size() requires sized_range<_InnerView>
+{ return _M_inner.size(); }
+
+constexpr auto
+size() const requires sized_range
+{ return _M_inner.size(); }
+  };
+
+  template
+   requires view<_Vp> && (_Nm > 0) && is_object_v<_Fp>
+ && regular_invocable<__detail::__unarize<_Fp&, _Nm>, 
range_reference_t<_Vp>>
+ && 
std::__detail::__can_reference,
+  range_reference_t<_Vp>>>
+  template
+  class adjacent_transform_view<_Vp, _Fp, _Nm>::_Iterator
+  {
+using _Parent = __detail::__maybe_const_t<_Const, adjacent_transform_view>;
+using _Base = __detail::__maybe_const_t<_Const, _Vp>;
+
+_Parent* _M_parent = nullptr;
+_InnerIter<_Const> _M_inner;
+
+constexpr
+_Iterator(_Parent& __parent,