[llvm-branch-commits] [libcxx] release/21.x: [libc++][ranges] Fix `ranges::join_view` segmented iterator trait (#158347) (PR #161008)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sat Sep 27 07:57:14 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: None (llvmbot)
<details>
<summary>Changes</summary>
Backport d1b5607dc113016b74d0a58e95fed00ea9ad7950
Requested by: @<!-- -->frederick-vs-ja
---
Full diff: https://github.com/llvm/llvm-project/pull/161008.diff
2 Files Affected:
- (modified) libcxx/include/__ranges/join_view.h (+7-2)
- (modified) libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp (+82-39)
``````````diff
diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h
index 327b349f476a7..364f056d8d2cf 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -410,8 +410,13 @@ struct __segmented_iterator_traits<_JoinViewIterator> {
static constexpr _LIBCPP_HIDE_FROM_ABI _JoinViewIterator
__compose(__segment_iterator __seg_iter, __local_iterator __local_iter) {
- return _JoinViewIterator(
- std::move(__seg_iter).__get_data(), std::move(__seg_iter).__get_iter(), std::move(__local_iter));
+ auto&& __parent = std::move(__seg_iter).__get_data();
+ auto&& __outer = std::move(__seg_iter).__get_iter();
+ if (__local_iter == ranges::end(*__outer)) {
+ ++__outer;
+ return _JoinViewIterator(*__parent, __outer);
+ }
+ return _JoinViewIterator(__parent, __outer, std::move(__local_iter));
}
};
diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp
index d7e6be9928a2d..5f730f0f5bba8 100644
--- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp
@@ -272,57 +272,100 @@ class Comparable {
friend bool operator==(const Comparable& lhs, long long rhs) { return comparable_data[lhs.index_] == rhs; }
};
-void test_deque() {
- { // empty deque
- std::deque<int> data;
- assert(std::ranges::find(data, 4) == data.end());
- assert(std::ranges::find(data.begin(), data.end(), 4) == data.end());
- }
-
- { // single element - match
- std::deque<int> data = {4};
- assert(std::ranges::find(data, 4) == data.begin());
- assert(std::ranges::find(data.begin(), data.end(), 4) == data.begin());
- }
-
- { // single element - no match
- std::deque<int> data = {3};
- assert(std::ranges::find(data, 4) == data.end());
- assert(std::ranges::find(data.begin(), data.end(), 4) == data.end());
- }
-
- // many elements
- for (auto size : {2, 3, 1023, 1024, 1025, 2047, 2048, 2049}) {
- { // last element match
+void test_segmented_iterator_types() {
+ // Test the optimized find algorithm for types that implement the segment iterator trait
+ // deque
+ {
+ { // empty deque
std::deque<int> data;
- data.resize(size);
- std::fill(data.begin(), data.end(), 3);
- data[size - 1] = 4;
- assert(std::ranges::find(data, 4) == data.end() - 1);
- assert(std::ranges::find(data.begin(), data.end(), 4) == data.end() - 1);
+ assert(std::ranges::find(data, 4) == data.end());
+ assert(std::ranges::find(data.begin(), data.end(), 4) == data.end());
}
- { // second-last element match
- std::deque<int> data;
- data.resize(size);
- std::fill(data.begin(), data.end(), 3);
- data[size - 2] = 4;
- assert(std::ranges::find(data, 4) == data.end() - 2);
- assert(std::ranges::find(data.begin(), data.end(), 4) == data.end() - 2);
+ { // single element - match
+ std::deque<int> data = {4};
+ assert(std::ranges::find(data, 4) == data.begin());
+ assert(std::ranges::find(data.begin(), data.end(), 4) == data.begin());
}
- { // no match
- std::deque<int> data;
- data.resize(size);
- std::fill(data.begin(), data.end(), 3);
+ { // single element - no match
+ std::deque<int> data = {3};
assert(std::ranges::find(data, 4) == data.end());
assert(std::ranges::find(data.begin(), data.end(), 4) == data.end());
}
+
+ // many elements
+ for (auto size : {2, 3, 1023, 1024, 1025, 2047, 2048, 2049}) {
+ { // last element match
+ std::deque<int> data;
+ data.resize(size);
+ std::fill(data.begin(), data.end(), 3);
+ data[size - 1] = 4;
+ assert(std::ranges::find(data, 4) == data.end() - 1);
+ assert(std::ranges::find(data.begin(), data.end(), 4) == data.end() - 1);
+ }
+
+ { // second-last element match
+ std::deque<int> data;
+ data.resize(size);
+ std::fill(data.begin(), data.end(), 3);
+ data[size - 2] = 4;
+ assert(std::ranges::find(data, 4) == data.end() - 2);
+ assert(std::ranges::find(data.begin(), data.end(), 4) == data.end() - 2);
+ }
+
+ { // no match
+ std::deque<int> data;
+ data.resize(size);
+ std::fill(data.begin(), data.end(), 3);
+ assert(std::ranges::find(data, 4) == data.end());
+ assert(std::ranges::find(data.begin(), data.end(), 4) == data.end());
+ }
+ }
+ }
+ // join_view ranges adaptor
+ {
+ { // single element - match
+ int data[1][1] = {{4}};
+ auto joined = std::views::join(data);
+ assert(std::ranges::find(joined, 4) == std::ranges::begin(joined));
+ }
+ { // single element - no match
+ // (reproducer for https://llvm.org/PR158279, where the iterator would never reach the end sentinel)
+ int data[1][1] = {{3}};
+ auto joined = std::views::join(data);
+ assert(std::ranges::find(joined, 4) == std::ranges::end(joined));
+ }
+ { // several sub-arrays of size 1 - match
+ int data[3][1] = {{0}, {4}, {0}};
+ auto joined = std::views::join(data);
+ assert(std::ranges::find(joined, 4) == std::next(std::ranges::begin(joined)));
+ }
+ { // several sub-arrays of size 2 - match in second element of an array
+ int data[3][2] = {{0, 0}, {0, 4}, {0, 0}};
+ auto joined = std::views::join(data);
+ assert(std::ranges::find(joined, 4) == std::ranges::next(std::ranges::begin(joined), 3));
+ }
+ { // vector of empty vectors
+ std::vector<std::vector<int>> data = {{}, {}};
+ auto joined = std::views::join(data);
+ assert(std::ranges::find(joined, 4) == std::ranges::end(joined));
+ }
+ { // vector of variably sized vectors - match
+ std::vector<std::vector<int>> data = {{}, {}, {3, 4}, {}, {}};
+ auto joined = std::views::join(data);
+ assert(std::ranges::find(joined, 4) == std::ranges::next(std::ranges::begin(joined)));
+ }
+ { // vector of variably sized vectors - no match
+ std::vector<std::vector<int>> data = {{}, {}, {3, 5}, {}, {}};
+ auto joined = std::views::join(data);
+ assert(std::ranges::find(joined, 4) == std::ranges::end(joined));
+ }
}
}
int main(int, char**) {
- test_deque();
+ test_segmented_iterator_types();
test();
static_assert(test());
``````````
</details>
https://github.com/llvm/llvm-project/pull/161008
More information about the llvm-branch-commits
mailing list