| $$ 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 <typename Sig> |
| struct FunctionTraits; |
| |
| $range ARITY 0..MAX_ARITY |
| $for ARITY [[ |
| $range ARG 1..ARITY |
| |
| // Function: Arity $(ARITY). |
| template <typename R[[]] |
| $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> |
| struct FunctionTraits<R(*)($for ARG , [[X$(ARG)]])> { |
| 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 <typename R, typename T[[]] |
| $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> |
| struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]])> { |
| 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 <typename R, typename T[[]] |
| $if ARITY > 0[[, ]] $for ARG , [[typename X$(ARG)]]> |
| struct FunctionTraits<R(T::*)($for ARG , [[X$(ARG)]]) const> { |
| 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 <typename StorageType, typename NormalizedSig> |
| 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 <typename StorageType, typename R[[]] |
| $if ARITY > 0 [[,]][[]] |
| $for ARG , [[typename X$(ARG)]]> |
| struct Invoker$(BOUND)<StorageType, R(*)($for ARG , [[X$(ARG)]])> { |
| static R DoInvoke(InvokerStorageBase* base[[]] |
| $if UNBOUND != 0 [[, ]][[]] |
| $for UNBOUND_ARG , [[typename internal::ParamTraits<X$(UNBOUND_ARG)>::ForwardType x$(UNBOUND_ARG)]]) { |
| StorageType* invoker = static_cast<StorageType*>(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 <typename StorageType, typename R, typename T[[]] |
| $if M_ARITY > 0[[, ]] $for M_ARG , [[typename X$(M_ARG)]]> |
| struct Invoker$(BOUND)<StorageType, R(T::*)($for M_ARG , [[X$(M_ARG)]])> { |
| static R DoInvoke(InvokerStorageBase* base[[]] |
| $if UNBOUND > 0 [[, ]][[]] |
| $for M_UNBOUND_ARG , [[typename internal::ParamTraits<X$(M_UNBOUND_ARG)>::ForwardType x$(M_UNBOUND_ARG)]]) { |
| StorageType* invoker = static_cast<StorageType*>(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 <typename Sig[[]] |
| $if BOUND > 0 [[, ]] |
| $for BOUND_ARG , [[typename P$(BOUND_ARG)]]> |
| class InvokerStorage$(BOUND) : public InvokerStorageBase { |
| public: |
| typedef InvokerStorage$(BOUND) StorageType; |
| typedef FunctionTraits<Sig> TargetTraits; |
| typedef Invoker$(BOUND)<StorageType, typename TargetTraits::NormalizedSig> 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<P$(BOUND_ARG)>::value, |
| p$(BOUND_ARG)_is_refcounted_type_and_needs_scoped_refptr); |
| COMPILE_ASSERT(!IsMethod::value || !is_array<P$(BOUND_ARG)>::value, |
| first_bound_argument_to_method_cannot_be_array); |
| ]] $else [[ |
| |
| COMPILE_ASSERT(!internal::UnsafeBindtoRefCountedArg<P$(BOUND_ARG)>::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<typename TargetTraits::B$(BOUND_ARG)>::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<typename ParamTraits<P$(BOUND_ARG)>::StorageType>(p$(BOUND_ARG)))]] { |
| MaybeRefcount<IsMethod, P1>::AddRef(p1_); |
| |
| ]] |
| } |
| |
| virtual ~InvokerStorage$(BOUND)() { |
| $if BOUND > 0 [[ |
| |
| MaybeRefcount<IsMethod, P1>::Release(p1_); |
| |
| ]] |
| } |
| |
| Sig f_; |
| |
| $for BOUND_ARG [[ |
| typename ParamTraits<P$(BOUND_ARG)>::StorageType p$(BOUND_ARG)_; |
| |
| ]] |
| }; |
| |
| ]] $$ for BOUND |
| |
| } // namespace internal |
| } // namespace base |
| |
| #endif // BASE_BIND_INTERNAL_H_ |