blob: 397a4d5c876608a07ecc5584c2f7f06d42250304 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2012 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000011// Bind() is an overloaded function that converts method calls into function
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020012// objects (aka functors). The method object is captured as a scoped_refptr<> if
13// possible, and as a raw pointer otherwise. Any arguments to the method are
14// captured by value. The return value of Bind is a stateful, nullary function
15// object. Care should be taken about the lifetime of objects captured by
16// Bind(); the returned functor knows nothing about the lifetime of a non
17// ref-counted method object or any arguments passed by pointer, and calling the
18// functor with a destroyed object will surely do bad things.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019//
20// Example usage:
21// struct Foo {
22// int Test1() { return 42; }
23// int Test2() const { return 52; }
24// int Test3(int x) { return x*x; }
25// float Test4(int x, float y) { return x + y; }
26// };
27//
28// int main() {
29// Foo foo;
30// cout << rtc::Bind(&Foo::Test1, &foo)() << endl;
31// cout << rtc::Bind(&Foo::Test2, &foo)() << endl;
32// cout << rtc::Bind(&Foo::Test3, &foo, 3)() << endl;
33// cout << rtc::Bind(&Foo::Test4, &foo, 7, 8.5f)() << endl;
34// }
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020035//
36// Example usage of ref counted objects:
37// struct Bar {
38// int AddRef();
39// int Release();
40//
41// void Test() {}
42// void BindThis() {
43// // The functor passed to AsyncInvoke() will keep this object alive.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070044// invoker.AsyncInvoke(RTC_FROM_HERE,rtc::Bind(&Bar::Test, this));
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020045// }
46// };
47//
48// int main() {
49// rtc::scoped_refptr<Bar> bar = new rtc::RefCountedObject<Bar>();
50// auto functor = rtc::Bind(&Bar::Test, bar);
51// bar = nullptr;
52// // The functor stores an internal scoped_refptr<Bar>, so this is safe.
53// functor();
54// }
55//
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000056
57#ifndef WEBRTC_BASE_BIND_H_
58#define WEBRTC_BASE_BIND_H_
59
deadbeef08187d42017-02-25 11:21:18 -080060#include <tuple>
61#include <type_traits>
62
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020063#include "webrtc/base/scoped_ref_ptr.h"
noahric5d9b92b2015-10-24 11:14:46 -070064#include "webrtc/base/template_util.h"
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020065
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066#define NONAME
67
68namespace rtc {
69namespace detail {
70// This is needed because the template parameters in Bind can't be resolved
71// if they're used both as parameters of the function pointer type and as
72// parameters to Bind itself: the function pointer parameters are exact
73// matches to the function prototype, but the parameters to bind have
74// references stripped. This trick allows the compiler to dictate the Bind
75// parameter types rather than deduce them.
76template <class T> struct identity { typedef T type; };
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020077
78// IsRefCounted<T>::value will be true for types that can be used in
79// rtc::scoped_refptr<T>, i.e. types that implements nullary functions AddRef()
80// and Release(), regardless of their return types. AddRef() and Release() can
81// be defined in T or any superclass of T.
82template <typename T>
83class IsRefCounted {
84 // This is a complex implementation detail done with SFINAE.
85
86 // Define types such that sizeof(Yes) != sizeof(No).
87 struct Yes { char dummy[1]; };
88 struct No { char dummy[2]; };
89 // Define two overloaded template functions with return types of different
90 // size. This way, we can use sizeof() on the return type to determine which
91 // function the compiler would have chosen. One function will be preferred
92 // over the other if it is possible to create it without compiler errors,
93 // otherwise the compiler will simply remove it, and default to the less
94 // preferred function.
95 template <typename R>
96 static Yes test(R* r, decltype(r->AddRef(), r->Release(), 42));
97 template <typename C> static No test(...);
98
99public:
100 // Trick the compiler to tell if it's possible to call AddRef() and Release().
101 static const bool value = sizeof(test<T>((T*)nullptr, 42)) == sizeof(Yes);
102};
103
104// TernaryTypeOperator is a helper class to select a type based on a static bool
105// value.
106template <bool condition, typename IfTrueT, typename IfFalseT>
107struct TernaryTypeOperator {};
108
109template <typename IfTrueT, typename IfFalseT>
110struct TernaryTypeOperator<true, IfTrueT, IfFalseT> {
111 typedef IfTrueT type;
112};
113
114template <typename IfTrueT, typename IfFalseT>
115struct TernaryTypeOperator<false, IfTrueT, IfFalseT> {
116 typedef IfFalseT type;
117};
118
119// PointerType<T>::type will be scoped_refptr<T> for ref counted types, and T*
120// otherwise.
121template <class T>
122struct PointerType {
123 typedef typename TernaryTypeOperator<IsRefCounted<T>::value,
124 scoped_refptr<T>,
125 T*>::type type;
126};
127
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128} // namespace detail
129
deadbeef08187d42017-02-25 11:21:18 -0800130template <class ObjectT, class MethodT, class R, typename... Args>
131class MethodFunctor {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000132 public:
deadbeef08187d42017-02-25 11:21:18 -0800133 MethodFunctor(MethodT method, ObjectT* object, Args... args)
134 : method_(method), object_(object), args_(args...) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000135 R operator()() const {
deadbeef08187d42017-02-25 11:21:18 -0800136 return CallMethod(typename sequence_generator<sizeof...(Args)>::type());
noahric5d9b92b2015-10-24 11:14:46 -0700137 }
138
139 private:
deadbeef08187d42017-02-25 11:21:18 -0800140 // Use sequence_generator (see template_util.h) to expand a MethodFunctor
141 // with 2 arguments to (std::get<0>(args_), std::get<1>(args_)), for
142 // instance.
143 template <int... S>
144 R CallMethod(sequence<S...>) const {
145 return (object_->*method_)(std::get<S>(args_)...);
146 }
147
noahric5d9b92b2015-10-24 11:14:46 -0700148 MethodT method_;
149 typename detail::PointerType<ObjectT>::type object_;
deadbeef08187d42017-02-25 11:21:18 -0800150 typename std::tuple<typename std::remove_reference<Args>::type...> args_;
noahric5d9b92b2015-10-24 11:14:46 -0700151};
152
deadbeef08187d42017-02-25 11:21:18 -0800153template <class FunctorT, class R, typename... Args>
154class Functor {
noahric5d9b92b2015-10-24 11:14:46 -0700155 public:
deadbeef08187d42017-02-25 11:21:18 -0800156 Functor(const FunctorT& functor, Args... args)
157 : functor_(functor), args_(args...) {}
158 R operator()() const {
159 return CallFunction(typename sequence_generator<sizeof...(Args)>::type());
160 }
noahric5d9b92b2015-10-24 11:14:46 -0700161
162 private:
deadbeef08187d42017-02-25 11:21:18 -0800163 // Use sequence_generator (see template_util.h) to expand a Functor
164 // with 2 arguments to (std::get<0>(args_), std::get<1>(args_)), for
165 // instance.
166 template <int... S>
167 R CallFunction(sequence<S...>) const {
168 return functor_(std::get<S>(args_)...);
169 }
170
noahric5d9b92b2015-10-24 11:14:46 -0700171 FunctorT functor_;
deadbeef08187d42017-02-25 11:21:18 -0800172 typename std::tuple<typename std::remove_reference<Args>::type...> args_;
noahric5d9b92b2015-10-24 11:14:46 -0700173};
174
deadbeef08187d42017-02-25 11:21:18 -0800175#define FP_T(x) R (ObjectT::*x)(Args...)
noahric5d9b92b2015-10-24 11:14:46 -0700176
deadbeef08187d42017-02-25 11:21:18 -0800177template <class ObjectT, class R, typename... Args>
178MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind(
noahric5d9b92b2015-10-24 11:14:46 -0700179 FP_T(method),
180 ObjectT* object,
deadbeef08187d42017-02-25 11:21:18 -0800181 typename detail::identity<Args>::type... args) {
182 return MethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(method, object,
183 args...);
noahric5d9b92b2015-10-24 11:14:46 -0700184}
185
186#undef FP_T
deadbeef08187d42017-02-25 11:21:18 -0800187#define FP_T(x) R (ObjectT::*x)(Args...) const
noahric5d9b92b2015-10-24 11:14:46 -0700188
deadbeef08187d42017-02-25 11:21:18 -0800189template <class ObjectT, class R, typename... Args>
190MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...> Bind(
noahric5d9b92b2015-10-24 11:14:46 -0700191 FP_T(method),
192 const ObjectT* object,
deadbeef08187d42017-02-25 11:21:18 -0800193 typename detail::identity<Args>::type... args) {
194 return MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...>(method, object,
195 args...);
noahric5d9b92b2015-10-24 11:14:46 -0700196}
197
198#undef FP_T
deadbeef08187d42017-02-25 11:21:18 -0800199#define FP_T(x) R (ObjectT::*x)(Args...)
noahric5d9b92b2015-10-24 11:14:46 -0700200
deadbeef08187d42017-02-25 11:21:18 -0800201template <class ObjectT, class R, typename... Args>
202MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind(
noahric5d9b92b2015-10-24 11:14:46 -0700203 FP_T(method),
204 const scoped_refptr<ObjectT>& object,
deadbeef08187d42017-02-25 11:21:18 -0800205 typename detail::identity<Args>::type... args) {
206 return MethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(method, object.get(),
207 args...);
noahric5d9b92b2015-10-24 11:14:46 -0700208}
209
210#undef FP_T
deadbeef08187d42017-02-25 11:21:18 -0800211#define FP_T(x) R (*x)(Args...)
noahric5d9b92b2015-10-24 11:14:46 -0700212
deadbeef08187d42017-02-25 11:21:18 -0800213template <class R, typename... Args>
214Functor<FP_T(NONAME), R, Args...> Bind(
noahric5d9b92b2015-10-24 11:14:46 -0700215 FP_T(function),
deadbeef08187d42017-02-25 11:21:18 -0800216 typename detail::identity<Args>::type... args) {
217 return Functor<FP_T(NONAME), R, Args...>(function, args...);
noahric5d9b92b2015-10-24 11:14:46 -0700218}
219
220#undef FP_T
221
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000222} // namespace rtc
223
224#undef NONAME
225
226#endif // WEBRTC_BASE_BIND_H_