1fe6060f1SDimitry Andric // -*- C++ -*- 2fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 3fe6060f1SDimitry Andric // 4fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7fe6060f1SDimitry Andric // 8fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 9bdd1243dSDimitry Andric 10fe6060f1SDimitry Andric #ifndef _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H 11fe6060f1SDimitry Andric #define _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H 12fe6060f1SDimitry Andric 13fe6060f1SDimitry Andric #include <__config> 14fe6060f1SDimitry Andric #include <__iterator/concepts.h> // indirectly_readable 15fe6060f1SDimitry Andric #include <__iterator/iterator_traits.h> // iter_reference_t 16fe6060f1SDimitry Andric #include <__memory/addressof.h> 17349cc55cSDimitry Andric #include <__utility/forward.h> 18fe6060f1SDimitry Andric #include <optional> 19fe6060f1SDimitry Andric 20fe6060f1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 21fe6060f1SDimitry Andric # pragma GCC system_header 22fe6060f1SDimitry Andric #endif 23fe6060f1SDimitry Andric 24fe6060f1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 25fe6060f1SDimitry Andric 2606c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20 27fe6060f1SDimitry Andric 28fe6060f1SDimitry Andric namespace ranges { 29fe6060f1SDimitry Andric // __non_propagating_cache is a helper type that allows storing an optional value in it, 30fe6060f1SDimitry Andric // but which does not copy the source's value when it is copy constructed/assigned to, 31fe6060f1SDimitry Andric // and which resets the source's value when it is moved-from. 32fe6060f1SDimitry Andric // 33fe6060f1SDimitry Andric // This type is used as an implementation detail of some views that need to cache the 34fe6060f1SDimitry Andric // result of `begin()` in order to provide an amortized O(1) begin() method. Typically, 35fe6060f1SDimitry Andric // we don't want to propagate the value of the cache upon copy because the cached iterator 36fe6060f1SDimitry Andric // may refer to internal details of the source view. 37fe6060f1SDimitry Andric template <class _Tp> 38fe6060f1SDimitry Andric requires is_object_v<_Tp> 39fe6060f1SDimitry Andric class _LIBCPP_TEMPLATE_VIS __non_propagating_cache { 40349cc55cSDimitry Andric struct __from_tag {}; 41349cc55cSDimitry Andric struct __forward_tag {}; 42349cc55cSDimitry Andric 43349cc55cSDimitry Andric // This helper class is needed to perform copy and move elision when 44349cc55cSDimitry Andric // constructing the contained type from an iterator. 45349cc55cSDimitry Andric struct __wrapper { 46349cc55cSDimitry Andric template <class... _Args> __wrapper__wrapper4706c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr explicit __wrapper(__forward_tag, _Args&&... __args) 4806c3fb27SDimitry Andric : __t_(std::forward<_Args>(__args)...) {} 49349cc55cSDimitry Andric template <class _Fn> __wrapper__wrapper5006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr explicit __wrapper(__from_tag, _Fn const& __f) : __t_(__f()) {} 51349cc55cSDimitry Andric _Tp __t_; 52349cc55cSDimitry Andric }; 53349cc55cSDimitry Andric 54349cc55cSDimitry Andric optional<__wrapper> __value_ = nullopt; 55fe6060f1SDimitry Andric 56fe6060f1SDimitry Andric public: 57fe6060f1SDimitry Andric _LIBCPP_HIDE_FROM_ABI __non_propagating_cache() = default; 58fe6060f1SDimitry Andric __non_propagating_cache(__non_propagating_cache const &)59*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __non_propagating_cache(__non_propagating_cache const&) noexcept 60*cb14a3feSDimitry Andric : __value_(nullopt) {} 61fe6060f1SDimitry Andric __non_propagating_cache(__non_propagating_cache && __other)62*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __non_propagating_cache(__non_propagating_cache&& __other) noexcept 63*cb14a3feSDimitry Andric : __value_(nullopt) { 64fe6060f1SDimitry Andric __other.__value_.reset(); 65fe6060f1SDimitry Andric } 66fe6060f1SDimitry Andric 67*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __non_propagating_cache& operator=(__non_propagating_cache const& __other) noexcept { 6881ad6265SDimitry Andric if (this != std::addressof(__other)) { 69fe6060f1SDimitry Andric __value_.reset(); 70fe6060f1SDimitry Andric } 71fe6060f1SDimitry Andric return *this; 72fe6060f1SDimitry Andric } 73fe6060f1SDimitry Andric 74*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __non_propagating_cache& operator=(__non_propagating_cache&& __other) noexcept { 75fe6060f1SDimitry Andric __value_.reset(); 76fe6060f1SDimitry Andric __other.__value_.reset(); 77fe6060f1SDimitry Andric return *this; 78fe6060f1SDimitry Andric } 79fe6060f1SDimitry Andric 80*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() { return __value_->__t_; } 81*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& operator*() const { return __value_->__t_; } 82fe6060f1SDimitry Andric __has_value()83*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr bool __has_value() const { return __value_.has_value(); } 84349cc55cSDimitry Andric 85349cc55cSDimitry Andric template <class _Fn> __emplace_from(_Fn const & __f)86*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __emplace_from(_Fn const& __f) { 87349cc55cSDimitry Andric return __value_.emplace(__from_tag{}, __f).__t_; 88349cc55cSDimitry Andric } 89349cc55cSDimitry Andric 90349cc55cSDimitry Andric template <class... _Args> __emplace(_Args &&...__args)91*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr _Tp& __emplace(_Args&&... __args) { 9281ad6265SDimitry Andric return __value_.emplace(__forward_tag{}, std::forward<_Args>(__args)...).__t_; 93349cc55cSDimitry Andric } 94fe6060f1SDimitry Andric }; 95fe6060f1SDimitry Andric 96fe6060f1SDimitry Andric struct __empty_cache {}; 97fe6060f1SDimitry Andric } // namespace ranges 98fe6060f1SDimitry Andric 9906c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 20 100fe6060f1SDimitry Andric 101fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 102fe6060f1SDimitry Andric 103fe6060f1SDimitry Andric #endif // _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H 104