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