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
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
55// Holds the Callback methods that don't require specialization to reduce
56// template bloat.
57class 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.
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
132}  // namespace internal
133}  // namespace base
134
135#endif  // BASE_CALLBACK_INTERNAL_H_
136