bind_internal.h.pump revision dc0f95d653279beabeb9817299e2902918ba123e
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 87// Method: Arity $(ARITY). 88template <typename R, typename T[[]] 89$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> 90struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]])> { 91 typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]); 92 typedef true_type IsMethod; 93}; 94 95// Const Method: Arity $(ARITY). 96template <typename R, typename T[[]] 97$if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> 98struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]]) const> { 99 typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]); 100 typedef true_type IsMethod; 101}; 102 103]] $$for ARITY 104 105// InvokerN<> 106// 107// The InvokerN templates contain a static DoInvoke() function that is the key 108// to implementing type erasure in the Callback() classes. 109// 110// DoInvoke() is a static function with a fixed signature that is independent 111// of StorageType; its first argument is a pointer to the non-templated common 112// baseclass of StorageType. This lets us store pointer to DoInvoke() in a 113// function pointer that has knowledge of the specific StorageType, and thus 114// no knowledge of the bound function and bound parameter types. 115// 116// As long as we ensure that DoInvoke() is only used with pointers there were 117// upcasted from the correct StorageType, we can be sure that execution is 118// safe. 119// 120// The InvokerN templates are the only point that knows the number of bound 121// and unbound arguments. This is intentional because it allows the other 122// templates classes in the system to only have as many specializations as 123// the max arity of function we wish to support. 124 125$range BOUND 0..MAX_ARITY 126$for BOUND [[ 127 128template <typename StorageType, typename NormalizedSig> 129struct Invoker$(BOUND); 130 131$range ARITY 0..MAX_ARITY 132$for ARITY [[ 133 134$var UNBOUND = ARITY - BOUND 135$if UNBOUND >= 0 [[ 136 137$$ Variables for function traits generation. 138$range ARG 1..ARITY 139$range BOUND_ARG 1..BOUND 140$range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY 141 142$$ Variables for method traits generation. We are always short one arity since 143$$ the first bound parameter is the object. 144$var M_ARITY = ARITY - 1 145$range M_ARG 1..M_ARITY 146$range M_BOUND_ARG 2..BOUND 147$range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY 148 149// Function: Arity $(ARITY) -> $(UNBOUND). 150template <typename StorageType, typename R[[]] 151$if ARITY > 0 [[,]][[]] 152$for ARG , [[typename X$(ARG)]]> 153struct Invoker$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> { 154$if ARITY > 0 [[ 155 156 COMPILE_ASSERT( 157 !($for ARG || [[ is_non_const_reference<X$(ARG)>::value ]]), 158 do_not_bind_functions_with_nonconst_ref); 159 160]] 161 162 static R DoInvoke(InvokerStorageBase* base[[]] 163$if UNBOUND != 0 [[, ]][[]] 164$for UNBOUND_ARG , [[const X$(UNBOUND_ARG)& x$(UNBOUND_ARG)]]) { 165 StorageType* invoker = static_cast<StorageType*>(base); 166 return invoker->f_($for BOUND_ARG , [[Unwrap(invoker->p$(BOUND_ARG)_)]][[]] 167$$ Add comma if there are both boudn and unbound args. 168$if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]] 169$for UNBOUND_ARG , [[x$(UNBOUND_ARG)]]); 170 } 171}; 172 173$if BOUND > 0 [[ 174 175// Method: Arity $(M_ARITY) -> $(UNBOUND). 176template <typename StorageType, typename R, typename T[[]] 177$if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]> 178struct Invoker$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> { 179$if M_ARITY > 0 [[ 180 181 COMPILE_ASSERT( 182 !($for M_ARG || [[ is_non_const_reference<X$(M_ARG)>::value ]]), 183 do_not_bind_functions_with_nonconst_ref); 184 185]] 186 187 static R DoInvoke(InvokerStorageBase* base[[]] 188$if UNBOUND > 0 [[, ]][[]] 189$for M_UNBOUND_ARG , [[const X$(M_UNBOUND_ARG)& x$(M_UNBOUND_ARG)]]) { 190 StorageType* invoker = static_cast<StorageType*>(base); 191 return (Unwrap(invoker->p1_)->*invoker->f_)([[]] 192$for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]] 193$if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]] 194$for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]); 195 } 196}; 197 198]] $$ if BOUND 199 200]] $$ if UNBOUND 201]] $$ for ARITY 202]] $$ for BOUND 203 204 205// InvokerStorageN<> 206// 207// These are the actual storage classes for the Invokers. 208// 209// Though these types are "classes", they are being used as structs with 210// all member variable public. We cannot make it a struct because it inherits 211// from a class which causes a compiler warning. We cannot add a "Run()" method 212// that forwards the unbound arguments because that would require we unwrap the 213// Sig type like in InvokerN above to know the return type, and the arity 214// of Run(). 215// 216// An alternate solution would be to merge InvokerN and InvokerStorageN, 217// but the generated code seemed harder to read. 218 219$for BOUND [[ 220$range BOUND_ARG 1..BOUND 221 222template <typename Sig[[]] 223$if BOUND > 0 [[, ]] 224$for BOUND_ARG , [[typename P$(BOUND_ARG)]]> 225class InvokerStorage$(BOUND) : public InvokerStorageBase { 226 public: 227 typedef InvokerStorage$(BOUND) StorageType; 228 typedef FunctionTraits<Sig> TargetTraits; 229 typedef Invoker$(BOUND)<StorageType, typename TargetTraits::NormalizedSig> Invoker; 230 typedef typename TargetTraits::IsMethod IsMethod; 231$for BOUND_ARG [[ 232$if BOUND_ARG == 1 [[ 233 234 // For methods, we need to be careful for parameter 1. We skip the 235 // scoped_refptr check because the binder itself takes care of this. We also 236 // disallow binding of an array as the method's target object. 237 COMPILE_ASSERT(IsMethod::value || 238 !internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value, 239 p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); 240 COMPILE_ASSERT(!IsMethod::value || !is_array<P$(BOUND_ARG)>::value, 241 first_bound_argument_to_method_cannot_be_array); 242]] $else [[ 243 244 COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::value, 245 p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); 246]] $$ $if BOUND_ARG 247]] $$ $for BOUND_ARG 248 249 250 251 InvokerStorage$(BOUND)(Sig f 252$if BOUND > 0 [[, ]] 253$for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) 254 : f_(f)[[]] 255$if BOUND == 0 [[ 256 { 257 258]] $else [[ 259, $for BOUND_ARG , [[p$(BOUND_ARG)_(static_cast<typename BindType<P$(BOUND_ARG)>::StorageType>(p$(BOUND_ARG)))]] { 260 MaybeRefcount<IsMethod, P1>::AddRef(p1_); 261 262]] 263 } 264 265 virtual ~InvokerStorage$(BOUND)() { 266$if BOUND > 0 [[ 267 268 MaybeRefcount<IsMethod, P1>::Release(p1_); 269 270]] 271 } 272 273 Sig f_; 274 275$for BOUND_ARG [[ 276 typename BindType<P$(BOUND_ARG)>::StorageType p$(BOUND_ARG)_; 277 278]] 279}; 280 281]] $$ for BOUND 282 283} // namespace internal 284} // namespace base 285 286#endif // BASE_BIND_INTERNAL_H_ 287