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_NON_PROPAGATING_CACHE_H |
11 | #define _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H |
12 | |
13 | #include <__config> |
14 | #include <__iterator/concepts.h> // indirectly_readable |
15 | #include <__iterator/iterator_traits.h> // iter_reference_t |
16 | #include <__memory/addressof.h> |
17 | #include <__utility/forward.h> |
18 | #include <optional> |
19 | |
20 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
21 | # pragma GCC system_header |
22 | #endif |
23 | |
24 | _LIBCPP_BEGIN_NAMESPACE_STD |
25 | |
26 | #if _LIBCPP_STD_VER >= 20 |
27 | |
28 | namespace ranges { |
29 | // __non_propagating_cache is a helper type that allows storing an optional value in it, |
30 | // but which does not copy the source's value when it is copy constructed/assigned to, |
31 | // and which resets the source's value when it is moved-from. |
32 | // |
33 | // This type is used as an implementation detail of some views that need to cache the |
34 | // result of `begin()` in order to provide an amortized O(1) begin() method. Typically, |
35 | // we don't want to propagate the value of the cache upon copy because the cached iterator |
36 | // may refer to internal details of the source view. |
37 | template <class _Tp> |
38 | requires is_object_v<_Tp> |
39 | class _LIBCPP_TEMPLATE_VIS __non_propagating_cache { |
40 | struct __from_tag {}; |
41 | struct __forward_tag {}; |
42 | |
43 | // This helper class is needed to perform copy and move elision when |
44 | // constructing the contained type from an iterator. |
45 | struct __wrapper { |
46 | template <class... _Args> |
47 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __wrapper(__forward_tag, _Args&&... __args) |
48 | : __t_(std::forward<_Args>(__args)...) {} |
49 | template <class _Fn> |
50 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __wrapper(__from_tag, _Fn const& __f) : __t_(__f()) {} |
51 | _Tp __t_; |
52 | }; |
53 | |
54 | optional<__wrapper> __value_ = nullopt; |
55 | |
56 | public: |
57 | _LIBCPP_HIDE_FROM_ABI __non_propagating_cache() = default; |
58 | |
59 | _LIBCPP_HIDE_FROM_ABI constexpr __non_propagating_cache(__non_propagating_cache const&) noexcept |
60 | : __value_(nullopt) {} |
61 | |
62 | _LIBCPP_HIDE_FROM_ABI constexpr __non_propagating_cache(__non_propagating_cache&& __other) noexcept |
63 | : __value_(nullopt) { |
64 | __other.__value_.reset(); |
65 | } |
66 | |
67 | _LIBCPP_HIDE_FROM_ABI constexpr __non_propagating_cache& operator=(__non_propagating_cache const& __other) noexcept { |
68 | if (this != std::addressof(__other)) { |
69 | __value_.reset(); |
70 | } |
71 | return *this; |
72 | } |
73 | |
74 | _LIBCPP_HIDE_FROM_ABI constexpr __non_propagating_cache& operator=(__non_propagating_cache&& __other) noexcept { |
75 | __value_.reset(); |
76 | __other.__value_.reset(); |
77 | return *this; |
78 | } |
79 | |
80 | _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() { return __value_->__t_; } |
81 | _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& operator*() const { return __value_->__t_; } |
82 | |
83 | _LIBCPP_HIDE_FROM_ABI constexpr bool __has_value() const { return __value_.has_value(); } |
84 | |
85 | template <class _Fn> |
86 | _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __emplace_from(_Fn const& __f) { |
87 | return __value_.emplace(__from_tag{}, __f).__t_; |
88 | } |
89 | |
90 | template <class... _Args> |
91 | _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __emplace(_Args&&... __args) { |
92 | return __value_.emplace(__forward_tag{}, std::forward<_Args>(__args)...).__t_; |
93 | } |
94 | }; |
95 | |
96 | struct __empty_cache {}; |
97 | } // namespace ranges |
98 | |
99 | #endif // _LIBCPP_STD_VER >= 20 |
100 | |
101 | _LIBCPP_END_NAMESPACE_STD |
102 | |
103 | #endif // _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H |
104 | |