• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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