Home | History | Annotate | Download | only in base
      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