1 // 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
8 #ifndef BASE_CALLBACK_INTERNAL_H_
9 #define BASE_CALLBACK_INTERNAL_H_
10 #pragma once
11
12 #include <stddef.h>
13
14 #include "base/base_api.h"
15 #include "base/memory/ref_counted.h"
16
17 namespace base {
18 namespace 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."
26 class InvokerStorageBase : public RefCountedThreadSafe<InvokerStorageBase> {
27 protected:
28 friend class RefCountedThreadSafe<InvokerStorageBase>;
~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.
41 template <typename T>
42 struct InvokerStorageHolder {
InvokerStorageHolderInvokerStorageHolder43 explicit InvokerStorageHolder(T* invoker_storage)
44 : invoker_storage_(invoker_storage) {
45 }
46
47 mutable scoped_refptr<InvokerStorageBase> invoker_storage_;
48 };
49
50 template <typename T>
MakeInvokerStorageHolder(T * o)51 InvokerStorageHolder<T> MakeInvokerStorageHolder(T* o) {
52 return InvokerStorageHolder<T>(o);
53 }
54
55 // Holds the Callback methods that don't require specialization to reduce
56 // template bloat.
57 class BASE_API CallbackBase {
58 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
86 // 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.
97 template <typename T>
98 struct 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.
108 template <typename T>
109 struct 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.
119 template <typename T, size_t n>
120 struct ParamTraits<T[n]> {
121 typedef const T* ForwardType;
122 typedef const T* StorageType;
123 };
124
125 // See comment for ParamTraits<T[n]>.
126 template <typename T>
127 struct ParamTraits<T[]> {
128 typedef const T* ForwardType;
129 typedef const T* StorageType;
130 };
131
132 } // namespace internal
133 } // namespace base
134
135 #endif // BASE_CALLBACK_INTERNAL_H_
136