[libcxx-commits] [PATCH] D122173: [libc++][ranges] Implement ranges::transform

Nikolas Klauser via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Sun Mar 27 16:27:51 PDT 2022


philnik added inline comments.


================
Comment at: libcxx/include/__algorithm/ranges_transform.h:38
+
+template <class _I1, class _I2, class _O1>
+using binary_transform_result = in_in_out_result<_I1, _I2, _O1>;
----------------
Mordante wrote:
> For consistency I think using `_Op` like in the unary type would be better.
I use `_O1` for consistency with `in_in_out_result` here.


================
Comment at: libcxx/include/__algorithm/ranges_transform.h:44
+
+  template <class _InputIterator, class _Sentinel,
+            class _OutputIterator,
----------------
Mordante wrote:
> var-const wrote:
> > Mordante wrote:
> > > Is there a reason why the naming of the types and variables differs from the other ranges algorithms?
> > > For example `ranges_find.h` uses 
> > > ```
> > >   template <input_iterator _Ip, sentinel_for<_Ip> _Sp, class _Tp, class _Proj = identity>
> > >     requires indirect_binary_predicate<ranges::equal_to, projected<_Ip, _Proj>, const _Tp*>
> > >   _LIBCPP_HIDE_FROM_ABI constexpr
> > >   _Ip operator()(_Ip __first, _Sp __last, const _Tp& __value, _Proj __proj = {}) const {
> > >     auto __pred = [&](auto&& __e) { return std::forward<decltype(__e)>(__e) == __value; };
> > >     return ranges::__find_if_impl(std::move(__first), std::move(__last), __pred, __proj);
> > >   }
> > > 
> > > ```
> > > I think it improves our codebase when we keep these names consistent.
> > > I'm also not to fond of `_InputIterator` and `_OutputIterator`, they are used in the non-range algorithms and there they use the LegacyIterators. So I like that the range based algorithms use a different naming scheme,
> > FWIW, I'm mildly in favor of using longer names (though I can see the argument for terser names given how verbose the template parameters are in these functions). I think range algorithms (both committed and in flight) aren't currently consistent in this regard.
> I'm not against longer names in general, but when I read `_InputIterator` I expect a `LegacyIterator` in the `<algorithm>` header. I also would like consistent naming, which can be achieved in two ways. Use the old names in new code or change the old code to use new names.There's a thread on Discord so I think it's easier to discuss it there.
This has been discussed on discord.


================
Comment at: libcxx/include/algorithm:104
+    constexpr ranges::unary_transform_result<I, O>
+      transform(I first1, S last1, O result, F op, Proj proj = {});                 // since C++20
+  template<input_range R, weakly_incrementable O, copy_constructible F,
----------------
var-const wrote:
> Nit: `s/first1/first/` (same for `last1`).
This is consistent with the standard synopsis.


================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.pass.cpp:78-84
+        int a[] = {1, 2, 3, 4, 5};
+        int b[5];
+        std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =
+          std::ranges::transform(In1(a), Sent1(In1(a + 5)), Out(b), [](int i) { return i * 2; });
+        assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));
+        assert(base(ret.in) == a + 5);
+        assert(base(ret.out) == b + 5);
----------------
var-const wrote:
> Optional: do you think it would be worthwhile to try reducing duplication here? Perhaps something like:
> 
> ```
> template <class In1, class Out>
> struct Result {
>   std::ranges::in_out_result<In1, Out> ret;
>   Out* out = nullptr;
> };
> 
> // ...
> 
> int a[] = {1, 2, 3, 4, 5};
> int b1[5], b2[5];
> 
> std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret_iter =
>     std::ranges::transform(In1(a), Sent1(In1(a + 5)), Out(b1), [](int i) { return i * 2; });
> auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
> std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =
>     std::ranges::transform(range, Out(b2), [](int i) { return i * 2; });
> 
> for (const auto& result : {Result{ret_iter, b1}, Result{ret_range, b2}}) {
>   assert((std::to_array(result.out) == std::array{2, 4, 6, 8, 10}));
>   assert(base(result.ret.in) == a + 5);
>   assert(base(result.ret.out) == b + 5);
> }
> ```
This looks way more complicated to make it a bit shorter to me.


================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.pass.cpp:209-212
+  }
+
+
+  { // first range one element
----------------
var-const wrote:
> Nit: one extra blank line.
I think it looks nicer without a blank line here.


================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.transform/ranges.transform.pass.cpp:330
+      std::array<int, 5> b;
+      std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =
+        std::ranges::transform(std::array{1, 2, 3, 5, 4}, b.data(), [](int i) { return i * i; });
----------------
Mordante wrote:
> Should these test also use `decltype(auto)`?
The `decltype(auto)` was specifically because `ranges::min` and friends return `const T&`. But I can also add a `decltype` here if you want.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122173/new/

https://reviews.llvm.org/D122173



More information about the libcxx-commits mailing list