[libcxx-commits] [PATCH] D121248: [libc++][ranges] Implement ranges::find{, _if, _if_not}

Louis Dionne via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Tue Mar 8 14:12:00 PST 2022


ldionne requested changes to this revision.
ldionne added inline comments.
This revision now requires changes to proceed.


================
Comment at: libcxx/docs/Status/RangesAlgorithms.csv:5-7
+Search,find,Nikolas Klauser,n/a, Complete
+Search,find_if,Nikolas Klauser,n/a, Complete
+Search,find_if_not,Nikolas Klauser,n/a, Complete
----------------



================
Comment at: libcxx/include/__algorithm/ranges_find.h:48
+    auto __pred = [&](const auto& __e) { return __value == __e; };
+    return __find_if::__fn::__go(ranges::begin(__r), ranges::end(__r), __pred, __proj);
+  }
----------------
I don't like that we are reaching into `__find_if::__fn` here. Instead, we should have something like this in `find_if.h`:

```
template <class _Ip, class _Sp, class _Pred, class _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr
_Ip __find_if_impl(_Ip __first, _Sp __last, _Pred& __pred, _Proj& __proj) {
    for (; __first != __last; ++__first) {
        if (std::invoke(__pred, std::invoke(__proj, *__first)))
            break;
    }
    return __first;
}
```

This provides a slightly (but not much) cleaner interface between the two headers, at least. TBH, I would support implementing this as `ranges::find_if(ranges::begin(__r), ranges::end(__r), __pred, std::move(__proj));` (and similarly for the iterator/sentinel version), even though I understand this will lead to additional moves over the current approach. In practice, I don't think this is likely to matter, since iterators should be cheap to copy (and hence to move), and same for projections.

So, I have a slight preference for implementation simplicity despite it causing additional moves, but if you want to keep it as-is, please use a namespace scope function at least (and add a libc++ specific test for the no-move behavior).


================
Comment at: libcxx/include/algorithm:48-71
+  template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*>
+    constexpr I find(I first, S last, const T& value, Proj proj = {});              // since C++20
+  template<input_range R, class T, class Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<R>, Proj>, const T*>
+    constexpr borrowed_iterator_t<R>
+      find(R&& r, const T& value, Proj proj = {});                                  // since C++20
----------------
This looks weirdly formatted -- please try to indent the return types consistently, etc.


================
Comment at: libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp:54-58
+    {
+      int a[] = {1, 2, 3, 4};
+      auto ret = std::ranges::find(a, a + 4, a + 3, [](int& i){ return &i; });
+      assert(ret == a + 3);
+    }
----------------
These projection tests are really clever. Something like this would be easier to read:

```
struct Point { int x; int y; };
Point points[] = {....};
auto ret = std::ranges::find(points, points + 4, 3, [](Point const& p) { return p.x; });
assert(ret == ....);
```



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D121248



More information about the libcxx-commits mailing list