blob: b83b04909fd6758b94ad0528622aaf0a6e884f43 [file] [log] [blame]
ajwong@chromium.orge2cca632011-02-15 10:27:38 +09001// 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 file contains utility functions and classes that help the
6// implementation, and management of the Callback objects.
7
ajwong@chromium.orgfa0ff432011-02-19 08:29:31 +09008#ifndef BASE_CALLBACK_INTERNAL_H_
9#define BASE_CALLBACK_INTERNAL_H_
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090010#pragma once
11
jhawkins@chromium.org8e73d062011-04-05 03:04:37 +090012#include <stddef.h>
13
rvargas@google.com73eb5d02011-03-25 04:00:20 +090014#include "base/base_api.h"
levin@chromium.org5c528682011-03-28 10:54:15 +090015#include "base/memory/ref_counted.h"
ajwong@chromium.orge2cca632011-02-15 10:27:38 +090016
17namespace base {
18namespace internal {
19
20// InvokerStorageBase is used to provide an opaque handle that the Callback
21// class can use to represent a function object with bound arguments. It
22// behaves as an existential type that is used by a corresponding
23// DoInvoke function to perform the function execution. This allows
24// us to shield the Callback class from the types of the bound argument via
25// "type erasure."
26class InvokerStorageBase : public RefCountedThreadSafe<InvokerStorageBase> {
27 protected:
28 friend class RefCountedThreadSafe<InvokerStorageBase>;
29 virtual ~InvokerStorageBase() {}
30};
31
32// This structure exists purely to pass the returned |invoker_storage_| from
33// Bind() to Callback while avoiding an extra AddRef/Release() pair.
34//
35// To do this, the constructor of Callback<> must take a const-ref. The
36// reference must be to a const object otherwise the compiler will emit a
37// warning about taking a reference to a temporary.
38//
39// Unfortunately, this means that the internal |invoker_storage_| field must
40// be made mutable.
41template <typename T>
42struct InvokerStorageHolder {
43 explicit InvokerStorageHolder(T* invoker_storage)
44 : invoker_storage_(invoker_storage) {
45 }
46
47 mutable scoped_refptr<InvokerStorageBase> invoker_storage_;
48};
49
50template <typename T>
51InvokerStorageHolder<T> MakeInvokerStorageHolder(T* o) {
52 return InvokerStorageHolder<T>(o);
53}
54
ajwong@chromium.orgfa0ff432011-02-19 08:29:31 +090055// Holds the Callback methods that don't require specialization to reduce
56// template bloat.
rvargas@google.com73eb5d02011-03-25 04:00:20 +090057class BASE_API CallbackBase {
ajwong@chromium.orgfa0ff432011-02-19 08:29:31 +090058 public:
59 // Returns true if Callback is null (doesn't refer to anything).
60 bool is_null() const;
61
62 // Returns the Callback into an uninitalized state.
63 void Reset();
64
65 bool Equals(const CallbackBase& other) const;
66
67 protected:
68 // In C++, it is safe to cast function pointers to function pointers of
69 // another type. It is not okay to use void*. We create a InvokeFuncStorage
70 // that that can store our function pointer, and then cast it back to
71 // the original type on usage.
72 typedef void(*InvokeFuncStorage)(void);
73
74 CallbackBase(InvokeFuncStorage polymorphic_invoke,
75 scoped_refptr<InvokerStorageBase>* invoker_storage);
76
77 // Force the destructor to be instaniated inside this translation unit so
78 // that our subclasses will not get inlined versions. Avoids more template
79 // bloat.
80 ~CallbackBase();
81
82 scoped_refptr<InvokerStorageBase> invoker_storage_;
83 InvokeFuncStorage polymorphic_invoke_;
84};
85
ajwong@chromium.orga7e74822011-03-24 11:02:17 +090086// This is a typetraits object that's used to take an argument type, and
87// extract a suitable type for storing and forwarding arguments.
88//
89// In particular, it strips off references, and converts arrays to
90// pointers for storage; and it avoids accidentally trying to create a
91// "reference of a reference" if the argument is a reference type.
92//
93// This array type becomes an issue for storage because we are passing bound
94// parameters by const reference. In this case, we end up passing an actual
95// array type in the initializer list which C++ does not allow. This will
96// break passing of C-string literals.
97template <typename T>
98struct ParamTraits {
99 typedef const T& ForwardType;
100 typedef T StorageType;
101};
102
103// The Storage should almost be impossible to trigger unless someone manually
104// specifies type of the bind parameters. However, in case they do,
105// this will guard against us accidentally storing a reference parameter.
106//
107// The ForwardType should only be used for unbound arguments.
108template <typename T>
109struct ParamTraits<T&> {
110 typedef T& ForwardType;
111 typedef T StorageType;
112};
113
114// Note that for array types, we implicitly add a const in the conversion. This
115// means that it is not possible to bind array arguments to functions that take
116// a non-const pointer. Trying to specialize the template based on a "const
117// T[n]" does not seem to match correctly, so we are stuck with this
118// restriction.
119template <typename T, size_t n>
120struct ParamTraits<T[n]> {
121 typedef const T* ForwardType;
122 typedef const T* StorageType;
123};
124
125// See comment for ParamTraits<T[n]>.
126template <typename T>
127struct ParamTraits<T[]> {
128 typedef const T* ForwardType;
129 typedef const T* StorageType;
130};
131
ajwong@chromium.orge2cca632011-02-15 10:27:38 +0900132} // namespace internal
133} // namespace base
134
ajwong@chromium.orgfa0ff432011-02-19 08:29:31 +0900135#endif // BASE_CALLBACK_INTERNAL_H_