[libcxx-commits] [libcxx] [libc++][ranges] Implement P1899 `ranges::stride_view`. (PR #65200)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Mon Feb 23 22:48:38 PST 2026


================
@@ -0,0 +1,103 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++23
+
+// constexpr __iterator operator+(difference_type __n, const __iterator &__i)
+// constexpr __iterator operator+(const __iterator &__i, difference_type __n)
+
+#include <ranges>
+#include <vector>
+
+#include "../types.h"
+#include "test_iterators.h"
+
+template <class T>
+concept CanPlus =
+    std::is_same_v<T, decltype(std::declval<T>() + std::declval<typename T::__iterator::difference_type>())> &&
+    std::is_same_v<T, decltype(std::declval<typename T::__iterator::difference_type>() + std::declval<T>())> &&
+    requires(T& t, T::__iterator::difference_type& u) { t = t + u; } &&
+    requires(T& t, T::__iterator::difference_type& u) { t = u + t; };
+
+// Make sure that we cannot use + on a stride view iterator and difference_type
+// over an input view.(sized sentinel)
+using InputView = BasicTestView<cpp17_input_iterator<int*>, sized_sentinel<cpp17_input_iterator<int*>>>;
+using StrideViewOverInputViewIterator = std::ranges::iterator_t<std::ranges::stride_view<InputView>>;
+
+static_assert(std::ranges::input_range<InputView>);
+static_assert(!CanPlus<StrideViewOverInputViewIterator>);
+
+// Make sure that we cannot use + on a stride view iterator and difference_type
+// over a forward view.(sized sentinel)
+using ForwardView                       = BasicTestView<forward_iterator<int*>, sized_sentinel<forward_iterator<int*>>>;
+using StrideViewOverForwardViewIterator = std::ranges::iterator_t<std::ranges::stride_view<ForwardView>>;
+
+static_assert(std::ranges::forward_range<ForwardView>);
+static_assert(!CanPlus<StrideViewOverForwardViewIterator>);
+
+// Make sure that we cannot use + on a stride view iterator and difference_type
+// over a bidirectional view. (sized sentinel)
+using BidirectionalView = BasicTestView<bidirectional_iterator<int*>, sized_sentinel<bidirectional_iterator<int*>>>;
+using StrideViewOverBidirectionalViewIterator = std::ranges::iterator_t<std::ranges::stride_view<BidirectionalView>>;
+
+static_assert(std::ranges::bidirectional_range<BidirectionalView>);
+static_assert(!CanPlus<StrideViewOverBidirectionalViewIterator>);
+
+// Make sure that we can use += on a stride view iterator and difference_type
+// over a random access view. (non sized sentinel)
+template <typename RandomAccessIterator = random_access_iterator<int*>>
+using RandomAccessView                       = BasicTestView<RandomAccessIterator>;
+using StrideViewOverRandomAccessViewIterator = std::ranges::iterator_t<std::ranges::stride_view<RandomAccessView<>>>;
+
+static_assert(std::ranges::random_access_range<RandomAccessView<>>);
+static_assert(CanPlus<StrideViewOverRandomAccessViewIterator>);
+
+constexpr bool test_random_access_operator_plus_equal() {
+  using Iter = std::vector<int>::iterator;
+  using Diff = Iter::difference_type;
+  std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+  // Test the operator+ between an iterator and its difference type. Pay attention solely to
+  // stride views over random-access ranges because operator+ is not applicable to others.
+
+  auto begin    = vec.begin();
+  auto end      = vec.end();
+  Diff distance = 4;
+
+  // Do not use the RandomAccessView defined in types.h to give the test user more power
+  // to customize an iterator and a default sentinel.
+  using Base = RandomAccessView<Iter>;
+  static_assert(std::ranges::random_access_range<Base>);
+
+  auto base_view                  = Base(begin, end);
+  auto stride_view_over_base_view = std::ranges::stride_view(base_view, 1);
+
+  auto base_view_offset                  = Base(begin + distance, end);
+  auto stride_view_over_base_view_offset = std::ranges::stride_view(base_view_offset, 1);
+
+  assert(*(stride_view_over_base_view.begin() + distance) == *(stride_view_over_base_view_offset.begin()));
+
+  auto distance_to_last                    = (end - 1) - begin;
+  auto stride_view_over_base_view_big_step = std::ranges::stride_view(base_view, distance_to_last);
+
+  assert(*(stride_view_over_base_view_big_step.begin() + 1) ==
+         *(stride_view_over_base_view.begin() + distance_to_last));
+  assert((stride_view_over_base_view_big_step.begin() + 2) == (stride_view_over_base_view.end()));
+
+  return true;
+}
+
+consteval bool do_static_tests() {
+  assert(test_random_access_operator_plus_equal());
+  return true;
+}
----------------
H-G-Hristov wrote:

Why is this necessary? I think wrapping is redundant. You can just stick to the common pattern:
```c++
assert(test);
static_assert(test);
```

https://github.com/llvm/llvm-project/pull/65200


More information about the libcxx-commits mailing list