[libcxx-commits] [PATCH] D101922: [libcxx][iterator] adds `std::ranges::advance`

Christopher Di Bella via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Fri May 14 10:47:14 PDT 2021


cjdb added inline comments.


================
Comment at: libcxx/include/__iterator/primitives.h:60-70
+      while (__n > 0) {
+        --__n;
+        ++__i;
+      }
+
+      // Otherwise, decrements `i` by `-n`.
+      if constexpr (bidirectional_iterator<_Ip>) {
----------------
cjdb wrote:
> ldionne wrote:
> > I understand why this works, but I find it's a slightly confusing way to write this. Instead, Maybe `else if constexpr (is_bidirectional_iterator<_Ip>) { handle bidirectional case } else { handle-forward-only-case }`.
> > 
> > It's not as clever, but maybe easier to understand?
> I can do that, but it results in code duplication.
> 
> ```
> else if constexpr (bidirectional_iterator<_Ip>) {
>   while (__n > 0) {
>     --__n;
>     ++_i;
>   }
>   while (__n < 0) {
>     ++__n;
>     --__i;
>   }
> }
> else {
>   while (__n > 0) {
>     --__n;
>     ++_i;
>   }
> }
> ```
> I suppose I could put the forward case into an `__advance_forward` and call that twice. WDYT?
> ```
> else if constexpr (bidirectional_iterator<_Ip>) {
>   __advance_forward(__i, __n);
>   __advance_backward(__i, __n);
> }
> else {
>   __advance_forward(__i, __n);
> }
> ```
PTAL.


================
Comment at: libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/advance.pass.cpp:33
+constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptrdiff_t const n) {
+  auto const distance = n < 0 ? -n : n;
+  assert(i.distance_traversed() == distance);
----------------
zoecarver wrote:
> Nit: I think `abs` would make this clearer. 
`abs` is not `constexpr`.


================
Comment at: libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/advance.pass.cpp:40
+constexpr void check_round_trip(stride_counting_iterator<I> const& i, std::ptrdiff_t const n) {
+  assert(i.distance_traversed() <= 1);
+  assert(i.displacement() == n < 0 ? -1 : 1);
----------------
zoecarver wrote:
> zoecarver wrote:
> > When would this not be exactly one?
> Maybe `i.distance_traversed() == 1 || n & i.distance_traversed() == 0`.
In the case where assignment happens, which has `distance_traversed == 0`.


================
Comment at: libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/advance.pass.cpp:127
+template <std::input_or_output_iterator I, std::sentinel_for<I> S = I>
+constexpr void check_assignable_case(std::ptrdiff_t const n) {
+  auto range = range_t{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
----------------
zoecarver wrote:
> What is the "assignable case"?
http://eel.is/c++draft/range.iter.ops#range.iter.op.advance-4.1


================
Comment at: libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/advance.pass.cpp:191
+  auto const result = std::ranges::advance(current, n, distance_apriori_sentinel(range.size()));
+  assert(current.base().base() == expected.coordinate);
+  assert(result == expected.result);
----------------
zoecarver wrote:
> If you dereference this, it should always be `n`, right? Maybe that's simpler and then we can get rid of `expected_t`. 
The point of these tests is to confirm that?


================
Comment at: libcxx/test/support/test_iterators.h:727
+
+  [[nodiscard]] constexpr I base() const& requires std::copyable<I> { return base_; }
+
----------------
ldionne wrote:
> `s/[[nodiscard]]//g`
I've removed it for some areas, but kept it where I think calling and not using is error-prone.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D101922



More information about the libcxx-commits mailing list