[libcxx-commits] [PATCH] D129796: [libc++][ranges] implement `std::ranges::equal_range`

Konstantin Varlamov via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jul 17 01:53:19 PDT 2022


var-const requested changes to this revision.
var-const added a comment.
This revision now requires changes to proceed.

Thanks!



================
Comment at: libcxx/include/__algorithm/equal_range.h:41
+    _Iter __mid     = _IterOps<_AlgPolicy>::next(__first, __half_len);
+    if (std::__invoke(__comp, std::__invoke(__proj, *__mid), __value)) {
+      __first = ++__mid;
----------------
Why not use `__make_projected`? Wouldn't this cause a visible change in behavior for the classic algorithm (now accepting a pointer-to-member as the comparator)? (alternatively, you could do a `static_assert(__is_callable)` like in e.g. `lower_bound`).


================
Comment at: libcxx/include/__algorithm/equal_range.h:50
+      return pair<_Iter, _Iter>(
+          std::__lower_bound_impl<_AlgPolicy>(__first, __mid, __value, __comp, __proj),
+          std::__upper_bound<_AlgPolicy, _Compare>(++__mp1, __end, __value, __comp, __proj));
----------------
Does this need to be forwarded, or not?


================
Comment at: libcxx/include/__algorithm/equal_range.h:50
+      return pair<_Iter, _Iter>(
+          std::__lower_bound_impl<_AlgPolicy>(__first, __mid, __value, __comp, __proj),
+          std::__upper_bound<_AlgPolicy, _Compare>(++__mp1, __end, __value, __comp, __proj));
----------------
var-const wrote:
> Does this need to be forwarded, or not?
You probably need to pass `_Compare` explicitly as well, I'm not sure why it wasn't done before (`_Compare` is normally a reference, so type deduction would decay it to a value).


================
Comment at: libcxx/include/__algorithm/equal_range.h:54
+  }
+  return pair<_Iter, _Iter>(__first, __first);
 }
----------------
Nit: `make_pair`?


================
Comment at: libcxx/include/__algorithm/equal_range.h:62
+  return std::__equal_range<_ClassicAlgPolicy, _Comp_ref>(
+      std::move(__first), std::move(__last), __value, static_cast<_Comp_ref>(__comp), std::__identity());
 }
----------------
Why is this cast necessary, and does it work in debug mode? (when `_Comp_ref` is a struct)


================
Comment at: libcxx/include/__algorithm/upper_bound.h:48
+upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) {
+  return std::__upper_bound<_ClassicAlgPolicy, _Compare&>(__first, __last, __value, __comp, std::__identity());
 }
----------------
Move?


================
Comment at: libcxx/include/__algorithm/upper_bound.h:57
 template <class _ForwardIterator, class _Tp>
-_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
----------------
Please don't remove the `inline`s -- this could increase binary size. We plan to do some investigation and potentially make a dedicated patch to clean up these unwanted `inline`s.


================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/equal.range/ranges_equal_range.pass.cpp:40
+    requires(Iter&& iter, Sent&& sent, const T& value, Comp&& comp, Proj&& proj) {
+      std::ranges::equal_range(std::forward<Iter>(iter), std::forward<Sent>(sent), value, comp, proj);
+    };
----------------
Do these have to be forwarded as well?


================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/equal.range/ranges_equal_range.pass.cpp:55
+template <class R, class T, class Proj = std::identity, class Comp = std::ranges::less>
+concept HasEqualRangeRange =
+    requires(R&& r, const T& value, Comp&& comp, Proj&& proj) {
----------------
Nit: I know it's a pattern, but perhaps we could rename this? `RangeRange` looks a little awkward.


================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/equal.range/ranges_equal_range.pass.cpp:71
+
+template <class InIter, std::size_t N1>
+constexpr void testEqualRangeImpl(std::array<int, N1>& in, int value, std::ranges::subrange<int*> expected) {
----------------
Nit: `s/N1/N/`.


================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/equal.range/ranges_equal_range.pass.cpp:96
+constexpr void testImpl() {
+  // no match and the searched value is in the middle
+  {
----------------
Nit: consider `s/is in the middle/would be in the middle/`.


================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/equal.range/ranges_equal_range.pass.cpp:120
+
+  // exact one match
+  {
----------------
Ultranit: `s/exact/exactly/`.


================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/equal.range/ranges_equal_range.pass.cpp:164
+    int value = 6;
+    [[maybe_unused]] std::same_as<std::ranges::dangling> decltype(auto) result =
+        std::ranges::equal_range(NonBorrowedRange<InIter>{in.data(), in.size()}, value);
----------------
This can be omitted -- I'll merge the `robust_against_dangling` patch very soon.


================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.binary.search/equal.range/ranges_equal_range.pass.cpp:195
+    {
+      auto result = std::ranges::equal_range(in, value, [](const Data& x, const Data& y) { return x.data < y.data; });
+
----------------
Optional: share this comparator across the two test cases?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D129796



More information about the libcxx-commits mailing list