[libcxx-commits] [libcxx] WIP [libc++][ranges] P3138R3: `views::cache_latest` (PR #151450)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Apr 23 22:48:01 PDT 2026
https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/151450
>From eaf69f0f586779e5b90679db846145beac296bfd Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Wed, 16 Jul 2025 23:17:31 +0300
Subject: [PATCH] [libc++][ranges] P3138R3: `views::cache_latest`
Implements: https://wg21.link/P3138R3
Closes #118134
References:
- https://wg21.link/range.cache.latest
- https://wg21.link/range.nonprop.cache
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +
libcxx/docs/ReleaseNotes/23.rst | 1 +
libcxx/docs/Status/Cxx2cPapers.csv | 2 +-
libcxx/include/CMakeLists.txt | 1 +
libcxx/include/__ranges/cache_latest_view.h | 228 +++++++++++++++
.../include/__ranges/non_propagating_cache.h | 2 +
libcxx/include/module.modulemap.in | 1 +
libcxx/include/ranges | 11 +
libcxx/include/version | 2 +
libcxx/modules/std/ranges.inc | 9 +
.../ranges/range.nonprop.cache/reset.pass.cpp | 52 ++++
.../ranges.version.compile.pass.cpp | 30 ++
.../version.version.compile.pass.cpp | 30 ++
.../cpo.compile.pass.cpp | 2 +-
.../range.cache.latest/adaptor.pass.cpp | 259 ++++++++++++++++++
.../range.cache.latest/base.pass.cpp | 85 ++++++
.../range.cache.latest/begin.pass.cpp | 107 ++++++++
.../range.cache.latest/ctad.compile.pass.cpp | 30 ++
.../range.cache.latest/ctor.default.pass.cpp | 81 ++++++
.../range.cache.latest/ctor.view.pass.cpp | 24 ++
.../enable_borrowed_range.compile.pass.cpp | 34 +++
.../range.cache.latest/end.pass.cpp | 109 ++++++++
.../range.cache.latest/general.pass.cpp | 75 +++++
.../iterator/ctor.default.pass.cpp | 81 ++++++
.../sentinel/ctor.default.pass.cpp | 81 ++++++
.../range.cache.latest/size.pass.cpp | 109 ++++++++
.../generate_feature_test_macro_components.py | 5 +
27 files changed, 1451 insertions(+), 2 deletions(-)
create mode 100644 libcxx/include/__ranges/cache_latest_view.h
create mode 100644 libcxx/test/libcxx/ranges/range.nonprop.cache/reset.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/adaptor.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/base.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/begin.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctad.compile.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctor.default.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctor.view.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/enable_borrowed_range.compile.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/end.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/general.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/iterator/ctor.default.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/sentinel/ctor.default.pass.cpp
create mode 100644 libcxx/test/std/ranges/range.adaptors/range.cache.latest/size.pass.cpp
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index 5f7d90e8eca5e..d5ee291430459 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -370,6 +370,8 @@ Status
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_as_rvalue`` ``202207L``
---------------------------------------------------------- -----------------
+ ``__cpp_lib_ranges_cache_latest`` ``202411L``
+ ---------------------------------------------------------- -----------------
``__cpp_lib_ranges_chunk`` *unimplemented*
---------------------------------------------------------- -----------------
``__cpp_lib_ranges_chunk_by`` ``202202L``
diff --git a/libcxx/docs/ReleaseNotes/23.rst b/libcxx/docs/ReleaseNotes/23.rst
index 0160ea2179ccc..d90fdb72bc789 100644
--- a/libcxx/docs/ReleaseNotes/23.rst
+++ b/libcxx/docs/ReleaseNotes/23.rst
@@ -45,6 +45,7 @@ Implemented Papers
- P2781R9: ``std::constant_wrapper`` (`Github <https://llvm.org/PR148179>`__)
- P3978R3: ``constant_wrapper`` should unwrap on call and subscript (`Github <https://llvm.org/PR189605>`__)
- P2164R9: ``views::enumerate`` (`Github <https://llvm.org/PR105251>`__)
+- P3138R5: ``views::cache_latest`` (`Github <https://llvm.org/PR118134>`__)
- P2322R6 (partial): ``ranges::fold_left_first`` and ``ranges::fold_left_first_with_iter`` are supported
(`Github <https://llvm.org/PR105208>`__)
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index 6b706ab036e01..6b82e6e369194 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -77,7 +77,7 @@
"`P2300R10 <https://wg21.link/P2300R10>`__","``std::execution``","2024-06 (St. Louis)","","","`#105440 <https://github.com/llvm/llvm-project/issues/105440>`__",""
"","","","","","",""
"`P3136R1 <https://wg21.link/P3136R1>`__","Retiring niebloids","2024-11 (Wrocław)","|Complete|","14","`#118133 <https://github.com/llvm/llvm-project/issues/118133>`__",""
-"`P3138R5 <https://wg21.link/P3138R5>`__","``views::cache_latest``","2024-11 (Wrocław)","","","`#118134 <https://github.com/llvm/llvm-project/issues/118134>`__",""
+"`P3138R5 <https://wg21.link/P3138R5>`__","``views::cache_latest``","2024-11 (Wrocław)","|Complete|","23","`#118134 <https://github.com/llvm/llvm-project/issues/118134>`__",""
"`P3379R0 <https://wg21.link/P3379R0>`__","Constrain ``std::expected`` equality operators","2024-11 (Wrocław)","|Complete|","21","`#118135 <https://github.com/llvm/llvm-project/issues/118135>`__",""
"`P2862R1 <https://wg21.link/P2862R1>`__","``text_encoding::name()`` should never return null values","2024-11 (Wrocław)","","","`#118371 <https://github.com/llvm/llvm-project/issues/118371>`__",""
"`P2897R7 <https://wg21.link/P2897R7>`__","``aligned_accessor``: An ``mdspan`` accessor expressing pointer over-alignment","2024-11 (Wrocław)","|Complete|","21","`#118372 <https://github.com/llvm/llvm-project/issues/118372>`__",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 95d822ee8c0b3..151567e1e8088 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -716,6 +716,7 @@ set(files
__ranges/adjacent_view.h
__ranges/all.h
__ranges/as_rvalue_view.h
+ __ranges/cache_latest_view.h
__ranges/chunk_by_view.h
__ranges/common_view.h
__ranges/concepts.h
diff --git a/libcxx/include/__ranges/cache_latest_view.h b/libcxx/include/__ranges/cache_latest_view.h
new file mode 100644
index 0000000000000..fcf6b22e364a2
--- /dev/null
+++ b/libcxx/include/__ranges/cache_latest_view.h
@@ -0,0 +1,228 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___RANGES_TO_CACHE_LATEST_VIEW_H
+#define _LIBCPP___RANGES_TO_CACHE_LATEST_VIEW_H
+
+#include <__concepts/constructible.h>
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iter_move.h>
+#include <__iterator/iter_swap.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/addressof.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/non_propagating_cache.h>
+#include <__ranges/range_adaptor.h>
+#include <__ranges/size.h>
+#include <__ranges/view_interface.h>
+#include <__type_traits/add_pointer.h>
+#include <__type_traits/conditional.h>
+#include <__type_traits/is_reference.h>
+#include <__utility/as_lvalue.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+namespace ranges {
+
+// [range.cache.latest.view]
+
+template <input_range _View>
+ requires view<_View>
+class cache_latest_view : public view_interface<cache_latest_view<_View>> {
+ _View __base_ = _View();
+ using __cache_t _LIBCPP_NODEBUG =
+ conditional_t<is_reference_v<range_reference_t<_View>>,
+ add_pointer_t<range_reference_t<_View>>,
+ range_reference_t<_View>>;
+
+ __non_propagating_cache<__cache_t> __cache_;
+
+ // [range.cache.latest.iterator], class cache_latest_view::iterator
+ class __iterator;
+ // [range.cache.latest.sentinel], class cache_latest_view::sentinel
+ class __sentinel;
+
+public:
+ _LIBCPP_HIDE_FROM_ABI cache_latest_view()
+ requires default_initializable<_View>
+ = default;
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit cache_latest_view(_View __base) : __base_{std::move(__base)} {}
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+ requires copy_constructible<_View>
+ {
+ return __base_;
+ }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { return __iterator(*this); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() { return __sentinel{*this}; }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+ requires sized_range<_View>
+ {
+ return ranges::size(__base_);
+ }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+ requires sized_range<const _View>
+ {
+ return ranges::size(__base_);
+ }
+
+ // TODO: Implement when P2846R6 is available.
+ // constexpr auto reserve_hint()
+ // requires approximately_sized_range<_View>
+ // {
+ // return ranges::reserve_hint(__base_);
+ // }
+ // constexpr auto reserve_hint() const
+ // requires approximately_sized_range<const _View>
+ // {
+ // return ranges::reserve_hint(__base_);
+ // }
+};
+
+template <class _Range>
+cache_latest_view(_Range&&) -> cache_latest_view<views::all_t<_Range>>;
+
+// [range.cache.latest.iterator]
+
+template <input_range _View>
+ requires view<_View>
+class cache_latest_view<_View>::__iterator {
+ cache_latest_view* __parent_;
+ iterator_t<_View> __current_;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(cache_latest_view& __parent)
+ : __parent_{std::addressof(__parent)}, __current_{ranges::begin(__parent.__base_)} {}
+
+ friend class cache_latest_view<_View>;
+
+public:
+ using difference_type = range_difference_t<_View>;
+ using value_type = range_value_t<_View>;
+ using iterator_concept = input_iterator_tag;
+
+ _LIBCPP_HIDE_FROM_ABI __iterator(__iterator&&) = default;
+ _LIBCPP_HIDE_FROM_ABI __iterator& operator=(__iterator&&) = default;
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_View>& base() const& noexcept { return __current_; }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr range_reference_t<_View>& operator*() const {
+ if constexpr (is_reference_v<range_reference_t<_View>>) {
+ if (!__parent_->__cache_.__has_value()) {
+ __parent_->__cache_.__emplace(std::addressof(std::__as_lvalue(*__current_)));
+ }
+ return **__parent_->__cache_;
+ } else {
+ if (!__parent_->__cache_.__has_value()) {
+ __parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__current_; });
+ }
+ return *__parent_->__cache_;
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
+ __parent_->__cache_.__reset();
+ ++__current_;
+ return *this;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_View>
+ iter_move(const __iterator& __i) noexcept(noexcept(ranges::iter_move(__i.__current_))) {
+ return ranges::iter_move(__i.__current_);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr void
+ iter_swap(const __iterator& __x,
+ const __iterator& __y) noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_)))
+ requires indirectly_swappable<iterator_t<_View>>
+ {
+ ranges::iter_swap(__x.__current_, __y.__current_);
+ }
+};
+
+// [range.cache.latest.sentinel]
+
+template <input_range _View>
+ requires view<_View>
+class cache_latest_view<_View>::__sentinel {
+ sentinel_t<_View> __end_ = sentinel_t<_View>();
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(cache_latest_view& __parent)
+ : __end_{ranges::end(__parent.__base_)} {}
+
+ friend class cache_latest_view<_View>;
+
+public:
+ _LIBCPP_HIDE_FROM_ABI __sentinel() = default;
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_View> base() const { return __end_; }
+
+ _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __sentinel& __y) {
+ return __x.__current_ == __y.__end_;
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<_View>
+ operator-(const __iterator& __x, const __sentinel& __y)
+ requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
+ {
+ return __x.__current_ - __y.__end_;
+ }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<_View>
+ operator-(const __sentinel& __x, const __iterator& __y)
+ requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
+ {
+ return __x.__end_ - __y.__current_;
+ }
+};
+
+namespace views {
+namespace __cache_latest_view {
+
+struct __fn : __range_adaptor_closure<__fn> {
+ template <class _Range>
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
+ operator()(_Range&& __range) noexcept(noexcept(/**/ cache_latest_view(std::forward<_Range>(__range))))
+ -> decltype(/*-------------------------------*/ cache_latest_view(std::forward<_Range>(__range))) {
+ return /*--------------------------------------*/ cache_latest_view(std::forward<_Range>(__range));
+ }
+};
+
+} // namespace __cache_latest_view
+
+inline namespace __cpo {
+inline constexpr auto cache_latest = __cache_latest_view::__fn{};
+} // namespace __cpo
+} // namespace views
+} // namespace ranges
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_TO_CACHE_LATEST_VIEW_H
diff --git a/libcxx/include/__ranges/non_propagating_cache.h b/libcxx/include/__ranges/non_propagating_cache.h
index beae13a98e9e3..74bf1d188ecb4 100644
--- a/libcxx/include/__ranges/non_propagating_cache.h
+++ b/libcxx/include/__ranges/non_propagating_cache.h
@@ -91,6 +91,8 @@ class __non_propagating_cache {
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __emplace(_Args&&... __args) {
return __value_.emplace(__forward_tag{}, std::forward<_Args>(__args)...).__t_;
}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr void __reset() { __value_.reset(); }
};
struct __empty_cache {};
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 234c230ee38d0..b31a299fd0235 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1881,6 +1881,7 @@ module std [system] {
export std.ranges.ref_view
}
module as_rvalue_view { header "__ranges/as_rvalue_view.h" }
+ module cache_latest_view { header "__ranges/cache_latest_view.h" }
module chunk_by_view {
header "__ranges/chunk_by_view.h"
export std.functional.bind_back
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 782b4a77c0367..bf00626c80bff 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -407,6 +407,13 @@ namespace std::ranges {
class chunk_by_view; // C++23
namespace views { inline constexpr unspecified chunk_by = unspecified; } // C++23
+
+ // [range.cache.latest], cache latest view
+ template<input_range V>
+ requires view<V>
+ class cache_latest_view; // C++26
+
+ namespace views { inline constexpr unspecified cache_latest = unspecified; } // C++26
}
namespace std {
@@ -502,6 +509,10 @@ namespace std {
# include <__ranges/zip_view.h>
# endif
+# if _LIBCPP_STD_VER >= 26
+# include <__ranges/cache_latest_view.h>
+# endif
+
# include <version>
// standard-mandated includes
diff --git a/libcxx/include/version b/libcxx/include/version
index b462fba39cd19..80ac395397931 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -206,6 +206,7 @@ __cpp_lib_ranges 202406L <algorithm> <fun
202110L // C++20
__cpp_lib_ranges_as_const 202207L <ranges>
__cpp_lib_ranges_as_rvalue 202207L <ranges>
+__cpp_lib_ranges_cache_latest 202411L <ranges>
__cpp_lib_ranges_chunk 202202L <ranges>
__cpp_lib_ranges_chunk_by 202202L <ranges>
__cpp_lib_ranges_concat 202403L <ranges>
@@ -524,6 +525,7 @@ __cpp_lib_void_t 201411L <type_traits>
# define __cpp_lib_ranges 202406L
// # define __cpp_lib_ranges_as_const 202207L
# define __cpp_lib_ranges_as_rvalue 202207L
+# define __cpp_lib_ranges_cache_latest 202411L
// # define __cpp_lib_ranges_chunk 202202L
# define __cpp_lib_ranges_chunk_by 202202L
# define __cpp_lib_ranges_contains 202207L
diff --git a/libcxx/modules/std/ranges.inc b/libcxx/modules/std/ranges.inc
index 97513bc686394..ec405630ae94d 100644
--- a/libcxx/modules/std/ranges.inc
+++ b/libcxx/modules/std/ranges.inc
@@ -363,6 +363,15 @@ export namespace std {
using std::ranges::views::enumerate;
}
#endif // _LIBCPP_STD_VER >= 23
+
+#if _LIBCPP_STD_VER >= 26
+ // [range.cache.latest], Cache latest view
+ using std::ranges::cache_latest_view;
+
+ namespace views {
+ using std::ranges::views::cache_latest;
+ }
+#endif
} // namespace ranges
namespace views = ranges::views;
diff --git a/libcxx/test/libcxx/ranges/range.nonprop.cache/reset.pass.cpp b/libcxx/test/libcxx/ranges/range.nonprop.cache/reset.pass.cpp
new file mode 100644
index 0000000000000..be00d58359245
--- /dev/null
+++ b/libcxx/test/libcxx/ranges/range.nonprop.cache/reset.pass.cpp
@@ -0,0 +1,52 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// constexpr void __reset();
+
+#include <ranges>
+
+#include <cassert>
+
+template <class T>
+constexpr void test() {
+ using Cache = std::ranges::__non_propagating_cache<T>;
+
+ // __reset on an empty cache
+ {
+ Cache cache;
+ assert(!cache.__has_value());
+ cache.__reset();
+ assert(!cache.__has_value());
+ }
+
+ // __reset on a non-empty cache
+ {
+ Cache cache;
+ cache.__emplace();
+ assert(cache.__has_value());
+ cache.__reset();
+ assert(!cache.__has_value());
+ }
+}
+
+struct T {};
+
+constexpr bool tests() {
+ test<T>();
+ test<int>();
+ return true;
+}
+
+int main(int, char**) {
+ tests();
+ static_assert(tests());
+
+ return 0;
+}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
index 7d763f877b321..3a882ac522d70 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp
@@ -36,6 +36,10 @@
# error "__cpp_lib_ranges_as_rvalue should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should not be defined before c++23"
# endif
@@ -94,6 +98,10 @@
# error "__cpp_lib_ranges_as_rvalue should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should not be defined before c++23"
# endif
@@ -152,6 +160,10 @@
# error "__cpp_lib_ranges_as_rvalue should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should not be defined before c++23"
# endif
@@ -213,6 +225,10 @@
# error "__cpp_lib_ranges_as_rvalue should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should not be defined before c++23"
# endif
@@ -286,6 +302,13 @@
# error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++23"
# endif
+# ifndef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_cache_latest != 202411L
+# error "__cpp_lib_ranges_cache_latest should have the value 202411L in c++23"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should be defined in c++23"
@@ -404,6 +427,13 @@
# error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++26"
# endif
+# ifndef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_cache_latest != 202411L
+# error "__cpp_lib_ranges_cache_latest should have the value 202411L in c++26"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should be defined in c++26"
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 93a156bd9a6be..7bdef2daab907 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -656,6 +656,10 @@
# error "__cpp_lib_ranges_as_rvalue should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should not be defined before c++23"
# endif
@@ -1620,6 +1624,10 @@
# error "__cpp_lib_ranges_as_rvalue should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should not be defined before c++23"
# endif
@@ -2749,6 +2757,10 @@
# error "__cpp_lib_ranges_as_rvalue should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should not be defined before c++23"
# endif
@@ -4145,6 +4157,10 @@
# error "__cpp_lib_ranges_as_rvalue should not be defined before c++23"
# endif
+# ifdef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should not be defined before c++23"
+# endif
+
# ifdef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should not be defined before c++23"
# endif
@@ -5718,6 +5734,13 @@
# error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++23"
# endif
+# ifndef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should be defined in c++23"
+# endif
+# if __cpp_lib_ranges_cache_latest != 202411L
+# error "__cpp_lib_ranges_cache_latest should have the value 202411L in c++23"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should be defined in c++23"
@@ -7645,6 +7668,13 @@
# error "__cpp_lib_ranges_as_rvalue should have the value 202207L in c++26"
# endif
+# ifndef __cpp_lib_ranges_cache_latest
+# error "__cpp_lib_ranges_cache_latest should be defined in c++26"
+# endif
+# if __cpp_lib_ranges_cache_latest != 202411L
+# error "__cpp_lib_ranges_cache_latest should have the value 202411L in c++26"
+# endif
+
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges_chunk
# error "__cpp_lib_ranges_chunk should be defined in c++26"
diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
index 9443ca6c90a30..e6c6c2bfd28ff 100644
--- a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
+++ b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
@@ -136,7 +136,7 @@ static_assert(test(std::views::zip, a, a));
#endif
#if TEST_STD_VER >= 26
-// static_assert(test(std::views::cache_latest, a));
+static_assert(test(std::views::cache_latest, a));
// static_assert(test(std::views::concat, a, a));
// static_assert(test(std::views::to_input, a));
#endif
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/adaptor.pass.cpp
new file mode 100644
index 0000000000000..779c59436c21d
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/adaptor.pass.cpp
@@ -0,0 +1,259 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+
+#include "test_iterators.h"
+#include "test_range.h"
+
+static_assert(std::is_same_v<decltype(std::views::cache_latest), decltype(std::ranges::views::cache_latest)>);
+
+struct NonView {};
+
+static_assert(std::default_initializable<NonView>);
+
+struct DefaultInitializableView : std::ranges::view_base {
+ int i_;
+
+ int* begin();
+ int* end();
+};
+
+static_assert(std::default_initializable<DefaultInitializableView>);
+static_assert(std::ranges::common_range<DefaultInitializableView>);
+static_assert(std::ranges::input_range<DefaultInitializableView>);
+
+struct CommonView : std::ranges::view_base {
+ int i_;
+
+ constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(&i_); }
+ constexpr forward_iterator<int*> end() { return begin(); }
+};
+
+static_assert(std::ranges::common_range<CommonView>);
+static_assert(std::ranges::forward_range<CommonView>);
+static_assert(std::ranges::input_range<CommonView>);
+
+struct NonCommonView : std::ranges::view_base {
+ int i_;
+
+ constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(&i_); }
+ constexpr sentinel_wrapper<forward_iterator<int*>> end() { return sentinel_wrapper<forward_iterator<int*>>(begin()); }
+};
+
+static_assert(!std::ranges::common_range<NonCommonView>);
+static_assert(std::ranges::forward_range<NonCommonView>);
+static_assert(std::ranges::input_range<NonCommonView>);
+static_assert(
+ std::derived_from< typename std::iterator_traits<std::ranges::iterator_t<NonCommonView>>::iterator_category,
+ std::input_iterator_tag>);
+
+// Check that the `cache_latest` adaptor can be used with a view.
+
+static_assert(!std::is_invocable_v<decltype(std::views::cache_latest)>);
+static_assert(!std::is_invocable_v<decltype(std::views::cache_latest), NonView>);
+static_assert(std::is_invocable_v<decltype(std::views::cache_latest), DefaultInitializableView>);
+static_assert(std::is_invocable_v<decltype(std::views::cache_latest), CommonView>);
+static_assert(std::is_invocable_v<decltype(std::views::cache_latest), NonCommonView>);
+
+static_assert(!CanBePiped<NonView, decltype(std::views::cache_latest)>);
+static_assert(CanBePiped<DefaultInitializableView&, decltype(std::views::cache_latest)>);
+static_assert(CanBePiped<CommonView&, decltype(std::views::cache_latest)>);
+static_assert(CanBePiped<NonCommonView&, decltype(std::views::cache_latest)>);
+
+constexpr bool test() {
+ { // view | views::cache_latest
+ {
+ DefaultInitializableView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<DefaultInitializableView>> decltype(auto) v =
+ view | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(std::ranges::input_range<decltype(v)>);
+ }
+ {
+ CommonView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<CommonView>> decltype(auto) v = view | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(std::ranges::input_range<decltype(v)>);
+ }
+ {
+ NonCommonView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<NonCommonView>> decltype(auto) v = view | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(std::ranges::input_range<decltype(v)>);
+ }
+ }
+
+ { // adaptor | views::cache_latest
+ {
+ DefaultInitializableView view{{}, 94};
+ const auto partial = std::views::transform(std::identity{}) | std::views::cache_latest;
+ std::same_as<std::ranges::cache_latest_view<
+ std::ranges::transform_view<DefaultInitializableView, std::identity>>> decltype(auto) v = partial(view);
+ assert(v.base().base().i_ == 94);
+
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(std::ranges::input_range<decltype(v)>);
+ }
+ {
+ CommonView view{{}, 94};
+ const auto partial = std::views::transform(std::identity{}) | std::views::cache_latest;
+ std::same_as<
+ std::ranges::cache_latest_view< std::ranges::transform_view<CommonView, std::identity>>> decltype(auto) v =
+ partial(view);
+ assert(v.base().base().i_ == 94);
+
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(std::ranges::input_range<decltype(v)>);
+ }
+ {
+ NonCommonView view{{}, 94};
+ const auto partial = std::views::transform(std::identity{}) | std::views::cache_latest;
+ std::same_as<
+ std::ranges::cache_latest_view< std::ranges::transform_view<NonCommonView, std::identity>>> decltype(auto) v =
+ partial(view);
+ assert(v.base().base().i_ == 94);
+
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(std::ranges::input_range<decltype(v)>);
+ }
+ }
+
+ { // views::cache_latest | adaptor
+ {
+ DefaultInitializableView view{{}, 94};
+ const auto partial = std::views::cache_latest | std::views::transform(std::identity{});
+ std::same_as<std::ranges::transform_view<std::ranges::cache_latest_view<DefaultInitializableView>,
+ std::identity>> decltype(auto) v = partial(view);
+ assert(v.base().base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ {
+ CommonView view{{}, 94};
+ const auto partial = std::views::cache_latest | std::views::transform(std::identity{});
+ std::same_as<
+ std::ranges::transform_view<std::ranges::cache_latest_view<CommonView>, std::identity>> decltype(auto) v =
+ partial(view);
+ assert(v.base().base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ {
+ NonCommonView view{{}, 94};
+ const auto partial = std::views::cache_latest | std::views::transform(std::identity{});
+ std::same_as<
+ std::ranges::transform_view<std::ranges::cache_latest_view<NonCommonView>, std::identity>> decltype(auto) v =
+ partial(view);
+ assert(v.base().base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ }
+
+ { // views::cache_latest | views::all
+ {
+ DefaultInitializableView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<DefaultInitializableView>> decltype(auto) v =
+ std::views::all(view) | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ {
+ CommonView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<CommonView>> decltype(auto) v =
+ std::views::all(view) | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ {
+ NonCommonView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<NonCommonView>> decltype(auto) v =
+ std::views::all(view) | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ }
+
+ { // views::cache_latest | views::all_t
+ {
+ DefaultInitializableView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<DefaultInitializableView>> decltype(auto) v =
+ std::views::all_t<DefaultInitializableView>(view) | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ {
+ CommonView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<CommonView>> decltype(auto) v =
+ std::views::all_t<CommonView>(view) | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ {
+ NonCommonView view{{}, 94};
+ std::same_as<std::ranges::cache_latest_view<NonCommonView>> decltype(auto) v =
+ std::views::all_t<NonCommonView>(view) | std::views::cache_latest;
+ assert(v.base().i_ == 94);
+
+ static_assert(std::ranges::input_range<decltype(v)>);
+ static_assert(!std::ranges::forward_range<decltype(v)>);
+ static_assert(!std::ranges::common_range<decltype(v)>);
+ }
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/base.pass.cpp
new file mode 100644
index 0000000000000..d0734633bb9c3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/base.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+// constexpr V base() const & requires copy_constructible<V> { return base_; }
+// constexpr V base() && { return std::move(base_); }
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+
+#include <utility>
+
+#include "MoveOnly.h"
+
+struct SimpleView : std::ranges::view_base {
+ int i_;
+
+ int* begin() const;
+ int* end() const;
+};
+
+struct MoveOnlyView : public SimpleView {
+ MoveOnly m_;
+};
+
+template <class T>
+concept HasBase = requires(T&& t) { std::forward<T>(t).base(); };
+
+static_assert(HasBase<std::ranges::cache_latest_view<SimpleView> const&>);
+static_assert(HasBase<std::ranges::cache_latest_view<SimpleView>&&>);
+
+static_assert(!HasBase<std::ranges::cache_latest_view<MoveOnlyView> const&>);
+static_assert(HasBase<std::ranges::cache_latest_view<MoveOnlyView>&&>);
+
+constexpr bool test() {
+ { // &
+ std::ranges::cache_latest_view<SimpleView> view(SimpleView{{}, 94});
+ std::same_as<SimpleView> decltype(auto) v = view.base();
+ assert(v.i_ == 94);
+ }
+
+ { // const &
+ const std::ranges::cache_latest_view<SimpleView> view(SimpleView{{}, 94});
+ std::same_as<SimpleView> decltype(auto) v = view.base();
+ assert(v.i_ == 94);
+ }
+
+ { // &&
+ std::ranges::cache_latest_view<SimpleView> view(SimpleView{{}, 94});
+ std::same_as<SimpleView> decltype(auto) v = std::move(view).base();
+ assert(v.i_ == 94);
+ }
+
+ { // const &&
+ const std::ranges::cache_latest_view<SimpleView> view(SimpleView{{}, 94});
+ std::same_as<SimpleView> decltype(auto) v = std::move(view).base();
+ assert(v.i_ == 94);
+ }
+
+ { // move only
+ std::ranges::cache_latest_view<MoveOnlyView> view(MoveOnlyView{{}, 94});
+ std::same_as<MoveOnlyView> decltype(auto) v = std::move(view).base();
+ assert(v.m_.get() == 94);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/begin.pass.cpp
new file mode 100644
index 0000000000000..3459ce015ef65
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/begin.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>
+
+// class cache_latest_view
+
+// constexpr auto begin();
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+
+#include "test_iterators.h"
+
+struct NonConstView : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+struct ConstView : std::ranges::view_base {
+ int* begin() const;
+ int* end() const;
+};
+
+struct ConstNonConstView : std::ranges::view_base {
+ int* begin();
+ int* end();
+ int* begin() const;
+ int* end() const;
+};
+
+template <class T>
+concept HasBegin = requires(T t) { t.begin(); };
+
+static_assert(HasBegin<std::ranges::cache_latest_view<NonConstView>>);
+static_assert(!HasBegin<const std::ranges::cache_latest_view<NonConstView>>);
+static_assert(HasBegin<std::ranges::cache_latest_view<ConstView>>);
+static_assert(!HasBegin<const std::ranges::cache_latest_view<ConstView>>);
+static_assert(HasBegin<std::ranges::cache_latest_view<ConstNonConstView>>);
+static_assert(!HasBegin<const std::ranges::cache_latest_view<ConstNonConstView>>);
+
+struct CommonView : std::ranges::view_base {
+ int i_;
+
+ constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(&i_); }
+ constexpr forward_iterator<int*> end() { return begin(); }
+};
+
+static_assert(std::ranges::common_range<CommonView>);
+static_assert(std::ranges::forward_range<CommonView>);
+static_assert(std::ranges::input_range<CommonView>);
+
+struct NonCommonView : std::ranges::view_base {
+ int i_;
+
+ constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(&i_); }
+ constexpr sentinel_wrapper<forward_iterator<int*>> end() { return sentinel_wrapper<forward_iterator<int*>>(begin()); }
+};
+
+static_assert(!std::ranges::common_range<NonCommonView>);
+static_assert(std::ranges::forward_range<NonCommonView>);
+static_assert(std::ranges::input_range<NonCommonView>);
+static_assert(
+ std::derived_from<typename std::iterator_traits<std::ranges::iterator_t<NonCommonView>>::iterator_category,
+ std::input_iterator_tag>);
+
+constexpr bool test() {
+ {
+ CommonView view{{}, 94};
+
+ std::same_as<std::ranges::cache_latest_view<CommonView>> decltype(auto) v = view | std::views::cache_latest;
+ assert(*v.begin() == view.i_);
+ // assert(&*v.begin() == std::addressof(view.i_));
+ }
+ {
+ NonCommonView view{{}, 94};
+
+ std::same_as<std::ranges::cache_latest_view<NonCommonView>> decltype(auto) v = view | std::views::cache_latest;
+ assert(*v.begin() == view.i_);
+ // assert(base(v.begin().base()) == std::addressof(view.i_));
+ }
+
+ {
+ int arr[] = {82, 94, 76};
+
+ std::same_as<std::ranges::cache_latest_view<std::ranges::ref_view<int[3]>>> decltype(auto) v =
+ arr | std::views::cache_latest;
+ assert(base(v.begin().base()) == arr);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctad.compile.pass.cpp
new file mode 100644
index 0000000000000..2ed5eab4abd46
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctad.compile.pass.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+// template<class R>
+// cache_latest_view(R&&) -> cache_latest_view<views::all_t<R>>;
+
+#include <concepts>
+#include <ranges>
+#include <utility>
+#include <vector>
+
+static_assert(std::same_as<decltype(std::ranges::cache_latest_view(std::vector<int>{})),
+ std::ranges::cache_latest_view<std::views::all_t<std::vector<int>>>>);
+
+static_assert(std::same_as<decltype(std::ranges::cache_latest_view(std::declval<std::vector<int>&>())),
+ std::ranges::cache_latest_view<std::views::all_t<std::vector<int>&>>>);
+
+static_assert(std::same_as<decltype(std::ranges::cache_latest_view(std::ranges::empty_view<int>{})),
+ std::ranges::cache_latest_view<std::ranges::empty_view<int>>>);
\ No newline at end of file
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..adae9479188d3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctor.default.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+// cache_latest_view() requires default_initializable<V> = default;
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+
+struct DefaultInitializableView : std::ranges::view_base {
+ int i_ = 94;
+
+ int* begin();
+ int* end();
+};
+
+static_assert(std::default_initializable<DefaultInitializableView>);
+static_assert(std::default_initializable<std::ranges::cache_latest_view<DefaultInitializableView>>);
+
+struct NoDefaultInitializableView : std::ranges::view_base {
+ NoDefaultInitializableView() = delete;
+
+ int* begin();
+ int* end();
+};
+
+static_assert(!std::default_initializable<NoDefaultInitializableView>);
+static_assert(!std::default_initializable<std::ranges::cache_latest_view<NoDefaultInitializableView>>);
+
+struct NoexceptView : std::ranges::view_base {
+ NoexceptView() noexcept;
+
+ int const* begin() const;
+ int const* end() const;
+};
+
+static_assert(noexcept(std::ranges::cache_latest_view<NoexceptView>()));
+
+struct NoNoexceptView : std::ranges::view_base {
+ NoNoexceptView() noexcept(false);
+
+ int const* begin() const;
+ int const* end() const;
+};
+
+static_assert(!noexcept(std::ranges::cache_latest_view<NoNoexceptView>()));
+
+constexpr bool test() {
+ { // value-initialized (i.e., whether T() is well-formed).
+ std::ranges::cache_latest_view<DefaultInitializableView> cache_latest_view{};
+ assert(cache_latest_view.base().i_ == 94);
+ }
+ { // direct-list-initialized from an empty initializer list (i.e., whether T{} is well-formed).
+ std::ranges::cache_latest_view<DefaultInitializableView> cache_latest_view = {};
+ assert(cache_latest_view.base().i_ == 94);
+ }
+ { // default-initialized (i.e., whether T t; is well-formed).
+ std::ranges::cache_latest_view<DefaultInitializableView> cache_latest_view;
+ assert(cache_latest_view.base().i_ == 94);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctor.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctor.view.pass.cpp
new file mode 100644
index 0000000000000..9803e7500e8d3
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/ctor.view.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+// constexpr explicit cache_latest_view(V base);
+
+constexpr bool test() { return true; }
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/enable_borrowed_range.compile.pass.cpp
new file mode 100644
index 0000000000000..ba721291c3be4
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/enable_borrowed_range.compile.pass.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+// Test that std::ranges::cache_latest_view is not std::ranges::borrowed_range.
+
+#include <ranges>
+
+struct BorrowedView : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+template <>
+inline constexpr bool std::ranges::enable_borrowed_range<BorrowedView> = true;
+
+static_assert(!std::ranges::borrowed_range<std::ranges::cache_latest_view<BorrowedView>>);
+
+struct NonBorrowedView : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+static_assert(!std::ranges::borrowed_range<std::ranges::cache_latest_view<NonBorrowedView>>);
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/end.pass.cpp
new file mode 100644
index 0000000000000..f3bf777c35a42
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/end.pass.cpp
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+// constexpr auto end();
+
+#include <cassert>
+#include <concepts>
+#include <ranges>
+
+#include "test_iterators.h"
+#include <print>
+
+struct NonConstView : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+struct ConstView : std::ranges::view_base {
+ int* begin() const;
+ int* end() const;
+};
+
+struct ConstNonConstView : std::ranges::view_base {
+ int* begin();
+ int* end();
+ int* begin() const;
+ int* end() const;
+};
+
+template <class T>
+concept HasEnd = requires(T t) { t.end(); };
+
+static_assert(HasEnd<std::ranges::cache_latest_view<NonConstView>>);
+static_assert(!HasEnd<const std::ranges::cache_latest_view<NonConstView>>);
+static_assert(HasEnd<std::ranges::cache_latest_view<ConstView>>);
+static_assert(!HasEnd<const std::ranges::cache_latest_view<ConstView>>);
+static_assert(HasEnd<std::ranges::cache_latest_view<ConstNonConstView>>);
+static_assert(!HasEnd<const std::ranges::cache_latest_view<ConstNonConstView>>);
+
+struct CommonView : std::ranges::view_base {
+ int i_;
+
+ constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(&i_); }
+ constexpr forward_iterator<int*> end() { return begin(); }
+};
+
+static_assert(std::ranges::common_range<CommonView>);
+static_assert(std::ranges::forward_range<CommonView>);
+static_assert(std::ranges::input_range<CommonView>);
+
+struct NonCommonView : std::ranges::view_base {
+ int i_;
+
+ constexpr forward_iterator<int*> begin() { return forward_iterator<int*>(&i_); }
+ constexpr sentinel_wrapper<forward_iterator<int*>> end() { return sentinel_wrapper<forward_iterator<int*>>(begin()); }
+};
+
+static_assert(!std::ranges::common_range<NonCommonView>);
+static_assert(std::ranges::forward_range<NonCommonView>);
+static_assert(std::ranges::input_range<NonCommonView>);
+static_assert(
+ std::derived_from<typename std::iterator_traits<std::ranges::iterator_t<NonCommonView>>::iterator_category,
+ std::input_iterator_tag>);
+
+constexpr bool test() {
+ {
+ CommonView view{{}, 94};
+
+ std::same_as<std::ranges::cache_latest_view<CommonView>> decltype(auto) v = view | std::views::cache_latest;
+
+ assert(*base(v.end().base()) == view.i_);
+ }
+ {
+ NonCommonView view{{}, 94};
+
+ std::same_as<std::ranges::cache_latest_view<NonCommonView>> decltype(auto) v = view | std::views::cache_latest;
+
+ assert(*base(v.end().base()) == view.i_);
+ }
+
+ {
+ int arr[] = {82, 94, 76};
+
+ std::same_as<std::ranges::cache_latest_view<std::ranges::ref_view<int[3]>>> decltype(auto) v =
+ arr | std::views::cache_latest;
+
+ assert(base(v.end().base()) == arr + 3);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/general.pass.cpp
new file mode 100644
index 0000000000000..82f91770a59e8
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/general.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+// Functional tests of std::ranges::cache_latest_view.
+
+#include <cassert>
+#include <ranges>
+#include <vector>
+#include <algorithm>
+
+constexpr bool test() {
+ // Motivational example from P3138R3.
+ std::vector<int> vec = {1, 2, 3, 4, 5};
+ std::vector<int> filtered_vec = {4, 16};
+
+ { // Uncached transform and filter.
+ int transform_counter = 0;
+ const auto get_square = [&](int i) {
+ ++transform_counter;
+ return i * i;
+ };
+ auto view = vec | std::views::transform(get_square) | std::views::filter([&](int i) { return i % 2 == 0; });
+
+ assert(std::ranges::equal(view, filtered_vec));
+ // The transform is called twice for each element that is not filtered out.
+ assert(transform_counter == 7);
+ }
+ { // Cached transform and filter.
+ int transform_counter = 0;
+ const auto get_square = [&](int i) {
+ ++transform_counter;
+ return i * i;
+ };
+ auto view = vec | std::views::transform(get_square) | std::views::cache_latest |
+ std::views::filter([&](int i) { return i % 2 == 0; });
+
+ assert(std::ranges::equal(view, filtered_vec));
+ // The transform is called only once for each element.
+ assert(transform_counter == 5);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/iterator/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/iterator/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..8232d0401ab37
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/iterator/ctor.default.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+
+// template<input_range V>
+// requires view<V>
+// template<bool Const>
+// class to_input_view<V>::iterator
+
+// iterator() requires default_initializable<iterator_t<Base>> = default;
+
+#include <cassert>
+#include <cstdint>
+#include <ranges>
+#include <type_traits>
+
+#include "test_iterators.h"
+
+struct DefaultInitializableIterator {
+ int i_; // Deliberately uninitialized.
+
+ using difference_type = std::intptr_t;
+ using value_type = int;
+ using iterator_category = std::random_access_iterator_tag;
+
+ constexpr int operator*() const { return i_; }
+
+ constexpr DefaultInitializableIterator& operator++() { return *this; }
+ constexpr void operator++(int) {}
+
+ friend constexpr bool operator==(const DefaultInitializableIterator&, const DefaultInitializableIterator&) = default;
+};
+
+static_assert(std::default_initializable<DefaultInitializableIterator>);
+
+struct DefaultInitializableIteratorView : std::ranges::view_base {
+ DefaultInitializableIterator begin() const;
+ DefaultInitializableIterator end() const;
+};
+
+struct NonDefaultInitializableIteratorView : std::ranges::view_base {
+ static_assert(!std::default_initializable<cpp20_input_iterator<int*>>);
+
+ cpp20_input_iterator<int*> begin() const;
+ sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
+};
+
+template <class View>
+using CacheLatestViewIteratorT = std::ranges::iterator_t<std::ranges::cache_latest_view<View>>;
+
+// Check that the to_input_view's iterator is default initializable when the underlying iterator is.
+// static_assert(std::default_initializable<CacheLatestViewIteratorT<DefaultInitializableIteratorView>>);
+// static_assert(!std::default_initializable<CacheLatestViewIteratorT<NonDefaultInitializableIteratorView>>);
+
+constexpr bool test() {
+ // {
+ // CacheLatestViewIteratorT<DefaultInitializableIteratorView> it;
+ // assert(*it == 0); // DefaultInitializableIterator has to be initialized to have value 0.
+ // }
+ // {
+ // CacheLatestViewIteratorT<DefaultInitializableIteratorView> it = {};
+ // assert(*it == 0); // DefaultInitializableIterator has to be initialized to have value 0.
+ // }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/sentinel/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/sentinel/ctor.default.pass.cpp
new file mode 100644
index 0000000000000..7d228552d0900
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/sentinel/ctor.default.pass.cpp
@@ -0,0 +1,81 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+
+// template<input_range V>
+// requires view<V>
+// template<bool Const>
+// class to_input_view<V>::iterator
+
+// iterator() requires default_initializable<iterator_t<Base>> = default;
+
+#include <cassert>
+#include <cstdint>
+#include <ranges>
+#include <type_traits>
+
+#include "test_iterators.h"
+
+struct DefaultInitializableIterator {
+ int i_; // Deliberately uninitialized.
+
+ using difference_type = std::intptr_t;
+ using value_type = int;
+ using iterator_category = std::random_access_iterator_tag;
+
+ constexpr int operator*() const { return i_; }
+
+ constexpr DefaultInitializableIterator& operator++() { return *this; }
+ constexpr void operator++(int) {}
+
+ friend constexpr bool operator==(const DefaultInitializableIterator&, const DefaultInitializableIterator&) = default;
+};
+
+static_assert(std::default_initializable<DefaultInitializableIterator>);
+
+struct DefaultInitializableIteratorView : std::ranges::view_base {
+ DefaultInitializableIterator begin() const;
+ DefaultInitializableIterator end() const;
+};
+
+struct NonDefaultInitializableIteratorView : std::ranges::view_base {
+ static_assert(!std::default_initializable<cpp20_input_iterator<int*>>);
+
+ cpp20_input_iterator<int*> begin() const;
+ sentinel_wrapper<cpp20_input_iterator<int*>> end() const;
+};
+
+template <class View>
+using CacheLatestViewSentinelT = std::ranges::sentinel_t<std::ranges::cache_latest_view<View>>;
+
+// Check that the to_input_view's iterator is default initializable when the underlying iterator is.
+// static_assert(std::default_initializable<CacheLatestViewSentinelT<DefaultInitializableIteratorView>>);
+// static_assert(!std::default_initializable<CacheLatestViewSentinelT<NonDefaultInitializableIteratorView>>);
+
+constexpr bool test() {
+ // {
+ // CacheLatestViewSentinelT<DefaultInitializableIteratorView> it;
+ // assert(*it == 0); // DefaultInitializableIterator has to be initialized to have value 0.
+ // }
+ // {
+ // CacheLatestViewSentinelT<DefaultInitializableIteratorView> it = {};
+ // assert(*it == 0); // DefaultInitializableIterator has to be initialized to have value 0.
+ // }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/std/ranges/range.adaptors/range.cache.latest/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/size.pass.cpp
new file mode 100644
index 0000000000000..229e70c0fc361
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/size.pass.cpp
@@ -0,0 +1,109 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 cache_latest_view
+
+// constexpr auto size() requires sized_range<V>;
+// constexpr auto size() const requires sized_range<const V>;
+
+#include <array>
+#include <cassert>
+#include <ranges>
+#include <utility>
+
+#include "test_iterators.h"
+
+template <class T>
+concept HasSize = requires(T t) { t.size(); };
+
+constexpr bool test() {
+ {
+ struct SubtractableIteratorsView : std::ranges::view_base {
+ forward_iterator<int*> begin();
+ sized_sentinel<forward_iterator<int*>> end();
+ };
+
+ using ToCacheLatestViewT = std::ranges::cache_latest_view<SubtractableIteratorsView>;
+
+ static_assert(std::ranges::sized_range<ToCacheLatestViewT&>);
+ static_assert(!std::ranges::range<const ToCacheLatestViewT&>); // no begin()/end()
+
+ static_assert(HasSize<ToCacheLatestViewT&>);
+ static_assert(HasSize<ToCacheLatestViewT&&>);
+ static_assert(!HasSize<const ToCacheLatestViewT&>);
+ static_assert(!HasSize<const ToCacheLatestViewT&&>);
+ }
+ {
+ struct NonSizedView : std::ranges::view_base {
+ bidirectional_iterator<int*> begin();
+ bidirectional_iterator<int*> end();
+ };
+
+ using ToCacheLatestViewT = std::ranges::cache_latest_view<NonSizedView>;
+
+ static_assert(!HasSize<ToCacheLatestViewT&>);
+ static_assert(!HasSize<ToCacheLatestViewT&&>);
+ static_assert(!HasSize<const ToCacheLatestViewT&>);
+ static_assert(!HasSize<const ToCacheLatestViewT&&>);
+ }
+ {
+ struct SizedView : std::ranges::view_base {
+ bidirectional_iterator<int*> begin();
+ bidirectional_iterator<int*> end();
+
+ int size() const;
+ };
+
+ using ToCacheLatestViewT = std::ranges::cache_latest_view<SizedView>;
+
+ static_assert(std::ranges::sized_range<ToCacheLatestViewT&>);
+ static_assert(!std::ranges::range<const ToCacheLatestViewT&>); // no begin()/end()
+
+ static_assert(HasSize<ToCacheLatestViewT&>);
+ static_assert(HasSize<ToCacheLatestViewT&&>);
+ static_assert(!HasSize<const ToCacheLatestViewT&>); // not a view, therefore no size()
+ static_assert(!HasSize<const ToCacheLatestViewT&&>);
+ }
+ {
+ // Test an empty view.
+ int arr[] = {94};
+ auto view = std::ranges::cache_latest_view(std::ranges::subrange(arr, arr));
+
+ assert(view.size() == 0);
+ assert(std::as_const(view).size() == 0);
+ }
+ {
+ // Test a non-empty view.
+ int arr[] = {94};
+ auto view = std::ranges::cache_latest_view(std::ranges::subrange(arr, arr + 1));
+
+ assert(view.size() == 1);
+ assert(std::as_const(view).size() == 1);
+ }
+ {
+ // Test a non-view.
+ std::array<int, 2> arr = {94, 82};
+ auto view = std::ranges::cache_latest_view(std::move(arr));
+
+ assert(view.size() == 2);
+ assert(std::as_const(view).size() == 2);
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 8f421e8cbd0f0..d58c57ef6186a 100644
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -1110,6 +1110,11 @@ def add_version_header(tc):
"values": {"c++23": 202207},
"headers": ["ranges"],
},
+ {
+ "name": "__cpp_lib_ranges_cache_latest",
+ "values": {"c++23": 202411},
+ "headers": ["ranges"],
+ },
{
"name": "__cpp_lib_ranges_chunk",
"values": {"c++23": 202202},
More information about the libcxx-commits
mailing list