blob: 5f4ea86e63316c4ba46b41931fb291d14f303084 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
[email protected]b38d3572011-02-15 01:27:382// 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
[email protected]59eff912011-02-18 23:29:318#ifndef BASE_CALLBACK_INTERNAL_H_
9#define BASE_CALLBACK_INTERNAL_H_
[email protected]b38d3572011-02-15 01:27:3810
Sumaid Syed22f60eeb2021-08-26 05:16:2611#include <utility>
12
[email protected]0bea7252011-08-05 15:34:0013#include "base/base_export.h"
tzik77d411392016-03-09 09:47:0314#include "base/callback_forward.h"
[email protected]3b63f8f42011-03-28 01:54:1515#include "base/memory/ref_counted.h"
[email protected]b38d3572011-02-15 01:27:3816
17namespace base {
tzik65adef82017-03-30 06:45:2118
19struct FakeBindState;
20
[email protected]b38d3572011-02-15 01:27:3821namespace internal {
tzik65adef82017-03-30 06:45:2122
Alex Clarke22c21a9c2019-07-06 07:31:0723class BindStateBase;
Alex Clarkef7b49a42019-05-22 19:07:2724class FinallyExecutorCommon;
Alex Clarkeb6d55d02019-05-21 20:45:2425class ThenAndCatchExecutorCommon;
Alex Clarke22c21a9c2019-07-06 07:31:0726
27template <typename ReturnType>
28class PostTaskExecutor;
tzik65adef82017-03-30 06:45:2129
30template <typename Functor, typename... BoundArgs>
31struct BindState;
32
Alex Clarkeb6d55d02019-05-21 20:45:2433class CallbackBase;
34class CallbackBaseCopyable;
35
Sergei Glazunovcbc7afd02022-08-31 21:19:0936struct BASE_EXPORT BindStateBaseRefCountTraits {
tzik65adef82017-03-30 06:45:2137 static void Destruct(const BindStateBase*);
38};
39
Vladislav Kuzkokov6d208e12017-11-08 21:31:0840template <typename T>
Daniel Cheng6f510fa2022-01-12 19:36:0341using PassingType = std::conditional_t<std::is_scalar_v<T>, T, T&&>;
Vladislav Kuzkokov6d208e12017-11-08 21:31:0842
[email protected]7296f2762011-11-21 19:23:4443// BindStateBase is used to provide an opaque handle that the Callback
[email protected]b38d3572011-02-15 01:27:3844// class can use to represent a function object with bound arguments. It
45// behaves as an existential type that is used by a corresponding
46// DoInvoke function to perform the function execution. This allows
47// us to shield the Callback class from the types of the bound argument via
48// "type erasure."
Honglin Yua6a4ba22019-08-09 02:30:1849// At the base level, the only task is to add reference counting data. Avoid
50// using or inheriting any virtual functions. Creating a vtable for every
51// BindState template instantiation results in a lot of bloat. Its only task is
52// to call the destructor which can be done with a function pointer.
tzik65adef82017-03-30 06:45:2153class BASE_EXPORT BindStateBase
54 : public RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits> {
tzik1886c272016-09-08 05:45:3855 public:
tzik65f396932017-04-03 05:27:3456 REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
57
tzik9697d49e2018-08-02 13:35:1958 enum CancellationQueryMode {
59 IS_CANCELLED,
60 MAYBE_VALID,
61 };
62
tzik1886c272016-09-08 05:45:3863 using InvokeFuncStorage = void(*)();
64
David Bienvenub4b441e2020-09-23 05:49:5765 BindStateBase(const BindStateBase&) = delete;
66 BindStateBase& operator=(const BindStateBase&) = delete;
67
tzik65adef82017-03-30 06:45:2168 private:
tzik1886c272016-09-08 05:45:3869 BindStateBase(InvokeFuncStorage polymorphic_invoke,
tzik30e0c312016-09-21 08:06:5470 void (*destructor)(const BindStateBase*));
tzik1fdcca32016-09-14 07:15:0071 BindStateBase(InvokeFuncStorage polymorphic_invoke,
tzik30e0c312016-09-21 08:06:5472 void (*destructor)(const BindStateBase*),
tzik9697d49e2018-08-02 13:35:1973 bool (*query_cancellation_traits)(const BindStateBase*,
74 CancellationQueryMode mode));
tzik65adef82017-03-30 06:45:2175
taptede7e804c2015-05-14 08:03:3276 ~BindStateBase() = default;
77
tzik65adef82017-03-30 06:45:2178 friend struct BindStateBaseRefCountTraits;
79 friend class RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits>;
80
taptede7e804c2015-05-14 08:03:3281 friend class CallbackBase;
tzikd4bb5b7d2017-08-28 19:08:5282 friend class CallbackBaseCopyable;
taptede7e804c2015-05-14 08:03:3283
Nate Fischer04068aa2021-03-10 22:20:5484 // Allowlist subclasses that access the destructor of BindStateBase.
tzik65adef82017-03-30 06:45:2185 template <typename Functor, typename... BoundArgs>
86 friend struct BindState;
87 friend struct ::base::FakeBindState;
88
tzik59aa6bb12016-09-08 10:58:5389 bool IsCancelled() const {
tzik9697d49e2018-08-02 13:35:1990 return query_cancellation_traits_(this, IS_CANCELLED);
tzik59aa6bb12016-09-08 10:58:5391 }
92
tzik9697d49e2018-08-02 13:35:1993 bool MaybeValid() const {
94 return query_cancellation_traits_(this, MAYBE_VALID);
95 }
Nicolas Ouellet-payeur40f8e9a2018-07-30 16:26:4896
tzik1886c272016-09-08 05:45:3897 // In C++, it is safe to cast function pointers to function pointers of
98 // another type. It is not okay to use void*. We create a InvokeFuncStorage
99 // that that can store our function pointer, and then cast it back to
100 // the original type on usage.
101 InvokeFuncStorage polymorphic_invoke_;
102
taptede7e804c2015-05-14 08:03:32103 // Pointer to a function that will properly destroy |this|.
tzik30e0c312016-09-21 08:06:54104 void (*destructor_)(const BindStateBase*);
tzik9697d49e2018-08-02 13:35:19105 bool (*query_cancellation_traits_)(const BindStateBase*,
106 CancellationQueryMode mode);
[email protected]b38d3572011-02-15 01:27:38107};
108
[email protected]59eff912011-02-18 23:29:31109// Holds the Callback methods that don't require specialization to reduce
110// template bloat.
tzik77d411392016-03-09 09:47:03111// CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and
112// CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation.
tzikd4bb5b7d2017-08-28 19:08:52113class BASE_EXPORT CallbackBase {
[email protected]59eff912011-02-18 23:29:31114 public:
tzik787d420b2018-06-25 16:12:02115 inline CallbackBase(CallbackBase&& c) noexcept;
Jüri Valdmannf841ac22018-05-18 22:36:28116 CallbackBase& operator=(CallbackBase&& c) noexcept;
dchengf8836042014-11-26 05:04:55117
tzikd4bb5b7d2017-08-28 19:08:52118 explicit CallbackBase(const CallbackBaseCopyable& c);
119 CallbackBase& operator=(const CallbackBaseCopyable& c);
tzik27d1e312016-09-13 05:28:59120
Jüri Valdmannf841ac22018-05-18 22:36:28121 explicit CallbackBase(CallbackBaseCopyable&& c) noexcept;
122 CallbackBase& operator=(CallbackBaseCopyable&& c) noexcept;
tzikf44c2f8d2017-03-08 08:41:15123
[email protected]59eff912011-02-18 23:29:31124 // Returns true if Callback is null (doesn't refer to anything).
tzik65adef82017-03-30 06:45:21125 bool is_null() const { return !bind_state_; }
tzik99de02b2016-07-01 05:54:12126 explicit operator bool() const { return !is_null(); }
[email protected]59eff912011-02-18 23:29:31127
tzik59aa6bb12016-09-08 10:58:53128 // Returns true if the callback invocation will be nop due to an cancellation.
129 // It's invalid to call this on uninitialized callback.
Nicolas Ouellet-payeur40f8e9a2018-07-30 16:26:48130 //
131 // Must be called on the Callback's destination sequence.
tzik59aa6bb12016-09-08 10:58:53132 bool IsCancelled() const;
133
Nicolas Ouellet-payeur40f8e9a2018-07-30 16:26:48134 // If this returns false, the callback invocation will be a nop due to a
135 // cancellation. This may(!) still return true, even on a cancelled callback.
136 //
137 // This function is thread-safe.
138 bool MaybeValid() const;
139
[email protected]1c35a482011-10-25 23:19:51140 // Returns the Callback into an uninitialized state.
[email protected]59eff912011-02-18 23:29:31141 void Reset();
142
[email protected]481915a772011-09-10 03:14:35143 protected:
Alex Clarkef7b49a42019-05-22 19:07:27144 friend class FinallyExecutorCommon;
Alex Clarkeb6d55d02019-05-21 20:45:24145 friend class ThenAndCatchExecutorCommon;
146
Alex Clarke22c21a9c2019-07-06 07:31:07147 template <typename ReturnType>
148 friend class PostTaskExecutor;
149
tzik1886c272016-09-08 05:45:38150 using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
[email protected]59eff912011-02-18 23:29:31151
[email protected]1c35a482011-10-25 23:19:51152 // Returns true if this callback equals |other|. |other| may be null.
tzik77d411392016-03-09 09:47:03153 bool EqualsInternal(const CallbackBase& other) const;
[email protected]1c35a482011-10-25 23:19:51154
Victor Hugo Vianna Silva5539a102022-02-08 10:33:11155 inline constexpr CallbackBase();
tzik10e783d62018-03-22 08:37:45156
[email protected]e24f8762011-12-20 00:10:04157 // Allow initializing of |bind_state_| via the constructor to avoid default
tzik1886c272016-09-08 05:45:38158 // initialization of the scoped_refptr.
tzik787d420b2018-06-25 16:12:02159 explicit inline CallbackBase(BindStateBase* bind_state);
[email protected]59eff912011-02-18 23:29:31160
tzik1886c272016-09-08 05:45:38161 InvokeFuncStorage polymorphic_invoke() const {
162 return bind_state_->polymorphic_invoke_;
163 }
164
[email protected]1c35a482011-10-25 23:19:51165 // Force the destructor to be instantiated inside this translation unit so
[email protected]59eff912011-02-18 23:29:31166 // that our subclasses will not get inlined versions. Avoids more template
167 // bloat.
168 ~CallbackBase();
169
[email protected]7296f2762011-11-21 19:23:44170 scoped_refptr<BindStateBase> bind_state_;
[email protected]59eff912011-02-18 23:29:31171};
172
tzik10e783d62018-03-22 08:37:45173constexpr CallbackBase::CallbackBase() = default;
tzik787d420b2018-06-25 16:12:02174CallbackBase::CallbackBase(CallbackBase&&) noexcept = default;
175CallbackBase::CallbackBase(BindStateBase* bind_state)
176 : bind_state_(AdoptRef(bind_state)) {}
tzik10e783d62018-03-22 08:37:45177
tzik77d411392016-03-09 09:47:03178// CallbackBase<Copyable> is a direct base class of Copyable Callbacks.
tzikd4bb5b7d2017-08-28 19:08:52179class BASE_EXPORT CallbackBaseCopyable : public CallbackBase {
tzik77d411392016-03-09 09:47:03180 public:
tzikd4bb5b7d2017-08-28 19:08:52181 CallbackBaseCopyable(const CallbackBaseCopyable& c);
tzik787d420b2018-06-25 16:12:02182 CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept = default;
tzikd4bb5b7d2017-08-28 19:08:52183 CallbackBaseCopyable& operator=(const CallbackBaseCopyable& c);
Jüri Valdmannf841ac22018-05-18 22:36:28184 CallbackBaseCopyable& operator=(CallbackBaseCopyable&& c) noexcept;
tzik77d411392016-03-09 09:47:03185
tzikd4bb5b7d2017-08-28 19:08:52186 protected:
tzik10e783d62018-03-22 08:37:45187 constexpr CallbackBaseCopyable() = default;
tzikd4bb5b7d2017-08-28 19:08:52188 explicit CallbackBaseCopyable(BindStateBase* bind_state)
189 : CallbackBase(bind_state) {}
Chris Watkins091d6292017-12-13 04:25:58190 ~CallbackBaseCopyable() = default;
tzikd4bb5b7d2017-08-28 19:08:52191};
tzik77d411392016-03-09 09:47:03192
Daniel Chengc0ac78c2021-03-03 18:22:24193// Helpers for the `Then()` implementation.
194template <typename OriginalCallback, typename ThenCallback>
195struct ThenHelper;
196
197// Specialization when original callback returns `void`.
198template <template <typename> class OriginalCallback,
199 template <typename>
200 class ThenCallback,
201 typename... OriginalArgs,
202 typename ThenR,
203 typename... ThenArgs>
204struct ThenHelper<OriginalCallback<void(OriginalArgs...)>,
205 ThenCallback<ThenR(ThenArgs...)>> {
206 static_assert(sizeof...(ThenArgs) == 0,
207 "|then| callback cannot accept parameters if |this| has a "
208 "void return type.");
209
210 static auto CreateTrampoline() {
211 return [](OriginalCallback<void(OriginalArgs...)> c1,
212 ThenCallback<ThenR(ThenArgs...)> c2, OriginalArgs... c1_args) {
213 std::move(c1).Run(std::forward<OriginalArgs>(c1_args)...);
214 return std::move(c2).Run();
215 };
216 }
217};
218
219// Specialization when original callback returns a non-void type.
220template <template <typename> class OriginalCallback,
221 template <typename>
222 class ThenCallback,
223 typename OriginalR,
224 typename... OriginalArgs,
225 typename ThenR,
226 typename... ThenArgs>
227struct ThenHelper<OriginalCallback<OriginalR(OriginalArgs...)>,
228 ThenCallback<ThenR(ThenArgs...)>> {
229 static_assert(sizeof...(ThenArgs) == 1,
230 "|then| callback must accept exactly one parameter if |this| "
231 "has a non-void return type.");
232 // TODO(dcheng): This should probably check is_convertible as well (same with
233 // `AssertBindArgsValidity`).
Daniel Cheng6f510fa2022-01-12 19:36:03234 static_assert(std::is_constructible_v<ThenArgs..., OriginalR&&>,
Daniel Chengc0ac78c2021-03-03 18:22:24235 "|then| callback's parameter must be constructible from "
236 "return type of |this|.");
237
238 static auto CreateTrampoline() {
239 return [](OriginalCallback<OriginalR(OriginalArgs...)> c1,
240 ThenCallback<ThenR(ThenArgs...)> c2, OriginalArgs... c1_args) {
241 return std::move(c2).Run(
242 std::move(c1).Run(std::forward<OriginalArgs>(c1_args)...));
243 };
244 }
245};
danakjfcc5e7c2020-10-23 17:43:27246
[email protected]b38d3572011-02-15 01:27:38247} // namespace internal
248} // namespace base
249
[email protected]59eff912011-02-18 23:29:31250#endif // BASE_CALLBACK_INTERNAL_H_