blob: 07f11f98d2cde4e730b0c811e6b176dac1fa9ca7 [file] [log] [blame]
[email protected]b38d3572011-02-15 01:27:381// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This defines a set of argument wrappers and related factory methods that
6// can be used specify the refcounting and reference semantics of arguments
7// that are bound by the Bind() function in base/bind.h.
8//
[email protected]e8bfc31d2011-09-28 00:26:379// The public functions are base::Unretained(), base::ConstRef(), and
10// base::IgnoreReturn().
11//
[email protected]b38d3572011-02-15 01:27:3812// Unretained() allows Bind() to bind a non-refcounted class.
13// ConstRef() allows binding a constant reference to an argument rather
14// than a copy.
[email protected]e8bfc31d2011-09-28 00:26:3715// IgnoreReturn() is used to adapt a 0-argument Callback with a return type to
16// a Closure. This is useful if you need to PostTask with a function that has
17// a return value that you don't care about.
[email protected]b38d3572011-02-15 01:27:3818//
19//
20// EXAMPLE OF Unretained():
21//
22// class Foo {
23// public:
[email protected]e8bfc31d2011-09-28 00:26:3724// void func() { cout << "Foo:f" << endl; }
[email protected]b38d3572011-02-15 01:27:3825// };
26//
27// // In some function somewhere.
28// Foo foo;
29// Callback<void(void)> foo_callback =
30// Bind(&Foo::func, Unretained(&foo));
31// foo_callback.Run(); // Prints "Foo:f".
32//
33// Without the Unretained() wrapper on |&foo|, the above call would fail
34// to compile because Foo does not support the AddRef() and Release() methods.
35//
36//
[email protected]e8bfc31d2011-09-28 00:26:3737// EXAMPLE OF ConstRef():
[email protected]b38d3572011-02-15 01:27:3838// void foo(int arg) { cout << arg << endl }
39//
40// int n = 1;
41// Callback<void(void)> no_ref = Bind(&foo, n);
42// Callback<void(void)> has_ref = Bind(&foo, ConstRef(n));
43//
44// no_ref.Run(); // Prints "1"
45// has_ref.Run(); // Prints "1"
46//
47// n = 2;
48// no_ref.Run(); // Prints "1"
49// has_ref.Run(); // Prints "2"
50//
51// Note that because ConstRef() takes a reference on |n|, |n| must outlive all
52// its bound callbacks.
53//
[email protected]e8bfc31d2011-09-28 00:26:3754//
55// EXAMPLE OF IgnoreReturn():
56// int DoSomething(int arg) { cout << arg << endl; }
57// Callback<int(void)> cb = Bind(&DoSomething, 1);
58// Closure c = IgnoreReturn(cb); // Prints "1"
59// or
60// ml->PostTask(FROM_HERE, IgnoreReturn(cb)); // Prints "1" on |ml|
[email protected]b38d3572011-02-15 01:27:3861
62#ifndef BASE_BIND_HELPERS_H_
63#define BASE_BIND_HELPERS_H_
64#pragma once
65
66#include "base/basictypes.h"
[email protected]e8bfc31d2011-09-28 00:26:3767#include "base/bind.h"
68#include "base/callback.h"
[email protected]93540582011-05-16 22:35:1469#include "base/memory/weak_ptr.h"
[email protected]b38d3572011-02-15 01:27:3870#include "base/template_util.h"
71
72namespace base {
73namespace internal {
74
75// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
76// for the existence of AddRef() and Release() functions of the correct
77// signature.
78//
79// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
80// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
81// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison
82// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
83//
84// The last link in particular show the method used below.
85//
86// For SFINAE to work with inherited methods, we need to pull some extra tricks
87// with multiple inheritance. In the more standard formulation, the overloads
88// of Check would be:
89//
90// template <typename C>
91// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*);
92//
93// template <typename C>
94// No NotTheCheckWeWant(...);
95//
96// static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes);
97//
98// The problem here is that template resolution will not match
99// C::TargetFunc if TargetFunc does not exist directly in C. That is, if
100// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match,
101// |value| will be false. This formulation only checks for whether or
102// not TargetFunc exist directly in the class being introspected.
103//
104// To get around this, we play a dirty trick with multiple inheritance.
105// First, We create a class BaseMixin that declares each function that we
106// want to probe for. Then we create a class Base that inherits from both T
107// (the class we wish to probe) and BaseMixin. Note that the function
108// signature in BaseMixin does not need to match the signature of the function
109// we are probing for; thus it's easiest to just use void(void).
110//
111// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
112// ambiguous resolution between BaseMixin and T. This lets us write the
113// following:
114//
115// template <typename C>
116// No GoodCheck(Helper<&C::TargetFunc>*);
117//
118// template <typename C>
119// Yes GoodCheck(...);
120//
121// static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes);
122//
123// Notice here that the variadic version of GoodCheck() returns Yes here
124// instead of No like the previous one. Also notice that we calculate |value|
125// by specializing GoodCheck() on Base instead of T.
126//
127// We've reversed the roles of the variadic, and Helper overloads.
128// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid
129// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve
130// to the variadic version if T has TargetFunc. If T::TargetFunc does not
131// exist, then &C::TargetFunc is not ambiguous, and the overload resolution
132// will prefer GoodCheck(Helper<&C::TargetFunc>*).
133//
134// This method of SFINAE will correctly probe for inherited names, but it cannot
135// typecheck those names. It's still a good enough sanity check though.
136//
137// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008.
138//
139// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted
140// this works well.
[email protected]7a1f7c6f2011-05-10 21:17:48141//
142// TODO(ajwong): Make this check for Release() as well.
143// See http://crbug.com/82038.
[email protected]b38d3572011-02-15 01:27:38144template <typename T>
145class SupportsAddRefAndRelease {
146 typedef char Yes[1];
147 typedef char No[2];
148
149 struct BaseMixin {
150 void AddRef();
[email protected]b38d3572011-02-15 01:27:38151 };
152
[email protected]690bda882011-04-13 22:40:46153// MSVC warns when you try to use Base if T has a private destructor, the
154// common pattern for refcounted types. It does this even though no attempt to
155// instantiate Base is made. We disable the warning for this definition.
156#if defined(OS_WIN)
157#pragma warning(disable:4624)
158#endif
[email protected]b38d3572011-02-15 01:27:38159 struct Base : public T, public BaseMixin {
160 };
[email protected]690bda882011-04-13 22:40:46161#if defined(OS_WIN)
162#pragma warning(default:4624)
163#endif
[email protected]b38d3572011-02-15 01:27:38164
[email protected]b224f792011-04-20 16:02:23165 template <void(BaseMixin::*)(void)> struct Helper {};
[email protected]b38d3572011-02-15 01:27:38166
167 template <typename C>
[email protected]7a1f7c6f2011-05-10 21:17:48168 static No& Check(Helper<&C::AddRef>*);
[email protected]b38d3572011-02-15 01:27:38169
170 template <typename >
171 static Yes& Check(...);
172
173 public:
[email protected]7a1f7c6f2011-05-10 21:17:48174 static const bool value = sizeof(Check<Base>(0)) == sizeof(Yes);
[email protected]b38d3572011-02-15 01:27:38175};
176
177
178// Helpers to assert that arguments of a recounted type are bound with a
179// scoped_refptr.
180template <bool IsClasstype, typename T>
181struct UnsafeBindtoRefCountedArgHelper : false_type {
182};
183
184template <typename T>
185struct UnsafeBindtoRefCountedArgHelper<true, T>
186 : integral_constant<bool, SupportsAddRefAndRelease<T>::value> {
187};
188
189template <typename T>
[email protected]c18b1052011-03-24 02:02:17190struct UnsafeBindtoRefCountedArg : false_type {
191};
192
193template <typename T>
194struct UnsafeBindtoRefCountedArg<T*>
[email protected]b38d3572011-02-15 01:27:38195 : UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> {
196};
197
198
199template <typename T>
200class UnretainedWrapper {
201 public:
202 explicit UnretainedWrapper(T* o) : obj_(o) {}
203 T* get() { return obj_; }
204 private:
205 T* obj_;
206};
207
208template <typename T>
209class ConstRefWrapper {
210 public:
211 explicit ConstRefWrapper(const T& o) : ptr_(&o) {}
212 const T& get() { return *ptr_; }
213 private:
214 const T* ptr_;
215};
216
217
218// Unwrap the stored parameters for the wrappers above.
219template <typename T>
220T Unwrap(T o) { return o; }
221
222template <typename T>
223T* Unwrap(UnretainedWrapper<T> unretained) { return unretained.get(); }
224
225template <typename T>
226const T& Unwrap(ConstRefWrapper<T> const_ref) {
227 return const_ref.get();
228}
229
[email protected]7a15d1172011-10-07 00:25:29230template <typename T>
231T* Unwrap(const scoped_refptr<T>& o) { return o.get(); }
232
233template <typename T>
234const WeakPtr<T>& Unwrap(const WeakPtr<T>& o) { return o; }
[email protected]b38d3572011-02-15 01:27:38235
236// Utility for handling different refcounting semantics in the Bind()
237// function.
[email protected]93540582011-05-16 22:35:14238template <typename IsMethod, typename T>
[email protected]b38d3572011-02-15 01:27:38239struct MaybeRefcount;
240
241template <typename T>
242struct MaybeRefcount<base::false_type, T> {
243 static void AddRef(const T&) {}
244 static void Release(const T&) {}
245};
246
247template <typename T, size_t n>
248struct MaybeRefcount<base::false_type, T[n]> {
249 static void AddRef(const T*) {}
250 static void Release(const T*) {}
251};
252
253template <typename T>
254struct MaybeRefcount<base::true_type, UnretainedWrapper<T> > {
255 static void AddRef(const UnretainedWrapper<T>&) {}
256 static void Release(const UnretainedWrapper<T>&) {}
257};
258
259template <typename T>
260struct MaybeRefcount<base::true_type, T*> {
261 static void AddRef(T* o) { o->AddRef(); }
262 static void Release(T* o) { o->Release(); }
263};
264
[email protected]7a15d1172011-10-07 00:25:29265// No need to additionally AddRef() and Release() since we are storing a
266// scoped_refptr<> inside the storage object already.
267template <typename T>
268struct MaybeRefcount<base::true_type, scoped_refptr<T> > {
269 static void AddRef(const scoped_refptr<T>& o) {}
270 static void Release(const scoped_refptr<T>& o) {}
271};
272
[email protected]b38d3572011-02-15 01:27:38273template <typename T>
274struct MaybeRefcount<base::true_type, const T*> {
275 static void AddRef(const T* o) { o->AddRef(); }
276 static void Release(const T* o) { o->Release(); }
277};
278
[email protected]93540582011-05-16 22:35:14279template <typename T>
280struct MaybeRefcount<base::true_type, WeakPtr<T> > {
281 static void AddRef(const WeakPtr<T>&) {}
282 static void Release(const WeakPtr<T>&) {}
283};
284
[email protected]e8bfc31d2011-09-28 00:26:37285template <typename R>
286void VoidReturnAdapter(Callback<R(void)> callback) {
287 callback.Run();
288}
289
[email protected]b38d3572011-02-15 01:27:38290} // namespace internal
291
292template <typename T>
293inline internal::UnretainedWrapper<T> Unretained(T* o) {
294 return internal::UnretainedWrapper<T>(o);
295}
296
297template <typename T>
298inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
299 return internal::ConstRefWrapper<T>(o);
300}
301
[email protected]e8bfc31d2011-09-28 00:26:37302template <typename R>
303Closure IgnoreReturn(Callback<R(void)> callback) {
304 return Bind(&internal::VoidReturnAdapter<R>, callback);
305}
306
[email protected]b38d3572011-02-15 01:27:38307} // namespace base
308
309#endif // BASE_BIND_HELPERS_H_