aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libstdc++-v3/include/bits/version.def8
-rw-r--r--libstdc++-v3/include/bits/version.h10
-rw-r--r--libstdc++-v3/include/std/ranges189
-rw-r--r--libstdc++-v3/testsuite/std/ranges/adaptors/cache_latest/1.cc72
4 files changed, 279 insertions, 0 deletions
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 0cdc2e8..eb2c6d8 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1847,6 +1847,14 @@ ftms = {
};
ftms = {
+ name = ranges_cache_latest;
+ values = {
+ v = 202411;
+ cxxmin = 26;
+ };
+};
+
+ftms = {
name = ranges_concat;
values = {
v = 202403;
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index ec52cba..05dadd6 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2045,6 +2045,16 @@
#endif /* !defined(__cpp_lib_is_virtual_base_of) && defined(__glibcxx_want_is_virtual_base_of) */
#undef __glibcxx_want_is_virtual_base_of
+#if !defined(__cpp_lib_ranges_cache_latest)
+# if (__cplusplus > 202302L)
+# define __glibcxx_ranges_cache_latest 202411L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_ranges_cache_latest)
+# define __cpp_lib_ranges_cache_latest 202411L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_ranges_cache_latest) && defined(__glibcxx_want_ranges_cache_latest) */
+#undef __glibcxx_want_ranges_cache_latest
+
#if !defined(__cpp_lib_ranges_concat)
# if (__cplusplus > 202302L) && (__cpp_pack_indexing)
# define __glibcxx_ranges_concat 202403L
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index def7527..6790fcf 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -57,6 +57,7 @@
#define __glibcxx_want_ranges
#define __glibcxx_want_ranges_as_const
#define __glibcxx_want_ranges_as_rvalue
+#define __glibcxx_want_ranges_cache_latest
#define __glibcxx_want_ranges_cartesian_product
#define __glibcxx_want_ranges_concat
#define __glibcxx_want_ranges_chunk
@@ -1534,6 +1535,8 @@ namespace views::__adaptor
this->_M_payload._M_apply(_Optional_func{__f}, __i);
return this->_M_get();
}
+
+ using _Optional_base<_Tp>::_M_reset;
};
template<range _Range>
@@ -10201,6 +10204,192 @@ namespace ranges
} // namespace ranges
#endif // __cpp_lib_ranges_concat
+#if __cpp_lib_ranges_cache_latest // C++ >= 26
+namespace ranges
+{
+ template<input_range _Vp>
+ requires view<_Vp>
+ class cache_latest_view : public view_interface<cache_latest_view<_Vp>>
+ {
+ _Vp _M_base = _Vp();
+
+ using __cache_t = __conditional_t<is_reference_v<range_reference_t<_Vp>>,
+ add_pointer_t<range_reference_t<_Vp>>,
+ range_reference_t<_Vp>>;
+ __detail::__non_propagating_cache<__cache_t> _M_cache;
+
+ class _Iterator;
+ class _Sentinel;
+
+ public:
+ cache_latest_view() requires default_initializable<_Vp> = default;
+
+ constexpr explicit
+ cache_latest_view(_Vp __base)
+ : _M_base(std::move(__base))
+ { }
+
+ constexpr _Vp
+ base() const & requires copy_constructible<_Vp>
+ { return _M_base; }
+
+ constexpr _Vp
+ base() &&
+ { return std::move(_M_base); }
+
+ constexpr auto
+ begin()
+ { return _Iterator(*this); }
+
+ constexpr auto
+ end()
+ { return _Sentinel(*this); }
+
+ constexpr auto
+ size() requires sized_range<_Vp>
+ { return ranges::size(_M_base); }
+
+ constexpr auto
+ size() const requires sized_range<const _Vp>
+ { return ranges::size(_M_base); }
+ };
+
+ template<typename _Range>
+ cache_latest_view(_Range&&) -> cache_latest_view<views::all_t<_Range>>;
+
+ template<input_range _Vp>
+ requires view<_Vp>
+ class cache_latest_view<_Vp>::_Iterator
+ {
+ cache_latest_view* _M_parent;
+ iterator_t<_Vp> _M_current;
+
+ constexpr explicit
+ _Iterator(cache_latest_view& __parent)
+ : _M_parent(std::__addressof(__parent)),
+ _M_current(ranges::begin(__parent._M_base))
+ { }
+
+ friend class cache_latest_view;
+
+ public:
+ using difference_type = range_difference_t<_Vp>;
+ using value_type = range_value_t<_Vp>;
+ using iterator_concept = input_iterator_tag;
+
+ _Iterator(_Iterator&&) = default;
+
+ _Iterator&
+ operator=(_Iterator&&) = default;
+
+ constexpr iterator_t<_Vp>
+ base() &&
+ { return std::move(_M_current); }
+
+ constexpr const iterator_t<_Vp>&
+ base() const & noexcept
+ { return _M_current; }
+
+ constexpr range_reference_t<_Vp>&
+ operator*() const
+ {
+ if constexpr (is_reference_v<range_reference_t<_Vp>>)
+ {
+ if (!_M_parent->_M_cache)
+ _M_parent->_M_cache = std::__addressof(__detail::__as_lvalue(*_M_current));
+ return **_M_parent->_M_cache;
+ }
+ else
+ {
+ if (!_M_parent->_M_cache)
+ _M_parent->_M_cache._M_emplace_deref(_M_current);
+ return *_M_parent->_M_cache;
+ }
+ }
+
+ constexpr _Iterator&
+ operator++()
+ {
+ _M_parent->_M_cache._M_reset();
+ ++_M_current;
+ return *this;
+ }
+
+ constexpr void
+ operator++(int)
+ { ++*this; }
+
+ friend constexpr range_rvalue_reference_t<_Vp>
+ iter_move(const _Iterator& __i)
+ noexcept(noexcept(ranges::iter_move(__i._M_current)))
+ { return ranges::iter_move(__i._M_current); }
+
+ friend constexpr void
+ iter_swap(const _Iterator& __x, const _Iterator& __y)
+ noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current)))
+ requires indirectly_swappable<iterator_t<_Vp>>
+ { ranges::iter_swap(__x._M_current, __y._M_current); }
+ };
+
+ template<input_range _Vp>
+ requires view<_Vp>
+ class cache_latest_view<_Vp>::_Sentinel
+ {
+ sentinel_t<_Vp> _M_end = sentinel_t<_Vp>();
+
+ constexpr explicit
+ _Sentinel(cache_latest_view& __parent)
+ : _M_end(ranges::end(__parent._M_base))
+ { }
+
+ friend class cache_latest_view;
+
+ public:
+ _Sentinel() = default;
+
+ constexpr sentinel_t<_Vp>
+ base() const
+ { return _M_end; }
+
+ friend constexpr bool
+ operator==(const _Iterator& __x, const _Sentinel& __y)
+ { return __x._M_current == __y._M_end; }
+
+ friend constexpr range_difference_t<_Vp>
+ operator-(const _Iterator& __x, const _Sentinel& __y)
+ requires sized_sentinel_for<sentinel_t<_Vp>, iterator_t<_Vp>>
+ { return __x._M_current - __y._M_end; }
+
+ friend constexpr range_difference_t<_Vp>
+ operator-(const _Sentinel& __x, const _Iterator& __y)
+ requires sized_sentinel_for<sentinel_t<_Vp>, iterator_t<_Vp>>
+ { return __x._M_end - __y._M_current; }
+ };
+
+ namespace views
+ {
+ namespace __detail
+ {
+ template<typename _Tp>
+ concept __can_cache_latest = requires { cache_latest_view(std::declval<_Tp>()); };
+ }
+
+ struct _CacheLatest : __adaptor::_RangeAdaptorClosure<_CacheLatest>
+ {
+ template<viewable_range _Range>
+ requires __detail::__can_cache_latest<_Range>
+ constexpr auto
+ operator() [[nodiscard]] (_Range&& __r) const
+ { return cache_latest_view(std::forward<_Range>(__r)); }
+
+ static constexpr bool _S_has_simple_call_op = true;
+ };
+
+ inline constexpr _CacheLatest cache_latest;
+ }
+} // namespace ranges
+#endif // __cpp_lib_ranges_cache_latest
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // library concepts
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/cache_latest/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/cache_latest/1.cc
new file mode 100644
index 0000000..5904831
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/cache_latest/1.cc
@@ -0,0 +1,72 @@
+// { dg-do run { target c++26 } }
+
+#include <ranges>
+
+#if __cpp_lib_ranges_cache_latest != 202411L
+# error "Feature-test macro __cpp_lib_ranges_cache_latest has wrong value in <ranges>"
+#endif
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+
+namespace ranges = std::ranges;
+namespace views = std::views;
+
+constexpr bool
+test01()
+{
+ int xs[] = {1,2,3,4,5};
+ auto v = xs | views::cache_latest;
+ VERIFY( ranges::equal(v, xs) );
+ VERIFY( ranges::size(v) == 5 );
+
+ auto it = v.begin();
+ auto st = v.end();
+ VERIFY( st - it == 5 );
+ VERIFY( it - st == -5 );
+ it++;
+ VERIFY( st - it == 4 );
+ VERIFY( it - st == -4 );
+
+ auto jt = v.begin();
+ ranges::iter_swap(it, jt);
+ VERIFY( ranges::equal(xs, (int[]){2,1,3,4,5}) );
+ int n = ranges::iter_move(it);
+ VERIFY( n == 1 );
+ ranges::iter_swap(it, jt);
+
+ auto w = views::iota(1, 6) | views::cache_latest;
+ VERIFY( ranges::equal(w, xs) );
+
+ return true;
+}
+
+constexpr bool
+test02()
+{
+ // Motivating example from P3138R5
+ int xs[] = {1, 2, 3, 4, 5};
+ int transform_count = 0;
+ auto v = xs | views::transform([&](int i){ ++transform_count; return i * i; })
+ | views::filter([](int i){ return i % 2 == 0; });
+ VERIFY( ranges::equal(v, (int[]){4, 16}) );
+ VERIFY( transform_count == 7 );
+
+ transform_count = 0;
+ auto w = xs | views::transform([&](int i){ ++transform_count; return i * i; })
+ | views::cache_latest
+ | views::filter([](int i){ return i % 2 == 0; });
+ VERIFY( ranges::equal(w, (int[]){4, 16}) );
+ VERIFY( transform_count == 5 );
+
+ return true;
+}
+
+int
+main()
+{
+ static_assert(test01());
+ static_assert(test02());
+ test01();
+ test02();
+}