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/weak_ptr.h"
21 #include "base/template_util.h"
22 #include "build/build_config.h"
25 #include "base/bind_internal_win.h"
31 // The method by which a function is invoked is determined by 3 different
34 // 1) The type of function (normal or method).
35 // 2) The arity of the function.
36 // 3) The number of bound parameters.
38 // The templates below handle the determination of each of these dimensions.
41 // FunctionTraits<> -- Provides a normalied signature, and other traits.
42 // InvokerN<> -- Provides a DoInvoke() function that actually executes
44 // InvokerStorageN<> -- Provides storage for the bound parameters, and
45 // typedefs to the above.
46 // IsWeakMethod<> -- Determines if we are binding a method to a WeakPtr<>.
48 // More details about the design of each class is included in a comment closer
52 // IsWeakMethod determines if we are binding a method to a WeakPtr<> for an
53 // object. It is used to select an InvokerN that will no-op itself in the
54 // event the WeakPtr<> for the target object is invalidated.
55 template <bool IsMethod, typename T>
56 struct IsWeakMethod : public false_type {};
59 struct IsWeakMethod<true, WeakPtr<T> > : public true_type {};
63 // The FunctionTraits<> template determines the type of function, and also
64 // creates a NormalizedType used to select the InvokerN classes. It turns out
65 // that syntactically, you only really have 2 variations when invoking a
66 // funciton pointer: normal, and method. One is invoked func_ptr(arg1). The
67 // other is invoked (*obj_->method_ptr(arg1)).
69 // However, in the type system, there are many more distinctions. In standard
70 // C++, there's all variations of const, and volatile on the function pointer.
71 // In Windows, there are additional calling conventions (eg., __stdcall,
72 // __fastcall, etc.). FunctionTraits<> handles categorizing each of these into
73 // a normalized signature.
75 // Having a NormalizedSignature signature, reduces the combinatoric
76 // complexity of defintions for the InvokerN<> later. Even though there are
77 // only 2 syntactic variations on invoking a function, without normalizing the
78 // signature, there would need to be one specialization of InvokerN for each
79 // unique (function_type, bound_arg, unbound_args) tuple in order to match all
80 // function signatures.
82 // By normalizing the function signature, we reduce function_type to exactly 2.
84 template <typename Sig>
85 struct FunctionTraits;
87 $range ARITY 0..MAX_ARITY
91 // Function: Arity $(ARITY).
92 template <typename R[[]]
93 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
94 struct FunctionTraits<R(*)($for ARG , [[X$(ARG)]])> {
95 typedef R (*NormalizedSig)($for ARG , [[X$(ARG)]]);
96 typedef false_type IsMethod;
102 // Target type for each bound parameter.
105 typedef X$(ARG) B$(ARG);
112 // Method: Arity $(ARITY).
113 template <typename R, typename T[[]]
114 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
115 struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]])> {
116 typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]);
117 typedef true_type IsMethod;
121 // Target type for each bound parameter.
125 typedef X$(ARG) B$(ARG + 1);
131 // Const Method: Arity $(ARITY).
132 template <typename R, typename T[[]]
133 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]>
134 struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]]) const> {
135 typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]);
136 typedef true_type IsMethod;
140 // Target type for each bound parameter.
144 typedef X$(ARG) B$(ARG + 1);
154 // The InvokerN templates contain a static DoInvoke() function that is the key
155 // to implementing type erasure in the Callback() classes.
157 // DoInvoke() is a static function with a fixed signature that is independent
158 // of StorageType; its first argument is a pointer to the non-templated common
159 // baseclass of StorageType. This lets us store pointer to DoInvoke() in a
160 // function pointer that has knowledge of the specific StorageType, and thus
161 // no knowledge of the bound function and bound parameter types.
163 // As long as we ensure that DoInvoke() is only used with pointers there were
164 // upcasted from the correct StorageType, we can be sure that execution is
167 // The InvokerN templates are the only point that knows the number of bound
168 // and unbound arguments. This is intentional because it allows the other
169 // templates classes in the system to only have as many specializations as
170 // the max arity of function we wish to support.
172 $range BOUND 0..MAX_ARITY
175 template <bool IsWeak, typename StorageType, typename NormalizedSig>
176 struct Invoker$(BOUND);
178 $range ARITY 0..MAX_ARITY
181 $var UNBOUND = ARITY - BOUND
184 $$ Variables for function traits generation.
186 $range BOUND_ARG 1..BOUND
187 $range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY
189 $$ Variables for method traits generation. We are always short one arity since
190 $$ the first bound parameter is the object.
191 $var M_ARITY = ARITY - 1
192 $range M_ARG 1..M_ARITY
193 $range M_BOUND_ARG 2..BOUND
194 $range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY
196 // Function: Arity $(ARITY) -> $(UNBOUND).
197 template <typename StorageType, typename R[[]]
198 $if ARITY > 0 [[,]][[]]
199 $for ARG , [[typename X$(ARG)]]>
200 struct Invoker$(BOUND)<false, StorageType, R(*)($for ARG , [[X$(ARG)]])> {
201 typedef R(*DoInvokeType)(
202 internal::InvokerStorageBase*[[]]
203 $if UNBOUND != 0 [[, ]]
204 $for UNBOUND_ARG , [[typename internal::ParamTraits<X$(UNBOUND_ARG)>::ForwardType]]);
206 static R DoInvoke(InvokerStorageBase* base[[]]
207 $if UNBOUND != 0 [[, ]][[]]
208 $for UNBOUND_ARG , [[typename internal::ParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)]]) {
209 StorageType* invoker = static_cast<StorageType*>(base);
210 return invoker->f_($for BOUND_ARG , [[Unwrap(invoker->p$(BOUND_ARG)_)]][[]]
211 $$ Add comma if there are both boudn and unbound args.
212 $if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]]
213 $for UNBOUND_ARG , [[x$(UNBOUND_ARG)]]);
219 // Method: Arity $(M_ARITY) -> $(UNBOUND).
220 template <typename StorageType, typename R, typename T[[]]
221 $if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]>
222 struct Invoker$(BOUND)<false, StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> {
223 typedef R(*DoInvokeType)(
224 internal::InvokerStorageBase*[[]]
225 $if UNBOUND != 0 [[, ]]
226 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType]]);
228 static R DoInvoke(InvokerStorageBase* base[[]]
229 $if UNBOUND > 0 [[, ]][[]]
230 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType x$(M_UNBOUND_ARG)]]) {
231 StorageType* invoker = static_cast<StorageType*>(base);
232 return (Unwrap(invoker->p1_)->*invoker->f_)([[]]
233 $for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]]
234 $if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]]
235 $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
239 // WeakPtr Method: Arity $(M_ARITY) -> $(UNBOUND).
240 template <typename StorageType, typename T[[]]
241 $if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]>
242 struct Invoker$(BOUND)<true, StorageType, void(T::*)($for M_ARG , [[X$(M_ARG)]])> {
243 typedef void(*DoInvokeType)(
244 internal::InvokerStorageBase*[[]]
245 $if UNBOUND != 0 [[, ]]
246 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType]]);
248 static void DoInvoke(InvokerStorageBase* base[[]]
249 $if UNBOUND > 0 [[, ]][[]]
250 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType x$(M_UNBOUND_ARG)]]) {
251 StorageType* invoker = static_cast<StorageType*>(base);
252 typename StorageType::P1Traits::StorageType& weak_ptr = invoker->p1_;
253 if (!weak_ptr.get()) {
256 (weak_ptr->*invoker->f_)([[]]
257 $for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]]
258 $if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]]
259 $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]);
271 // These are the actual storage classes for the Invokers.
273 // Though these types are "classes", they are being used as structs with
274 // all member variable public. We cannot make it a struct because it inherits
275 // from a class which causes a compiler warning. We cannot add a "Run()" method
276 // that forwards the unbound arguments because that would require we unwrap the
277 // Sig type like in InvokerN above to know the return type, and the arity
280 // An alternate solution would be to merge InvokerN and InvokerStorageN,
281 // but the generated code seemed harder to read.
284 $range BOUND_ARG 1..BOUND
286 template <typename Sig[[]]
288 $for BOUND_ARG , [[typename P$(BOUND_ARG)]]>
289 class InvokerStorage$(BOUND) : public InvokerStorageBase {
291 typedef InvokerStorage$(BOUND) StorageType;
292 typedef FunctionTraits<Sig> TargetTraits;
293 typedef typename TargetTraits::IsMethod IsMethod;
294 typedef Sig Signature;
297 typedef ParamTraits<P$(BOUND_ARG)> P$(BOUND_ARG)Traits;
302 typedef Invoker$(BOUND)<false, StorageType,
303 typename TargetTraits::NormalizedSig> Invoker;
305 typedef Invoker$(BOUND)<IsWeakMethod<IsMethod::value, P1>::value, StorageType,
306 typename TargetTraits::NormalizedSig> Invoker;
307 COMPILE_ASSERT(!(IsWeakMethod<IsMethod::value, P1>::value) ||
308 is_void<typename TargetTraits::Return>::value,
309 weak_ptrs_can_only_bind_to_methods_without_return_values);
314 $if BOUND_ARG == 1 [[
316 // For methods, we need to be careful for parameter 1. We skip the
317 // scoped_refptr check because the binder itself takes care of this. We also
318 // disallow binding of an array as the method's target object.
319 COMPILE_ASSERT(IsMethod::value ||
320 !internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value,
321 p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr);
322 COMPILE_ASSERT(!IsMethod::value || !is_array<P$(BOUND_ARG)>::value,
323 first_bound_argument_to_method_cannot_be_array);
326 COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value,
327 p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr);
334 // Do not allow binding a non-const reference parameter. Non-const reference
335 // parameters are disallowed by the Google style guide. Also, binding a
336 // non-const reference parameter can make for subtle bugs because the
337 // invoked function will receive a reference to the stored copy of the
338 // argument and not the original.
340 !($for BOUND_ARG || [[ is_non_const_reference<typename TargetTraits::B$(BOUND_ARG)>::value ]]),
341 do_not_bind_functions_with_nonconst_ref);
346 InvokerStorage$(BOUND)(Sig f
348 $for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]])
354 , $for BOUND_ARG , [[p$(BOUND_ARG)_(static_cast<typename ParamTraits<P$(BOUND_ARG)>::StorageType>(p$(BOUND_ARG)))]] {
355 MaybeRefcount<IsMethod, P1>::AddRef(p1_);
360 virtual ~InvokerStorage$(BOUND)() {
363 MaybeRefcount<IsMethod, P1>::Release(p1_);
371 typename ParamTraits<P$(BOUND_ARG)>::StorageType p$(BOUND_ARG)_;
378 } // namespace internal
381 #endif // BASE_BIND_INTERNAL_H_