xref: /openbsd-src/gnu/llvm/libcxx/include/__ranges/non_propagating_cache.h (revision 4bdff4bed0e3d54e55670334c7d0077db4170f86)
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