176d0caaeSpatrick // -*- C++ -*- 276d0caaeSpatrick //===----------------------------------------------------------------------===// 376d0caaeSpatrick // 476d0caaeSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 576d0caaeSpatrick // See https://llvm.org/LICENSE.txt for license information. 676d0caaeSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 776d0caaeSpatrick // 876d0caaeSpatrick //===----------------------------------------------------------------------===// 9*4bdff4beSrobert 1076d0caaeSpatrick #ifndef _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H 1176d0caaeSpatrick #define _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H 1276d0caaeSpatrick 1376d0caaeSpatrick #include <__config> 1476d0caaeSpatrick #include <__iterator/concepts.h> // indirectly_readable 1576d0caaeSpatrick #include <__iterator/iterator_traits.h> // iter_reference_t 1676d0caaeSpatrick #include <__memory/addressof.h> 17*4bdff4beSrobert #include <__utility/forward.h> 1876d0caaeSpatrick #include <optional> 1976d0caaeSpatrick #include <type_traits> 2076d0caaeSpatrick 2176d0caaeSpatrick #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 2276d0caaeSpatrick # pragma GCC system_header 2376d0caaeSpatrick #endif 2476d0caaeSpatrick 2576d0caaeSpatrick _LIBCPP_BEGIN_NAMESPACE_STD 2676d0caaeSpatrick 27*4bdff4beSrobert #if _LIBCPP_STD_VER > 17 2876d0caaeSpatrick 2976d0caaeSpatrick namespace ranges { 3076d0caaeSpatrick // __non_propagating_cache is a helper type that allows storing an optional value in it, 3176d0caaeSpatrick // but which does not copy the source's value when it is copy constructed/assigned to, 3276d0caaeSpatrick // and which resets the source's value when it is moved-from. 3376d0caaeSpatrick // 3476d0caaeSpatrick // This type is used as an implementation detail of some views that need to cache the 3576d0caaeSpatrick // result of `begin()` in order to provide an amortized O(1) begin() method. Typically, 3676d0caaeSpatrick // we don't want to propagate the value of the cache upon copy because the cached iterator 3776d0caaeSpatrick // may refer to internal details of the source view. 3876d0caaeSpatrick template<class _Tp> 3976d0caaeSpatrick requires is_object_v<_Tp> 4076d0caaeSpatrick class _LIBCPP_TEMPLATE_VIS __non_propagating_cache { 41*4bdff4beSrobert struct __from_tag { }; 42*4bdff4beSrobert struct __forward_tag { }; 43*4bdff4beSrobert 44*4bdff4beSrobert // This helper class is needed to perform copy and move elision when 45*4bdff4beSrobert // constructing the contained type from an iterator. 46*4bdff4beSrobert struct __wrapper { 47*4bdff4beSrobert template<class ..._Args> __wrapper__wrapper48*4bdff4beSrobert constexpr explicit __wrapper(__forward_tag, _Args&& ...__args) : __t_(std::forward<_Args>(__args)...) { } 49*4bdff4beSrobert template<class _Fn> __wrapper__wrapper50*4bdff4beSrobert constexpr explicit __wrapper(__from_tag, _Fn const& __f) : __t_(__f()) { } 51*4bdff4beSrobert _Tp __t_; 52*4bdff4beSrobert }; 53*4bdff4beSrobert 54*4bdff4beSrobert optional<__wrapper> __value_ = nullopt; 5576d0caaeSpatrick 5676d0caaeSpatrick public: 5776d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI __non_propagating_cache() = default; 5876d0caaeSpatrick 5976d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI __non_propagating_cache(__non_propagating_cache const &)6076d0caaeSpatrick constexpr __non_propagating_cache(__non_propagating_cache const&) noexcept 6176d0caaeSpatrick : __value_(nullopt) 6276d0caaeSpatrick { } 6376d0caaeSpatrick 6476d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI __non_propagating_cache(__non_propagating_cache && __other)6576d0caaeSpatrick constexpr __non_propagating_cache(__non_propagating_cache&& __other) noexcept 6676d0caaeSpatrick : __value_(nullopt) 6776d0caaeSpatrick { 6876d0caaeSpatrick __other.__value_.reset(); 6976d0caaeSpatrick } 7076d0caaeSpatrick 7176d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI 7276d0caaeSpatrick constexpr __non_propagating_cache& operator=(__non_propagating_cache const& __other) noexcept { 73*4bdff4beSrobert if (this != std::addressof(__other)) { 7476d0caaeSpatrick __value_.reset(); 7576d0caaeSpatrick } 7676d0caaeSpatrick return *this; 7776d0caaeSpatrick } 7876d0caaeSpatrick 7976d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI 8076d0caaeSpatrick constexpr __non_propagating_cache& operator=(__non_propagating_cache&& __other) noexcept { 8176d0caaeSpatrick __value_.reset(); 8276d0caaeSpatrick __other.__value_.reset(); 8376d0caaeSpatrick return *this; 8476d0caaeSpatrick } 8576d0caaeSpatrick 8676d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI 87*4bdff4beSrobert constexpr _Tp& operator*() { return __value_->__t_; } 8876d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI 89*4bdff4beSrobert constexpr _Tp const& operator*() const { return __value_->__t_; } 9076d0caaeSpatrick 9176d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI __has_value()9276d0caaeSpatrick constexpr bool __has_value() const { return __value_.has_value(); } 93*4bdff4beSrobert 94*4bdff4beSrobert template<class _Fn> 9576d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI __emplace_from(_Fn const & __f)96*4bdff4beSrobert constexpr _Tp& __emplace_from(_Fn const& __f) { 97*4bdff4beSrobert return __value_.emplace(__from_tag{}, __f).__t_; 98*4bdff4beSrobert } 99*4bdff4beSrobert 100*4bdff4beSrobert template<class ..._Args> 10176d0caaeSpatrick _LIBCPP_HIDE_FROM_ABI __emplace(_Args &&...__args)102*4bdff4beSrobert constexpr _Tp& __emplace(_Args&& ...__args) { 103*4bdff4beSrobert return __value_.emplace(__forward_tag{}, std::forward<_Args>(__args)...).__t_; 104*4bdff4beSrobert } 10576d0caaeSpatrick }; 10676d0caaeSpatrick 10776d0caaeSpatrick struct __empty_cache { }; 10876d0caaeSpatrick } // namespace ranges 10976d0caaeSpatrick 110*4bdff4beSrobert #endif // _LIBCPP_STD_VER > 17 11176d0caaeSpatrick 11276d0caaeSpatrick _LIBCPP_END_NAMESPACE_STD 11376d0caaeSpatrick 11476d0caaeSpatrick #endif // _LIBCPP___RANGES_NON_PROPAGATING_CACHE_H 115