Skip to content

Commit 49f5b6e

Browse files
committed
[libc++][ranges] P3138R3: views::cache_latest
Implements: https://wg21.link/P3138R3 Closes #118134 - https://wg21.link/range.cache.latest - https://wg21.link/range.nonprop.cache
1 parent c04b98f commit 49f5b6e

File tree

27 files changed

+1447
-2
lines changed

27 files changed

+1447
-2
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@ Status
370370
---------------------------------------------------------- -----------------
371371
``__cpp_lib_ranges_as_rvalue`` ``202207L``
372372
---------------------------------------------------------- -----------------
373+
``__cpp_lib_ranges_cache_latest`` ``202411L``
374+
---------------------------------------------------------- -----------------
373375
``__cpp_lib_ranges_chunk`` *unimplemented*
374376
---------------------------------------------------------- -----------------
375377
``__cpp_lib_ranges_chunk_by`` ``202202L``

libcxx/docs/ReleaseNotes/22.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Implemented Papers
4040

4141
- P2321R2: ``zip`` (`Github <https://llvm.org/PR105169>`__) (The paper is partially implemented. ``zip_transform_view``
4242
is implemented in this release)
43+
- P3138R3: ``std::ranges::cache_latest`` (`Github <https://llvm.org/PR118134>`__)
4344
- P3168R2: Give ``std::optional`` Range Support (`Github <https://llvm.org/PR105430>`__)
4445

4546
Improvements and New Features

libcxx/docs/Status/Cxx2cPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
"`P2300R10 <https://wg21.link/P2300R10>`__","``std::execution``","2024-06 (St. Louis)","","","`#105440 <https://github.com/llvm/llvm-project/issues/105440>`__",""
7878
"","","","","",""
7979
"`P3136R1 <https://wg21.link/P3136R1>`__","Retiring niebloids","2024-11 (Wrocław)","|Complete|","14","`#118133 <https://github.com/llvm/llvm-project/issues/118133>`__",""
80-
"`P3138R5 <https://wg21.link/P3138R5>`__","``views::cache_latest``","2024-11 (Wrocław)","","","`#118134 <https://github.com/llvm/llvm-project/issues/118134>`__",""
80+
"`P3138R5 <https://wg21.link/P3138R5>`__","``views::cache_latest``","2024-11 (Wrocław)","|Complete|","22","`#118134 <https://github.com/llvm/llvm-project/issues/118134>`__",""
8181
"`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>`__",""
8282
"`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>`__",""
8383
"`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>`__",""

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,7 @@ set(files
697697
__ranges/access.h
698698
__ranges/all.h
699699
__ranges/as_rvalue_view.h
700+
__ranges/cache_latest_view.h
700701
__ranges/chunk_by_view.h
701702
__ranges/common_view.h
702703
__ranges/concepts.h
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___RANGES_TO_CACHE_LATEST_VIEW_H
11+
#define _LIBCPP___RANGES_TO_CACHE_LATEST_VIEW_H
12+
13+
#include <__concepts/constructible.h>
14+
#include <__config>
15+
#include <__iterator/concepts.h>
16+
#include <__iterator/iter_move.h>
17+
#include <__iterator/iter_swap.h>
18+
#include <__iterator/iterator_traits.h>
19+
#include <__memory/addressof.h>
20+
#include <__ranges/access.h>
21+
#include <__ranges/all.h>
22+
#include <__ranges/concepts.h>
23+
#include <__ranges/non_propagating_cache.h>
24+
#include <__ranges/range_adaptor.h>
25+
#include <__ranges/size.h>
26+
#include <__ranges/view_interface.h>
27+
#include <__type_traits/add_pointer.h>
28+
#include <__type_traits/conditional.h>
29+
#include <__type_traits/is_reference.h>
30+
#include <__utility/as_lvalue.h>
31+
#include <__utility/forward.h>
32+
#include <__utility/move.h>
33+
34+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
35+
# pragma GCC system_header
36+
#endif
37+
38+
_LIBCPP_PUSH_MACROS
39+
#include <__undef_macros>
40+
41+
_LIBCPP_BEGIN_NAMESPACE_STD
42+
43+
#if _LIBCPP_STD_VER >= 26
44+
45+
namespace ranges {
46+
47+
// [range.cache.latest.view]
48+
49+
template <input_range _View>
50+
requires view<_View>
51+
class cache_latest_view : public view_interface<cache_latest_view<_View>> {
52+
_View __base_ = _View(); // exposition only
53+
using __cache_t _LIBCPP_NODEBUG =
54+
conditional_t<is_reference_v<range_reference_t<_View>>, // exposition only
55+
add_pointer_t<range_reference_t<_View>>,
56+
range_reference_t<_View>>;
57+
58+
__non_propagating_cache<__cache_t> __cache_; // exposition only
59+
60+
// [range.cache.latest.iterator], class cache_latest_view::iterator
61+
class iterator; // exposition only
62+
// [range.cache.latest.sentinel], class cache_latest_view::sentinel
63+
class sentinel; // exposition only
64+
65+
public:
66+
_LIBCPP_HIDE_FROM_ABI cache_latest_view()
67+
requires default_initializable<_View>
68+
= default;
69+
_LIBCPP_HIDE_FROM_ABI constexpr explicit cache_latest_view(_View __base) : __base_{std::move(__base)} {}
70+
71+
_LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
72+
requires copy_constructible<_View>
73+
{
74+
return __base_;
75+
}
76+
_LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
77+
78+
_LIBCPP_HIDE_FROM_ABI constexpr auto begin() { return iterator(*this); }
79+
_LIBCPP_HIDE_FROM_ABI constexpr auto end() { return sentinel{*this}; }
80+
81+
_LIBCPP_HIDE_FROM_ABI constexpr auto size()
82+
requires sized_range<_View>
83+
{
84+
return ranges::size(__base_);
85+
}
86+
_LIBCPP_HIDE_FROM_ABI constexpr auto size() const
87+
requires sized_range<const _View>
88+
{
89+
return ranges::size(__base_);
90+
}
91+
92+
// TODO: Implement when P2846R6 is available.
93+
// constexpr auto reserve_hint()
94+
// requires approximately_sized_range<_View>
95+
// {
96+
// return ranges::reserve_hint(__base_);
97+
// }
98+
// constexpr auto reserve_hint() const
99+
// requires approximately_sized_range<const _View>
100+
// {
101+
// return ranges::reserve_hint(__base_);
102+
// }
103+
};
104+
105+
template <class _Range>
106+
cache_latest_view(_Range&&) -> cache_latest_view<views::all_t<_Range>>;
107+
108+
// [range.cache.latest.iterator]
109+
110+
template <input_range _View>
111+
requires view<_View>
112+
class cache_latest_view<_View>::iterator {
113+
cache_latest_view* __parent_; // exposition only
114+
iterator_t<_View> __current_; // exposition only
115+
116+
_LIBCPP_HIDE_FROM_ABI constexpr explicit iterator(cache_latest_view& __parent) // exposition only
117+
: __parent_{std::addressof(__parent)}, __current_{ranges::begin(__parent.__base_)} {}
118+
119+
friend class cache_latest_view<_View>;
120+
121+
public:
122+
using difference_type = range_difference_t<_View>;
123+
using value_type = range_value_t<_View>;
124+
using iterator_concept = input_iterator_tag;
125+
126+
_LIBCPP_HIDE_FROM_ABI iterator(iterator&&) = default;
127+
_LIBCPP_HIDE_FROM_ABI iterator& operator=(iterator&&) = default;
128+
129+
_LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); }
130+
_LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_View>& base() const& noexcept { return __current_; }
131+
132+
_LIBCPP_HIDE_FROM_ABI constexpr range_reference_t<_View>& operator*() const {
133+
if constexpr (is_reference_v<range_reference_t<_View>>) {
134+
if (!__parent_->__cache_.__has_value()) {
135+
__parent_->__cache_.__emplace(std::addressof(std::__as_lvalue(*__current_)));
136+
}
137+
return **__parent_->__cache_;
138+
} else {
139+
if (!__parent_->__cache_.__has_value()) {
140+
__parent_->__cache_.__emplace_from([&]() -> decltype(auto) { return *__current_; });
141+
}
142+
return *__parent_->__cache_;
143+
}
144+
}
145+
146+
_LIBCPP_HIDE_FROM_ABI constexpr iterator& operator++() {
147+
__parent_->__cache_.__reset();
148+
++__current_;
149+
return *this;
150+
}
151+
_LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
152+
153+
_LIBCPP_HIDE_FROM_ABI friend constexpr range_rvalue_reference_t<_View>
154+
iter_move(const iterator& __i) noexcept(noexcept(ranges::iter_move(__i.__current_))) {
155+
return ranges::iter_move(__i.__current_);
156+
}
157+
158+
_LIBCPP_HIDE_FROM_ABI friend constexpr void
159+
iter_swap(const iterator& __x,
160+
const iterator& __y) noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_)))
161+
requires indirectly_swappable<iterator_t<_View>>
162+
{
163+
ranges::iter_swap(__x.__current_, __y.__current_);
164+
}
165+
};
166+
167+
// [range.cache.latest.sentinel]
168+
169+
template <input_range _View>
170+
requires view<_View>
171+
class cache_latest_view<_View>::sentinel {
172+
sentinel_t<_View> __end_ = sentinel_t<_View>(); // exposition only
173+
174+
_LIBCPP_HIDE_FROM_ABI constexpr explicit sentinel(cache_latest_view& __parent) // exposition only
175+
: __end_{ranges::end(__parent.__base_)} {}
176+
177+
friend class cache_latest_view<_View>;
178+
179+
public:
180+
_LIBCPP_HIDE_FROM_ABI sentinel() = default;
181+
182+
_LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_View> base() const { return __end_; }
183+
184+
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const iterator& __x, const sentinel& __y) {
185+
return __x.__current_ == __y.__end_;
186+
}
187+
188+
_LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<_View> operator-(const iterator& __x, const sentinel& __y)
189+
requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
190+
{
191+
return __x.__current_ - __y.__end_;
192+
}
193+
_LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<_View> operator-(const sentinel& __x, const iterator& __y)
194+
requires sized_sentinel_for<sentinel_t<_View>, iterator_t<_View>>
195+
{
196+
return __x.__end_ - __y.__current_;
197+
}
198+
};
199+
200+
namespace views {
201+
namespace __cache_latest_view {
202+
203+
struct __fn : __range_adaptor_closure<__fn> {
204+
template <class _Range>
205+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto
206+
operator()(_Range&& __range) noexcept(noexcept(/**/ cache_latest_view(std::forward<_Range>(__range))))
207+
-> decltype(/*-------------------------------*/ cache_latest_view(std::forward<_Range>(__range))) {
208+
return /*--------------------------------------*/ cache_latest_view(std::forward<_Range>(__range));
209+
}
210+
};
211+
212+
} // namespace __cache_latest_view
213+
214+
inline namespace __cpo {
215+
inline constexpr auto cache_latest = __cache_latest_view::__fn{};
216+
} // namespace __cpo
217+
} // namespace views
218+
} // namespace ranges
219+
220+
#endif // _LIBCPP_STD_VER >= 26
221+
222+
_LIBCPP_END_NAMESPACE_STD
223+
224+
_LIBCPP_POP_MACROS
225+
226+
#endif // _LIBCPP___RANGES_TO_CACHE_LATEST_VIEW_H

libcxx/include/__ranges/non_propagating_cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class __non_propagating_cache {
9191
_LIBCPP_HIDE_FROM_ABI constexpr _Tp& __emplace(_Args&&... __args) {
9292
return __value_.emplace(__forward_tag{}, std::forward<_Args>(__args)...).__t_;
9393
}
94+
95+
_LIBCPP_HIDE_FROM_ABI constexpr void __reset() { __value_.reset(); }
9496
};
9597

9698
struct __empty_cache {};

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,6 +1851,7 @@ module std [system] {
18511851
module access { header "__ranges/access.h" }
18521852
module all { header "__ranges/all.h" }
18531853
module as_rvalue_view { header "__ranges/as_rvalue_view.h" }
1854+
module cache_latest_view { header "__ranges/cache_latest_view.h" }
18541855
module chunk_by_view {
18551856
header "__ranges/chunk_by_view.h"
18561857
export std.functional.bind_back

libcxx/include/ranges

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,13 @@ namespace std::ranges {
362362
class chunk_by_view; // C++23
363363
364364
namespace views { inline constexpr unspecified chunk_by = unspecified; } // C++23
365+
366+
// [range.cache.latest], cache latest view
367+
template<input_range V>
368+
requires view<V>
369+
class cache_latest_view; // C++26
370+
371+
namespace views { inline constexpr unspecified cache_latest = unspecified; } // C++26
365372
}
366373
367374
namespace std {
@@ -453,6 +460,10 @@ namespace std {
453460
# include <__ranges/zip_view.h>
454461
# endif
455462

463+
# if _LIBCPP_STD_VER >= 26
464+
# include <__ranges/cache_latest_view.h>
465+
# endif
466+
456467
# include <version>
457468

458469
// standard-mandated includes

libcxx/include/version

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ __cpp_lib_ranges 202406L <algorithm> <fun
200200
202110L // C++20
201201
__cpp_lib_ranges_as_const 202207L <ranges>
202202
__cpp_lib_ranges_as_rvalue 202207L <ranges>
203+
__cpp_lib_ranges_cache_latest 202411L <ranges>
203204
__cpp_lib_ranges_chunk 202202L <ranges>
204205
__cpp_lib_ranges_chunk_by 202202L <ranges>
205206
__cpp_lib_ranges_concat 202403L <ranges>
@@ -518,6 +519,7 @@ __cpp_lib_void_t 201411L <type_traits>
518519
# define __cpp_lib_ranges 202406L
519520
// # define __cpp_lib_ranges_as_const 202207L
520521
# define __cpp_lib_ranges_as_rvalue 202207L
522+
# define __cpp_lib_ranges_cache_latest 202411L
521523
// # define __cpp_lib_ranges_chunk 202202L
522524
# define __cpp_lib_ranges_chunk_by 202202L
523525
# define __cpp_lib_ranges_contains 202207L

libcxx/modules/std/ranges.inc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,15 @@ export namespace std {
351351
using std::ranges::views::cartesian_product;
352352
}
353353
#endif
354+
355+
#if _LIBCPP_STD_VER >= 26
356+
// [range.cache.latest], Cache latest view
357+
using std::ranges::cache_latest_view;
358+
359+
namespace views {
360+
using std::ranges::views::cache_latest;
361+
}
362+
#endif
354363
} // namespace ranges
355364

356365
namespace views = ranges::views;

0 commit comments

Comments
 (0)