[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