[libcxx-commits] [libcxx] [libc++][ranges] Fix `ranges::join_view` segmented iterator trait (PR #158347)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Sep 14 12:10:44 PDT 2025


https://github.com/lbonn updated https://github.com/llvm/llvm-project/pull/158347

>From 192c9206b9c8fb8b727f7c7385f08850255ec404 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           | 13 ++++++-
 .../range.join.iterator/find.pass.cpp         | 37 +++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)
 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..af9be814eed1b 100644
--- a/libcxx/include/__ranges/join_view.h
+++ b/libcxx/include/__ranges/join_view.h
@@ -255,7 +255,18 @@ struct join_view<_View>::__iterator final : public __join_view_iterator_category
 
   _LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent* __parent, _Outer __outer, _Inner __inner)
     requires forward_range<_Base>
-      : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {}
+      : __outer_(std::move(__outer)), __inner_(std::move(__inner)), __parent_(__parent) {
+    auto __get_inner_range = [&]() -> decltype(auto) {
+      if constexpr (__ref_is_glvalue)
+        return *__get_outer();
+      else
+        return *__parent_->__inner_;
+    };
+    if (__inner_ == ranges::end(std::__as_lvalue(__get_inner_range()))) {
+      ++__get_outer();
+      __satisfy();
+    }
+  }
 
 public:
   using iterator_concept =
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