[libcxx-commits] [libcxx] [libc++] Partially implement P2846R6: `reserve_hint` (PR #206385)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jun 28 19:29:51 PDT 2026


https://github.com/inquisitivecrystal updated https://github.com/llvm/llvm-project/pull/206385

>From 315066dead028c4df0b8345a1517ae234fc890ff Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Wed, 24 Jun 2026 23:31:10 -0700
Subject: [PATCH 1/9] Implement ranges::reserve_hint CPO

---
 libcxx/include/__ranges/size.h | 53 ++++++++++++++++++++++++++++++++++
 libcxx/include/ranges          |  1 +
 2 files changed, 54 insertions(+)

diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h
index 5da3a6ff268e8..3dfeade03fce5 100644
--- a/libcxx/include/__ranges/size.h
+++ b/libcxx/include/__ranges/size.h
@@ -131,6 +131,59 @@ inline constexpr auto ssize = __ssize::__fn{};
 } // namespace __cpo
 } // namespace ranges
 
+#  if _LIBCPP_STD_VER >= 26
+
+// [range.prim.size.hint]
+
+namespace ranges {
+namespace __reserve_hint {
+void reserve_hint() = delete;
+
+template <typename _Tp>
+concept __std_size = requires(_Tp&& __t) { ranges::size(__t); };
+
+template <typename _Tp>
+concept __member_reserve_hint = !__std_size<_Tp> && requires(_Tp&& __t) {
+  { auto(__t.reserve_hint()) } -> __integer_like;
+};
+
+template <typename _Tp>
+concept __freestanding_reserve_hint =
+    !__std_size<_Tp> && !__member_reserve_hint<_Tp> && __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) {
+      { auto(reserve_hint(__t)) } -> __integer_like;
+    };
+
+struct __fn {
+  // `[range.prim.size.hint]`: `std::size(t)` is a valid expression
+  template <__std_size _Tp>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
+      noexcept(noexcept(ranges::size(__t))) {
+    return ranges::size(__t);
+  }
+
+  // `[range.prim.size.hint]`: `auto(t.reserve_hint())` is a valid expression
+  template <__member_reserve_hint _Tp>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
+      noexcept(noexcept(auto(__t.reserve_hint()))) {
+    return auto(__t.reserve_hint());
+  }
+
+  // `[range.prim.size.hint]`: `auto(reserve_hint(t))` is a valid expression
+  template <__freestanding_reserve_hint _Tp>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
+      noexcept(noexcept(auto(reserve_hint(__t)))) {
+    return auto(reserve_hint(__t));
+  }
+};
+} // namespace __reserve_hint
+
+inline namespace __cpo {
+inline constexpr auto reserve_hint = __reserve_hint::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+#  endif // _LIBCPP_STD_VER >= 26
+
 #endif // _LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index d82a41942327b..6448e74edb28b 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -26,6 +26,7 @@ namespace std::ranges {
 
     inline constexpr unspecified size = unspecified;
     inline constexpr unspecified ssize = unspecified;
+    inline constexpr unspecified reserve_hint = unspecified; // Since C++26
   }
 
   // [range.range], ranges

>From c8fca33b7b0d382d3eed0d39adaf2e305a31b35b Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Wed, 24 Jun 2026 23:32:19 -0700
Subject: [PATCH 2/9] Implement approximately_sized_range concept

---
 libcxx/include/__ranges/concepts.h | 14 ++++++++++++++
 libcxx/include/ranges              |  4 ++++
 2 files changed, 18 insertions(+)

diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h
index bf75fe8a6fef4..e7cfc94506120 100644
--- a/libcxx/include/__ranges/concepts.h
+++ b/libcxx/include/__ranges/concepts.h
@@ -80,10 +80,24 @@ using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<_Rp>>;
 template <range _Rp>
 using range_common_reference_t = iter_common_reference_t<iterator_t<_Rp>>;
 
+#  if _LIBCPP_STD_VER >= 26
+
+// [range.approximately.sized]
+template <class _Tp>
+concept approximately_sized_range = range<_Tp> && requires(_Tp& __t) { ranges::reserve_hint(__t); };
+
+// [range.sized]
+template <class _Tp>
+concept sized_range = approximately_sized_range<_Tp> && requires(_Tp& __t) { ranges::size(__t); };
+
+#  else // _LIBCPP_STD_VER < 26
+
 // [range.sized]
 template <class _Tp>
 concept sized_range = range<_Tp> && requires(_Tp& __t) { ranges::size(__t); };
 
+#  endif
+
 template <sized_range _Rp>
 using range_size_t = decltype(ranges::size(std::declval<_Rp&>()));
 
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 6448e74edb28b..8e0d464bca6ea 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -53,6 +53,10 @@ namespace std::ranges {
   template <range R>
     using range_common_reference_t = iter_common_reference_t<iterator_t<R>>;
 
+  // [range.approximately.sized], approximately sized ranges
+  template<class T>
+    concept approximately_sized_range = ...;
+
   // [range.sized], sized ranges
   template<class>
     inline constexpr bool disable_sized_range = false;

>From f96ffb52ebc591564db86d673ea708a6f873f712 Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Wed, 24 Jun 2026 23:32:53 -0700
Subject: [PATCH 3/9] Implement reserve_hint for views

---
 .../__ranges/adjacent_transform_view.h        | 16 +++++++++++++
 libcxx/include/__ranges/adjacent_view.h       | 24 +++++++++++++++++++
 libcxx/include/__ranges/as_rvalue_view.h      | 16 +++++++++++++
 libcxx/include/__ranges/common_view.h         | 16 +++++++++++++
 libcxx/include/__ranges/drop_view.h           | 18 ++++++++++++++
 libcxx/include/__ranges/elements_view.h       | 16 +++++++++++++
 libcxx/include/__ranges/enumerate_view.h      | 16 +++++++++++++
 libcxx/include/__ranges/owning_view.h         | 16 +++++++++++++
 libcxx/include/__ranges/ref_view.h            |  9 +++++++
 libcxx/include/__ranges/reverse_view.h        | 16 +++++++++++++
 libcxx/include/__ranges/stride_view.h         | 19 +++++++++++++++
 libcxx/include/__ranges/take_view.h           | 20 ++++++++++++++++
 libcxx/include/__ranges/transform_view.h      | 16 +++++++++++++
 13 files changed, 218 insertions(+)

diff --git a/libcxx/include/__ranges/adjacent_transform_view.h b/libcxx/include/__ranges/adjacent_transform_view.h
index 4863d074482dc..e7e05539e8aaa 100644
--- a/libcxx/include/__ranges/adjacent_transform_view.h
+++ b/libcxx/include/__ranges/adjacent_transform_view.h
@@ -149,6 +149,22 @@ class adjacent_transform_view : public view_interface<adjacent_transform_view<_V
   {
     return __inner_.size();
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_InnerView>
+  {
+    return __inner_.reserve_hint();
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _InnerView>
+  {
+    return __inner_.reserve_hint();
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <forward_range _View, move_constructible _Fn, size_t _Np>
diff --git a/libcxx/include/__ranges/adjacent_view.h b/libcxx/include/__ranges/adjacent_view.h
index 40474b85c794f..27b116e30eee9 100644
--- a/libcxx/include/__ranges/adjacent_view.h
+++ b/libcxx/include/__ranges/adjacent_view.h
@@ -139,6 +139,30 @@ class adjacent_view : public view_interface<adjacent_view<_View, _Np>> {
     __sz -= std::min<_CT>(__sz, _Np - 1);
     return static_cast<_ST>(__sz);
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    using _ST = decltype(ranges::reserve_hint(__base_));
+    using _CT = common_type_t<_ST, size_t>;
+    auto __sz = static_cast<_CT>(ranges::reserve_hint(__base_));
+    __sz -= std::min<_CT>(__sz, _Np - 1);
+    return static_cast<_ST>(__sz);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    using _ST = decltype(ranges::reserve_hint(__base_));
+    using _CT = common_type_t<_ST, size_t>;
+    auto __sz = static_cast<_CT>(ranges::reserve_hint(__base_));
+    __sz -= std::min<_CT>(__sz, _Np - 1);
+    return static_cast<_ST>(__sz);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 struct __adjacent_view_iter_access {
diff --git a/libcxx/include/__ranges/as_rvalue_view.h b/libcxx/include/__ranges/as_rvalue_view.h
index a553f39998e0e..705cf559a7ee0 100644
--- a/libcxx/include/__ranges/as_rvalue_view.h
+++ b/libcxx/include/__ranges/as_rvalue_view.h
@@ -99,6 +99,22 @@ class as_rvalue_view : public view_interface<as_rvalue_view<_View>> {
   {
     return ranges::size(__base_);
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <class _Range>
diff --git a/libcxx/include/__ranges/common_view.h b/libcxx/include/__ranges/common_view.h
index eec1045c8a758..4f1dfbf5d9ac2 100644
--- a/libcxx/include/__ranges/common_view.h
+++ b/libcxx/include/__ranges/common_view.h
@@ -101,6 +101,22 @@ class common_view : public view_interface<common_view<_View>> {
   {
     return ranges::size(__base_);
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <class _Range>
diff --git a/libcxx/include/__ranges/drop_view.h b/libcxx/include/__ranges/drop_view.h
index e3754e64d536f..9cae5c1c30276 100644
--- a/libcxx/include/__ranges/drop_view.h
+++ b/libcxx/include/__ranges/drop_view.h
@@ -139,6 +139,24 @@ class drop_view : public view_interface<drop_view<_View>> {
   {
     return __size(*this);
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    const auto __s = static_cast<range_difference_t<_View>>(ranges::reserve_hint(__base_));
+    return __to_unsigned_like(__s < __count_ ? 0 : __s - __count_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    const auto __s = static_cast<range_difference_t<const _View>>(ranges::reserve_hint(__base_));
+    return __to_unsigned_like(__s < __count_ ? 0 : __s - __count_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <class _Range>
diff --git a/libcxx/include/__ranges/elements_view.h b/libcxx/include/__ranges/elements_view.h
index b1419f2a1dd91..9ce87e6814dbe 100644
--- a/libcxx/include/__ranges/elements_view.h
+++ b/libcxx/include/__ranges/elements_view.h
@@ -133,6 +133,22 @@ class elements_view : public view_interface<elements_view<_View, _Np>> {
     return ranges::size(__base_);
   }
 
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
+
 private:
   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
 };
diff --git a/libcxx/include/__ranges/enumerate_view.h b/libcxx/include/__ranges/enumerate_view.h
index bb7696897af00..1a67a23e864d7 100644
--- a/libcxx/include/__ranges/enumerate_view.h
+++ b/libcxx/include/__ranges/enumerate_view.h
@@ -115,6 +115,22 @@ class enumerate_view : public view_interface<enumerate_view<_View>> {
     return __base_;
   }
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <class _Range>
diff --git a/libcxx/include/__ranges/owning_view.h b/libcxx/include/__ranges/owning_view.h
index 1ab81afee774a..b1e8415c3a477 100644
--- a/libcxx/include/__ranges/owning_view.h
+++ b/libcxx/include/__ranges/owning_view.h
@@ -99,6 +99,22 @@ class owning_view : public view_interface<owning_view<_Rp>> {
   {
     return ranges::data(__r_);
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_Rp>
+  {
+    return ranges::reserve_hint(__r_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _Rp>
+  {
+    return ranges::reserve_hint(__r_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(owning_view);
 
diff --git a/libcxx/include/__ranges/ref_view.h b/libcxx/include/__ranges/ref_view.h
index 109a10cec299e..34f129ace54e7 100644
--- a/libcxx/include/__ranges/ref_view.h
+++ b/libcxx/include/__ranges/ref_view.h
@@ -73,6 +73,15 @@ class ref_view : public view_interface<ref_view<_Range>> {
   {
     return ranges::data(*__range_);
   }
+
+#  if _LIBCPP_STD_VER >= 26
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<_Range>
+  {
+    return ranges::reserve_hint(*__range_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <class _Range>
diff --git a/libcxx/include/__ranges/reverse_view.h b/libcxx/include/__ranges/reverse_view.h
index b016cc231f2b5..fc8e609705661 100644
--- a/libcxx/include/__ranges/reverse_view.h
+++ b/libcxx/include/__ranges/reverse_view.h
@@ -111,6 +111,22 @@ class reverse_view : public view_interface<reverse_view<_View>> {
   {
     return ranges::size(__base_);
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <class _Range>
diff --git a/libcxx/include/__ranges/stride_view.h b/libcxx/include/__ranges/stride_view.h
index 780bb25743c15..d4b7cce06eb91 100644
--- a/libcxx/include/__ranges/stride_view.h
+++ b/libcxx/include/__ranges/stride_view.h
@@ -30,6 +30,7 @@
 #include <__ranges/concepts.h>
 #include <__ranges/enable_borrowed_range.h>
 #include <__ranges/range_adaptor.h>
+#include <__ranges/size.h>
 #include <__ranges/view_interface.h>
 #include <__type_traits/make_unsigned.h>
 
@@ -129,6 +130,24 @@ class stride_view : public view_interface<stride_view<_View>> {
   {
     return std::__to_unsigned_like(ranges::__div_ceil(ranges::distance(__base_), __stride_));
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    auto __s = static_cast<range_difference_t<decltype((__base_))>>(ranges::reserve_hint(__base_));
+    return __to_unsigned_like(__div_ceil(__s, __stride_));
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    auto __s = static_cast<range_difference_t<decltype((__base_))>>(ranges::reserve_hint(__base_));
+    return __to_unsigned_like(__div_ceil(__s, __stride_));
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 }; // class stride_view
 
 template <class _Range>
diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h
index 999f686537f2c..f97a88ccf9297 100644
--- a/libcxx/include/__ranges/take_view.h
+++ b/libcxx/include/__ranges/take_view.h
@@ -155,6 +155,26 @@ class take_view : public view_interface<take_view<_View>> {
     auto __n = ranges::size(__base_);
     return ranges::min(__n, static_cast<decltype(__n)>(__count_));
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() {
+    if constexpr (approximately_sized_range<_View>) {
+      auto __n = static_cast<range_difference_t<_View>>(ranges::reserve_hint(__base_));
+      return __to_unsigned_like(ranges::min(__n, __count_));
+    }
+    return __to_unsigned_like(__count_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const {
+    if constexpr (approximately_sized_range<const _View>) {
+      auto __n = static_cast<range_difference_t<const _View>>(ranges::reserve_hint(__base_));
+      return __to_unsigned_like(ranges::min(__n, __count_));
+    }
+    return __to_unsigned_like(__count_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <view _View>
diff --git a/libcxx/include/__ranges/transform_view.h b/libcxx/include/__ranges/transform_view.h
index 1484be006e841..c26b7ea362a8d 100644
--- a/libcxx/include/__ranges/transform_view.h
+++ b/libcxx/include/__ranges/transform_view.h
@@ -139,6 +139,22 @@ class _LIBCPP_ABI_LLVM18_NO_UNIQUE_ADDRESS transform_view : public view_interfac
   {
     return ranges::size(__base_);
   }
+
+#  if _LIBCPP_STD_VER >= 26
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires approximately_sized_range<_View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires approximately_sized_range<const _View>
+  {
+    return ranges::reserve_hint(__base_);
+  }
+
+#  endif //_LIBCPP_STD_VER >= 26
 };
 
 template <class _Range, class _Fn>

>From 04c8de26c3707ebea7247894855612f120acb1c0 Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Wed, 24 Jun 2026 23:35:18 -0700
Subject: [PATCH 4/9] Implement reserve_hint for concat_view (LWG4553)

---
 libcxx/include/__ranges/concat_view.h | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/libcxx/include/__ranges/concat_view.h b/libcxx/include/__ranges/concat_view.h
index 3bbe9db12e0f8..33d269b9fd09a 100644
--- a/libcxx/include/__ranges/concat_view.h
+++ b/libcxx/include/__ranges/concat_view.h
@@ -176,6 +176,28 @@ class concat_view : public view_interface<concat_view<_Views...>> {
         [](auto... __sizes) { return (make_unsigned_t<common_type_t<decltype(__sizes)...>>(__sizes) + ...); },
         std::__tuple_transform(ranges::size, __views_));
   }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint()
+    requires(approximately_sized_range<_Views> && ...)
+  {
+    return apply(
+        [](auto... __sizes) static {
+          using _CT = make_unsigned_t<common_type_t<decltype(__sizes)...>>;
+          return (_CT(__sizes) + ...);
+        },
+        std::__tuple_transform(ranges::reserve_hint, __views_));
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto reserve_hint() const
+    requires(approximately_sized_range<const _Views> && ...)
+  {
+    return apply(
+        [](auto... __sizes) static {
+          using _CT = make_unsigned_t<common_type_t<decltype(__sizes)...>>;
+          return (_CT(__sizes) + ...);
+        },
+        std::__tuple_transform(ranges::reserve_hint, __views_));
+  }
 };
 
 template <class... _Views>

>From 5938495f415e0b8ecf51efe47d5e9189f5968a19 Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Thu, 28 May 2026 01:02:44 -0700
Subject: [PATCH 5/9] Add new items to module

---
 libcxx/modules/std/ranges.inc | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 876942bdffbf5..9e87e2653908a 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -25,6 +25,10 @@ export namespace std {
       using std::ranges::__cpo::empty;
       using std::ranges::__cpo::size;
       using std::ranges::__cpo::ssize;
+
+#if _LIBCPP_STD_VER >= 26
+      using std::ranges::__cpo::reserve_hint;
+#endif
     } // namespace __cpo
 
     // [range.range], ranges
@@ -50,6 +54,11 @@ export namespace std {
     using std::ranges::disable_sized_range;
     using std::ranges::sized_range;
 
+#if _LIBCPP_STD_VER >= 26
+    // [range.approximately.sized], approximately sized ranges
+    using std::ranges::approximately_sized_range;
+#endif
+
     // [range.view], views
     using std::ranges::enable_view;
     using std::ranges::view;

>From e9a3212c848a9d2a47e1634869b016b488481ee0 Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Thu, 25 Jun 2026 00:12:01 -0700
Subject: [PATCH 6/9] Test reserve_hint

---
 .../ranges/range.access/reserve_hint.pass.cpp | 100 ++++++++++++++
 .../range.access/reserve_hint.verify.cpp      |  21 +++
 .../reserve_hint.pass.cpp                     | 130 ++++++++++++++++++
 .../range.adjacent/reserve_hint.pass.cpp      | 108 +++++++++++++++
 .../range.owning.view/reserve_hint.pass.cpp   |  86 ++++++++++++
 .../range.ref.view/range.ref.view.pass.cpp    |  29 ++++
 .../range.as.rvalue/reserve_hint.pass.cpp     |  90 ++++++++++++
 .../range.common.view/reserve_hint.pass.cpp   |  63 +++++++++
 .../range.adaptors/range.common.view/types.h  |  31 +++++
 .../range.concat/reserve_hint.pass.cpp        | 107 ++++++++++++++
 .../range.drop/reserve_hint.pass.cpp          |  59 ++++++++
 .../ranges/range.adaptors/range.drop/types.h  |  14 ++
 .../range.elements/reserve_hint.pass.cpp      |  90 ++++++++++++
 .../range.enumerate/reserve_hint.pass.cpp     |  82 +++++++++++
 .../range.reverse/reserve_hint.pass.cpp       |  89 ++++++++++++
 .../range.stride.view/reserve_hint.pass.cpp   |  99 +++++++++++++
 .../range.adaptors/range.stride.view/types.h  |  19 ++-
 .../range.take/reserve_hint.pass.cpp          |  87 ++++++++++++
 .../ranges/range.adaptors/range.take/types.h  |  14 ++
 .../range.transform/reserve_hint.pass.cpp     |  44 ++++++
 .../range.adaptors/range.transform/types.h    |  33 +++++
 21 files changed, 1391 insertions(+), 4 deletions(-)
 create mode 100644 libcxx/test/std/ranges/range.access/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.access/reserve_hint.verify.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.adjacent.transform/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.adjacent/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.as.rvalue/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.common.view/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.drop/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.elements/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.reverse/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.stride.view/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.take/reserve_hint.pass.cpp
 create mode 100644 libcxx/test/std/ranges/range.adaptors/range.transform/reserve_hint.pass.cpp

diff --git a/libcxx/test/std/ranges/range.access/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.access/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..4e5f11fba445e
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/reserve_hint.pass.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// std::ranges::reserve_hint
+
+#include <cassert>
+#include <ranges>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+using RangeReserveHintT = decltype(std::ranges::reserve_hint);
+
+struct Incomplete;
+static_assert(!std::is_invocable_v<RangeReserveHintT, Incomplete[]>);
+static_assert(!std::is_invocable_v<RangeReserveHintT, Incomplete(&)[]>);
+static_assert(!std::is_invocable_v<RangeReserveHintT, Incomplete(&&)[]>);
+
+extern int bounded_array[42];
+
+struct SizedSentinelRange {
+  int data_[42] = {};
+  constexpr int* begin() { return data_; }
+  constexpr auto end() { return sized_sentinel<int*>(data_ + 42); }
+};
+
+struct HasSizeMember {
+  constexpr std::size_t size() { return 42; }
+};
+
+struct HasSizeFunction {
+  friend constexpr std::size_t size(HasSizeFunction _) { return 42; }
+};
+
+struct HasReserveHintMember {
+  constexpr std::size_t reserve_hint() { return 42; }
+};
+
+struct HasReserveHintFunction {
+  friend constexpr std::size_t reserve_hint(HasReserveHintFunction _) { return 42; }
+};
+
+struct HasReserveHintMemberBool {
+  constexpr bool reserve_hint() { return false; }
+};
+
+static_assert(!std::is_invocable_v<RangeReserveHintT, HasReserveHintMemberBool>);
+
+static_assert(std::ranges::reserve_hint(bounded_array) == 42);
+ASSERT_SAME_TYPE(decltype(std::ranges::reserve_hint(bounded_array)), std::size_t);
+
+bool constexpr test_sized_sentinel_range() {
+  SizedSentinelRange b;
+  assert(std::ranges::reserve_hint(b) == 42);
+  ASSERT_SAME_TYPE(decltype(std::ranges::reserve_hint(b)), std::size_t);
+
+  return true;
+}
+
+static_assert(std::ranges::reserve_hint(HasSizeMember{}) == 42);
+ASSERT_SAME_TYPE(decltype(std::ranges::reserve_hint(HasSizeMember{})), std::size_t);
+
+static_assert(std::ranges::reserve_hint(HasSizeFunction{}) == 42);
+ASSERT_SAME_TYPE(decltype(std::ranges::reserve_hint(HasSizeFunction{})), std::size_t);
+
+static_assert(std::ranges::reserve_hint(HasReserveHintMember{}) == 42);
+ASSERT_SAME_TYPE(decltype(std::ranges::reserve_hint(HasReserveHintMember{})), std::size_t);
+
+static_assert(std::ranges::reserve_hint(HasReserveHintFunction{}) == 42);
+ASSERT_SAME_TYPE(decltype(std::ranges::reserve_hint(HasReserveHintFunction{})), std::size_t);
+
+// test that the order of preference is ranges::size, then member reserve_hint,
+// then function reserve_hint
+struct HasSizeAndReserveHint {
+  constexpr std::size_t size() { return 42; }
+  constexpr std::size_t reserve_hint() { return 0; }
+  friend constexpr std::size_t reserve_hint(HasSizeAndReserveHint _) { return 0; }
+};
+
+struct HasReserveHintMemberAndFunction {
+  constexpr std::size_t reserve_hint() { return 42; }
+  friend constexpr std::size_t reserve_hint(HasReserveHintMemberAndFunction _) { return 0; }
+};
+
+static_assert(std::ranges::reserve_hint(HasSizeAndReserveHint{}) == 42);
+static_assert(std::ranges::reserve_hint(HasReserveHintMemberAndFunction{}) == 42);
+
+int main(int, char**) {
+  test_sized_sentinel_range();
+  static_assert(test_sized_sentinel_range());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.access/reserve_hint.verify.cpp b/libcxx/test/std/ranges/range.access/reserve_hint.verify.cpp
new file mode 100644
index 0000000000000..760620c6bd271
--- /dev/null
+++ b/libcxx/test/std/ranges/range.access/reserve_hint.verify.cpp
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// std::ranges::reserve_hint
+
+#include <ranges>
+
+extern int arr[];
+
+// Verify that for an array of unknown bound `ranges::reserve_hint` is ill-formed.
+void test() {
+  std::ranges::reserve_hint(arr);
+  // expected-error-re at -1 {{{{no matching function for call to object of type 'const (std::ranges::)?__reserve_hint::__fn'}}}}
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.adjacent.transform/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.adjacent.transform/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..291810bfecf7d
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.adjacent.transform/reserve_hint.pass.cpp
@@ -0,0 +1,130 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<InnerView>;
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const InnerView>;
+
+#include <cassert>
+#include <ranges>
+#include <utility>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "helpers.h"
+
+int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+struct NonApproximatelySizedView : std::ranges::view_base {
+  using iterator = forward_iterator<int*>;
+  iterator begin() const;
+  iterator end() const;
+};
+
+struct ApproximatelySizedView : std::ranges::view_base {
+  unsigned int size_;
+  constexpr explicit ApproximatelySizedView(unsigned int size) : size_(size) {}
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + size_); }
+  constexpr unsigned int reserve_hint() const { return size_; }
+};
+
+struct ApproximatelySizedNotConstView : std::ranges::view_base {
+  unsigned int size_;
+  constexpr explicit ApproximatelySizedNotConstView(unsigned int size) : size_(size) {}
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + size_); }
+  constexpr unsigned int reserve_hint() { return size_; }
+};
+
+// Test with different values of N for an approximately sized view
+template <std::size_t N, class Fn>
+constexpr void test_approx_sized_view() {
+  std::ranges::adjacent_transform_view<ApproximatelySizedView, Fn, N> v(ApproximatelySizedView(5), Fn{});
+  static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+  static_assert(std::ranges::approximately_sized_range<const decltype(v)>);
+
+  auto expected_hint = 5 - (N - 1);
+  assert(v.reserve_hint() == expected_hint);
+  assert(std::as_const(v).reserve_hint() == expected_hint);
+}
+
+// Test with different values of N for a non-const approximately sized view
+template <std::size_t N, class Fn>
+constexpr void test_nonconst_approx_sized() {
+  // non-const-only reserve_hint
+  std::ranges::adjacent_transform_view<ApproximatelySizedNotConstView, Fn, N> v(
+      ApproximatelySizedNotConstView(5), Fn{});
+  static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+  static_assert(!std::ranges::approximately_sized_range<const decltype(v)>);
+
+  auto expected_hint = 5 - (N - 1);
+  assert(v.reserve_hint() == expected_hint);
+}
+
+template <std::size_t N, class Fn>
+constexpr void test_empty_range() {
+  std::ranges::adjacent_transform_view<ApproximatelySizedView, Fn, N> v(ApproximatelySizedView(0), Fn{});
+  static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+  static_assert(std::ranges::approximately_sized_range<const decltype(v)>);
+
+  assert(v.reserve_hint() == 0);
+  assert(std::as_const(v).reserve_hint() == 0);
+}
+
+template <std::size_t N, class Fn>
+constexpr void test_N_greater_than_size() {
+  if constexpr (N > 2) {
+    std::ranges::adjacent_transform_view<ApproximatelySizedView, Fn, N> v(ApproximatelySizedView(2), Fn{});
+    static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+    static_assert(std::ranges::approximately_sized_range<const decltype(v)>);
+    assert(v.reserve_hint() == 0);
+    assert(std::as_const(v).reserve_hint() == 0);
+  }
+}
+
+template <std::size_t N, class Fn>
+constexpr void test() {
+  test_approx_sized_view<N, Fn>();
+  test_nonconst_approx_sized<N, Fn>();
+  test_empty_range<N, Fn>();
+  test_N_greater_than_size<N, Fn>();
+}
+
+template <std::size_t N>
+constexpr void test() {
+  test<N, MakeTuple>();
+  test<N, Tie>();
+  test<N, GetFirst>();
+  test<N, Multiply>();
+}
+
+constexpr bool test() {
+  // non-approximately-sized range has no reserve_hint
+  static_assert(!std::ranges::approximately_sized_range<
+                std::ranges::adjacent_transform_view<NonApproximatelySizedView, Multiply, 2>>);
+  static_assert(!std::ranges::approximately_sized_range<
+                const std::ranges::adjacent_transform_view<NonApproximatelySizedView, Multiply, 2>>);
+
+  test<1>();
+  test<2>();
+  test<3>();
+  test<5>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.adjacent/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.adjacent/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..d55e90112fad3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.adjacent/reserve_hint.pass.cpp
@@ -0,0 +1,108 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<View>;
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const View>;
+
+#include <cassert>
+#include <ranges>
+#include <utility>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+
+int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+struct NonApproximatelySizedView : std::ranges::view_base {
+  using iterator = forward_iterator<int*>;
+  iterator begin() const;
+  iterator end() const;
+};
+
+struct ApproximatelySizedView : std::ranges::view_base {
+  unsigned int size_;
+  constexpr explicit ApproximatelySizedView(unsigned int size) : size_(size) {}
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + size_); }
+  constexpr unsigned int reserve_hint() const { return size_; }
+};
+
+struct ApproximatelySizedNotConstView : std::ranges::view_base {
+  unsigned int size_;
+  constexpr explicit ApproximatelySizedNotConstView(unsigned int size) : size_(size) {}
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + size_); }
+  constexpr unsigned int reserve_hint() { return size_; }
+};
+
+template <std::size_t N>
+constexpr void test() {
+  {
+    // Test with different values of N for an approximately sized view
+    std::ranges::adjacent_view<ApproximatelySizedView, N> v(ApproximatelySizedView(5));
+    static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+    static_assert(std::ranges::approximately_sized_range<const decltype(v)>);
+
+    auto expected_hint = 5 - (N - 1);
+    assert(v.reserve_hint() == expected_hint);
+    assert(std::as_const(v).reserve_hint() == expected_hint);
+  }
+  {
+    // Test with different values of N for a non-const approximately sized view
+    std::ranges::adjacent_view<ApproximatelySizedNotConstView, N> v(ApproximatelySizedNotConstView(5));
+    static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+    static_assert(!std::ranges::approximately_sized_range<const decltype(v)>);
+
+    auto expected_hint = 5 - (N - 1);
+    assert(v.reserve_hint() == expected_hint);
+  }
+  {
+    // empty range
+    std::ranges::adjacent_view<ApproximatelySizedView, N> v(ApproximatelySizedView(0));
+    static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+    static_assert(std::ranges::approximately_sized_range<const decltype(v)>);
+
+    assert(v.reserve_hint() == 0);
+    assert(std::as_const(v).reserve_hint() == 0);
+  }
+  {
+    // N greater than range size
+    if constexpr (N > 2) {
+      std::ranges::adjacent_view<ApproximatelySizedView, N> v(ApproximatelySizedView(2));
+      static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+      static_assert(std::ranges::approximately_sized_range<const decltype(v)>);
+      assert(v.reserve_hint() == 0);
+      assert(std::as_const(v).reserve_hint() == 0);
+    }
+  }
+}
+
+constexpr bool test() {
+  // non-approximately-sized range has no reserve_hint
+  static_assert(!std::ranges::approximately_sized_range<std::ranges::adjacent_view<NonApproximatelySizedView, 2>>);
+  static_assert(
+      !std::ranges::approximately_sized_range<const std::ranges::adjacent_view<NonApproximatelySizedView, 2>>);
+
+  test<1>();
+  test<2>();
+  test<3>();
+  test<5>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..41a30d9355429
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/reserve_hint.pass.cpp
@@ -0,0 +1,86 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<R>
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const R>
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <utility>
+
+#include "test_iterators.h"
+
+int globalBuff[8];
+
+template <class T>
+concept HasReserveHint = requires(T t) { t.reserve_hint(); };
+
+constexpr bool test() {
+  {
+    struct NoReserveHint {
+      bidirectional_iterator<int*> begin();
+      bidirectional_iterator<int*> end();
+    };
+    using OwningView = std::ranges::owning_view<NoReserveHint>;
+    static_assert(!HasReserveHint<OwningView&>);
+    static_assert(!HasReserveHint<OwningView&&>);
+    static_assert(!HasReserveHint<const OwningView&>);
+    static_assert(!HasReserveHint<const OwningView&&>);
+  }
+  {
+    struct ReserveHintMember {
+      bidirectional_iterator<int*> begin();
+      bidirectional_iterator<int*> end();
+      int reserve_hint() const;
+    };
+    using OwningView = std::ranges::owning_view<ReserveHintMember>;
+    static_assert(!std::ranges::sized_range<OwningView&>);
+    static_assert(std::ranges::approximately_sized_range<OwningView&>);
+    static_assert(!std::ranges::range<const OwningView&>); // no begin/end
+    static_assert(HasReserveHint<OwningView&>);
+    static_assert(HasReserveHint<OwningView&&>);
+    static_assert(!HasReserveHint<const OwningView&>); // not a range, therefore no reserve_hint()
+    static_assert(!HasReserveHint<const OwningView&&>);
+  }
+  {
+    // Test an empty view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a));
+    assert(ov.reserve_hint() == 0);
+    assert(std::as_const(ov).reserve_hint() == 0);
+  }
+  {
+    // Test a non-empty view.
+    int a[] = {1};
+    auto ov = std::ranges::owning_view(std::ranges::subrange(a, a + 1));
+    assert(ov.reserve_hint() == 1);
+    assert(std::as_const(ov).reserve_hint() == 1);
+  }
+  {
+    // Test a non-view.
+    std::array<int, 2> a = {1, 2};
+    auto ov              = std::ranges::owning_view(std::move(a));
+    assert(ov.reserve_hint() == 2);
+    assert(std::as_const(ov).reserve_hint() == 2);
+  }
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.ref.view/range.ref.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.ref.view/range.ref.view.pass.cpp
index 88e7179da5496..d527ead60cfc3 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.all/range.ref.view/range.ref.view.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.ref.view/range.ref.view.pass.cpp
@@ -109,6 +109,20 @@ concept DataIsInvocable = requires (std::ranges::ref_view<R> view) { view.data()
 static_assert(std::same_as<decltype(std::ranges::ref_view(std::declval<Range&>())),
               std::ranges::ref_view<Range>>);
 
+#if TEST_STD_VER >= 26
+template <class R>
+concept ReserveHintIsInvocable = requires(std::ranges::ref_view<R> view) { view.reserve_hint(); };
+
+struct ApproximatelySizedRange {
+  int start_;
+  unsigned int reserve_hint_;
+
+  constexpr auto begin() const { return forward_iterator<int*>(globalBuff + start_); }
+  constexpr auto end() const { return forward_iterator<int*>(globalBuff + 8); }
+  constexpr unsigned int reserve_hint() const { return reserve_hint_; }
+};
+#endif
+
 constexpr bool test() {
   {
     // ref_view::base
@@ -184,6 +198,21 @@ constexpr bool test() {
     static_assert(!SizeIsInvocable<ForwardRange>);
   }
 
+#if TEST_STD_VER >= 26
+  // ref_view::reserve_hint
+  {
+    ApproximatelySizedRange range1{2, 5};
+    std::ranges::ref_view<ApproximatelySizedRange> view1 = range1;
+    assert(view1.reserve_hint() == 5);
+
+    ApproximatelySizedRange range2{7, 0};
+    std::ranges::ref_view<ApproximatelySizedRange> view2 = range2;
+    assert(view2.reserve_hint() == 0);
+
+    static_assert(!ReserveHintIsInvocable<ForwardRange>);
+  }
+#endif
+
   {
     // ref_view::data
     Range range1;
diff --git a/libcxx/test/std/ranges/range.adaptors/range.as.rvalue/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.as.rvalue/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..2acdb9d6e7ce5
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.as.rvalue/reserve_hint.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// <ranges>
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<V>;
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const V>;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+
+// forward_iterator + sentinel end so that ranges::size doesn't apply,
+// making these ranges approximately_sized only via their member reserve_hint().
+
+struct ConstReserveHintView : std::ranges::view_base {
+  bool* hint_called;
+  constexpr auto begin() const { return forward_iterator<int*>(nullptr); }
+  constexpr auto end() const { return sentinel_wrapper<forward_iterator<int*>>(forward_iterator<int*>(nullptr)); }
+
+  constexpr unsigned int reserve_hint() const {
+    *hint_called = true;
+    return 3;
+  }
+};
+
+struct NonConstReserveHintView : std::ranges::view_base {
+  bool* hint_called;
+  constexpr auto begin() const { return forward_iterator<int*>(nullptr); }
+  constexpr auto end() const { return sentinel_wrapper<forward_iterator<int*>>(forward_iterator<int*>(nullptr)); }
+
+  constexpr unsigned int reserve_hint() {
+    *hint_called = true;
+    return 5;
+  }
+};
+
+struct NoReserveHintView : std::ranges::view_base {
+  constexpr auto begin() const { return forward_iterator<int*>(nullptr); }
+  constexpr auto end() const { return sentinel_wrapper<forward_iterator<int*>>(forward_iterator<int*>(nullptr)); }
+};
+
+template <class T>
+concept HasReserveHint = requires(T v) { v.reserve_hint(); };
+
+static_assert(!std::ranges::sized_range<std::ranges::as_rvalue_view<ConstReserveHintView>>);
+static_assert(!std::ranges::sized_range<std::ranges::as_rvalue_view<NonConstReserveHintView>>);
+static_assert(!std::ranges::sized_range<std::ranges::as_rvalue_view<NoReserveHintView>>);
+
+static_assert(HasReserveHint<std::ranges::as_rvalue_view<ConstReserveHintView>>);
+static_assert(HasReserveHint<const std::ranges::as_rvalue_view<ConstReserveHintView>>);
+static_assert(HasReserveHint<std::ranges::as_rvalue_view<NonConstReserveHintView>>);
+static_assert(!HasReserveHint<const std::ranges::as_rvalue_view<NonConstReserveHintView>>);
+static_assert(!HasReserveHint<std::ranges::as_rvalue_view<NoReserveHintView>>);
+static_assert(!HasReserveHint<const std::ranges::as_rvalue_view<NoReserveHintView>>);
+
+constexpr bool test() {
+  {
+    bool hint_called = false;
+    std::ranges::as_rvalue_view view(ConstReserveHintView{{}, &hint_called});
+    assert(view.reserve_hint() == 3);
+    assert(hint_called);
+  }
+
+  {
+    bool hint_called = false;
+    std::ranges::as_rvalue_view view(NonConstReserveHintView{{}, &hint_called});
+    assert(view.reserve_hint() == 5);
+    assert(hint_called);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..eb900e6432fc0
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/reserve_hint.pass.cpp
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<V>;
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const V>;
+
+#include <ranges>
+#include <cassert>
+
+#include "test_iterators.h"
+#include "types.h"
+
+template <class View>
+concept ReserveHintEnabled = requires(View v) { v.reserve_hint(); };
+
+constexpr bool test() {
+  int buf[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    static_assert(ReserveHintEnabled<std::ranges::common_view<ApproximatelySizedView>&>);
+    static_assert(ReserveHintEnabled<std::ranges::common_view<ApproximatelySizedView> const&>);
+    static_assert(!ReserveHintEnabled<std::ranges::common_view<CopyableView>&>);
+    static_assert(!ReserveHintEnabled<std::ranges::common_view<CopyableView> const&>);
+    static_assert(ReserveHintEnabled<std::ranges::common_view<NonConstApproximatelySizedView>&>);
+    static_assert(!ReserveHintEnabled<std::ranges::common_view<NonConstApproximatelySizedView> const&>);
+  }
+
+  {
+    ApproximatelySizedView view(buf, buf + 8, 5);
+    std::ranges::common_view<ApproximatelySizedView> common(view);
+    assert(common.reserve_hint() == 5);
+  }
+
+  {
+    ApproximatelySizedView view(buf, buf + 8, 5);
+    const std::ranges::common_view<ApproximatelySizedView> common(view);
+    assert(common.reserve_hint() == 5);
+  }
+
+  {
+    NonConstApproximatelySizedView view(buf, buf + 8, 5);
+    std::ranges::common_view<NonConstApproximatelySizedView> common(view);
+    assert(common.reserve_hint() == 5);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
index 56f2f6ad5fcbf..3dc8fdc670cb5 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
@@ -123,4 +123,35 @@ static_assert(HasConstAndNonConstBegin<std::ranges::common_view<NonSimpleNonComm
 static_assert(HasConstBegin<const std::ranges::common_view<NonSimpleNonCommonView>>);
 static_assert(HasOnlyConstBegin<const std::ranges::common_view<NonSimpleNonCommonView>>);
 
+#if TEST_STD_VER >= 26
+
+struct ApproximatelySizedView : std::ranges::view_base {
+  int* begin_;
+  int* end_;
+  unsigned int hint_;
+  constexpr explicit ApproximatelySizedView(int* b, int* e, unsigned int hint) : begin_(b), end_(e), hint_(hint) {}
+  constexpr auto begin() const { return forward_iterator<int*>(begin_); }
+  constexpr auto end() const { return sentinel_wrapper<forward_iterator<int*>>(forward_iterator<int*>(end_)); }
+  constexpr unsigned int reserve_hint() const { return hint_; }
+};
+static_assert(!std::ranges::common_range<ApproximatelySizedView>);
+static_assert(std::ranges::approximately_sized_range<ApproximatelySizedView>);
+static_assert(std::ranges::approximately_sized_range<const ApproximatelySizedView>);
+
+struct NonConstApproximatelySizedView : std::ranges::view_base {
+  int* begin_;
+  int* end_;
+  unsigned int hint_;
+  constexpr explicit NonConstApproximatelySizedView(int* b, int* e, unsigned int hint)
+      : begin_(b), end_(e), hint_(hint) {}
+  constexpr auto begin() const { return forward_iterator<int*>(begin_); }
+  constexpr auto end() const { return sentinel_wrapper<forward_iterator<int*>>(forward_iterator<int*>(end_)); }
+  constexpr unsigned int reserve_hint() { return hint_; }
+};
+static_assert(!std::ranges::common_range<NonConstApproximatelySizedView>);
+static_assert(std::ranges::approximately_sized_range<NonConstApproximatelySizedView>);
+static_assert(!std::ranges::approximately_sized_range<const NonConstApproximatelySizedView>);
+
+#endif // TEST_STD_VER >= 26
+
 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_COMMON_VIEW_TYPES_H
diff --git a/libcxx/test/std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..1652d33eafe0c
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp
@@ -0,0 +1,107 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// <ranges>
+
+// constexpr auto reserve_hint()
+//     requires (approximately_sized_range<Views> && ...);
+// constexpr auto reserve_hint() const
+//     requires (approximately_sized_range<const Views> && ...);
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+// All views use forward_iterator as their iterator so that ranges::size doesn't apply,
+// making approximately_sized_range depend solely on the reserve_hint() member.
+
+int buffer[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+struct ApproximatelySizedView : std::ranges::view_base {
+  unsigned int hint_;
+  constexpr explicit ApproximatelySizedView(unsigned int hint) : hint_(hint) {}
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + hint_); }
+  constexpr unsigned int reserve_hint() const { return hint_; }
+};
+
+struct ApproximatelySizedNotConstView : std::ranges::view_base {
+  unsigned int hint_;
+  constexpr explicit ApproximatelySizedNotConstView(unsigned int hint) : hint_(hint) {}
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + hint_); }
+  constexpr unsigned int reserve_hint() { return hint_; }
+};
+
+struct IntHintView : std::ranges::view_base {
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + 4); }
+  constexpr int reserve_hint() const { return 4; }
+};
+
+struct UnsignedHintView : std::ranges::view_base {
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + 5); }
+  constexpr unsigned int reserve_hint() const { return 5; }
+};
+
+struct NoHintView : std::ranges::view_base {
+  constexpr auto begin() const { return forward_iterator<int*>(buffer); }
+  constexpr auto end() const { return forward_iterator<int*>(buffer + 3); }
+};
+
+constexpr bool test() {
+  {
+    // single range
+    std::ranges::concat_view v(ApproximatelySizedView(8));
+    assert(v.reserve_hint() == 8);
+    assert(std::as_const(v).reserve_hint() == 8);
+  }
+
+  {
+    // multiple ranges same type
+    std::ranges::concat_view v(ApproximatelySizedView(2), ApproximatelySizedView(3));
+    assert(v.reserve_hint() == 5);
+    assert(std::as_const(v).reserve_hint() == 5);
+  }
+
+  {
+    // const-view non-approximately-sized range
+    std::ranges::concat_view v(ApproximatelySizedNotConstView(2), ApproximatelySizedView(3));
+    assert(v.reserve_hint() == 5);
+    static_assert(std::ranges::approximately_sized_range<decltype(v)>);
+    static_assert(!std::ranges::approximately_sized_range<decltype(std::as_const(v))>);
+  }
+
+  {
+    // underlying range not approximately-sized
+    std::ranges::concat_view v(NoHintView{}, ApproximatelySizedView(8));
+    static_assert(!std::ranges::approximately_sized_range<decltype(v)>);
+    static_assert(!std::ranges::approximately_sized_range<decltype(std::as_const(v))>);
+  }
+
+  {
+    // two ranges with different hint types: common type of int and unsigned int is unsigned int
+    std::ranges::concat_view v(IntHintView{}, UnsignedHintView{});
+    assert(v.reserve_hint() == 9);
+    ASSERT_SAME_TYPE(decltype(v.reserve_hint()), unsigned int);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.drop/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..33045591c412d
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.drop/reserve_hint.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//   requires approximately_sized_range<V>
+// constexpr auto reserve_hint() const
+//   requires approximately_sized_range<const V>
+
+#include <cassert>
+#include <ranges>
+
+#include "test_macros.h"
+#include "types.h"
+
+template <class T>
+concept ReserveHintInvocable = requires(std::ranges::drop_view<T> t) { t.reserve_hint(); };
+
+constexpr bool test() {
+  // approximately_sized_range<V>
+  std::ranges::drop_view dropView1(MoveOnlyView(), 4);
+  assert(dropView1.reserve_hint() == 4);
+
+  // approximately_sized_range<V>
+  std::ranges::drop_view dropView2(MoveOnlyView(), 0);
+  assert(dropView2.reserve_hint() == 8);
+
+  // approximately_sized_range<const V>
+  const std::ranges::drop_view dropView3(MoveOnlyView(), 8);
+  assert(dropView3.reserve_hint() == 0);
+
+  // approximately_sized_range<const V>
+  const std::ranges::drop_view dropView4(MoveOnlyView(), 10);
+  assert(dropView4.reserve_hint() == 0);
+
+  // mutable-only approximately_sized_range
+  std::ranges::drop_view dropView5(ApproximatelySizedNotConstView(8), 3);
+  assert(dropView5.reserve_hint() == 5);
+  static_assert(ReserveHintInvocable<ApproximatelySizedNotConstView>);
+  static_assert(!ReserveHintInvocable<const ApproximatelySizedNotConstView>);
+
+  // Because ForwardView is not approximately_sized_range.
+  static_assert(!ReserveHintInvocable<ForwardView>);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/types.h b/libcxx/test/std/ranges/range.adaptors/range.drop/types.h
index 73d1e5045ad22..c0bb72a138d8b 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.drop/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.drop/types.h
@@ -141,4 +141,18 @@ struct View : std::ranges::view_base {
   int* end_;
 };
 
+#if TEST_STD_VER >= 26
+
+struct ApproximatelySizedNotConstView : std::ranges::view_base {
+  unsigned int hint_;
+  constexpr explicit ApproximatelySizedNotConstView(unsigned int hint) : hint_(hint) {}
+  constexpr forward_iterator<int*> begin() const { return forward_iterator<int*>(globalBuff); }
+  constexpr forward_iterator<int*> end() const { return forward_iterator<int*>(globalBuff + 8); }
+  constexpr unsigned int reserve_hint() { return hint_; }
+};
+static_assert(std::ranges::approximately_sized_range<ApproximatelySizedNotConstView>);
+static_assert(!std::ranges::approximately_sized_range<const ApproximatelySizedNotConstView>);
+
+#endif // TEST_STD_VER >= 26
+
 #endif // TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_DROP_TYPES_H
diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..085648add5c99
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.elements/reserve_hint.pass.cpp
@@ -0,0 +1,90 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// <ranges>
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<V>
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const V>
+
+#include <cassert>
+#include <ranges>
+#include <tuple>
+
+#include "types.h"
+
+template <class T>
+concept HasReserveHint = requires(T t) { t.reserve_hint(); };
+
+struct NonApproximatelySized : std::ranges::view_base {
+  using iterator = forward_iterator<std::tuple<int>*>;
+  iterator begin() const;
+  iterator end() const;
+};
+static_assert(!std::ranges::approximately_sized_range<NonApproximatelySized>);
+static_assert(!std::ranges::approximately_sized_range<const NonApproximatelySized>);
+
+static_assert(!HasReserveHint<std::ranges::elements_view<NonApproximatelySized, 0>>);
+static_assert(!HasReserveHint<const std::ranges::elements_view<NonApproximatelySized, 0>>);
+
+struct ApproximatelySizedTupleView : TupleBufferView {
+  unsigned int hint_;
+
+  template <std::size_t N>
+  constexpr ApproximatelySizedTupleView(std::tuple<int> (&buf)[N], unsigned int hint)
+      : TupleBufferView(buf), hint_(hint) {}
+
+  constexpr auto begin() const { return forward_iterator<std::tuple<int>*>(buffer_); }
+  constexpr auto end() const { return forward_iterator<std::tuple<int>*>(buffer_ + size_); }
+  constexpr unsigned int reserve_hint() const { return hint_; }
+};
+static_assert(HasReserveHint<std::ranges::elements_view<ApproximatelySizedTupleView, 0>>);
+static_assert(HasReserveHint<const std::ranges::elements_view<ApproximatelySizedTupleView, 0>>);
+
+struct ApproximatelySizedNotConstTupleView : TupleBufferView {
+  unsigned int hint_;
+
+  template <std::size_t N>
+  constexpr ApproximatelySizedNotConstTupleView(std::tuple<int> (&buf)[N], unsigned int hint)
+      : TupleBufferView(buf), hint_(hint) {}
+
+  constexpr auto begin() const { return forward_iterator<std::tuple<int>*>(buffer_); }
+  constexpr auto end() const { return forward_iterator<std::tuple<int>*>(buffer_ + size_); }
+  constexpr unsigned int reserve_hint() { return hint_; }
+};
+static_assert(HasReserveHint<std::ranges::elements_view<ApproximatelySizedNotConstTupleView, 0>>);
+static_assert(!HasReserveHint<const std::ranges::elements_view<ApproximatelySizedNotConstTupleView, 0>>);
+
+constexpr bool test() {
+  std::tuple<int> buffer[] = {{1}, {2}, {3}};
+
+  // non-const and const are approximately_sized
+  {
+    auto ev = std::views::elements<0>(ApproximatelySizedTupleView(buffer, 5));
+    assert(ev.reserve_hint() == 5);
+    assert(std::as_const(ev).reserve_hint() == 5);
+  }
+
+  {
+    // mutable-only approximately_sized_range
+    auto ev = std::views::elements<0>(ApproximatelySizedNotConstTupleView(buffer, 5));
+    assert(ev.reserve_hint() == 5);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..bd391377e3a08
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp
@@ -0,0 +1,82 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// <ranges>
+
+// class enumerate_view
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<V>;
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const V>;
+
+#include <cassert>
+#include <ranges>
+
+#include "test_iterators.h"
+
+#include "types.h"
+
+template <class T>
+concept HasMemberReserveHint = requires(T t) { t.reserve_hint(); };
+
+static constexpr int globalBuff[8] = {};
+
+struct NonApproximatelySizedView : std::ranges::view_base {
+  using iterator = forward_iterator<const int*>;
+  iterator begin() const;
+  iterator end() const;
+};
+
+static_assert(!std::ranges::approximately_sized_range<NonApproximatelySizedView>);
+static_assert(!std::ranges::approximately_sized_range<const NonApproximatelySizedView>);
+
+static_assert(!HasMemberReserveHint<std::ranges::enumerate_view<NonApproximatelySizedView>>);
+static_assert(!HasMemberReserveHint<const std::ranges::enumerate_view<NonApproximatelySizedView>>);
+
+struct ApproximatelySizedView : std::ranges::view_base {
+  unsigned int size_;
+  constexpr explicit ApproximatelySizedView(unsigned int hint) : size_(hint) {}
+  constexpr auto begin() const { return forward_iterator<const int*>(globalBuff); }
+  constexpr auto end() const { return forward_iterator<const int*>(globalBuff + 8); }
+  constexpr unsigned int reserve_hint() const { return size_; }
+};
+
+static_assert(HasMemberReserveHint<std::ranges::enumerate_view<ApproximatelySizedView>>);
+static_assert(HasMemberReserveHint<const std::ranges::enumerate_view<ApproximatelySizedView>>);
+
+struct ApproximatelySizedNotConstView : std::ranges::view_base {
+  unsigned int size_;
+  constexpr explicit ApproximatelySizedNotConstView(unsigned int hint) : size_(hint) {}
+  constexpr auto begin() const { return forward_iterator<const int*>(globalBuff); }
+  constexpr auto end() const { return forward_iterator<const int*>(globalBuff + 8); }
+  constexpr unsigned int reserve_hint() { return size_; }
+};
+
+static_assert(HasMemberReserveHint<std::ranges::enumerate_view<ApproximatelySizedNotConstView>>);
+static_assert(!HasMemberReserveHint<const std::ranges::enumerate_view<ApproximatelySizedNotConstView>>);
+
+constexpr bool test() {
+  // Non-const and const are reserve_hint-able
+  {
+    auto view = std::views::enumerate(ApproximatelySizedView{5});
+    assert(view.reserve_hint() == 5);
+    assert(std::as_const(view).reserve_hint() == 5);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..91ced350bbaad
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/reserve_hint.pass.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<V>
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const V>
+
+#include <cassert>
+#include <ranges>
+
+#include "test_macros.h"
+#include "types.h"
+
+// end -  begin = 8, but size may return something else.
+template <CopyCategory CC>
+struct BidirApproxSizedRange : std::ranges::view_base {
+  int* ptr_;
+  std::size_t reserve_hint_;
+
+  constexpr BidirApproxSizedRange(int* ptr, std::size_t reserve_hint) : ptr_(ptr), reserve_hint_(reserve_hint) {}
+  constexpr BidirApproxSizedRange(const BidirApproxSizedRange&)
+    requires(CC == Copyable)
+  = default;
+  constexpr BidirApproxSizedRange(BidirApproxSizedRange&&)
+    requires(CC == MoveOnly)
+  = default;
+  constexpr BidirApproxSizedRange& operator=(const BidirApproxSizedRange&)
+    requires(CC == Copyable)
+  = default;
+  constexpr BidirApproxSizedRange& operator=(BidirApproxSizedRange&&)
+    requires(CC == MoveOnly)
+  = default;
+
+  constexpr bidirectional_iterator<int*> begin() { return bidirectional_iterator<int*>{ptr_}; }
+  constexpr bidirectional_iterator<const int*> begin() const { return bidirectional_iterator<const int*>{ptr_}; }
+  constexpr bidirectional_iterator<int*> end() { return bidirectional_iterator<int*>{ptr_ + 8}; }
+  constexpr bidirectional_iterator<const int*> end() const { return bidirectional_iterator<const int*>{ptr_ + 8}; }
+
+  constexpr std::size_t size() const { return reserve_hint_; }
+};
+
+constexpr bool test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  // Non-common, non-const bidirectional range.
+  {
+    auto rev = std::ranges::reverse_view(BidirApproxSizedRange<Copyable>{buffer, 4});
+    assert(std::ranges::reserve_hint(rev) == 4);
+    assert(rev.reserve_hint() == 4);
+    assert(std::move(rev).reserve_hint() == 4);
+
+    ASSERT_SAME_TYPE(decltype(rev.reserve_hint()), std::size_t);
+    ASSERT_SAME_TYPE(decltype(std::move(rev).reserve_hint()), std::size_t);
+  }
+  // Non-common, const bidirectional range.
+  {
+    const auto rev = std::ranges::reverse_view(BidirApproxSizedRange<Copyable>{buffer, 4});
+    assert(std::ranges::reserve_hint(rev) == 4);
+    assert(rev.reserve_hint() == 4);
+    assert(std::move(rev).reserve_hint() == 4);
+
+    ASSERT_SAME_TYPE(decltype(rev.reserve_hint()), std::size_t);
+    ASSERT_SAME_TYPE(decltype(std::move(rev).reserve_hint()), std::size_t);
+  }
+  // Non-common, non-const (move only) bidirectional range.
+  {
+    auto rev = std::ranges::reverse_view(BidirApproxSizedRange<MoveOnly>{buffer, 4});
+    assert(std::move(rev).reserve_hint() == 4);
+
+    ASSERT_SAME_TYPE(decltype(std::move(rev).reserve_hint()), std::size_t);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.stride.view/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..97b4dcfc8b4a4
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/reserve_hint.pass.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<V>
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const V>
+
+#include <cassert>
+#include <ranges>
+
+#include "types.h"
+
+// There is no reserve_hint function on a stride view over a view that
+// is *not* an approximately sized range
+static_assert(!std::ranges::approximately_sized_range<BasicTestView<cpp17_input_iterator<int*>>>);
+static_assert(
+    !std::ranges::approximately_sized_range<std::ranges::stride_view<BasicTestView<cpp17_input_iterator<int*>>>>);
+
+// There is a reserve_hint function on a stride view over a view that
+// *is *an approximately sized range
+static_assert(std::ranges::approximately_sized_range<
+              BasicTestView<int*, sentinel_wrapper<int*>, /*IsSized=*/false, /*IsApproximatelySized=*/true>>);
+static_assert(std::ranges::approximately_sized_range<std::ranges::stride_view<
+                  BasicTestView<int*, sentinel_wrapper<int*>, /*IsSized=*/false, /*IsApproximatelySized=*/true>>>);
+
+using Iota = std::ranges::iota_view<int, int>;
+using ApproximatelySizedView =
+    BasicTestView<std::ranges::iterator_t<Iota>,
+                  std::ranges::sentinel_t<Iota>,
+                  /*IsSized=*/false,
+                  /*IsApproximatelySized=*/true>;
+
+constexpr ApproximatelySizedView make_approximately_sized(Iota&& iota) {
+  return ApproximatelySizedView(std::ranges::begin(iota), std::ranges::end(iota));
+}
+
+constexpr bool test() {
+  {
+    // Test with stride as exact multiple of number of elements in view strided over.
+    auto view    = make_approximately_sized(std::views::iota(0, 12));
+    auto strided = std::views::stride(view, 3);
+    static_assert(std::ranges::approximately_sized_range<decltype(strided)>);
+    assert(strided.reserve_hint() == 4);
+  }
+
+  {
+    // Test with stride as inexact multiple of number of elements in view strided over.
+    auto view = make_approximately_sized(std::views::iota(0, 22));
+    static_assert(std::ranges::approximately_sized_range<decltype(view)>);
+    auto strided = std::views::stride(view, 3);
+    static_assert(std::ranges::approximately_sized_range<decltype(strided)>);
+    assert(strided.size() == 8);
+  }
+
+  {
+    // Empty range.
+    auto view    = make_approximately_sized(std::views::iota(0, 0));
+    auto strided = view | std::views::stride(3);
+    assert(strided.reserve_hint() == 0);
+  }
+
+  {
+    // Stride larger than range size.
+    auto view    = make_approximately_sized(std::views::iota(0, 3));
+    auto strided = view | std::views::stride(10);
+    assert(strided.reserve_hint() == 1);
+  }
+
+  {
+    // Stride equal to range size.
+    auto view    = make_approximately_sized(std::views::iota(0, 3));
+    auto strided = view | std::views::stride(5);
+    assert(strided.reserve_hint() == 1);
+  }
+
+  {
+    // Stride of 1.
+    auto view    = make_approximately_sized(std::views::iota(0, 7));
+    auto strided = view | std::views::stride(1);
+    assert(strided.size() == 7);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h
index 5a8d6b6ca2f71..49da1473dc4e1 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.stride.view/types.h
@@ -172,8 +172,9 @@ struct MaybeView<true> : std::ranges::view_base {};
 template <std::input_iterator Iter,
           std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>,
           bool IsSized                 = false,
+          bool IsApproximatelySized    = false,
           bool IsView                  = false,
-          bool IsCopyable              = false >
+          bool IsCopyable              = false>
   requires((!IsSized) || (IsSized && IterDifferable<Iter>))
 struct BasicTestViewOrRange : MaybeView<IsView> {
   Iter begin_{};
@@ -192,6 +193,12 @@ struct BasicTestViewOrRange : MaybeView<IsView> {
     return begin_ - end_;
   }
 
+  constexpr auto reserve_hint() const
+    requires IsApproximatelySized
+  {
+    return begin_ - end_;
+  }
+
   constexpr BasicTestViewOrRange(BasicTestViewOrRange&& other)      = default;
   constexpr BasicTestViewOrRange& operator=(BasicTestViewOrRange&&) = default;
 
@@ -210,12 +217,16 @@ struct BasicTestViewOrRange : MaybeView<IsView> {
   = default;
 };
 
-template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>, bool IsSized = false>
+template <std::input_iterator Iter,
+          std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>,
+          bool IsSized                 = false,
+          bool IsApproximatelySized    = false>
   requires((!IsSized) || (IsSized && IterDifferable<Iter>))
-using BasicTestView = BasicTestViewOrRange<Iter, Sent, IsSized, true /* IsView */, true /* IsCopyable */>;
+using BasicTestView =
+    BasicTestViewOrRange<Iter, Sent, IsSized, IsApproximatelySized, true /* IsView */, true /* IsCopyable */>;
 
 template <std::input_iterator Iter, std::sentinel_for<Iter> Sent = sentinel_wrapper<Iter>, bool IsCopyable = true>
-using MaybeCopyableAlwaysMoveableView = BasicTestViewOrRange<Iter, Sent, false, true, IsCopyable>;
+using MaybeCopyableAlwaysMoveableView = BasicTestViewOrRange<Iter, Sent, false, false, true, IsCopyable>;
 
 static_assert(std::ranges::view<MaybeCopyableAlwaysMoveableView<cpp17_input_iterator<int*>>>);
 static_assert(std::ranges::view<MaybeCopyableAlwaysMoveableView<cpp17_input_iterator<int*>,
diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..65e89e285563f
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.take/reserve_hint.pass.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<V>
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const V>
+
+#include <ranges>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "test_range.h"
+#include "types.h"
+
+template <class T>
+concept ReserveHintEnabled = requires(const std::ranges::take_view<T>& tv) { tv.reserve_hint(); };
+
+constexpr bool test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    static_assert(ReserveHintEnabled<ApproximatelySizedForwardView>);
+  }
+
+  {
+    std::ranges::take_view<SimpleViewNonSized> tv(SimpleViewNonSized{buffer, buffer + 8}, 100);
+    assert(tv.reserve_hint() == 100);
+  }
+
+  {
+    std::ranges::take_view<ApproximatelySizedForwardView> tv(ApproximatelySizedForwardView{buffer}, 0);
+    assert(tv.reserve_hint() == 0);
+  }
+
+  {
+    const std::ranges::take_view<ApproximatelySizedForwardView> tv(ApproximatelySizedForwardView{buffer}, 2);
+    assert(tv.reserve_hint() == 2);
+  }
+
+  {
+    std::ranges::take_view<ApproximatelySizedForwardView> tv(ApproximatelySizedForwardView{buffer}, 4);
+    assert(tv.reserve_hint() == 4);
+  }
+
+  {
+    const std::ranges::take_view<ApproximatelySizedForwardView> tv(ApproximatelySizedForwardView{buffer}, 6);
+    assert(tv.reserve_hint() == 6);
+  }
+
+  {
+    std::ranges::take_view<ApproximatelySizedForwardView> tv(ApproximatelySizedForwardView{buffer}, 8);
+    assert(tv.reserve_hint() == 8);
+  }
+
+  {
+    const std::ranges::take_view<ApproximatelySizedForwardView> tv(ApproximatelySizedForwardView{buffer}, 8);
+    assert(tv.reserve_hint() == 8);
+  }
+
+  {
+    std::ranges::take_view<ApproximatelySizedForwardView> tv(ApproximatelySizedForwardView{buffer}, 10);
+    assert(tv.reserve_hint() == 8);
+  }
+
+  {
+    const std::ranges::take_view<ApproximatelySizedForwardView> tv(ApproximatelySizedForwardView{buffer}, 10);
+    assert(tv.reserve_hint() == 8);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/types.h b/libcxx/test/std/ranges/range.adaptors/range.take/types.h
index 7590ce33bffc1..a51edc93862b1 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.take/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.take/types.h
@@ -54,6 +54,20 @@ static_assert(std::ranges::view<SizedRandomAccessView>);
 static_assert(std::ranges::random_access_range<SizedRandomAccessView>);
 static_assert(std::ranges::sized_range<SizedRandomAccessView>);
 
+#if TEST_STD_VER >= 26
+using ForwardIter = forward_iterator<int*>;
+struct ApproximatelySizedForwardView : std::ranges::view_base {
+  int* ptr_;
+  constexpr explicit ApproximatelySizedForwardView(int* ptr) : ptr_(ptr) {}
+  constexpr auto begin() const { return ForwardIter(ptr_); }
+  constexpr auto end() const { return ForwardIter(ptr_ + 8); }
+  constexpr std::size_t reserve_hint() const { return 8; }
+};
+static_assert(std::ranges::view<ApproximatelySizedForwardView>);
+static_assert(!std::ranges::sized_range<ApproximatelySizedForwardView>);
+static_assert(std::ranges::approximately_sized_range<ApproximatelySizedForwardView>);
+#endif
+
 struct View : std::ranges::view_base {
   constexpr explicit View(int* b, int* e) : begin_(b), end_(e) { }
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/reserve_hint.pass.cpp
new file mode 100644
index 0000000000000..78ae794f82915
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.transform/reserve_hint.pass.cpp
@@ -0,0 +1,44 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++26
+
+// constexpr auto reserve_hint()
+//     requires approximately_sized_range<V>
+// constexpr auto reserve_hint() const
+//     requires approximately_sized_range<const V>
+
+#include <cassert>
+#include <ranges>
+
+#include "types.h"
+
+template <class T>
+concept ReserveHintInvocable = requires(T t) { t.reserve_hint(); };
+
+constexpr bool test() {
+  {
+    std::ranges::transform_view transformView(ApproximatelySizedView{5}, PlusOne{});
+    assert(transformView.reserve_hint() == 5);
+  }
+
+  static_assert(ReserveHintInvocable<std::ranges::transform_view<ApproximatelySizedView, PlusOne>>);
+  static_assert(ReserveHintInvocable<const std::ranges::transform_view<ApproximatelySizedView, PlusOne>>);
+
+  static_assert(ReserveHintInvocable<std::ranges::transform_view<ApproximatelySizedNotConstView, PlusOne>>);
+  static_assert(!ReserveHintInvocable<const std::ranges::transform_view<ApproximatelySizedNotConstView, PlusOne>>);
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/types.h b/libcxx/test/std/ranges/range.adaptors/range.transform/types.h
index e94e7dfcdaeb7..0d94fc02c1f2e 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.transform/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.transform/types.h
@@ -114,6 +114,39 @@ struct SizedSentinelNotConstView : std::ranges::view_base {
 bool operator==(const ForwardIter &lhs, int* rhs);
 bool operator==(int* lhs, const ForwardIter &rhs);
 
+#if TEST_STD_VER >= 26
+struct ApproximatelySizedView : std::ranges::view_base {
+  int start_;
+  unsigned int reserve_hint_;
+
+  constexpr explicit ApproximatelySizedView(unsigned int hint, int start = 0) : start_(start), reserve_hint_(hint) {}
+  constexpr auto begin() const { return forward_iterator<int*>(globalBuff + start_); }
+  constexpr auto end() const { return forward_iterator<int*>(globalBuff + 8); }
+  constexpr unsigned int reserve_hint() const { return reserve_hint_; }
+};
+
+static_assert(std::ranges::view<ApproximatelySizedView>);
+static_assert(!std::ranges::sized_range<ApproximatelySizedView>);
+static_assert(std::ranges::approximately_sized_range<ApproximatelySizedView>);
+static_assert(std::ranges::approximately_sized_range<const ApproximatelySizedView>);
+
+struct ApproximatelySizedNotConstView : std::ranges::view_base {
+  int start_;
+  unsigned int reserve_hint_;
+
+  constexpr explicit ApproximatelySizedNotConstView(unsigned int hint, int start = 0)
+      : start_(start), reserve_hint_(hint) {}
+  constexpr auto begin() const { return forward_iterator<int*>(globalBuff + start_); }
+  constexpr auto end() const { return forward_iterator<int*>(globalBuff + 8); }
+  constexpr unsigned int reserve_hint() { return reserve_hint_; }
+};
+
+static_assert(std::ranges::view<ApproximatelySizedNotConstView>);
+static_assert(!std::ranges::sized_range<ApproximatelySizedNotConstView>);
+static_assert(std::ranges::approximately_sized_range<ApproximatelySizedNotConstView>);
+static_assert(!std::ranges::approximately_sized_range<const ApproximatelySizedNotConstView>);
+#endif
+
 struct Range {
   int *begin() const;
   int *end() const;

>From 59df762a288c647f90e8537524cdfbc9b1f22f6f Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Thu, 25 Jun 2026 01:58:37 -0700
Subject: [PATCH 7/9] Update libc++ c++26 status

---
 libcxx/docs/Status/Cxx26Issues.csv | 2 +-
 libcxx/docs/Status/Cxx26Papers.csv | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/docs/Status/Cxx26Issues.csv b/libcxx/docs/Status/Cxx26Issues.csv
index d4f7a44910e00..804cb2580411f 100644
--- a/libcxx/docs/Status/Cxx26Issues.csv
+++ b/libcxx/docs/Status/Cxx26Issues.csv
@@ -336,7 +336,7 @@
 "`LWG4549 <https://wg21.link/LWG4549>`__","``vprint_nonunicode_buffered`` ignores its stream parameter","2026-03 (Croydon)","","","`#189878 <https://github.com/llvm/llvm-project/issues/189878>`__",""
 "`LWG4550 <https://wg21.link/LWG4550>`__","Need new feature test macros for ``<stdckdint.h>`` and ``<stdbit.h>``","2026-03 (Croydon)","","","`#189879 <https://github.com/llvm/llvm-project/issues/189879>`__",""
 "`LWG4552 <https://wg21.link/LWG4552>`__","``compare_exchange_weak`` writes a value on spurious failure, not memory contents","2026-03 (Croydon)","","","`#189880 <https://github.com/llvm/llvm-project/issues/189880>`__",""
-"`LWG4553 <https://wg21.link/LWG4553>`__","Wording for FR-025-246 25.7.18.2 Add a ``reserve_hint`` function to ``concat_view``","2026-03 (Croydon)","","","`#189881 <https://github.com/llvm/llvm-project/issues/189881>`__",""
+"`LWG4553 <https://wg21.link/LWG4553>`__","Wording for FR-025-246 25.7.18.2 Add a ``reserve_hint`` function to ``concat_view``","2026-03 (Croydon)","|Complete|","23","`#189881 <https://github.com/llvm/llvm-project/issues/189881>`__",""
 "`LWG4554 <https://wg21.link/LWG4554>`__","Remove undefined behaviour from ``hive`` for invalid limits","2026-03 (Croydon)","","","`#189882 <https://github.com/llvm/llvm-project/issues/189882>`__",""
 "`LWG4555 <https://wg21.link/LWG4555>`__","Remove ``is_consteval_only``","2026-03 (Croydon)","","","`#189883 <https://github.com/llvm/llvm-project/issues/189883>`__",""
 "`LWG4556 <https://wg21.link/LWG4556>`__","Unclear properties of reflection strings","2026-03 (Croydon)","","","`#189884 <https://github.com/llvm/llvm-project/issues/189884>`__",""
diff --git a/libcxx/docs/Status/Cxx26Papers.csv b/libcxx/docs/Status/Cxx26Papers.csv
index 9744940459bcd..f4d57a47a0c8f 100644
--- a/libcxx/docs/Status/Cxx26Papers.csv
+++ b/libcxx/docs/Status/Cxx26Papers.csv
@@ -112,7 +112,7 @@
 "`P3430R3 <https://wg21.link/P3430R3>`__","simd issues: explicit, unsequenced, identity-element position, and members of disabled simd","2025-02 (Hagenberg)","","","`#127881 <https://github.com/llvm/llvm-project/issues/127881>`__",""
 "`P2663R7 <https://wg21.link/P2663R7>`__","Interleaved complex values support in ``std::simd``","2025-02 (Hagenberg)","","","`#127882 <https://github.com/llvm/llvm-project/issues/127882>`__",""
 "`P2933R4 <https://wg21.link/P2933R4>`__","Extend ``<bit>`` header function with overloads for ``std::simd``","2025-02 (Hagenberg)","","","`#127883 <https://github.com/llvm/llvm-project/issues/127883>`__",""
-"`P2846R6 <https://wg21.link/P2846R6>`__","``reserve_hint``: Eagerly reserving memory for not-quite-sized lazy ranges","2025-02 (Hagenberg)","","","`#127884 <https://github.com/llvm/llvm-project/issues/127884>`__",""
+"`P2846R6 <https://wg21.link/P2846R6>`__","``reserve_hint``: Eagerly reserving memory for not-quite-sized lazy ranges","2025-02 (Hagenberg)","|Partial|","23","`#127884 <https://github.com/llvm/llvm-project/issues/127884>`__","``__cpp_lib_ranges_reserve_hint`` is not set. Container operations that take a range as input do not respect ``reserve_hint``. ``chunk_view`` and ``slide_view`` support blocked on `P2442R1 <https://wg21.link/P2442R1>`__. ``as_const_view`` support blocked on `P2278R4 <https://wg21.link/P2278R4>`__."
 "`P3471R4 <https://wg21.link/P3471R4>`__","Standard Library Hardening","2025-02 (Hagenberg)","","","`#127885 <https://github.com/llvm/llvm-project/issues/127885>`__",""
 "`P0447R28 <https://wg21.link/P0447R28>`__","Introduction of ``std::hive`` to the standard library","2025-02 (Hagenberg)","","","`#127886 <https://github.com/llvm/llvm-project/issues/127886>`__",""
 "`P3019R14 <https://wg21.link/P3019R14>`__","``indirect`` and ``polymorphic``: Vocabulary Types for Composite Class Design","2025-02 (Hagenberg)","","","`#127887 <https://github.com/llvm/llvm-project/issues/127887>`__",""

>From 19d3a72610d4032c3a5ec6282697a9b3e01cbf7f Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Sun, 28 Jun 2026 18:53:59 -0700
Subject: [PATCH 8/9] Change __freestanding to __unqualified per review

---
 libcxx/include/__ranges/size.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h
index 3dfeade03fce5..d442c9972ae91 100644
--- a/libcxx/include/__ranges/size.h
+++ b/libcxx/include/__ranges/size.h
@@ -148,7 +148,7 @@ concept __member_reserve_hint = !__std_size<_Tp> && requires(_Tp&& __t) {
 };
 
 template <typename _Tp>
-concept __freestanding_reserve_hint =
+concept __unqualified_reserve_hint =
     !__std_size<_Tp> && !__member_reserve_hint<_Tp> && __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) {
       { auto(reserve_hint(__t)) } -> __integer_like;
     };
@@ -169,7 +169,7 @@ struct __fn {
   }
 
   // `[range.prim.size.hint]`: `auto(reserve_hint(t))` is a valid expression
-  template <__freestanding_reserve_hint _Tp>
+  template <__unqualified_reserve_hint _Tp>
   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
       noexcept(noexcept(auto(reserve_hint(__t)))) {
     return auto(reserve_hint(__t));

>From 8ab948211bb9273b8ac833d3c57883c2f15a9a2c Mon Sep 17 00:00:00 2001
From: inquisitivecrystal
 <22333129+inquisitivecrystal at users.noreply.github.com>
Date: Sun, 28 Jun 2026 19:27:00 -0700
Subject: [PATCH 9/9] Add missing includes

---
 libcxx/include/__ranges/take_view.h                              | 1 +
 libcxx/test/std/ranges/range.adaptors/range.common.view/types.h  | 1 +
 .../std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp | 1 +
 .../ranges/range.adaptors/range.elements/reserve_hint.pass.cpp   | 1 +
 .../ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp  | 1 +
 5 files changed, 5 insertions(+)

diff --git a/libcxx/include/__ranges/take_view.h b/libcxx/include/__ranges/take_view.h
index f97a88ccf9297..b252ad3ecf104 100644
--- a/libcxx/include/__ranges/take_view.h
+++ b/libcxx/include/__ranges/take_view.h
@@ -37,6 +37,7 @@
 #include <__ranges/view_interface.h>
 #include <__type_traits/decay.h>
 #include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/make_unsigned.h>
 #include <__type_traits/maybe_const.h>
 #include <__type_traits/remove_cvref.h>
 #include <__utility/auto_cast.h>
diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
index 3dc8fdc670cb5..130423389ad68 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
+++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h
@@ -11,6 +11,7 @@
 
 #include <ranges>
 
+#include "test_macros.h"
 #include "test_iterators.h"
 
 struct DefaultConstructibleView : std::ranges::view_base {
diff --git a/libcxx/test/std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp
index 1652d33eafe0c..e2b4e8400ba86 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.concat/reserve_hint.pass.cpp
@@ -17,6 +17,7 @@
 
 #include <cassert>
 #include <ranges>
+#include <utility>
 
 #include "test_iterators.h"
 #include "test_macros.h"
diff --git a/libcxx/test/std/ranges/range.adaptors/range.elements/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.elements/reserve_hint.pass.cpp
index 085648add5c99..96be6d3942e1d 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.elements/reserve_hint.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.elements/reserve_hint.pass.cpp
@@ -18,6 +18,7 @@
 #include <cassert>
 #include <ranges>
 #include <tuple>
+#include <utility>
 
 #include "types.h"
 
diff --git a/libcxx/test/std/ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp
index bd391377e3a08..f7ae9c610a4ab 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.enumerate/reserve_hint.pass.cpp
@@ -19,6 +19,7 @@
 
 #include <cassert>
 #include <ranges>
+#include <utility>
 
 #include "test_iterators.h"
 



More information about the libcxx-commits mailing list