| 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 __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 | |