$$ This is a pump file for generating file templates. Pump is a python $$ script that is part of the Google Test suite of utilities. Description $$ can be found here: $$ $$ http://code.google.com/p/googletest/wiki/PumpManual $$ $var MAX_ARITY = 6 // Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_BIND_INTERNAL_H_ #define BASE_BIND_INTERNAL_H_ #pragma once #include "base/bind_helpers.h" #include "base/callback_internal.h" #include "base/template_util.h" #include "build/build_config.h" #if defined(OS_WIN) #include "base/bind_internal_win.h" #endif namespace base { namespace internal { // The method by which a function is invoked is determined by 3 different // dimensions: // // 1) The type of function (normal or method). // 2) The arity of the function. // 3) The number of bound parameters. // // The templates below handle the determination of each of these dimensions. // In brief: // // FunctionTraits<> -- Provides a normalied signature, and other traits. // InvokerN<> -- Provides a DoInvoke() function that actually executes // a calback. // InvokerStorageN<> -- Provides storage for the bound parameters, and // typedefs to the above. // // More details about the design of each class is included in a comment closer // to their defition. // FunctionTraits<> // // The FunctionTraits<> template determines the type of function, and also // creates a NormalizedType used to select the InvokerN classes. It turns out // that syntactically, you only really have 2 variations when invoking a // funciton pointer: normal, and method. One is invoked func_ptr(arg1). The // other is invoked (*obj_->method_ptr(arg1)). // // However, in the type system, there are many more distinctions. In standard // C++, there's all variations of const, and volatile on the function pointer. // In Windows, there are additional calling conventions (eg., __stdcall, // __fastcall, etc.). FunctionTraits<> handles categorizing each of these into // a normalized signature. // // Having a NormalizedSignature signature, reduces the combinatoric // complexity of defintions for the InvokerN<> later. Even though there are // only 2 syntactic variations on invoking a function, without normalizing the // signature, there would need to be one specialization of InvokerN for each // unique (function_type, bound_arg, unbound_args) tuple in order to match all // function signatures. // // By normalizing the function signature, we reduce function_type to exactly 2. template struct FunctionTraits; $range ARITY 0..MAX_ARITY $for ARITY [[ $range ARG 1..ARITY // Function: Arity $(ARITY). template 0[[, ]] $for ARG , [[typename X$(ARG)]]> struct FunctionTraits { typedef R (*NormalizedSig)($for ARG , [[X$(ARG)]]); typedef false_type IsMethod; $if ARITY > 0 [[ // Target type for each bound parameter. $for ARG [[ typedef X$(ARG) B$(ARG); ]] $$ for ARG ]] $$ if ARITY > 0 }; // Method: Arity $(ARITY). template 0[[, ]] $for ARG , [[typename X$(ARG)]]> struct FunctionTraits { typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]); typedef true_type IsMethod; // Target type for each bound parameter. typedef T B1; $for ARG [[ typedef X$(ARG) B$(ARG + 1); ]] $$ for ARG }; // Const Method: Arity $(ARITY). template 0[[, ]] $for ARG , [[typename X$(ARG)]]> struct FunctionTraits { typedef R (T::*NormalizedSig)($for ARG , [[X$(ARG)]]); typedef true_type IsMethod; // Target type for each bound parameter. typedef T B1; $for ARG [[ typedef X$(ARG) B$(ARG + 1); ]] $$ for ARG }; ]] $$for ARITY // InvokerN<> // // The InvokerN templates contain a static DoInvoke() function that is the key // to implementing type erasure in the Callback() classes. // // DoInvoke() is a static function with a fixed signature that is independent // of StorageType; its first argument is a pointer to the non-templated common // baseclass of StorageType. This lets us store pointer to DoInvoke() in a // function pointer that has knowledge of the specific StorageType, and thus // no knowledge of the bound function and bound parameter types. // // As long as we ensure that DoInvoke() is only used with pointers there were // upcasted from the correct StorageType, we can be sure that execution is // safe. // // The InvokerN templates are the only point that knows the number of bound // and unbound arguments. This is intentional because it allows the other // templates classes in the system to only have as many specializations as // the max arity of function we wish to support. $range BOUND 0..MAX_ARITY $for BOUND [[ template struct Invoker$(BOUND); $range ARITY 0..MAX_ARITY $for ARITY [[ $var UNBOUND = ARITY - BOUND $if UNBOUND >= 0 [[ $$ Variables for function traits generation. $range ARG 1..ARITY $range BOUND_ARG 1..BOUND $range UNBOUND_ARG (ARITY - UNBOUND + 1)..ARITY $$ Variables for method traits generation. We are always short one arity since $$ the first bound parameter is the object. $var M_ARITY = ARITY - 1 $range M_ARG 1..M_ARITY $range M_BOUND_ARG 2..BOUND $range M_UNBOUND_ARG (M_ARITY - UNBOUND + 1)..M_ARITY // Function: Arity $(ARITY) -> $(UNBOUND). template 0 [[,]][[]] $for ARG , [[typename X$(ARG)]]> struct Invoker$(BOUND) { static R DoInvoke(InvokerStorageBase* base[[]] $if UNBOUND != 0 [[, ]][[]] $for UNBOUND_ARG , [[typename internal::ParamTraits::ForwardType x$(UNBOUND_ARG)]]) { StorageType* invoker = static_cast(base); return invoker->f_($for BOUND_ARG , [[Unwrap(invoker->p$(BOUND_ARG)_)]][[]] $$ Add comma if there are both boudn and unbound args. $if UNBOUND > 0 [[$if BOUND > 0 [[, ]]]][[]] $for UNBOUND_ARG , [[x$(UNBOUND_ARG)]]); } }; $if BOUND > 0 [[ // Method: Arity $(M_ARITY) -> $(UNBOUND). template 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]> struct Invoker$(BOUND) { static R DoInvoke(InvokerStorageBase* base[[]] $if UNBOUND > 0 [[, ]][[]] $for M_UNBOUND_ARG , [[typename internal::ParamTraits::ForwardType x$(M_UNBOUND_ARG)]]) { StorageType* invoker = static_cast(base); return (Unwrap(invoker->p1_)->*invoker->f_)([[]] $for M_BOUND_ARG , [[Unwrap(invoker->p$(M_BOUND_ARG)_)]][[]] $if UNBOUND > 0 [[$if BOUND > 1 [[, ]]]][[]] $for M_UNBOUND_ARG , [[x$(M_UNBOUND_ARG)]]); } }; ]] $$ if BOUND ]] $$ if UNBOUND ]] $$ for ARITY ]] $$ for BOUND // InvokerStorageN<> // // These are the actual storage classes for the Invokers. // // Though these types are "classes", they are being used as structs with // all member variable public. We cannot make it a struct because it inherits // from a class which causes a compiler warning. We cannot add a "Run()" method // that forwards the unbound arguments because that would require we unwrap the // Sig type like in InvokerN above to know the return type, and the arity // of Run(). // // An alternate solution would be to merge InvokerN and InvokerStorageN, // but the generated code seemed harder to read. $for BOUND [[ $range BOUND_ARG 1..BOUND template 0 [[, ]] $for BOUND_ARG , [[typename P$(BOUND_ARG)]]> class InvokerStorage$(BOUND) : public InvokerStorageBase { public: typedef InvokerStorage$(BOUND) StorageType; typedef FunctionTraits TargetTraits; typedef Invoker$(BOUND) Invoker; typedef typename TargetTraits::IsMethod IsMethod; $for BOUND_ARG [[ $if BOUND_ARG == 1 [[ // For methods, we need to be careful for parameter 1. We skip the // scoped_refptr check because the binder itself takes care of this. We also // disallow binding of an array as the method's target object. COMPILE_ASSERT(IsMethod::value || !internal::UnsafeBindtoRefCountedArg::value, p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); COMPILE_ASSERT(!IsMethod::value || !is_array::value, first_bound_argument_to_method_cannot_be_array); ]] $else [[ COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg::value, p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); ]] $$ $if BOUND_ARG ]] $$ $for BOUND_ARG $if BOUND > 0 [[ // Do not allow binding a non-const reference parameter. Non-const reference // parameters are disallowed by the Google style guide. Also, binding a // non-const reference parameter can make for subtle bugs because the // invoked function will receive a reference to the stored copy of the // argument and not the original. COMPILE_ASSERT( !($for BOUND_ARG || [[ is_non_const_reference::value ]]), do_not_bind_functions_with_nonconst_ref); ]] InvokerStorage$(BOUND)(Sig f $if BOUND > 0 [[, ]] $for BOUND_ARG , [[const P$(BOUND_ARG)& p$(BOUND_ARG)]]) : f_(f)[[]] $if BOUND == 0 [[ { ]] $else [[ , $for BOUND_ARG , [[p$(BOUND_ARG)_(static_cast::StorageType>(p$(BOUND_ARG)))]] { MaybeRefcount::AddRef(p1_); ]] } virtual ~InvokerStorage$(BOUND)() { $if BOUND > 0 [[ MaybeRefcount::Release(p1_); ]] } Sig f_; $for BOUND_ARG [[ typename ParamTraits::StorageType p$(BOUND_ARG)_; ]] }; ]] $$ for BOUND } // namespace internal } // namespace base #endif // BASE_BIND_INTERNAL_H_