[libcxx-commits] [PATCH] D116303: [libc++][ranges] Implement std::ranges::swap_ranges()
Arthur O'Dwyer via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Dec 28 16:16:48 PST 2021
Quuxplusone requested changes to this revision.
Quuxplusone added a subscriber: jloser.
Quuxplusone added a comment.
This revision now requires changes to proceed.
The code looks pretty solid to me (although I am still requesting to reorganize it). The tests need more fleshing out.
Part of the reason for this PR is to experiment and see whether we want {`__algorithm/in_in_result.h`, etc} or {`__algorithm/results.h`}. I would say that AFAICT it provides no interesting evidence //for// either option, but it's definitely not evidence //against// my hypothesis that {`__algorithm/in_in_result.h`, etc} is the right choice. :) The use of `in_in_result.h` here feels pretty natural and self-documenting.
================
Comment at: libcxx/include/__algorithm/swap_ranges.h:12-19
+#include <__algorithm/in_in_result.h>
#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iter_swap.h>
+#include <__ranges/concepts.h>
+#include <__ranges/dangling.h>
#include <__utility/swap.h>
----------------
The includes needed by `std::swap_ranges` and `std::ranges::swap_ranges` practically don't overlap at all, nor are they ever used together, nor is there any circular dependency between them. Therefore (and for other pre-existing prejudices about code organization ;)) I think `ranges::swap_ranges` should be moved into a new file `__algorithm/ranges_swap_ranges.h`.
================
Comment at: libcxx/include/__algorithm/swap_ranges.h:22
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
+# pragma GCC system_header
#endif
----------------
Please leave the spacing here consistent with every other header file. (I know, clang-format strikes again; but we have //hundreds// of header files that use the old spacing, and we shouldn't change them one at a time (or, IMHO, at all).)
================
Comment at: libcxx/include/__algorithm/swap_ranges.h:46-47
+ requires indirectly_swappable<_I1, _I2>
+ constexpr ranges::swap_ranges_result<_I1, _I2> operator()(_I1 __first1, _S1 __last1,
+ _I2 __first2, _S2 __last2) const
+ {
----------------
================
Comment at: libcxx/include/__algorithm/swap_ranges.h:49-50
+ {
+ while (__first1 != __last1 &&
+ __first2 != __last2)
+ {
----------------
================
Comment at: libcxx/include/__algorithm/swap_ranges.h:54
+ ++__first1;
+ ++__first2;
+ }
----------------
================
Comment at: libcxx/include/algorithm:662-669
+#include <__bits> // __libcpp_clz
#include <__config>
#include <__debug>
-#include <__bits> // __libcpp_clz
#include <cstddef>
#include <cstring>
#include <functional>
#include <initializer_list>
----------------
These changes LGTM, and also IIUC you should remove the comment on line 673 as well. But please make these changes in a separate trivial PR (which I'll "LGTM" as soon as I see it).
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp:75-76
+
+ auto r = std::ranges::swap_ranges(r1, r2);
+ ASSERT_SAME_TYPE(decltype(r), std::ranges::in_in_result<std::ranges::iterator_t<Range>, std::ranges::iterator_t<Range>>);
+ assert(r.in1 == std::ranges::end(r1));
----------------
I suspect that in the process of adding all the below-requested tests, you'll realize that //either// the templated `test2` should go away entirely, //or// it needs a few more template parameters. Whatever happens, I'd prefer to stay away from circular-looking assertions like this, where we depend on metaprogramming to tell us the answer to some other metaprogramming. Ideally, the tests would be as simple and self-evident as possible, e.g.
```
{
std::list<int> r1 = {1, 2, 3};
std::vector<int> r2 = {4, 5, 6};
using It1 = std::list<int>::iterator;
using It2 = std::vector<int>::iterator;
std::same_as<std::ranges::in_in_result<It1, It2>> auto r =
std::ranges::swap_ranges(r1, r2);
// Or: auto r = std::ranges::swap_ranges(r1, r2);
// ASSERT_SAME_TYPE(decltype(r), std::ranges::in_in_result<It1, It2>);
assert(r.in1 == r1.end());
assert(r.in2 == r2.end());
assert((r1 == std::list<int>{4, 5, 6}));
assert((r2 == std::vector<int>{1, 2, 3}));
}
```
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp:95-101
+int main(int, char**) {
+ tests1();
+ tests2();
+ static_assert(tests1());
+ static_assert(tests2());
+ return 0;
+}
----------------
(1) I'm not thrilled by the `test1, test2, tests1, tests2` naming scheme. I'd prefer a very minor modification: keep `test1` and `test2`, but combine `tests[12]` into a new `constexpr bool test()` that does //all// of the calls to `test[12]`, and then `main` just does the usual `test() / static_assert(test())`. Alternatively, maybe the templated `test[12]` disappear, and then you just rename `tests[12]` to `test_iterator_sentinel` and `test_range`.
(2) I don't see any tests for
- non-contiguous range types
- non-iterator sentinel types
- two inputs that aren't of the same length
- non-forward iterators (e.g. `cpp20_input_iterator` and `cpp17_input_iterator`), and ranges thereof
- borrowed range types e.g. `subrange` (right?)
- non-borrowed range types as rvalues, which IIUC should return `swap_ranges_result<dangling, Iter2>` or `swap_ranges_result<Iter1, dangling>` so let's test that
- SFINAE-friendliness (I believe you can-and-should just add a line to @jloser's `cpo.compile.pass.cpp`, or optionally start a new sibling file specifically for the ranges algorithms)
- the non-constrainedness of `swap_ranges_result`, e.g. `swap_ranges_result<int, int> p;` is a perfectly fine declaration (Admittedly this is basically implied by the fact that `swap_ranges_result<dangling, dangling>` is OK — `dangling` is not an iterator either — but IMO let's test it anyway just for the record. It's the least important of these items by far, though)
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D116303/new/
https://reviews.llvm.org/D116303
More information about the libcxx-commits
mailing list