callback_internal.h (7978B)
1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // This file contains utility functions and classes that help the 6 // implementation, and management of the Callback objects. 7 8 #ifndef BASE_FUNCTIONAL_CALLBACK_INTERNAL_H_ 9 #define BASE_FUNCTIONAL_CALLBACK_INTERNAL_H_ 10 11 #include <utility> 12 13 #include "base/base_export.h" 14 #include "base/compiler_specific.h" 15 #include "base/functional/callback_forward.h" 16 #include "base/memory/ref_counted.h" 17 18 namespace base { 19 20 struct FakeBindState; 21 22 namespace internal { 23 24 class BindStateBase; 25 26 template <typename Functor, typename... BoundArgs> 27 struct BindState; 28 29 struct BASE_EXPORT BindStateBaseRefCountTraits { 30 static void Destruct(const BindStateBase*); 31 }; 32 33 template <typename T> 34 using PassingType = std::conditional_t<std::is_scalar_v<T>, T, T&&>; 35 36 // BindStateBase is used to provide an opaque handle that the Callback 37 // class can use to represent a function object with bound arguments. It 38 // behaves as an existential type that is used by a corresponding 39 // DoInvoke function to perform the function execution. This allows 40 // us to shield the Callback class from the types of the bound argument via 41 // "type erasure." 42 // At the base level, the only task is to add reference counting data. Avoid 43 // using or inheriting any virtual functions. Creating a vtable for every 44 // BindState template instantiation results in a lot of bloat. Its only task is 45 // to call the destructor which can be done with a function pointer. 46 class BASE_EXPORT BindStateBase 47 : public RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits> { 48 public: 49 REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE(); 50 51 enum CancellationQueryMode { 52 IS_CANCELLED, 53 MAYBE_VALID, 54 }; 55 56 using InvokeFuncStorage = void (*)(); 57 58 BindStateBase(const BindStateBase&) = delete; 59 BindStateBase& operator=(const BindStateBase&) = delete; 60 61 private: 62 BindStateBase(InvokeFuncStorage polymorphic_invoke, 63 void (*destructor)(const BindStateBase*)); 64 BindStateBase(InvokeFuncStorage polymorphic_invoke, 65 void (*destructor)(const BindStateBase*), 66 bool (*query_cancellation_traits)(const BindStateBase*, 67 CancellationQueryMode mode)); 68 69 ~BindStateBase() = default; 70 71 friend struct BindStateBaseRefCountTraits; 72 friend class RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits>; 73 74 friend class BindStateHolder; 75 76 // Allowlist subclasses that access the destructor of BindStateBase. 77 template <typename Functor, typename... BoundArgs> 78 friend struct BindState; 79 friend struct ::base::FakeBindState; 80 81 bool IsCancelled() const { 82 return query_cancellation_traits_(this, IS_CANCELLED); 83 } 84 85 bool MaybeValid() const { 86 return query_cancellation_traits_(this, MAYBE_VALID); 87 } 88 89 // In C++, it is safe to cast function pointers to function pointers of 90 // another type. It is not okay to use void*. We create a InvokeFuncStorage 91 // that that can store our function pointer, and then cast it back to 92 // the original type on usage. 93 InvokeFuncStorage polymorphic_invoke_; 94 95 // Pointer to a function that will properly destroy |this|. 96 void (*destructor_)(const BindStateBase*); 97 bool (*query_cancellation_traits_)(const BindStateBase*, 98 CancellationQueryMode mode); 99 }; 100 101 // Minimal wrapper around a `scoped_refptr<BindStateBase>`. It allows more 102 // expensive operations (such as ones that destroy `BindStateBase` or manipulate 103 // refcounts) to be defined out-of-line to reduce binary size. 104 class BASE_EXPORT TRIVIAL_ABI BindStateHolder { 105 public: 106 using InvokeFuncStorage = BindStateBase::InvokeFuncStorage; 107 108 // Used to construct a null callback. 109 inline constexpr BindStateHolder() noexcept; 110 111 // Used to construct a callback by `base::BindOnce()`/`base::BindRepeating(). 112 inline explicit BindStateHolder(BindStateBase* bind_state); 113 114 // BindStateHolder is always copyable so it can be used by `OnceCallback` and 115 // `RepeatingCallback`. `OnceCallback` restricts copies so a `BindStateHolder` 116 // used with a `OnceCallback will never be copied. 117 BindStateHolder(const BindStateHolder&); 118 BindStateHolder& operator=(const BindStateHolder&); 119 120 // Subtle: since `this` is marked as TRIVIAL_ABI, the move operations must 121 // leave a moved-from `BindStateHolder` in a trivially destructible state. 122 inline BindStateHolder(BindStateHolder&&) noexcept; 123 BindStateHolder& operator=(BindStateHolder&&) noexcept; 124 125 ~BindStateHolder(); 126 127 bool is_null() const { return !bind_state_; } 128 explicit operator bool() const { return !is_null(); } 129 130 bool IsCancelled() const; 131 bool MaybeValid() const; 132 133 void Reset(); 134 135 bool operator==(const BindStateHolder& other) const { 136 return bind_state_ == other.bind_state_; 137 } 138 139 const scoped_refptr<BindStateBase>& bind_state() const { return bind_state_; } 140 141 InvokeFuncStorage polymorphic_invoke() const { 142 return bind_state_->polymorphic_invoke_; 143 } 144 145 private: 146 scoped_refptr<BindStateBase> bind_state_; 147 }; 148 149 constexpr BindStateHolder::BindStateHolder() noexcept = default; 150 151 // TODO(dcheng): Try plumbing a scoped_refptr all the way through, since 152 // scoped_refptr is marked as TRIVIAL_ABI. 153 BindStateHolder::BindStateHolder(BindStateBase* bind_state) 154 : bind_state_(AdoptRef(bind_state)) {} 155 156 // Unlike the copy constructor, copy assignment operator, and move assignment 157 // operator, the move constructor is defaulted in the header because it 158 // generates minimal code: move construction does not change any refcounts, nor 159 // does it potentially destroy `BindStateBase`. 160 BindStateHolder::BindStateHolder(BindStateHolder&&) noexcept = default; 161 162 // Helpers for the `Then()` implementation. 163 template <typename OriginalCallback, typename ThenCallback> 164 struct ThenHelper; 165 166 // Specialization when original callback returns `void`. 167 template <template <typename> class OriginalCallback, 168 template <typename> 169 class ThenCallback, 170 typename... OriginalArgs, 171 typename ThenR, 172 typename... ThenArgs> 173 struct ThenHelper<OriginalCallback<void(OriginalArgs...)>, 174 ThenCallback<ThenR(ThenArgs...)>> { 175 static_assert(sizeof...(ThenArgs) == 0, 176 "|then| callback cannot accept parameters if |this| has a " 177 "void return type."); 178 179 static auto CreateTrampoline() { 180 return [](OriginalCallback<void(OriginalArgs...)> c1, 181 ThenCallback<ThenR(ThenArgs...)> c2, OriginalArgs... c1_args) { 182 std::move(c1).Run(std::forward<OriginalArgs>(c1_args)...); 183 return std::move(c2).Run(); 184 }; 185 } 186 }; 187 188 // Specialization when original callback returns a non-void type. 189 template <template <typename> class OriginalCallback, 190 template <typename> 191 class ThenCallback, 192 typename OriginalR, 193 typename... OriginalArgs, 194 typename ThenR, 195 typename... ThenArgs> 196 struct ThenHelper<OriginalCallback<OriginalR(OriginalArgs...)>, 197 ThenCallback<ThenR(ThenArgs...)>> { 198 static_assert(sizeof...(ThenArgs) == 1, 199 "|then| callback must accept exactly one parameter if |this| " 200 "has a non-void return type."); 201 // TODO(dcheng): This should probably check is_convertible as well (same with 202 // `AssertBindArgsValidity`). 203 static_assert(std::is_constructible_v<ThenArgs..., OriginalR&&>, 204 "|then| callback's parameter must be constructible from " 205 "return type of |this|."); 206 207 static auto CreateTrampoline() { 208 return [](OriginalCallback<OriginalR(OriginalArgs...)> c1, 209 ThenCallback<ThenR(ThenArgs...)> c2, OriginalArgs... c1_args) { 210 return std::move(c2).Run( 211 std::move(c1).Run(std::forward<OriginalArgs>(c1_args)...)); 212 }; 213 } 214 }; 215 216 } // namespace internal 217 } // namespace base 218 219 #endif // BASE_FUNCTIONAL_CALLBACK_INTERNAL_H_