1 $$ This is a pump file for generating file templates. Pump is a python
2 $$ script that is part of the Google Test suite of utilities. Description
5 $$ http://code.google.com/p/googletest/wiki/PumpManual
10 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
11 // Use of this source code is governed by a BSD-style license that can be
12 // found in the LICENSE file.
14 #ifndef BASE_BIND_INTERNAL_H_
15 #define BASE_BIND_INTERNAL_H_
18 #include "base/bind_helpers.h"
19 #include "base/callback_internal.h"
20 #include "base/memory/raw_scoped_refptr_mismatch_checker.h"
21 #include "base/memory/weak_ptr.h"
22 #include "base/template_util.h"
23 #include "build/build_config.h"
26 #include "base/bind_internal_win.h"
32 // The method by which a function is invoked is determined by 3 different
35 // 1) The type of function (normal or method).
36 // 2) The arity of the function.
37 // 3) The number of bound parameters.
39 // The templates below handle the determination of each of these dimensions.
42 // FunctionTraits<> -- Provides a normalied signature, and other traits.
43 // InvokerN<> -- Provides a DoInvoke() function that actually executes
45 // InvokerStorageN<> -- Provides storage for the bound parameters, and
46 // typedefs to the above.
47 // IsWeakMethod<> -- Determines if we are binding a method to a WeakPtr<>.
49 // More details about the design of each class is included in a comment closer
53 // IsWeakMethod determines if we are binding a method to a WeakPtr<> for an
54 // object. It is used to select an InvokerN that will no-op itself in the
55 // event the WeakPtr<> for the target object is invalidated.
56 template <bool IsMethod, typename T>
57 struct IsWeakMethod : public false_type {};
60 struct IsWeakMethod<true, WeakPtr<T> > : public true_type {};
64 // The FunctionTraits<> template determines the type of function, and also
65 // creates a NormalizedType used to select the InvokerN classes. It turns out
66 // that syntactically, you only really have 2 variations when invoking a
67 // funciton pointer: normal, and method. One is invoked func_ptr(arg1). The
68 // other is invoked (*obj_->method_ptr(arg1)).
70 // However, in the type system, there are many more distinctions. In standard
71 // C++, there's all variations of const, and volatile on the function pointer.
72 // In Windows, there are additional calling conventions (eg., __stdcall,
73 // __fastcall, etc.). FunctionTraits<> handles categorizing each of these into
74 // a normalized signature.
76 // Having a NormalizedSignature signature, reduces the combinatoric
77 // complexity of defintions for the InvokerN<> later. Even though there are
78 // only 2 syntactic variations on invoking a function, without normalizing the
79 // signature, there would need to be one specialization of InvokerN for each
80 // unique (function_type, bound_arg, unbound_args) tuple in order to match all
81 // function signatures.
83 // By normalizing the function signature, we reduce function_type to exactly 2.
85 template <typename Sig>
86 struct FunctionTraits;
88 $range ARITY 0..MAX_ARITY
92 // Function: Arity $(ARITY).
93 template <typename R[[]]
94 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
95 struct FunctionTraits<R(*)($for ARG , [[X$(ARG)]])> {
96 typedef R (*NormalizedSig)($for ARG , [[X$(ARG)]]);
97 typedef false_type IsMethod;
103 // Target type for each bound parameter.
106 typedef X$(ARG) B$(ARG);
113 // Method: Arity $(ARITY).
114 template <typename R, typename T[[]]
115 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
116 struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]])> {
117 typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]);
118 typedef true_type IsMethod;
122 // Target type for each bound parameter.
126 typedef X$(ARG) B$(ARG + 1);
132 // Const Method: Arity $(ARITY).
133 template <typename R, typename T[[]]
134 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
135 struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]]) const> {
136 typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]);
137 typedef true_type IsMethod;
141 // Target type for each bound parameter.
145 typedef X$(ARG) B$(ARG + 1);
155 // The InvokerN templates contain a static DoInvoke() function that is the key
156 // to implementing type erasure in the Callback() classes.
158 // DoInvoke() is a static function with a fixed signature that is independent
159 // of StorageType; its first argument is a pointer to the non-templated common
160 // baseclass of StorageType. This lets us store pointer to DoInvoke() in a
161 // function pointer that has knowledge of the specific StorageType, and thus
162 // no knowledge of the bound function and bound parameter types.
164 // As long as we ensure that DoInvoke() is only used with pointers there were
165 // upcasted from the correct StorageType, we can be sure that execution is
168 // The InvokerN templates are the only point that knows the number of bound
169 // and unbound arguments. This is intentional because it allows the other
170 // templates classes in the system to only have as many specializations as
171 // the max arity of function we wish to support.
173 $range BOUND 0..MAX_ARITY
176 template <bool IsWeak, typename StorageType, typename NormalizedSig>
177 struct Invoker$(BOUND);
179 $range ARITY 0..MAX_ARITY
182 $var UNBOUND = ARITY - BOUND
185 $$ Variables for function traits generation.
187 $range BOUND_ARG 1..BOUND
188 $range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY
190 $$ Variables for method traits generation. We are always short one arity since
191 $$ the first bound parameter is the object.
192 $var M_ARITY = ARITY - 1
193 $range M_ARG 1..M_ARITY
194 $range M_BOUND_ARG 2..BOUND
195 $range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY
197 // Function: Arity $(ARITY) -> $(UNBOUND).
198 template <typename StorageType, typename R[[]]
199 $if ARITY > 0 [[,]][[]]
200 $for ARG , [[typename X$(ARG)]]>
201 struct Invoker$(BOUND)<false, StorageType, R(*)($for ARG , [[X$(ARG)]])> {
202 typedef R(*DoInvokeType)(
203 internal::InvokerStorageBase*[[]]
204 $if UNBOUND != 0 [[, ]]
205 $for UNBOUND_ARG , [[typename internal::ParamTraits<X$(UNBOUND_ARG)>::ForwardType]]);
207 static R DoInvoke(InvokerStorageBase* base[[]]
208 $if UNBOUND != 0 [[, ]][[]]
209 $for UNBOUND_ARG , [[typename internal::ParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)]]) {
210 StorageType* invoker = static_cast<StorageType*>(base);
211 return invoker->f_($for BOUND_ARG , [[Unwrap(invoker->p$(BOUND_ARG)_)]][[]]
212 $$ Add comma if there are both boudn and unbound args.
213 $if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]]
214 $for UNBOUND_ARG , [[x$(UNBOUND_ARG)]]);
220 // Method: Arity $(M_ARITY) -> $(UNBOUND).
221 template <typename StorageType, typename R, typename T[[]]
222 $if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]>
223 struct Invoker$(BOUND)<false, StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> {
224 typedef R(*DoInvokeType)(
225 internal::InvokerStorageBase*[[]]
226 $if UNBOUND != 0 [[, ]]
227 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType]]);
229 static R DoInvoke(InvokerStorageBase* base[[]]
230 $if UNBOUND > 0 [[, ]][[]]
231 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType x$(M_UNBOUND_ARG)]]) {
232 StorageType* invoker = static_cast<StorageType*>(base);
233 return (Unwrap(invoker->p1_)->*invoker->f_)([[]]
234 $for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]]
235 $if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]]
236 $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
240 // WeakPtr Method: Arity $(M_ARITY) -> $(UNBOUND).
241 template <typename StorageType, typename T[[]]
242 $if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]>
243 struct Invoker$(BOUND)<true, StorageType, void(T::*)($for M_ARG , [[X$(M_ARG)]])> {
244 typedef void(*DoInvokeType)(
245 internal::InvokerStorageBase*[[]]
246 $if UNBOUND != 0 [[, ]]
247 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType]]);
249 static void DoInvoke(InvokerStorageBase* base[[]]
250 $if UNBOUND > 0 [[, ]][[]]
251 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType x$(M_UNBOUND_ARG)]]) {
252 StorageType* invoker = static_cast<StorageType*>(base);
253 typename StorageType::P1Traits::StorageType& weak_ptr = invoker->p1_;
254 if (!weak_ptr.get()) {
257 (weak_ptr->*invoker->f_)([[]]
258 $for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]]
259 $if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]]
260 $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
272 // This set of functions help in fully binding the free parameters in a
275 $range BOUND_ARG 1..BOUND
278 template <typename Sig, $for BOUND_ARG , [[typename P$(BOUND_ARG)]]>
279 void BindMoreFunc$(BOUND)(const base::Callback<Sig>& callback, [[]]
280 $for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) {
281 callback.Run($for BOUND_ARG , [[p$(BOUND_ARG)]]);
289 // These are the actual storage classes for the Invokers.
291 // Though these types are "classes", they are being used as structs with
292 // all member variable public. We cannot make it a struct because it inherits
293 // from a class which causes a compiler warning. We cannot add a "Run()" method
294 // that forwards the unbound arguments because that would require we unwrap the
295 // Sig type like in InvokerN above to know the return type, and the arity
298 // An alternate solution would be to merge InvokerN and InvokerStorageN,
299 // but the generated code seemed harder to read.
302 $range BOUND_ARG 1..BOUND
304 template <typename Sig[[]]
306 $for BOUND_ARG , [[typename P$(BOUND_ARG)]]>
307 class InvokerStorage$(BOUND) : public InvokerStorageBase {
309 typedef InvokerStorage$(BOUND) StorageType;
310 typedef FunctionTraits<Sig> TargetTraits;
311 typedef typename TargetTraits::IsMethod IsMethod;
312 typedef Sig Signature;
315 typedef ParamTraits<P$(BOUND_ARG)> P$(BOUND_ARG)Traits;
320 typedef Invoker$(BOUND)<false, StorageType,
321 typename TargetTraits::NormalizedSig> Invoker;
323 typedef Invoker$(BOUND)<IsWeakMethod<IsMethod::value, P1>::value, StorageType,
324 typename TargetTraits::NormalizedSig> Invoker;
325 COMPILE_ASSERT(!(IsWeakMethod<IsMethod::value, P1>::value) ||
326 is_void<typename TargetTraits::Return>::value,
327 weak_ptrs_can_only_bind_to_methods_without_return_values);
332 $if BOUND_ARG == 1 [[
334 // For methods, we need to be careful for parameter 1. We skip the
335 // scoped_refptr check because the binder itself takes care of this. We also
336 // disallow binding of an array as the method's target object.
337 COMPILE_ASSERT(IsMethod::value ||
338 internal::NeedsScopedRefptrButGetsRawPtr<
339 typename ParamTraits<P$(BOUND_ARG)>::StorageType>::value == 0,
340 p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr);
341 COMPILE_ASSERT(!IsMethod::value || !is_array<P$(BOUND_ARG)>::value,
342 first_bound_argument_to_method_cannot_be_array);
345 COMPILE_ASSERT(internal::NeedsScopedRefptrButGetsRawPtr<
346 typename ParamTraits<P$(BOUND_ARG)>::StorageType>::value == 0,
347 p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr);
354 // Do not allow binding a non-const reference parameter. Non-const reference
355 // parameters are disallowed by the Google style guide. Also, binding a
356 // non-const reference parameter can make for subtle bugs because the
357 // invoked function will receive a reference to the stored copy of the
358 // argument and not the original.
360 !($for BOUND_ARG || [[ is_non_const_reference<typename TargetTraits::B$(BOUND_ARG)>::value ]]),
361 do_not_bind_functions_with_nonconst_ref);
366 InvokerStorage$(BOUND)(Sig f
368 $for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]])
374 , $for BOUND_ARG , [[p$(BOUND_ARG)_(static_cast<typename ParamTraits<P$(BOUND_ARG)>::StorageType>(p$(BOUND_ARG)))]] {
375 MaybeRefcount<IsMethod, P1>::AddRef(p1_);
380 virtual ~InvokerStorage$(BOUND)() {
383 MaybeRefcount<IsMethod, P1>::Release(p1_);
391 typename ParamTraits<P$(BOUND_ARG)>::StorageType p$(BOUND_ARG)_;
398 } // namespace internal
401 #endif // BASE_BIND_INTERNAL_H_