Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: webrtc/base/bind.h

Issue 2711113008: Adding rtc::Unretained to allow avoiding rtc::Bind reference capture. (Closed)
Patch Set: Rebase onto master Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | webrtc/base/bind_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2012 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2012 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 // Bind() is an overloaded function that converts method calls into function 11 // Bind() is an overloaded function that converts method calls into function
12 // objects (aka functors). The method object is captured as a scoped_refptr<> if 12 // 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 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 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 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 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 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. 18 // functor with a destroyed object will surely do bad things.
19 // 19 //
20 // To prevent the method object from being captured as a scoped_refptr<>, you
21 // can use Unretained. But this should only be done when absolutely necessary,
22 // and when the caller knows the extra reference isn't needed.
23 //
20 // Example usage: 24 // Example usage:
21 // struct Foo { 25 // struct Foo {
22 // int Test1() { return 42; } 26 // int Test1() { return 42; }
23 // int Test2() const { return 52; } 27 // int Test2() const { return 52; }
24 // int Test3(int x) { return x*x; } 28 // int Test3(int x) { return x*x; }
25 // float Test4(int x, float y) { return x + y; } 29 // float Test4(int x, float y) { return x + y; }
26 // }; 30 // };
27 // 31 //
28 // int main() { 32 // int main() {
29 // Foo foo; 33 // Foo foo;
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 122
119 // PointerType<T>::type will be scoped_refptr<T> for ref counted types, and T* 123 // PointerType<T>::type will be scoped_refptr<T> for ref counted types, and T*
120 // otherwise. 124 // otherwise.
121 template <class T> 125 template <class T>
122 struct PointerType { 126 struct PointerType {
123 typedef typename TernaryTypeOperator<IsRefCounted<T>::value, 127 typedef typename TernaryTypeOperator<IsRefCounted<T>::value,
124 scoped_refptr<T>, 128 scoped_refptr<T>,
125 T*>::type type; 129 T*>::type type;
126 }; 130 };
127 131
132 template <typename T>
133 class UnretainedWrapper {
134 public:
135 explicit UnretainedWrapper(T* o) : ptr_(o) {}
136 T* get() const { return ptr_; }
137
138 private:
139 T* ptr_;
140 };
141
128 } // namespace detail 142 } // namespace detail
129 143
144 template <typename T>
145 static inline detail::UnretainedWrapper<T> Unretained(T* o) {
146 return detail::UnretainedWrapper<T>(o);
147 }
148
130 template <class ObjectT, class MethodT, class R, typename... Args> 149 template <class ObjectT, class MethodT, class R, typename... Args>
131 class MethodFunctor { 150 class MethodFunctor {
132 public: 151 public:
133 MethodFunctor(MethodT method, ObjectT* object, Args... args) 152 MethodFunctor(MethodT method, ObjectT* object, Args... args)
134 : method_(method), object_(object), args_(args...) {} 153 : method_(method), object_(object), args_(args...) {}
135 R operator()() const { 154 R operator()() const {
136 return CallMethod(typename sequence_generator<sizeof...(Args)>::type()); 155 return CallMethod(typename sequence_generator<sizeof...(Args)>::type());
137 } 156 }
138 157
139 private: 158 private:
140 // Use sequence_generator (see template_util.h) to expand a MethodFunctor 159 // 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 160 // with 2 arguments to (std::get<0>(args_), std::get<1>(args_)), for
142 // instance. 161 // instance.
143 template <int... S> 162 template <int... S>
144 R CallMethod(sequence<S...>) const { 163 R CallMethod(sequence<S...>) const {
145 return (object_->*method_)(std::get<S>(args_)...); 164 return (object_->*method_)(std::get<S>(args_)...);
146 } 165 }
147 166
148 MethodT method_; 167 MethodT method_;
149 typename detail::PointerType<ObjectT>::type object_; 168 typename detail::PointerType<ObjectT>::type object_;
150 typename std::tuple<typename std::remove_reference<Args>::type...> args_; 169 typename std::tuple<typename std::remove_reference<Args>::type...> args_;
151 }; 170 };
152 171
172 template <class ObjectT, class MethodT, class R, typename... Args>
173 class UnretainedMethodFunctor {
174 public:
175 UnretainedMethodFunctor(MethodT method,
176 detail::UnretainedWrapper<ObjectT> object,
177 Args... args)
178 : method_(method), object_(object.get()), args_(args...) {}
179 R operator()() const {
180 return CallMethod(typename sequence_generator<sizeof...(Args)>::type());
181 }
182
183 private:
184 // Use sequence_generator (see template_util.h) to expand an
185 // UnretainedMethodFunctor with 2 arguments to (std::get<0>(args_),
186 // std::get<1>(args_)), for instance.
187 template <int... S>
188 R CallMethod(sequence<S...>) const {
189 return (object_->*method_)(std::get<S>(args_)...);
190 }
191
192 MethodT method_;
193 ObjectT* object_;
194 typename std::tuple<typename std::remove_reference<Args>::type...> args_;
195 };
196
153 template <class FunctorT, class R, typename... Args> 197 template <class FunctorT, class R, typename... Args>
154 class Functor { 198 class Functor {
155 public: 199 public:
156 Functor(const FunctorT& functor, Args... args) 200 Functor(const FunctorT& functor, Args... args)
157 : functor_(functor), args_(args...) {} 201 : functor_(functor), args_(args...) {}
158 R operator()() const { 202 R operator()() const {
159 return CallFunction(typename sequence_generator<sizeof...(Args)>::type()); 203 return CallFunction(typename sequence_generator<sizeof...(Args)>::type());
160 } 204 }
161 205
162 private: 206 private:
(...skipping 13 matching lines...) Expand all
176 220
177 template <class ObjectT, class R, typename... Args> 221 template <class ObjectT, class R, typename... Args>
178 MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind( 222 MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind(
179 FP_T(method), 223 FP_T(method),
180 ObjectT* object, 224 ObjectT* object,
181 typename detail::identity<Args>::type... args) { 225 typename detail::identity<Args>::type... args) {
182 return MethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(method, object, 226 return MethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(method, object,
183 args...); 227 args...);
184 } 228 }
185 229
230 template <class ObjectT, class R, typename... Args>
231 MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind(
232 FP_T(method),
233 const scoped_refptr<ObjectT>& object,
234 typename detail::identity<Args>::type... args) {
235 return MethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(method, object.get(),
236 args...);
237 }
238
239 template <class ObjectT, class R, typename... Args>
240 UnretainedMethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind(
241 FP_T(method),
242 detail::UnretainedWrapper<ObjectT> object,
243 typename detail::identity<Args>::type... args) {
244 return UnretainedMethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(
245 method, object, args...);
246 }
247
186 #undef FP_T 248 #undef FP_T
187 #define FP_T(x) R (ObjectT::*x)(Args...) const 249 #define FP_T(x) R (ObjectT::*x)(Args...) const
188 250
189 template <class ObjectT, class R, typename... Args> 251 template <class ObjectT, class R, typename... Args>
190 MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...> Bind( 252 MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...> Bind(
191 FP_T(method), 253 FP_T(method),
192 const ObjectT* object, 254 const ObjectT* object,
193 typename detail::identity<Args>::type... args) { 255 typename detail::identity<Args>::type... args) {
194 return MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...>(method, object, 256 return MethodFunctor<const ObjectT, FP_T(NONAME), R, Args...>(method, object,
195 args...); 257 args...);
196 } 258 }
197
198 #undef FP_T
199 #define FP_T(x) R (ObjectT::*x)(Args...)
200
201 template <class ObjectT, class R, typename... Args> 259 template <class ObjectT, class R, typename... Args>
202 MethodFunctor<ObjectT, FP_T(NONAME), R, Args...> Bind( 260 UnretainedMethodFunctor<const ObjectT, FP_T(NONAME), R, Args...> Bind(
203 FP_T(method), 261 FP_T(method),
204 const scoped_refptr<ObjectT>& object, 262 detail::UnretainedWrapper<const ObjectT> object,
205 typename detail::identity<Args>::type... args) { 263 typename detail::identity<Args>::type... args) {
206 return MethodFunctor<ObjectT, FP_T(NONAME), R, Args...>(method, object.get(), 264 return UnretainedMethodFunctor<const ObjectT, FP_T(NONAME), R, Args...>(
207 args...); 265 method, object, args...);
208 } 266 }
209 267
210 #undef FP_T 268 #undef FP_T
211 #define FP_T(x) R (*x)(Args...) 269 #define FP_T(x) R (*x)(Args...)
212 270
213 template <class R, typename... Args> 271 template <class R, typename... Args>
214 Functor<FP_T(NONAME), R, Args...> Bind( 272 Functor<FP_T(NONAME), R, Args...> Bind(
215 FP_T(function), 273 FP_T(function),
216 typename detail::identity<Args>::type... args) { 274 typename detail::identity<Args>::type... args) {
217 return Functor<FP_T(NONAME), R, Args...>(function, args...); 275 return Functor<FP_T(NONAME), R, Args...>(function, args...);
218 } 276 }
219 277
220 #undef FP_T 278 #undef FP_T
221 279
222 } // namespace rtc 280 } // namespace rtc
223 281
224 #undef NONAME 282 #undef NONAME
225 283
226 #endif // WEBRTC_BASE_BIND_H_ 284 #endif // WEBRTC_BASE_BIND_H_
OLDNEW
« no previous file with comments | « no previous file | webrtc/base/bind_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698