[libcxx-commits] [PATCH] D126616: [libc++] Implement ranges::move{, _backward}
Konstantin Varlamov via Phabricator via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jun 3 21:15:27 PDT 2022
var-const requested changes to this revision.
var-const added inline comments.
This revision now requires changes to proceed.
================
Comment at: libcxx/include/__algorithm/move.h:37
+ }
+ return pair<_InIter, _OutIter>(std::move(__first), std::move(__result));
}
----------------
Nit: you can use `std::make_pair`.
================
Comment at: libcxx/include/__algorithm/move.h:40
-template <class _InputIterator, class _OutputIterator>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
-_OutputIterator
-__move(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
-{
- return _VSTD::__move_constexpr(__first, __last, __result);
+template <class _InValueT,
+ class _OutValueT,
----------------
Nit: I think we usually don't add `T` to template type names.
================
Comment at: libcxx/include/__algorithm/move.h:49
+#ifndef _LIBCPP_COMPILER_GCC
+ && !is_trivially_copyable<_InValueT>::value
+#endif
----------------
Can you provide a bit more context about this workaround?
================
Comment at: libcxx/include/__algorithm/move.h:54
+ const size_t __n = static_cast<size_t>(__last - __first);
+ if (__n > 0)
+ ::__builtin_memmove(__result, __first, __n * sizeof(_OutValueT));
----------------
Is this check necessary? Does `__builtin_memmove` require the argument not to be zero?
================
Comment at: libcxx/include/__algorithm/move.h:74
+ && __is_trivially_move_assignable_unwrapped<_InIter>::value
+ && __is_trivially_move_assignable_unwrapped<_OutIter>::value> >
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
----------------
Question: if `_InIter` and `_OutIter` have the same underlying value type, wouldn't `__is_trivially_move_assignable_unwrapped` always return the same result for both of them?
================
Comment at: libcxx/include/__algorithm/move.h:77
+pair<reverse_iterator<_InIter>, reverse_iterator<_OutIter>>
+__move_impl(reverse_iterator<_InIter> __first,
+ reverse_iterator<_InIter> __last,
----------------
Question: this is a new optimization that isn't directly related to implementing `ranges::move`, right?
================
Comment at: libcxx/include/__algorithm/move.h:85
+ std::__move_impl(__last_base, __first_base, __result_first);
+ return std::make_pair(__last, reverse_iterator<_OutIter>(std::__rewrap_iter(__result.base(), __result_first)));
+}
----------------
Very optional: you can use `make_reverse_iterator`.
================
Comment at: libcxx/include/__algorithm/move.h:91
+pair<reverse_iterator<reverse_iterator<_InIter>>, reverse_iterator<reverse_iterator<_OutIter> > >
+__copy_impl(reverse_iterator<reverse_iterator<_InIter> > __first,
+ reverse_iterator<reverse_iterator<_InIter> > __last,
----------------
Is this used? (same for this function's implementation below)
================
Comment at: libcxx/include/__algorithm/move.h:126
template <class _InputIterator, class _OutputIterator>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
----------------
Nit: this should be `_InIter` for consistency (I'd personally prefer `_InputIter`, but feel free to ignore).
================
Comment at: libcxx/include/__algorithm/move_backward.h:28
{
- if (__libcpp_is_constant_evaluated()) {
- return _VSTD::__move_backward_constexpr(__first, __last, __result);
- } else {
- return _VSTD::__rewrap_iter(__result,
- _VSTD::__move_backward(_VSTD::__unwrap_iter(__first),
- _VSTD::__unwrap_iter(__last),
- _VSTD::__unwrap_iter(__result)));
- }
+ return std::__move(reverse_iterator<_BidirectionalIterator1>(__last),
+ reverse_iterator<_BidirectionalIterator1>(__first),
----------------
I'd rather keep the previous approach -- it's more verbose, but also straightforward, symmetrical with `move.h`, and avoiding the extra overhead from using reverse iterators (which includes the additional mental burden when reading the code and more complicated types when debugging).
================
Comment at: libcxx/include/__algorithm/ranges_move.h:20
+#include <__ranges/dangling.h>
+#include <__utility/declval.h>
+#include <__utility/move.h>
----------------
Nit: seems unused (in the other ranges header as well).
================
Comment at: libcxx/include/__algorithm/ranges_move.h:40
+ template <class _InIter, class _Sent, class _OutIter>
+ requires __iter_move::__move_deref<_InIter>
+ _LIBCPP_HIDE_FROM_ABI constexpr static
----------------
Question: can you provide more context on this constraint?
================
Comment at: libcxx/include/__algorithm/ranges_move.h:55
+ }
+ return {__first, __result};
+ }
----------------
Nit: move the iterators?
================
Comment at: libcxx/include/__algorithm/ranges_move_backward.h:45
+ move_backward_result<_InIter, _OutIter> __move_backward_impl(_InIter __first, _Sent __last, _OutIter __result) {
+ auto __ret = std::__move(std::make_reverse_iterator(ranges::next(__first, __last)),
+ std::make_reverse_iterator(__first),
----------------
Why does this function forward to `__move` with reverse iterators rather than `__move_backward`? (I understand that `__move_backward` would have to be added) While this would be more boilerplate, I think it would be simpler, more consistent, and avoid the extra overhead from using reverse iterators (and probably the need to treat them specially in `__move`).
================
Comment at: libcxx/include/__algorithm/ranges_move_backward.h:72
+ move_backward_result<borrowed_iterator_t<_Range>, _Iter> operator()(_Range&& __range, _Iter __result) const {
+ return __move_backward_impl(ranges::begin(__range), ranges::end(__range), __result);
+ }
----------------
Nit: move `result`.
================
Comment at: libcxx/include/algorithm:352
+ constexpr ranges::copy_backward_result<I1, I2>
+ ranges::move_backward(I1 first, S1 last, I2 result); // since C++20
+
----------------
Please double-check the synopsis, there are a few mentions of `copy` that should be `move` (e.g., `s/copy_backward_result/move_backward_result/`).
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:15
+// template<input_iterator I, sentinel_for<I> S, weakly_incrementable O>
+// requires indirectly_copyable<I, O>
+// constexpr ranges::copy_result<I, O> ranges::move(I first, S last, O result);
----------------
Same as synopsis, there are a few mentions of `copy` (in the other test file as well).
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:38
+struct NotIndirectlyCopyable {};
+static_assert(!HasMoveIt<int*, NotIndirectlyCopyable*>);
+static_assert(!HasMoveIt<int*, int*, SentinelForNotSemiregular>);
----------------
Question: are these types for checking the `weakly_incrementable` constraint? Just clarifying because the names seem unrelated.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:52
+static_assert(!HasMoveR<InputRangeNotSentinelSemiregular, int*>);
+static_assert(!HasMoveR<InputRangeNotSentinelEqualityComparableWith, int*>);
+
----------------
Please also check the `weakly_incrementable` constraint.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:94
+
+struct IterMoveIter {
+ using value_type = int;
----------------
How about a name like `IteratorWithIterMove` to make it a little easier to parse?
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:101
+
+ constexpr int& operator*() const; // iterator with iter_move should not be derefernced
+
----------------
Nit: `s/derefernced/dereferenced/`.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:111
+
+constexpr bool test() {
+ test_in_iterators<cpp20_output_iterator<int*>>();
----------------
Can you add a test case that deals with a move-only type?
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:121
+ std::array<int, 4> out;
+ std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =
+ std::ranges::move(std::array {1, 2, 3, 4}, out.data());
----------------
Nit: `decltype(auto)`.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:138
+ struct MoveOnce {
+ bool copied = false;
+ constexpr MoveOnce() = default;
----------------
Nit: `s/copied/moved/`.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp:168
+ OnlyForwardsMovable* next = nullptr;
+ bool canCopy = false;
+ OnlyForwardsMovable() = default;
----------------
Nit: `s/canCopy/canMove/`.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp:3
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
----------------
Comments from the other test file apply here as well.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp:13
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+
----------------
Ultranit: there's an extra blank line.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp:139
+
+ { // check that every element is copied exactly once
+ struct CopyOnce {
----------------
Nit: `s/copied/moved/`.
================
Comment at: libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp:140
+ { // check that every element is copied exactly once
+ struct CopyOnce {
+ bool copied = false;
----------------
Nit: `s/CopyOnce/MoveOnce/`.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D126616/new/
https://reviews.llvm.org/D126616
More information about the libcxx-commits
mailing list