blob: 6b692a85a9d5424231489d964226d38f5b5932da [file] [log] [blame]
ajwong@chromium.orge2cca632011-02-15 10:27:38 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_BIND_INTERNAL_H_
6#define BASE_BIND_INTERNAL_H_
ajwong@chromium.orge2cca632011-02-15 10:27:38 +09007
avia6a6a682015-12-27 07:15:14 +09008#include <stddef.h>
9
tzikf09a3702016-06-03 16:25:20 +090010#include <tuple>
vmpstr495da402015-11-18 17:43:26 +090011#include <type_traits>
12
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090013#include "base/bind_helpers.h"
ajwong@chromium.orgfa0ff432011-02-19 08:29:31 +090014#include "base/callback_internal.h"
ajwong@chromium.org27e56852011-10-01 15:31:41 +090015#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
ajwong@chromium.orgc711b822011-05-17 07:35:14 +090016#include "base/memory/weak_ptr.h"
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090017#include "base/template_util.h"
tzik07e99402015-02-06 04:11:26 +090018#include "base/tuple.h"
ajwong@chromium.orgcb175342011-02-27 10:25:59 +090019#include "build/build_config.h"
20
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090021namespace base {
22namespace internal {
23
brettw@chromium.org11e3bfd2012-07-13 05:06:40 +090024// See base/callback.h for user documentation.
25//
26//
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090027// CONCEPTS:
tzik9f27e1f2016-07-01 14:54:12 +090028// Functor -- A movable type representing something that should be called.
29// All function pointers and Callback<> are functors even if the
30// invocation syntax differs.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090031// RunType -- A function type (as opposed to function _pointer_ type) for
tzik9f27e1f2016-07-01 14:54:12 +090032// a Callback<>::Run(). Usually just a convenience typedef.
tzikb0632222015-12-15 15:41:49 +090033// (Bound)Args -- A set of types that stores the arguments.
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090034//
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090035// Types:
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090036// ForceVoidReturn<> -- Helper class for translating function signatures to
37// equivalent forms with a "void" return type.
tzik9f27e1f2016-07-01 14:54:12 +090038// FunctorTraits<> -- Type traits used to determine the correct RunType and
39// invocation manner for a Functor. This is where function
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090040// signature adapters are applied.
tzik9f27e1f2016-07-01 14:54:12 +090041// InvokeHelper<> -- Take a Functor + arguments and actully invokes it.
tzik07e99402015-02-06 04:11:26 +090042// Handle the differing syntaxes needed for WeakPtr<>
tzik9f27e1f2016-07-01 14:54:12 +090043// support. This is separate from Invoker to avoid creating
44// multiple version of Invoker<>.
45// Invoker<> -- Unwraps the curried parameters and executes the Functor.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090046// BindState<> -- Stores the curried parameters, and is the main entry point
tzik9f27e1f2016-07-01 14:54:12 +090047// into the Bind() system.
ajwong@chromium.orge0648232011-02-19 09:52:15 +090048
tzik8df08a52014-11-26 16:54:58 +090049// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
50// pointer to a RefCounted type.
51// Implementation note: This non-specialized case handles zero-arity case only.
52// Non-zero-arity cases should be handled by the specialization below.
53template <typename... Args>
tzik56bd7652016-03-10 16:17:25 +090054struct HasRefCountedTypeAsRawPtr : std::false_type {};
tzik8df08a52014-11-26 16:54:58 +090055
56// Implementation note: Select true_type if the first parameter is a raw pointer
57// to a RefCounted type. Otherwise, skip the first parameter and check rest of
58// parameters recursively.
59template <typename T, typename... Args>
60struct HasRefCountedTypeAsRawPtr<T, Args...>
vmpstr495da402015-11-18 17:43:26 +090061 : std::conditional<NeedsScopedRefptrButGetsRawPtr<T>::value,
tzik56bd7652016-03-10 16:17:25 +090062 std::true_type,
vmpstr495da402015-11-18 17:43:26 +090063 HasRefCountedTypeAsRawPtr<Args...>>::type {};
tzik8df08a52014-11-26 16:54:58 +090064
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090065// ForceVoidReturn<>
66//
67// Set of templates that support forcing the function return type to void.
68template <typename Sig>
69struct ForceVoidReturn;
70
tzik012481a2014-11-20 19:09:45 +090071template <typename R, typename... Args>
72struct ForceVoidReturn<R(Args...)> {
tzik9f27e1f2016-07-01 14:54:12 +090073 using RunType = void(Args...);
ajwong@chromium.org6f015bd2011-11-29 07:13:54 +090074};
75
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090076// FunctorTraits<>
77//
78// See description at top of file.
tzik9f27e1f2016-07-01 14:54:12 +090079template <typename Functor>
80struct FunctorTraits;
81
82// For functions.
83template <typename R, typename... Args>
84struct FunctorTraits<R (*)(Args...)> {
85 using RunType = R(Args...);
86 static constexpr bool is_method = false;
87
88 template <typename... RunArgs>
89 static R Invoke(R (*function)(Args...), RunArgs&&... args) {
90 return function(std::forward<RunArgs>(args)...);
91 }
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +090092};
93
tzik9f27e1f2016-07-01 14:54:12 +090094#if defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
95
96// For functions.
97template <typename R, typename... Args>
98struct FunctorTraits<R(__stdcall*)(Args...)> {
99 using RunType = R(Args...);
100 static constexpr bool is_method = false;
101
102 template <typename... RunArgs>
103 static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) {
104 return function(std::forward<RunArgs>(args)...);
105 }
106};
107
108// For functions.
109template <typename R, typename... Args>
110struct FunctorTraits<R(__fastcall*)(Args...)> {
111 using RunType = R(Args...);
112 static constexpr bool is_method = false;
113
114 template <typename... RunArgs>
115 static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) {
116 return function(std::forward<RunArgs>(args)...);
117 }
118};
119
120#endif // defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
121
122// For methods.
123template <typename R, typename Receiver, typename... Args>
124struct FunctorTraits<R (Receiver::*)(Args...)> {
125 using RunType = R(Receiver*, Args...);
126 static constexpr bool is_method = true;
127
128 template <typename ReceiverPtr, typename... RunArgs>
129 static R Invoke(R (Receiver::*method)(Args...),
130 ReceiverPtr&& receiver_ptr,
131 RunArgs&&... args) {
132 // Clang skips CV qualifier check on a method pointer invocation when the
133 // receiver is a subclass. Store the receiver into a const reference to
134 // T to ensure the CV check works.
135 // https://llvm.org/bugs/show_bug.cgi?id=27037
136 Receiver& receiver = *receiver_ptr;
137 return (receiver.*method)(std::forward<RunArgs>(args)...);
138 }
139};
140
141// For const methods.
142template <typename R, typename Receiver, typename... Args>
143struct FunctorTraits<R (Receiver::*)(Args...) const> {
144 using RunType = R(const Receiver*, Args...);
145 static constexpr bool is_method = true;
146
147 template <typename ReceiverPtr, typename... RunArgs>
148 static R Invoke(R (Receiver::*method)(Args...) const,
149 ReceiverPtr&& receiver_ptr,
150 RunArgs&&... args) {
151 // Clang skips CV qualifier check on a method pointer invocation when the
152 // receiver is a subclass. Store the receiver into a const reference to
153 // T to ensure the CV check works.
154 // https://llvm.org/bugs/show_bug.cgi?id=27037
155 const Receiver& receiver = *receiver_ptr;
156 return (receiver.*method)(std::forward<RunArgs>(args)...);
157 }
158};
159
160// For IgnoreResults.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900161template <typename T>
tzik9f27e1f2016-07-01 14:54:12 +0900162struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
tzik260fab52015-12-19 18:18:46 +0900163 using RunType =
tzik9f27e1f2016-07-01 14:54:12 +0900164 typename ForceVoidReturn<typename FunctorTraits<T>::RunType>::RunType;
165
166 template <typename IgnoreResultType, typename... RunArgs>
167 static void Invoke(IgnoreResultType&& ignore_result_helper,
168 RunArgs&&... args) {
169 FunctorTraits<T>::Invoke(ignore_result_helper.functor_,
170 std::forward<RunArgs>(args)...);
171 }
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900172};
173
tzik9f27e1f2016-07-01 14:54:12 +0900174// For Callbacks.
175template <typename R, typename... Args, CopyMode copy_mode>
176struct FunctorTraits<Callback<R(Args...), copy_mode>> {
177 using RunType = R(Args...);
178 static constexpr bool is_method = false;
179
180 template <typename CallbackType, typename... RunArgs>
181 static R Invoke(CallbackType&& callback, RunArgs&&... args) {
182 DCHECK(!callback.is_null());
183 return std::forward<CallbackType>(callback).Run(
184 std::forward<RunArgs>(args)...);
185 }
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900186};
187
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900188// InvokeHelper<>
189//
tzik9f27e1f2016-07-01 14:54:12 +0900190// There are 2 logical InvokeHelper<> specializations: normal, WeakCalls.
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900191//
192// The normal type just calls the underlying runnable.
193//
tzik9f27e1f2016-07-01 14:54:12 +0900194// WeakCalls need special syntax that is applied to the first argument to check
195// if they should no-op themselves.
tzike1ad6f62016-06-01 17:22:51 +0900196template <bool is_weak_call, typename ReturnType>
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900197struct InvokeHelper;
198
tzike1ad6f62016-06-01 17:22:51 +0900199template <typename ReturnType>
200struct InvokeHelper<false, ReturnType> {
tzik9f27e1f2016-07-01 14:54:12 +0900201 template <typename Functor, typename... RunArgs>
202 static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) {
203 using Traits = FunctorTraits<typename std::decay<Functor>::type>;
204 return Traits::Invoke(std::forward<Functor>(functor),
205 std::forward<RunArgs>(args)...);
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900206 }
207};
208
tzike1ad6f62016-06-01 17:22:51 +0900209template <typename ReturnType>
210struct InvokeHelper<true, ReturnType> {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900211 // WeakCalls are only supported for functions with a void return type.
212 // Otherwise, the function result would be undefined if the the WeakPtr<>
213 // is invalidated.
tzik56bd7652016-03-10 16:17:25 +0900214 static_assert(std::is_void<ReturnType>::value,
avi486c61f2015-11-24 23:26:24 +0900215 "weak_ptrs can only bind to methods without return values");
ajwong@chromium.orga7e74822011-03-24 11:02:17 +0900216
tzik9f27e1f2016-07-01 14:54:12 +0900217 template <typename Functor, typename BoundWeakPtr, typename... RunArgs>
218 static inline void MakeItSo(Functor&& functor,
219 BoundWeakPtr weak_ptr,
220 RunArgs&&... args) {
221 if (!weak_ptr)
222 return;
223 using Traits = FunctorTraits<typename std::decay<Functor>::type>;
224 Traits::Invoke(std::forward<Functor>(functor),
225 std::forward<BoundWeakPtr>(weak_ptr),
226 std::forward<RunArgs>(args)...);
227 }
228};
ajwong@chromium.orge2cca632011-02-15 10:27:38 +0900229
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900230// Invoker<>
231//
232// See description at the top of the file.
tzikfa6c9852016-06-28 21:22:21 +0900233template <typename StorageType, typename UnboundRunType>
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900234struct Invoker;
235
tzikfa6c9852016-06-28 21:22:21 +0900236template <typename StorageType, typename R, typename... UnboundArgs>
237struct Invoker<StorageType, R(UnboundArgs...)> {
tzik0d4bab22016-03-09 14:46:05 +0900238 static R Run(BindStateBase* base, UnboundArgs&&... unbound_args) {
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900239 // Local references to make debugger stepping easier. If in a debugger,
240 // you really want to warp ahead and step through the
241 // InvokeHelper<>::MakeItSo() call below.
tzikfa6c9852016-06-28 21:22:21 +0900242 const StorageType* storage = static_cast<StorageType*>(base);
243 static constexpr size_t num_bound_args =
244 std::tuple_size<decltype(storage->bound_args_)>::value;
tzik9f27e1f2016-07-01 14:54:12 +0900245 return RunImpl(storage->functor_,
tzikfa6c9852016-06-28 21:22:21 +0900246 storage->bound_args_,
247 MakeIndexSequence<num_bound_args>(),
248 std::forward<UnboundArgs>(unbound_args)...);
249 }
250
tzik9f27e1f2016-07-01 14:54:12 +0900251 private:
252 template <typename Functor, typename BoundArgsTuple, size_t... indices>
253 static inline R RunImpl(Functor&& functor,
tzikfa6c9852016-06-28 21:22:21 +0900254 BoundArgsTuple&& bound,
255 IndexSequence<indices...>,
256 UnboundArgs&&... unbound_args) {
257 static constexpr bool is_method =
tzik9f27e1f2016-07-01 14:54:12 +0900258 FunctorTraits<typename std::decay<Functor>::type>::is_method;
tzikfa6c9852016-06-28 21:22:21 +0900259
260 using DecayedArgsTuple = typename std::decay<BoundArgsTuple>::type;
261 static constexpr bool is_weak_call =
262 IsWeakMethod<is_method,
263 typename std::tuple_element<
264 indices,
265 DecayedArgsTuple>::type...>::value;
266
tzike1ad6f62016-06-01 17:22:51 +0900267 return InvokeHelper<is_weak_call, R>::MakeItSo(
tzik9f27e1f2016-07-01 14:54:12 +0900268 std::forward<Functor>(functor),
269 Unwrap(base::get<indices>(std::forward<BoundArgsTuple>(bound)))...,
tzik0d4bab22016-03-09 14:46:05 +0900270 std::forward<UnboundArgs>(unbound_args)...);
ajwong@chromium.org6f015bd2011-11-29 07:13:54 +0900271 }
272};
273
tzikfa6c9852016-06-28 21:22:21 +0900274// Used to implement MakeUnboundRunType.
275template <typename Functor, typename... BoundArgs>
276struct MakeUnboundRunTypeImpl {
tzik9f27e1f2016-07-01 14:54:12 +0900277 using RunType =
278 typename FunctorTraits<typename std::decay<Functor>::type>::RunType;
tzikfa6c9852016-06-28 21:22:21 +0900279 using ReturnType = ExtractReturnType<RunType>;
280 using Args = ExtractArgs<RunType>;
281 using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), Args>;
282 using Type = MakeFunctionType<ReturnType, UnboundArgs>;
283};
284
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900285// BindState<>
286//
tzik9f27e1f2016-07-01 14:54:12 +0900287// This stores all the state passed into Bind().
288template <typename Functor, typename... BoundArgs>
289struct BindState final : BindStateBase {
290 template <typename... ForwardBoundArgs>
291 explicit BindState(Functor functor, ForwardBoundArgs&&... bound_args)
tapted9cef4212015-05-14 17:03:32 +0900292 : BindStateBase(&Destroy),
tzik9f27e1f2016-07-01 14:54:12 +0900293 functor_(std::move(functor)),
294 bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
295 DCHECK(functor_);
296 }
ajwong@chromium.orgc9c79af2011-11-22 04:23:44 +0900297
tzik9f27e1f2016-07-01 14:54:12 +0900298 Functor functor_;
299 std::tuple<BoundArgs...> bound_args_;
dmichael2f7bc202014-12-19 07:30:11 +0900300
301 private:
tapted9cef4212015-05-14 17:03:32 +0900302 ~BindState() {}
303
304 static void Destroy(BindStateBase* self) {
305 delete static_cast<BindState*>(self);
306 }
ajwong@chromium.org6f015bd2011-11-29 07:13:54 +0900307};
308
tzik9f27e1f2016-07-01 14:54:12 +0900309// Used to implement MakeBindStateType.
310template <bool is_method, typename Functor, typename... BoundArgs>
311struct MakeBindStateTypeImpl;
312
313template <typename Functor, typename... BoundArgs>
314struct MakeBindStateTypeImpl<false, Functor, BoundArgs...> {
315 static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value,
316 "A parameter is a refcounted type and needs scoped_refptr.");
317 using Type = BindState<typename std::decay<Functor>::type,
318 typename std::decay<BoundArgs>::type...>;
319};
320
321template <typename Functor>
322struct MakeBindStateTypeImpl<true, Functor> {
323 using Type = BindState<typename std::decay<Functor>::type>;
324};
325
326template <typename Functor, typename Receiver, typename... BoundArgs>
327struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> {
328 static_assert(
329 !std::is_array<typename std::remove_reference<Receiver>::type>::value,
330 "First bound argument to a method cannot be an array.");
331 static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value,
332 "A parameter is a refcounted type and needs scoped_refptr.");
333
334 private:
335 using DecayedReceiver = typename std::decay<Receiver>::type;
336
337 public:
338 using Type = BindState<
339 typename std::decay<Functor>::type,
340 typename std::conditional<
341 std::is_pointer<DecayedReceiver>::value,
342 scoped_refptr<typename std::remove_pointer<DecayedReceiver>::type>,
343 DecayedReceiver>::type,
344 typename std::decay<BoundArgs>::type...>;
345};
346
347template <typename Functor, typename... BoundArgs>
348using MakeBindStateType = typename MakeBindStateTypeImpl<
349 FunctorTraits<typename std::decay<Functor>::type>::is_method,
350 Functor,
351 BoundArgs...>::Type;
352
ajwong@chromium.orge2cca632011-02-15 10:27:38 +0900353} // namespace internal
tzikfa6c9852016-06-28 21:22:21 +0900354
355// Returns a RunType of bound functor.
356// E.g. MakeUnboundRunType<R(A, B, C), A, B> is evaluated to R(C).
357template <typename Functor, typename... BoundArgs>
358using MakeUnboundRunType =
359 typename internal::MakeUnboundRunTypeImpl<Functor, BoundArgs...>::Type;
360
ajwong@chromium.orge2cca632011-02-15 10:27:38 +0900361} // namespace base
362
363#endif // BASE_BIND_INTERNAL_H_