diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst index 358889d8dbc37..a2d8c4f5bbc2b 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/22.rst b/libcxx/docs/ReleaseNotes/22.rst index e56f0a88db138..36d20963b09d7 100644 --- a/libcxx/docs/ReleaseNotes/22.rst +++ b/libcxx/docs/ReleaseNotes/22.rst @@ -40,6 +40,7 @@ Implemented Papers - P2321R2: ``zip`` (`Github `__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release) +- P3138R3: ``std::ranges::cache_latest`` (`Github `__) - P3168R2: Give ``std::optional`` Range Support (`Github `__) Improvements and New Features diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv index f873d16808afe..337d7518f8900 100644 --- a/libcxx/docs/Status/Cxx2cPapers.csv +++ b/libcxx/docs/Status/Cxx2cPapers.csv @@ -77,7 +77,7 @@ "`P2300R10 `__","``std::execution``","2024-06 (St. Louis)","","","`#105440 `__","" "","","","","","" "`P3136R1 `__","Retiring niebloids","2024-11 (Wrocław)","|Complete|","14","`#118133 `__","" -"`P3138R5 `__","``views::cache_latest``","2024-11 (Wrocław)","","","`#118134 `__","" +"`P3138R5 `__","``views::cache_latest``","2024-11 (Wrocław)","|Complete|","22","`#118134 `__","" "`P3379R0 `__","Constrain ``std::expected`` equality operators","2024-11 (Wrocław)","|Complete|","21","`#118135 `__","" "`P2862R1 `__","``text_encoding::name()`` should never return null values","2024-11 (Wrocław)","","","`#118371 `__","" "`P2897R7 `__","``aligned_accessor``: An ``mdspan`` accessor expressing pointer over-alignment","2024-11 (Wrocław)","|Complete|","21","`#118372 `__","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index db918a16e9a61..5e880898daf1b 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -697,6 +697,7 @@ set(files __ranges/access.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..d0d2cb8e1aad8 --- /dev/null +++ b/libcxx/include/__ranges/cache_latest_view.h @@ -0,0 +1,226 @@ +// -*- 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 + requires view<_View> +class cache_latest_view : public view_interface> { + _View __base_ = _View(); // exposition only + using __cache_t _LIBCPP_NODEBUG = + conditional_t>, // exposition only + add_pointer_t>, + range_reference_t<_View>>; + + __non_propagating_cache<__cache_t> __cache_; // exposition only + + // [range.cache.latest.iterator], class cache_latest_view::iterator + class iterator; // exposition only + // [range.cache.latest.sentinel], class cache_latest_view::sentinel + class sentinel; // exposition only + +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)} {} + + _LIBCPP_HIDE_FROM_ABI constexpr _View base() const& + requires copy_constructible<_View> + { + return __base_; + } + _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); } + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { return iterator(*this); } + _LIBCPP_HIDE_FROM_ABI constexpr auto end() { return sentinel{*this}; } + + _LIBCPP_HIDE_FROM_ABI constexpr auto size() + requires sized_range<_View> + { + return ranges::size(__base_); + } + _LIBCPP_HIDE_FROM_ABI constexpr auto size() const + requires sized_range + { + 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 + // { + // return ranges::reserve_hint(__base_); + // } +}; + +template +cache_latest_view(_Range&&) -> cache_latest_view>; + +// [range.cache.latest.iterator] + +template + requires view<_View> +class cache_latest_view<_View>::iterator { + cache_latest_view* __parent_; // exposition only + iterator_t<_View> __current_; // exposition only + + _LIBCPP_HIDE_FROM_ABI constexpr explicit iterator(cache_latest_view& __parent) // exposition only + : __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; + + _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> base() && { return std::move(__current_); } + _LIBCPP_HIDE_FROM_ABI constexpr const iterator_t<_View>& base() const& noexcept { return __current_; } + + _LIBCPP_HIDE_FROM_ABI constexpr range_reference_t<_View>& operator*() const { + if constexpr (is_reference_v>) { + 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; } + + _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> + { + ranges::iter_swap(__x.__current_, __y.__current_); + } +}; + +// [range.cache.latest.sentinel] + +template + requires view<_View> +class cache_latest_view<_View>::sentinel { + sentinel_t<_View> __end_ = sentinel_t<_View>(); // exposition only + + _LIBCPP_HIDE_FROM_ABI constexpr explicit sentinel(cache_latest_view& __parent) // exposition only + : __end_{ranges::end(__parent.__base_)} {} + + friend class cache_latest_view<_View>; + +public: + _LIBCPP_HIDE_FROM_ABI sentinel() = default; + + _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_; + } + + _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<_View> operator-(const iterator& __x, const sentinel& __y) + requires sized_sentinel_for, iterator_t<_View>> + { + return __x.__current_ - __y.__end_; + } + _LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<_View> operator-(const sentinel& __x, const iterator& __y) + requires sized_sentinel_for, iterator_t<_View>> + { + return __x.__end_ - __y.__current_; + } +}; + +namespace views { +namespace __cache_latest_view { + +struct __fn : __range_adaptor_closure<__fn> { + template + [[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 63cf8e847751f..c19d1254782d8 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1851,6 +1851,7 @@ module std [system] { module access { header "__ranges/access.h" } module all { header "__ranges/all.h" } 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 96d7a6b897188..3e3bde01a1b34 100644 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -362,6 +362,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 + requires view + class cache_latest_view; // C++26 + + namespace views { inline constexpr unspecified cache_latest = unspecified; } // C++26 } namespace std { @@ -453,6 +460,10 @@ namespace std { # include <__ranges/zip_view.h> # endif +# if _LIBCPP_STD_VER >= 26 +# include <__ranges/cache_latest_view.h> +# endif + # include // standard-mandated includes diff --git a/libcxx/include/version b/libcxx/include/version index 16917a3bd9ddd..3a73450bfc88f 100644 --- a/libcxx/include/version +++ b/libcxx/include/version @@ -200,6 +200,7 @@ __cpp_lib_ranges 202406L __cpp_lib_ranges_as_rvalue 202207L +__cpp_lib_ranges_cache_latest 202411L __cpp_lib_ranges_chunk 202202L __cpp_lib_ranges_chunk_by 202202L __cpp_lib_ranges_concat 202403L @@ -518,6 +519,7 @@ __cpp_lib_void_t 201411L # 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 7ede42e4f7b0a..1f09c8c5fdca1 100644 --- a/libcxx/modules/std/ranges.inc +++ b/libcxx/modules/std/ranges.inc @@ -351,6 +351,15 @@ export namespace std { using std::ranges::views::cartesian_product; } #endif + +#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 + +#include + +template +constexpr void test() { + using Cache = std::ranges::__non_propagating_cache; + + // __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(); + test(); + 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 df19f03e7dba1..dab58019979a1 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 @@ -86,6 +90,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 @@ -136,6 +144,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 @@ -189,6 +201,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 @@ -254,6 +270,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" @@ -367,6 +390,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 cde2f258b7732..6c76e28cd7f41 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 @@ -644,6 +644,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 @@ -1584,6 +1588,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 @@ -2695,6 +2703,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 @@ -4079,6 +4091,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 @@ -5640,6 +5656,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" @@ -7543,6 +7566,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 49497875dcf95..df0df24ce4cd2 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 @@ -132,7 +132,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 + +// + +// class cache_latest_view + +#include +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +static_assert(std::is_same_v); + +struct NonView {}; + +static_assert(std::default_initializable); + +struct DefaultInitializableView : std::ranges::view_base { + int i_; + + int* begin(); + int* end(); +}; + +static_assert(std::default_initializable); +static_assert(std::ranges::common_range); +static_assert(std::ranges::input_range); + +struct CommonView : std::ranges::view_base { + int i_; + + constexpr forward_iterator begin() { return forward_iterator(&i_); } + constexpr forward_iterator end() { return begin(); } +}; + +static_assert(std::ranges::common_range); +static_assert(std::ranges::forward_range); +static_assert(std::ranges::input_range); + +struct NonCommonView : std::ranges::view_base { + int i_; + + constexpr forward_iterator begin() { return forward_iterator(&i_); } + constexpr sentinel_wrapper> end() { return sentinel_wrapper>(begin()); } +}; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::forward_range); +static_assert(std::ranges::input_range); +static_assert( + std::derived_from< typename std::iterator_traits>::iterator_category, + std::input_iterator_tag>); + +// Check that the `cache_latest` adaptor can be used with a view. + +static_assert(!std::is_invocable_v); +static_assert(!std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); +static_assert(std::is_invocable_v); + +static_assert(!CanBePiped); +static_assert(CanBePiped); +static_assert(CanBePiped); +static_assert(CanBePiped); + +constexpr bool test() { + { // view | views::cache_latest + { + DefaultInitializableView view{{}, 94}; + std::same_as> decltype(auto) v = + view | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::input_range); + } + { + CommonView view{{}, 94}; + std::same_as> decltype(auto) v = view | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::input_range); + } + { + NonCommonView view{{}, 94}; + std::same_as> decltype(auto) v = view | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::input_range); + } + } + + { // adaptor | views::cache_latest + { + DefaultInitializableView view{{}, 94}; + const auto partial = std::views::transform(std::identity{}) | std::views::cache_latest; + std::same_as>> decltype(auto) v = partial(view); + assert(v.base().base().i_ == 94); + + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::input_range); + } + { + 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>> decltype(auto) v = + partial(view); + assert(v.base().base().i_ == 94); + + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::input_range); + } + { + 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>> decltype(auto) v = + partial(view); + assert(v.base().base().i_ == 94); + + static_assert(!std::ranges::common_range); + static_assert(!std::ranges::forward_range); + static_assert(std::ranges::input_range); + } + } + + { // views::cache_latest | adaptor + { + DefaultInitializableView view{{}, 94}; + const auto partial = std::views::cache_latest | std::views::transform(std::identity{}); + std::same_as, + std::identity>> decltype(auto) v = partial(view); + assert(v.base().base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + { + CommonView view{{}, 94}; + const auto partial = std::views::cache_latest | std::views::transform(std::identity{}); + std::same_as< + std::ranges::transform_view, std::identity>> decltype(auto) v = + partial(view); + assert(v.base().base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + { + NonCommonView view{{}, 94}; + const auto partial = std::views::cache_latest | std::views::transform(std::identity{}); + std::same_as< + std::ranges::transform_view, std::identity>> decltype(auto) v = + partial(view); + assert(v.base().base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + } + + { // views::cache_latest | views::all + { + DefaultInitializableView view{{}, 94}; + std::same_as> decltype(auto) v = + std::views::all(view) | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + { + CommonView view{{}, 94}; + std::same_as> decltype(auto) v = + std::views::all(view) | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + { + NonCommonView view{{}, 94}; + std::same_as> decltype(auto) v = + std::views::all(view) | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + } + + { // views::cache_latest | views::all_t + { + DefaultInitializableView view{{}, 94}; + std::same_as> decltype(auto) v = + std::views::all_t(view) | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + { + CommonView view{{}, 94}; + std::same_as> decltype(auto) v = + std::views::all_t(view) | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + { + NonCommonView view{{}, 94}; + std::same_as> decltype(auto) v = + std::views::all_t(view) | std::views::cache_latest; + assert(v.base().i_ == 94); + + static_assert(std::ranges::input_range); + static_assert(!std::ranges::forward_range); + static_assert(!std::ranges::common_range); + } + } + + 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 + +// + +// class cache_latest_view + +// constexpr V base() const & requires copy_constructible { return base_; } +// constexpr V base() && { return std::move(base_); } + +#include +#include +#include + +#include + +#include "MoveOnly.h" + +struct SimpleView : std::ranges::view_base { + int i_; + + int* begin() const; + int* end() const; +}; + +struct MoveOnlyView : public SimpleView { + MoveOnly m_; +}; + +template +concept HasBase = requires(T&& t) { std::forward(t).base(); }; + +static_assert(HasBase const&>); +static_assert(HasBase&&>); + +static_assert(!HasBase const&>); +static_assert(HasBase&&>); + +constexpr bool test() { + { // & + std::ranges::cache_latest_view view(SimpleView{{}, 94}); + std::same_as decltype(auto) v = view.base(); + assert(v.i_ == 94); + } + + { // const & + const std::ranges::cache_latest_view view(SimpleView{{}, 94}); + std::same_as decltype(auto) v = view.base(); + assert(v.i_ == 94); + } + + { // && + std::ranges::cache_latest_view view(SimpleView{{}, 94}); + std::same_as decltype(auto) v = std::move(view).base(); + assert(v.i_ == 94); + } + + { // const && + const std::ranges::cache_latest_view view(SimpleView{{}, 94}); + std::same_as decltype(auto) v = std::move(view).base(); + assert(v.i_ == 94); + } + + { // move only + std::ranges::cache_latest_view view(MoveOnlyView{{}, 94}); + std::same_as 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 + +// + +// class cache_latest_view + +// constexpr auto begin(); + +#include +#include +#include + +#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 +concept HasBegin = requires(T t) { t.begin(); }; + +static_assert(HasBegin>); +static_assert(!HasBegin>); +static_assert(HasBegin>); +static_assert(!HasBegin>); +static_assert(HasBegin>); +static_assert(!HasBegin>); + +struct CommonView : std::ranges::view_base { + int i_; + + constexpr forward_iterator begin() { return forward_iterator(&i_); } + constexpr forward_iterator end() { return begin(); } +}; + +static_assert(std::ranges::common_range); +static_assert(std::ranges::forward_range); +static_assert(std::ranges::input_range); + +struct NonCommonView : std::ranges::view_base { + int i_; + + constexpr forward_iterator begin() { return forward_iterator(&i_); } + constexpr sentinel_wrapper> end() { return sentinel_wrapper>(begin()); } +}; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::forward_range); +static_assert(std::ranges::input_range); +static_assert( + std::derived_from>::iterator_category, + std::input_iterator_tag>); + +constexpr bool test() { + { + CommonView view{{}, 94}; + + std::same_as> 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> 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>> 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 + +// + +// class cache_latest_view + +// template +// cache_latest_view(R&&) -> cache_latest_view>; + +#include +#include +#include +#include + +static_assert(std::same_as{})), + std::ranges::cache_latest_view>>>); + +static_assert(std::same_as&>())), + std::ranges::cache_latest_view&>>>); + +static_assert(std::same_as{})), + std::ranges::cache_latest_view>>); \ 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 + +// + +// class cache_latest_view + +// cache_latest_view() requires default_initializable = default; + +#include +#include +#include + +struct DefaultInitializableView : std::ranges::view_base { + int i_ = 94; + + int* begin(); + int* end(); +}; + +static_assert(std::default_initializable); +static_assert(std::default_initializable>); + +struct NoDefaultInitializableView : std::ranges::view_base { + NoDefaultInitializableView() = delete; + + int* begin(); + int* end(); +}; + +static_assert(!std::default_initializable); +static_assert(!std::default_initializable>); + +struct NoexceptView : std::ranges::view_base { + NoexceptView() noexcept; + + int const* begin() const; + int const* end() const; +}; + +static_assert(noexcept(std::ranges::cache_latest_view())); + +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())); + +constexpr bool test() { + { // value-initialized (i.e., whether T() is well-formed). + std::ranges::cache_latest_view 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 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 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 + +// + +// 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 + +// + +// class cache_latest_view + +// Test that std::ranges::cache_latest_view is not std::ranges::borrowed_range. + +#include + +struct BorrowedView : std::ranges::view_base { + int* begin(); + int* end(); +}; + +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(!std::ranges::borrowed_range>); + +struct NonBorrowedView : std::ranges::view_base { + int* begin(); + int* end(); +}; + +static_assert(!std::ranges::borrowed_range>); 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 + +// + +// class cache_latest_view + +// constexpr auto end(); + +#include +#include +#include + +#include "test_iterators.h" +#include + +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 +concept HasEnd = requires(T t) { t.end(); }; + +static_assert(HasEnd>); +static_assert(!HasEnd>); +static_assert(HasEnd>); +static_assert(!HasEnd>); +static_assert(HasEnd>); +static_assert(!HasEnd>); + +struct CommonView : std::ranges::view_base { + int i_; + + constexpr forward_iterator begin() { return forward_iterator(&i_); } + constexpr forward_iterator end() { return begin(); } +}; + +static_assert(std::ranges::common_range); +static_assert(std::ranges::forward_range); +static_assert(std::ranges::input_range); + +struct NonCommonView : std::ranges::view_base { + int i_; + + constexpr forward_iterator begin() { return forward_iterator(&i_); } + constexpr sentinel_wrapper> end() { return sentinel_wrapper>(begin()); } +}; + +static_assert(!std::ranges::common_range); +static_assert(std::ranges::forward_range); +static_assert(std::ranges::input_range); +static_assert( + std::derived_from>::iterator_category, + std::input_iterator_tag>); + +constexpr bool test() { + { + CommonView view{{}, 94}; + + std::same_as> decltype(auto) v = view | std::views::cache_latest; + + assert(*base(v.end().base()) == view.i_); + } + { + NonCommonView view{{}, 94}; + + std::same_as> decltype(auto) v = view | std::views::cache_latest; + + assert(*base(v.end().base()) == view.i_); + } + + { + int arr[] = {82, 94, 76}; + + std::same_as>> 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 + +// + +// 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 + +// + +// class cache_latest_view + +// Functional tests of std::ranges::cache_latest_view. + +#include +#include +#include +#include + +constexpr bool test() { + // Motivational example from P3138R3. + std::vector vec = {1, 2, 3, 4, 5}; + std::vector 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..ec907d4f4668c --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/iterator/ctor.default.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// requires view +// template +// class to_input_view::iterator + +// iterator() requires default_initializable> = default; + +#include +#include +#include + +#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); + +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 begin() const; + sentinel_wrapper> end() const; +}; + +template +using CacheLatestViewIteratorT = std::ranges::iterator_t>; + +// Check that the to_input_view's iterator is default initializable when the underlying iterator is. +static_assert(std::default_initializable>); +static_assert(!std::default_initializable>); + +constexpr bool test() { + { + CacheLatestViewIteratorT it; + assert(*it == 0); // DefaultInitializableIterator has to be initialized to have value 0. + } + { + CacheLatestViewIteratorT 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..4b02bc1cad3c2 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.cache.latest/sentinel/ctor.default.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template +// requires view +// template +// class to_input_view::iterator + +// iterator() requires default_initializable> = default; + +#include +#include +#include + +#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); + +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 begin() const; + sentinel_wrapper> end() const; +}; + +template +using CacheLatestViewSentinelT = std::ranges::sentinel_t>; + +// Check that the to_input_view's iterator is default initializable when the underlying iterator is. +static_assert(std::default_initializable>); +static_assert(!std::default_initializable>); + +constexpr bool test() { + { + CacheLatestViewSentinelT it; + assert(*it == 0); // DefaultInitializableIterator has to be initialized to have value 0. + } + { + CacheLatestViewSentinelT 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 + +// + +// class cache_latest_view + +// constexpr auto size() requires sized_range; +// constexpr auto size() const requires sized_range; + +#include +#include +#include +#include + +#include "test_iterators.h" + +template +concept HasSize = requires(T t) { t.size(); }; + +constexpr bool test() { + { + struct SubtractableIteratorsView : std::ranges::view_base { + forward_iterator begin(); + sized_sentinel> end(); + }; + + using ToCacheLatestViewT = std::ranges::cache_latest_view; + + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::range); // no begin()/end() + + static_assert(HasSize); + static_assert(HasSize); + static_assert(!HasSize); + static_assert(!HasSize); + } + { + struct NonSizedView : std::ranges::view_base { + bidirectional_iterator begin(); + bidirectional_iterator end(); + }; + + using ToCacheLatestViewT = std::ranges::cache_latest_view; + + static_assert(!HasSize); + static_assert(!HasSize); + static_assert(!HasSize); + static_assert(!HasSize); + } + { + struct SizedView : std::ranges::view_base { + bidirectional_iterator begin(); + bidirectional_iterator end(); + + int size() const; + }; + + using ToCacheLatestViewT = std::ranges::cache_latest_view; + + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::range); // no begin()/end() + + static_assert(HasSize); + static_assert(HasSize); + static_assert(!HasSize); // not a view, therefore no size() + static_assert(!HasSize); + } + { + // 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 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 c1e579c775746..8924ef9c5df13 100644 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -1086,6 +1086,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},