[libcxx-commits] [PATCH] D120637: [libc++][ranges] Implement ranges::minmax and ranges::minmax_element
Konstantin Varlamov via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Mar 8 21:29:16 PST 2022
var-const requested changes to this revision.
var-const added a comment.
This revision now requires changes to proceed.
@philnik Please update `RangesAlgorithms.csv` as well. Thanks!
================
Comment at: libcxx/include/__algorithm/ranges_minmax.h:62
+ auto __less = [&](auto&& __it1, auto&& __it2) -> bool {
+ return std::invoke(__comp, std::invoke(__proj, __it1), std::invoke(__proj, __it2));
+ };
----------------
Do `__it1` and `__it2` need to be forwarded, given that they are forwarding references?
================
Comment at: libcxx/include/__algorithm/ranges_minmax.h:70
+ if (__less(*__first, __result.min))
+ __result.min = *__first;
+ else
----------------
I have a concern similar to `mismatch` -- this could be a lot of copying in the worst case. Would it be worthwhile to have different implementations of the algorithm for `input_range` and `forward_range`?
================
Comment at: libcxx/include/__algorithm/ranges_minmax.h:76-81
+ if (++__first == __last) {
+ if (__less(__i, __result.min))
+ __result.min = __i;
+ else if (!__less(__i, __result.max))
+ __result.max = __i;
+ return __result;
----------------
Same optional suggestion re. using lambdas as in `minmax_element`.
================
Comment at: libcxx/include/__algorithm/ranges_minmax_element.h:57
+ if (++__first == __last) {
+ if (__less(__i, __result.min))
+ __result.min = __i;
----------------
Very optional: I found several nested conditions with similar comparisons a little hard to keep track off. Consider streamlining some of this flow using a helper -- maybe something like:
```
auto __less = [&](_Ip& __it1, _Ip& __it2) -> bool {
return std::invoke(__comp, std::invoke(__proj, *__it1), std::invoke(__proj, *__it2));
};
auto __maybe_update_min = [&__result](_Ip& __it) {
if (__less(__it, __result.min)) {
__result.min = __it;
}
};
auto __maybe_update_max = [&__result](_Ip& __it) {
if (!__less(__it, __result.max)) {
__result.max = __it;
}
};
ranges::minmax_result<_Ip> __result {__first, __first};
if (__first == __last || ++__first == __last)
return __result;
if (__less(__first, __result.min))
__result.min = __first;
else
__result.max = __first;
while (++__first != __last) {
_Ip __i = __first;
if (++__first == __last) {
__maybe_update_min(__i);
__maybe_update_max(__i);
return __result;
}
if (__less(__first, __i)) {
__maybe_update_min(__first);
__maybe_update_max(__i);
} else {
__maybe_update_min(__i);
__maybe_update_max(__first);
}
}
```
================
Comment at: libcxx/include/__algorithm/ranges_minmax_element.h:84
+ ranges::minmax_result<_Ip> operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const {
+ return __go(__first, __last, __comp, __proj);
+ }
----------------
Would it make sense to move `__first` and maybe `__last`?
================
Comment at: libcxx/include/__algorithm/ranges_minmax_element.h:91
+ ranges::minmax_result<borrowed_iterator_t<_Rp>> operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
+ return __go(ranges::begin(__r), ranges::end(__r), __comp, __proj);
+ }
----------------
Question: does `__r` need to be forwarded, perhaps?
================
Comment at: libcxx/include/algorithm:766
#include <__algorithm/ranges_min_element.h>
+#include <__algorithm/ranges_minmax.h>
+#include <__algorithm/ranges_minmax_element.h>
----------------
You probably also need to update the synopsis.
================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.minmax.pass.cpp:28
+#include <cassert>
+#include <random>
+#include <ranges>
----------------
`<random>` is unused, right? (here and in the other test file)
================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.minmax.pass.cpp:31
+
+#include "test_macros.h"
+#include "test_iterators.h"
----------------
Is `"test_macros.h"` used?
================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.minmax.pass.cpp:195
+
+int main(int, char**) {
+ test();
----------------
I'd add a few test cases to make sure the algorithm works correctly:
- make sure to test both an even- and an odd-length range (since the algorithm effectively iterates in steps of two);
- empty range;
- single-element range;
- sorted range (both ascending and descending);
- all elements compare equal (this should also test that "Returns `X{x, y}`, where `x` is a copy of the //leftmost// element with the smallest value and `y` a copy of the //rightmost// element with the largest value in the input range").
This applies to `minmax_element` as well.
================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.minmax.pass.cpp:199
+
+ {
+ std::shared_ptr<int> a[] = { std::make_shared<int>(42) };
----------------
Can you add a comment explaining the main intention of this test case? It seems to be to test `move_iterator` behavior, but then it uses `shared_ptr` as well.
================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.minmax_element.pass.cpp:41
+
+static_assert(HasMinMaxElement<int (&)[10]>);
+static_assert(HasMinMaxElement<int (&&)[10]>);
----------------
Similar to other patches: I think there needs to be a SFINAE test for every constraint (in both test files).
================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.minmax_element.pass.cpp:216
+
+constexpr bool test() {
+
----------------
Nit: seems like an extra blank line.
================
Comment at: libcxx/test/std/algorithms/alg.sorting/alg.min.max/ranges.minmax_element.pass.cpp:220
+ test<bidirectional_iterator<const int*>>();
+ test<random_access_iterator<const int*>>();
+ test<const int*>();
----------------
Optional: also test with a contiguous iterator for good measure (echoing Arthur's comment from another patch)?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D120637/new/
https://reviews.llvm.org/D120637
More information about the libcxx-commits
mailing list