Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libcxx/docs/FeatureTestMacroTable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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``
Expand Down
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes/22.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Implemented Papers

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

Improvements and New Features
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2cPapers.csv
Original file line number Diff line number Diff line change
Expand Up @@ -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|","22","`#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>`__",""
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
226 changes: 226 additions & 0 deletions libcxx/include/__ranges/cache_latest_view.h
Original file line number Diff line number Diff line change
@@ -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 <input_range _View>
requires view<_View>
class cache_latest_view : public view_interface<cache_latest_view<_View>> {
_View __base_ = _View(); // exposition only
using __cache_t _LIBCPP_NODEBUG =
conditional_t<is_reference_v<range_reference_t<_View>>, // exposition only
add_pointer_t<range_reference_t<_View>>,
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<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_; // 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<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; }

_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>(); // 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<sentinel_t<_View>, 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<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
2 changes: 2 additions & 0 deletions libcxx/include/__ranges/non_propagating_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions libcxx/include/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -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<input_range V>
requires view<V>
class cache_latest_view; // C++26

namespace views { inline constexpr unspecified cache_latest = unspecified; } // C++26
}

namespace std {
Expand Down Expand Up @@ -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 <version>

// standard-mandated includes
Expand Down
2 changes: 2 additions & 0 deletions libcxx/include/version
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,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>
Expand Down Expand Up @@ -518,6 +519,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
Expand Down
9 changes: 9 additions & 0 deletions libcxx/modules/std/ranges.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
52 changes: 52 additions & 0 deletions libcxx/test/libcxx/ranges/range.nonprop.cache/reset.pass.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
Loading
Loading