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 3 $$ can be found here: 4 $$ 5 $$ http://code.google.com/p/googletest/wiki/PumpManual 6 $$ 7 8 $var MAX_ARITY = 6 9 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. 13 14 #ifndef BASE_BIND_INTERNAL_H_ 15 #define BASE_BIND_INTERNAL_H_ 16 #pragma once 17 18 #include "base/bind_helpers.h" 19 #include "base/callback_internal.h" 20 #include "base/template_util.h" 21 #include "build/build_config.h" 22 23 #if defined(OS_WIN) 24 #include "base/bind_internal_win.h" 25 #endif 26 27 namespace base { 28 namespace internal { 29 30 // The method by which a function is invoked is determined by 3 different 31 // dimensions: 32 // 33 // 1) The type of function (normal or method). 34 // 2) The arity of the function. 35 // 3) The number of bound parameters. 36 // 37 // The templates below handle the determination of each of these dimensions. 38 // In brief: 39 // 40 // FunctionTraits<> -- Provides a normalied signature, and other traits. 41 // InvokerN<> -- Provides a DoInvoke() function that actually executes 42 // a calback. 43 // InvokerStorageN<> -- Provides storage for the bound parameters, and 44 // typedefs to the above. 45 // 46 // More details about the design of each class is included in a comment closer 47 // to their defition. 48 49 // FunctionTraits<> 50 // 51 // The FunctionTraits<> template determines the type of function, and also 52 // creates a NormalizedType used to select the InvokerN classes. It turns out 53 // that syntactically, you only really have 2 variations when invoking a 54 // funciton pointer: normal, and method. One is invoked func_ptr(arg1). The 55 // other is invoked (*obj_->method_ptr(arg1)). 56 // 57 // However, in the type system, there are many more distinctions. In standard 58 // C++, there's all variations of const, and volatile on the function pointer. 59 // In Windows, there are additional calling conventions (eg., __stdcall, 60 // __fastcall, etc.). FunctionTraits<> handles categorizing each of these into 61 // a normalized signature. 62 // 63 // Having a NormalizedSignature signature, reduces the combinatoric 64 // complexity of defintions for the InvokerN<> later. Even though there are 65 // only 2 syntactic variations on invoking a function, without normalizing the 66 // signature, there would need to be one specialization of InvokerN for each 67 // unique (function_type, bound_arg, unbound_args) tuple in order to match all 68 // function signatures. 69 // 70 // By normalizing the function signature, we reduce function_type to exactly 2. 71 72 template <typename Sig> 73 struct FunctionTraits; 74 75 $range ARITY 0..MAX_ARITY 76 $for ARITY [[ 77 $range ARG 1..ARITY 78 79 // Function: Arity $(ARITY). 80 template <typename R[[]] 81 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> 82 struct FunctionTraits<R(*)($for ARG , [[X$(ARG)]])> { 83 typedef R (*NormalizedSig)($for ARG , [[X$(ARG)]]); 84 typedef false_type IsMethod; 85 86 $if ARITY > 0 [[ 87 88 // Target type for each bound parameter. 89 90 $for ARG [[ 91 typedef X$(ARG) B$(ARG); 92 93 ]] $$ for ARG 94 ]] $$ if ARITY > 0 95 96 }; 97 98 // Method: Arity $(ARITY). 99 template <typename R, typename T[[]] 100 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> 101 struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]])> { 102 typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]); 103 typedef true_type IsMethod; 104 105 // Target type for each bound parameter. 106 typedef T B1; 107 108 $for ARG [[ 109 typedef X$(ARG) B$(ARG + 1); 110 111 ]] $$ for ARG 112 113 }; 114 115 // Const Method: Arity $(ARITY). 116 template <typename R, typename T[[]] 117 $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> 118 struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]]) const> { 119 typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]); 120 typedef true_type IsMethod; 121 122 // Target type for each bound parameter. 123 typedef T B1; 124 125 $for ARG [[ 126 typedef X$(ARG) B$(ARG + 1); 127 128 ]] $$ for ARG 129 130 }; 131 132 ]] $$for ARITY 133 134 // InvokerN<> 135 // 136 // The InvokerN templates contain a static DoInvoke() function that is the key 137 // to implementing type erasure in the Callback() classes. 138 // 139 // DoInvoke() is a static function with a fixed signature that is independent 140 // of StorageType; its first argument is a pointer to the non-templated common 141 // baseclass of StorageType. This lets us store pointer to DoInvoke() in a 142 // function pointer that has knowledge of the specific StorageType, and thus 143 // no knowledge of the bound function and bound parameter types. 144 // 145 // As long as we ensure that DoInvoke() is only used with pointers there were 146 // upcasted from the correct StorageType, we can be sure that execution is 147 // safe. 148 // 149 // The InvokerN templates are the only point that knows the number of bound 150 // and unbound arguments. This is intentional because it allows the other 151 // templates classes in the system to only have as many specializations as 152 // the max arity of function we wish to support. 153 154 $range BOUND 0..MAX_ARITY 155 $for BOUND [[ 156 157 template <typename StorageType, typename NormalizedSig> 158 struct Invoker$(BOUND); 159 160 $range ARITY 0..MAX_ARITY 161 $for ARITY [[ 162 163 $var UNBOUND = ARITY - BOUND 164 $if UNBOUND >= 0 [[ 165 166 $$ Variables for function traits generation. 167 $range ARG 1..ARITY 168 $range BOUND_ARG 1..BOUND 169 $range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY 170 171 $$ Variables for method traits generation. We are always short one arity since 172 $$ the first bound parameter is the object. 173 $var M_ARITY = ARITY - 1 174 $range M_ARG 1..M_ARITY 175 $range M_BOUND_ARG 2..BOUND 176 $range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY 177 178 // Function: Arity $(ARITY) -> $(UNBOUND). 179 template <typename StorageType, typename R[[]] 180 $if ARITY > 0 [[,]][[]] 181 $for ARG , [[typename X$(ARG)]]> 182 struct Invoker$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> { 183 static R DoInvoke(InvokerStorageBase* base[[]] 184 $if UNBOUND != 0 [[, ]][[]] 185 $for UNBOUND_ARG , [[typename internal::ParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)]]) { 186 StorageType* invoker = static_cast<StorageType*>(base); 187 return invoker->f_($for BOUND_ARG , [[Unwrap(invoker->p$(BOUND_ARG)_)]][[]] 188 $$ Add comma if there are both boudn and unbound args. 189 $if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]] 190 $for UNBOUND_ARG , [[x$(UNBOUND_ARG)]]); 191 } 192 }; 193 194 $if BOUND > 0 [[ 195 196 // Method: Arity $(M_ARITY) -> $(UNBOUND). 197 template <typename StorageType, typename R, typename T[[]] 198 $if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]> 199 struct Invoker$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> { 200 static R DoInvoke(InvokerStorageBase* base[[]] 201 $if UNBOUND > 0 [[, ]][[]] 202 $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType x$(M_UNBOUND_ARG)]]) { 203 StorageType* invoker = static_cast<StorageType*>(base); 204 return (Unwrap(invoker->p1_)->*invoker->f_)([[]] 205 $for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]] 206 $if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]] 207 $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]); 208 } 209 }; 210 211 ]] $$ if BOUND 212 213 ]] $$ if UNBOUND 214 ]] $$ for ARITY 215 ]] $$ for BOUND 216 217 218 // InvokerStorageN<> 219 // 220 // These are the actual storage classes for the Invokers. 221 // 222 // Though these types are "classes", they are being used as structs with 223 // all member variable public. We cannot make it a struct because it inherits 224 // from a class which causes a compiler warning. We cannot add a "Run()" method 225 // that forwards the unbound arguments because that would require we unwrap the 226 // Sig type like in InvokerN above to know the return type, and the arity 227 // of Run(). 228 // 229 // An alternate solution would be to merge InvokerN and InvokerStorageN, 230 // but the generated code seemed harder to read. 231 232 $for BOUND [[ 233 $range BOUND_ARG 1..BOUND 234 235 template <typename Sig[[]] 236 $if BOUND > 0 [[, ]] 237 $for BOUND_ARG , [[typename P$(BOUND_ARG)]]> 238 class InvokerStorage$(BOUND) : public InvokerStorageBase { 239 public: 240 typedef InvokerStorage$(BOUND) StorageType; 241 typedef FunctionTraits<Sig> TargetTraits; 242 typedef Invoker$(BOUND)<StorageType, typename TargetTraits::NormalizedSig> Invoker; 243 typedef typename TargetTraits::IsMethod IsMethod; 244 245 $for BOUND_ARG [[ 246 $if BOUND_ARG == 1 [[ 247 248 // For methods, we need to be careful for parameter 1. We skip the 249 // scoped_refptr check because the binder itself takes care of this. We also 250 // disallow binding of an array as the method's target object. 251 COMPILE_ASSERT(IsMethod::value || 252 !internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value, 253 p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); 254 COMPILE_ASSERT(!IsMethod::value || !is_array<P$(BOUND_ARG)>::value, 255 first_bound_argument_to_method_cannot_be_array); 256 ]] $else [[ 257 258 COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value, 259 p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); 260 ]] $$ $if BOUND_ARG 261 ]] $$ $for BOUND_ARG 262 263 264 $if BOUND > 0 [[ 265 266 // Do not allow binding a non-const reference parameter. Non-const reference 267 // parameters are disallowed by the Google style guide. Also, binding a 268 // non-const reference parameter can make for subtle bugs because the 269 // invoked function will receive a reference to the stored copy of the 270 // argument and not the original. 271 COMPILE_ASSERT( 272 !($for BOUND_ARG || [[ is_non_const_reference<typename TargetTraits::B$(BOUND_ARG)>::value ]]), 273 do_not_bind_functions_with_nonconst_ref); 274 275 ]] 276 277 278 InvokerStorage$(BOUND)(Sig f 279 $if BOUND > 0 [[, ]] 280 $for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) 281 : f_(f)[[]] 282 $if BOUND == 0 [[ 283 { 284 285 ]] $else [[ 286 , $for BOUND_ARG , [[p$(BOUND_ARG)_(static_cast<typename ParamTraits<P$(BOUND_ARG)>::StorageType>(p$(BOUND_ARG)))]] { 287 MaybeRefcount<IsMethod, P1>::AddRef(p1_); 288 289 ]] 290 } 291 292 virtual ~InvokerStorage$(BOUND)() { 293 $if BOUND > 0 [[ 294 295 MaybeRefcount<IsMethod, P1>::Release(p1_); 296 297 ]] 298 } 299 300 Sig f_; 301 302 $for BOUND_ARG [[ 303 typename ParamTraits<P$(BOUND_ARG)>::StorageType p$(BOUND_ARG)_; 304 305 ]] 306 }; 307 308 ]] $$ for BOUND 309 310 } // namespace internal 311 } // namespace base 312 313 #endif // BASE_BIND_INTERNAL_H_ 314