[libcxx-commits] [libcxx] [libc++][ranges] Fix `ranges::join_view` segmented iterator trait (PR #158347)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Sep 12 11:56:44 PDT 2025
https://github.com/lbonn created https://github.com/llvm/llvm-project/pull/158347
The outer iterator needs to move to the next segment when calling __compose.
Without this change, `find_segment_if` would never reach the end of the join_view which caused erroneous result when calling `ranges::find` on a join_view of bidirectional ranges.
Other specializations using the segmented iterator trait were likely to be affected as well.
Fixes #158279, #93180
cc @philnik777
>From da8fb07b4138cec29b3d5cb7613e11c3f95a297a Mon Sep 17 00:00:00 2001
From: lbonn <github at lbonnans.net>
Date: Fri, 12 Sep 2025 20:41:06 +0200
Subject: [PATCH] [libc++][ranges] Fix `ranges::join_view` segmented iterator
trait
The outer iterator needs to move to the next segment when calling
__compose.
Without this change, `find_segment_if` would never reach the end of the
join_view which caused erroneous result when calling `ranges::find` on a
join_view of bidirectional ranges.
Other specializations using the segmented iterator trait were likely to
be affected as well.
---
libcxx/include/__ranges/join_view.h | 8 +++-
.../range.join.iterator/find.pass.cpp | 37 +++++++++++++++++++
2 files changed, 43 insertions(+), 2 deletions(-)
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/find.pass.cpp
diff --git a/libcxx/include/__ranges/join_view.h b/libcxx/include/__ranges/join_view.h
index 327b349f476a7..6097754f403ec 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -410,8 +410,12 @@ 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&& __outer = std::move(__seg_iter).__get_iter();
+ if (__local_iter == ranges::end(*__outer)) {
+ ++__outer;
+ return _JoinViewIterator(*std::move(__seg_iter).__get_data(), __outer);
+ }
+ return _JoinViewIterator(std::move(__seg_iter).__get_data(), __outer, std::move(__local_iter));
}
};
diff --git a/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/find.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/find.pass.cpp
new file mode 100644
index 0000000000000..f8bee2227d0b9
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.join/range.join.iterator/find.pass.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+#include <algorithm>
+#include <cassert>
+#include <ranges>
+#include <type_traits>
+
+#include "../types.h"
+
+constexpr bool test() {
+ // Test the segmented iterator implementation of join_view
+ // https://github.com/llvm/llvm-project/issues/158279
+ {
+ int buffer1[2][1] = {{1}, {2}};
+ auto joined = std::views::join(buffer1);
+ assert(std::ranges::find(joined, 1) == std::ranges::begin(joined));
+ assert(std::ranges::find(joined, 2) == std::ranges::next(std::ranges::begin(joined)));
+ assert(std::ranges::find(joined, 3) == std::ranges::end(joined));
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
More information about the libcxx-commits
mailing list