1// Copyright (c) 2012 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
11#include <stddef.h>
12#include <map>
13#include <memory>
14#include <type_traits>
15#include <vector>
16
17#include "base/atomic_ref_count.h"
18#include "base/base_export.h"
19#include "base/macros.h"
20#include "base/memory/ref_counted.h"
21#include "base/memory/scoped_ptr.h"
22#include "base/template_util.h"
23
24namespace base {
25namespace internal {
26class CallbackBase;
27
28// BindStateBase is used to provide an opaque handle that the Callback
29// class can use to represent a function object with bound arguments.  It
30// behaves as an existential type that is used by a corresponding
31// DoInvoke function to perform the function execution.  This allows
32// us to shield the Callback class from the types of the bound argument via
33// "type erasure."
34// At the base level, the only task is to add reference counting data. Don't use
35// RefCountedThreadSafe since it requires the destructor to be a virtual method.
36// Creating a vtable for every BindState template instantiation results in a lot
37// of bloat. Its only task is to call the destructor which can be done with a
38// function pointer.
39class BindStateBase {
40 protected:
41  explicit BindStateBase(void (*destructor)(BindStateBase*))
42      : ref_count_(0), destructor_(destructor) {}
43  ~BindStateBase() = default;
44
45 private:
46  friend class scoped_refptr<BindStateBase>;
47  friend class CallbackBase;
48
49  void AddRef();
50  void Release();
51
52  AtomicRefCount ref_count_;
53
54  // Pointer to a function that will properly destroy |this|.
55  void (*destructor_)(BindStateBase*);
56
57  DISALLOW_COPY_AND_ASSIGN(BindStateBase);
58};
59
60// Holds the Callback methods that don't require specialization to reduce
61// template bloat.
62class BASE_EXPORT CallbackBase {
63 public:
64  CallbackBase(const CallbackBase& c);
65  CallbackBase& operator=(const CallbackBase& c);
66
67  // Returns true if Callback is null (doesn't refer to anything).
68  bool is_null() const { return bind_state_.get() == NULL; }
69
70  // Returns the Callback into an uninitialized state.
71  void Reset();
72
73 protected:
74  // In C++, it is safe to cast function pointers to function pointers of
75  // another type. It is not okay to use void*. We create a InvokeFuncStorage
76  // that that can store our function pointer, and then cast it back to
77  // the original type on usage.
78  using InvokeFuncStorage = void(*)();
79
80  // Returns true if this callback equals |other|. |other| may be null.
81  bool Equals(const CallbackBase& other) const;
82
83  // Allow initializing of |bind_state_| via the constructor to avoid default
84  // initialization of the scoped_refptr.  We do not also initialize
85  // |polymorphic_invoke_| here because doing a normal assignment in the
86  // derived Callback templates makes for much nicer compiler errors.
87  explicit CallbackBase(BindStateBase* bind_state);
88
89  // Force the destructor to be instantiated inside this translation unit so
90  // that our subclasses will not get inlined versions.  Avoids more template
91  // bloat.
92  ~CallbackBase();
93
94  scoped_refptr<BindStateBase> bind_state_;
95  InvokeFuncStorage polymorphic_invoke_;
96};
97
98// A helper template to determine if given type is non-const move-only-type,
99// i.e. if a value of the given type should be passed via std::move() in a
100// destructive way. Types are considered to be move-only if they have a
101// sentinel MoveOnlyTypeForCPP03 member: a class typically gets this from using
102// the DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND macro.
103// It would be easy to generalize this trait to all move-only types... but this
104// confuses template deduction in VS2013 with certain types such as
105// std::unique_ptr.
106// TODO(dcheng): Revisit this when Windows switches to VS2015 by default.
107template <typename T> struct IsMoveOnlyType {
108  template <typename U>
109  static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
110
111  template <typename U>
112  static NoType Test(...);
113
114  static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) &&
115                            !is_const<T>::value;
116};
117
118// Specialization of IsMoveOnlyType so that std::unique_ptr is still considered
119// move-only, even without the sentinel member.
120template <typename T>
121struct IsMoveOnlyType<std::unique_ptr<T>> : std::true_type {};
122
123template <typename>
124struct CallbackParamTraitsForMoveOnlyType;
125
126template <typename>
127struct CallbackParamTraitsForNonMoveOnlyType;
128
129// TODO(tzik): Use a default parameter once MSVS supports variadic templates
130// with default values.
131// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
132//
133// This is a typetraits object that's used to take an argument type, and
134// extract a suitable type for storing and forwarding arguments.
135//
136// In particular, it strips off references, and converts arrays to
137// pointers for storage; and it avoids accidentally trying to create a
138// "reference of a reference" if the argument is a reference type.
139//
140// This array type becomes an issue for storage because we are passing bound
141// parameters by const reference. In this case, we end up passing an actual
142// array type in the initializer list which C++ does not allow.  This will
143// break passing of C-string literals.
144template <typename T>
145struct CallbackParamTraits
146    : std::conditional<IsMoveOnlyType<T>::value,
147         CallbackParamTraitsForMoveOnlyType<T>,
148         CallbackParamTraitsForNonMoveOnlyType<T>>::type {
149};
150
151template <typename T>
152struct CallbackParamTraitsForNonMoveOnlyType {
153  using ForwardType = const T&;
154  using StorageType = T;
155};
156
157// The Storage should almost be impossible to trigger unless someone manually
158// specifies type of the bind parameters.  However, in case they do,
159// this will guard against us accidentally storing a reference parameter.
160//
161// The ForwardType should only be used for unbound arguments.
162template <typename T>
163struct CallbackParamTraitsForNonMoveOnlyType<T&> {
164  using ForwardType = T&;
165  using StorageType = T;
166};
167
168// Note that for array types, we implicitly add a const in the conversion. This
169// means that it is not possible to bind array arguments to functions that take
170// a non-const pointer. Trying to specialize the template based on a "const
171// T[n]" does not seem to match correctly, so we are stuck with this
172// restriction.
173template <typename T, size_t n>
174struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
175  using ForwardType = const T*;
176  using StorageType = const T*;
177};
178
179// See comment for CallbackParamTraits<T[n]>.
180template <typename T>
181struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
182  using ForwardType = const T*;
183  using StorageType = const T*;
184};
185
186// Parameter traits for movable-but-not-copyable scopers.
187//
188// Callback<>/Bind() understands movable-but-not-copyable semantics where
189// the type cannot be copied but can still have its state destructively
190// transferred (aka. moved) to another instance of the same type by calling a
191// helper function.  When used with Bind(), this signifies transferal of the
192// object's state to the target function.
193//
194// For these types, the ForwardType must not be a const reference, or a
195// reference.  A const reference is inappropriate, and would break const
196// correctness, because we are implementing a destructive move.  A non-const
197// reference cannot be used with temporaries which means the result of a
198// function or a cast would not be usable with Callback<> or Bind().
199template <typename T>
200struct CallbackParamTraitsForMoveOnlyType {
201  using ForwardType = T;
202  using StorageType = T;
203};
204
205// CallbackForward() is a very limited simulation of C++11's std::forward()
206// used by the Callback/Bind system for a set of movable-but-not-copyable
207// types.  It is needed because forwarding a movable-but-not-copyable
208// argument to another function requires us to invoke the proper move
209// operator to create a rvalue version of the type.  The supported types are
210// whitelisted below as overloads of the CallbackForward() function. The
211// default template compiles out to be a no-op.
212//
213// In C++11, std::forward would replace all uses of this function.  However, it
214// is impossible to implement a general std::forward without C++11 due to a lack
215// of rvalue references.
216//
217// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
218// simulate std::forward() and forward the result of one Callback as a
219// parameter to another callback. This is to support Callbacks that return
220// the movable-but-not-copyable types whitelisted above.
221template <typename T>
222typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(
223    T& t) {
224  return t;
225}
226
227template <typename T>
228typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
229    T& t) {
230  return std::move(t);
231}
232
233}  // namespace internal
234}  // namespace base
235
236#endif  // BASE_CALLBACK_INTERNAL_H_
237