aboutsummaryrefslogtreecommitdiff
path: root/webrtc/base/bind.h.pump
blob: 6fb849095d4ac983f401a7f100e56bb33f9424dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
 *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// To generate bind.h from bind.h.pump, execute:
// /home/build/google3/third_party/gtest/scripts/pump.py bind.h.pump

// Bind() is an overloaded function that converts method calls into function
// objects (aka functors). The method object is captured as a scoped_refptr<> if
// possible, and as a raw pointer otherwise. Any arguments to the method are
// captured by value. The return value of Bind is a stateful, nullary function
// object. Care should be taken about the lifetime of objects captured by
// Bind(); the returned functor knows nothing about the lifetime of a non
// ref-counted method object or any arguments passed by pointer, and calling the
// functor with a destroyed object will surely do bad things.
//
// Example usage:
//   struct Foo {
//     int Test1() { return 42; }
//     int Test2() const { return 52; }
//     int Test3(int x) { return x*x; }
//     float Test4(int x, float y) { return x + y; }
//   };
//
//   int main() {
//     Foo foo;
//     cout << rtc::Bind(&Foo::Test1, &foo)() << endl;
//     cout << rtc::Bind(&Foo::Test2, &foo)() << endl;
//     cout << rtc::Bind(&Foo::Test3, &foo, 3)() << endl;
//     cout << rtc::Bind(&Foo::Test4, &foo, 7, 8.5f)() << endl;
//   }
//
// Example usage of ref counted objects:
//   struct Bar {
//     int AddRef();
//     int Release();
//
//     void Test() {}
//     void BindThis() {
//       // The functor passed to AsyncInvoke() will keep this object alive.
//       invoker.AsyncInvoke(rtc::Bind(&Bar::Test, this));
//     }
//   };
//
//   int main() {
//     rtc::scoped_refptr<Bar> bar = new rtc::RefCountedObject<Bar>();
//     auto functor = rtc::Bind(&Bar::Test, bar);
//     bar = nullptr;
//     // The functor stores an internal scoped_refptr<Bar>, so this is safe.
//     functor();
//   }
//

#ifndef WEBRTC_BASE_BIND_H_
#define WEBRTC_BASE_BIND_H_

#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/base/template_util.h"

#define NONAME

namespace rtc {
namespace detail {
// This is needed because the template parameters in Bind can't be resolved
// if they're used both as parameters of the function pointer type and as
// parameters to Bind itself: the function pointer parameters are exact
// matches to the function prototype, but the parameters to bind have
// references stripped. This trick allows the compiler to dictate the Bind
// parameter types rather than deduce them.
template <class T> struct identity { typedef T type; };

// IsRefCounted<T>::value will be true for types that can be used in
// rtc::scoped_refptr<T>, i.e. types that implements nullary functions AddRef()
// and Release(), regardless of their return types. AddRef() and Release() can
// be defined in T or any superclass of T.
template <typename T>
class IsRefCounted {
  // This is a complex implementation detail done with SFINAE.

  // Define types such that sizeof(Yes) != sizeof(No).
  struct Yes { char dummy[1]; };
  struct No { char dummy[2]; };
  // Define two overloaded template functions with return types of different
  // size. This way, we can use sizeof() on the return type to determine which
  // function the compiler would have chosen. One function will be preferred
  // over the other if it is possible to create it without compiler errors,
  // otherwise the compiler will simply remove it, and default to the less
  // preferred function.
  template <typename R>
  static Yes test(R* r, decltype(r->AddRef(), r->Release(), 42));
  template <typename C> static No test(...);

public:
  // Trick the compiler to tell if it's possible to call AddRef() and Release().
  static const bool value = sizeof(test<T>((T*)nullptr, 42)) == sizeof(Yes);
};

// TernaryTypeOperator is a helper class to select a type based on a static bool
// value.
template <bool condition, typename IfTrueT, typename IfFalseT>
struct TernaryTypeOperator {};

template <typename IfTrueT, typename IfFalseT>
struct TernaryTypeOperator<true, IfTrueT, IfFalseT> {
  typedef IfTrueT type;
};

template <typename IfTrueT, typename IfFalseT>
struct TernaryTypeOperator<false, IfTrueT, IfFalseT> {
  typedef IfFalseT type;
};

// PointerType<T>::type will be scoped_refptr<T> for ref counted types, and T*
// otherwise.
template <class T>
struct PointerType {
  typedef typename TernaryTypeOperator<IsRefCounted<T>::value,
                                       scoped_refptr<T>,
                                       T*>::type type;
};

}  // namespace detail

$var n = 9
$range i 0..n
$for i [[
$range j 1..i

template <class ObjectT, class MethodT, class R$for j [[,
          class P$j]]>
class MethodFunctor$i {
 public:
  MethodFunctor$i(MethodT method, ObjectT* object$for j [[,
                 P$j p$j]])
      : method_(method), object_(object)$for j [[,
      p$(j)_(p$j)]] {}
  R operator()() const {
    return (object_->*method_)($for j , [[p$(j)_]]); }
 private:
  MethodT method_;
  typename detail::PointerType<ObjectT>::type object_;$for j [[

  typename rtc::remove_reference<P$j>::type p$(j)_;]]

};

template <class FunctorT, class R$for j [[,
          class P$j]]>
class Functor$i {
 public:
  $if i == 0 [[explicit ]]
Functor$i(const FunctorT& functor$for j [[, P$j p$j]])
      : functor_(functor)$for j [[,
      p$(j)_(p$j)]] {}
  R operator()() const {
    return functor_($for j , [[p$(j)_]]); }
 private:
  FunctorT functor_;$for j [[

  typename rtc::remove_reference<P$j>::type p$(j)_;]]

};


#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]])

template <class ObjectT, class R$for j [[,
          class P$j]]>
MethodFunctor$i<ObjectT, FP_T(NONAME), R$for j [[, P$j]]>
Bind(FP_T(method), ObjectT* object$for j [[,
     typename detail::identity<P$j>::type p$j]]) {
  return MethodFunctor$i<ObjectT, FP_T(NONAME), R$for j [[, P$j]]>(
      method, object$for j [[, p$j]]);
}

#undef FP_T
#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]]) const

template <class ObjectT, class R$for j [[,
          class P$j]]>
MethodFunctor$i<const ObjectT, FP_T(NONAME), R$for j [[, P$j]]>
Bind(FP_T(method), const ObjectT* object$for j [[,
     typename detail::identity<P$j>::type p$j]]) {
  return MethodFunctor$i<const ObjectT, FP_T(NONAME), R$for j [[, P$j]]>(
      method, object$for j [[, p$j]]);
}

#undef FP_T
#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]])

template <class ObjectT, class R$for j [[,
          class P$j]]>
MethodFunctor$i<ObjectT, FP_T(NONAME), R$for j [[, P$j]]>
Bind(FP_T(method), const scoped_refptr<ObjectT>& object$for j [[,
     typename detail::identity<P$j>::type p$j]]) {
  return MethodFunctor$i<ObjectT, FP_T(NONAME), R$for j [[, P$j]]>(
      method, object.get()$for j [[, p$j]]);
}

#undef FP_T
#define FP_T(x) R (*x)($for j , [[P$j]])

template <class R$for j [[,
          class P$j]]>
Functor$i<FP_T(NONAME), R$for j [[, P$j]]>
Bind(FP_T(function)$for j [[,
     typename detail::identity<P$j>::type p$j]]) {
  return Functor$i<FP_T(NONAME), R$for j [[, P$j]]>(
      function$for j [[, p$j]]);
}

#undef FP_T

]]

}  // namespace rtc

#undef NONAME

#endif  // WEBRTC_BASE_BIND_H_