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