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 27namespace base { 28namespace 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 72template <typename Sig> 73struct FunctionTraits; 74 75$range ARITY 0..MAX_ARITY 76$for ARITY [[ 77$range ARG 1..ARITY 78 79// Function: Arity $(ARITY). 80template <typename R[[]] 81$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> 82struct 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). 99template <typename R, typename T[[]] 100$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> 101struct 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). 116template <typename R, typename T[[]] 117$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> 118struct 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 157template <typename StorageType, typename NormalizedSig> 158struct 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). 179template <typename StorageType, typename R[[]] 180$if ARITY > 0 [[,]][[]] 181$for ARG , [[typename X$(ARG)]]> 182struct 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). 197template <typename StorageType, typename R, typename T[[]] 198$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]> 199struct 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 235template <typename Sig[[]] 236$if BOUND > 0 [[, ]] 237$for BOUND_ARG , [[typename P$(BOUND_ARG)]]> 238class 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