blob: 3682bf9d355a14da9fe6b7e1d2b17e2899019474 [file] [log] [blame]
Vitaly Bukacbed2062015-08-17 12:54:05 -07001// 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>
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080014#include <type_traits>
Vitaly Bukacbed2062015-08-17 12:54:05 -070015#include <vector>
16
Vitaly Bukacbed2062015-08-17 12:54:05 -070017#include "base/base_export.h"
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -070018#include "base/callback_forward.h"
Vitaly Bukacbed2062015-08-17 12:54:05 -070019#include "base/macros.h"
20#include "base/memory/ref_counted.h"
21#include "base/memory/scoped_ptr.h"
Vitaly Bukacbed2062015-08-17 12:54:05 -070022
Vitaly Bukacbed2062015-08-17 12:54:05 -070023namespace base {
24namespace internal {
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -070025template <CopyMode copy_mode>
Vitaly Bukacbed2062015-08-17 12:54:05 -070026class 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>;
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -070047 template <CopyMode copy_mode>
Vitaly Bukacbed2062015-08-17 12:54:05 -070048 friend class CallbackBase;
49
50 void AddRef();
51 void Release();
52
Vitaly Bukab1fcfc02015-09-14 10:24:39 -070053 std::atomic<int32_t> ref_count_;
Vitaly Bukacbed2062015-08-17 12:54:05 -070054
55 // Pointer to a function that will properly destroy |this|.
56 void (*destructor_)(BindStateBase*);
57
58 DISALLOW_COPY_AND_ASSIGN(BindStateBase);
59};
60
61// Holds the Callback methods that don't require specialization to reduce
62// template bloat.
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -070063// CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and
64// CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation.
65template <>
66class BASE_EXPORT CallbackBase<CopyMode::MoveOnly> {
Vitaly Bukacbed2062015-08-17 12:54:05 -070067 public:
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -070068 CallbackBase(CallbackBase&& c);
69 CallbackBase& operator=(CallbackBase&& c);
Vitaly Bukacbed2062015-08-17 12:54:05 -070070
71 // Returns true if Callback is null (doesn't refer to anything).
72 bool is_null() const { return bind_state_.get() == NULL; }
73
74 // Returns the Callback into an uninitialized state.
75 void Reset();
76
77 protected:
78 // In C++, it is safe to cast function pointers to function pointers of
79 // another type. It is not okay to use void*. We create a InvokeFuncStorage
80 // that that can store our function pointer, and then cast it back to
81 // the original type on usage.
Alex Vakulenko674f0eb2016-01-20 08:10:48 -080082 using InvokeFuncStorage = void(*)();
Vitaly Bukacbed2062015-08-17 12:54:05 -070083
84 // Returns true if this callback equals |other|. |other| may be null.
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -070085 bool EqualsInternal(const CallbackBase& other) const;
Vitaly Bukacbed2062015-08-17 12:54:05 -070086
87 // Allow initializing of |bind_state_| via the constructor to avoid default
88 // initialization of the scoped_refptr. We do not also initialize
89 // |polymorphic_invoke_| here because doing a normal assignment in the
90 // derived Callback templates makes for much nicer compiler errors.
91 explicit CallbackBase(BindStateBase* bind_state);
92
93 // Force the destructor to be instantiated inside this translation unit so
94 // that our subclasses will not get inlined versions. Avoids more template
95 // bloat.
96 ~CallbackBase();
97
98 scoped_refptr<BindStateBase> bind_state_;
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -070099 InvokeFuncStorage polymorphic_invoke_ = nullptr;
Vitaly Bukacbed2062015-08-17 12:54:05 -0700100};
101
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -0700102// CallbackBase<Copyable> is a direct base class of Copyable Callbacks.
103template <>
104class BASE_EXPORT CallbackBase<CopyMode::Copyable>
105 : public CallbackBase<CopyMode::MoveOnly> {
106 public:
107 CallbackBase(const CallbackBase& c);
108 CallbackBase(CallbackBase&& c);
109 CallbackBase& operator=(const CallbackBase& c);
110 CallbackBase& operator=(CallbackBase&& c);
111 protected:
112 explicit CallbackBase(BindStateBase* bind_state)
113 : CallbackBase<CopyMode::MoveOnly>(bind_state) {}
114 ~CallbackBase() {}
115};
116
117extern template class CallbackBase<CopyMode::MoveOnly>;
118extern template class CallbackBase<CopyMode::Copyable>;
119
Vitaly Bukacbed2062015-08-17 12:54:05 -0700120// A helper template to determine if given type is non-const move-only-type,
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800121// i.e. if a value of the given type should be passed via std::move() in a
122// destructive way. Types are considered to be move-only if they have a
123// sentinel MoveOnlyTypeForCPP03 member: a class typically gets this from using
124// the DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND macro.
125// It would be easy to generalize this trait to all move-only types... but this
126// confuses template deduction in VS2013 with certain types such as
127// std::unique_ptr.
128// TODO(dcheng): Revisit this when Windows switches to VS2015 by default.
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -0700129
Vitaly Bukacbed2062015-08-17 12:54:05 -0700130template <typename T> struct IsMoveOnlyType {
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -0700131 // Types YesType and NoType are guaranteed such that sizeof(YesType) <
132 // sizeof(NoType).
133 using YesType = char;
134 struct NoType { YesType dummy[2]; };
135
Vitaly Bukacbed2062015-08-17 12:54:05 -0700136 template <typename U>
137 static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
138
139 template <typename U>
140 static NoType Test(...);
141
142 static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) &&
Vitaly Buka8750b272015-08-18 18:39:08 -0700143 !std::is_const<T>::value;
Vitaly Bukacbed2062015-08-17 12:54:05 -0700144};
145
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800146// Specialization of IsMoveOnlyType so that std::unique_ptr is still considered
147// move-only, even without the sentinel member.
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -0700148template <typename T, typename D>
149struct IsMoveOnlyType<std::unique_ptr<T, D>> : std::true_type {};
150
151// Specialization of std::vector, so that it's considered move-only if the
152// element type is move-only. Allocator is explicitly ignored when determining
153// move-only status of the std::vector.
154template <typename T, typename Allocator>
155struct IsMoveOnlyType<std::vector<T, Allocator>> : IsMoveOnlyType<T> {};
Vitaly Bukacbed2062015-08-17 12:54:05 -0700156
157template <typename>
158struct CallbackParamTraitsForMoveOnlyType;
159
160template <typename>
161struct CallbackParamTraitsForNonMoveOnlyType;
162
163// TODO(tzik): Use a default parameter once MSVS supports variadic templates
164// with default values.
165// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
166//
167// This is a typetraits object that's used to take an argument type, and
Alex Vakulenkobf79a9e2016-03-28 15:11:43 -0700168// extract a suitable type for forwarding arguments.
Vitaly Bukacbed2062015-08-17 12:54:05 -0700169template <typename T>
170struct CallbackParamTraits
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800171 : std::conditional<IsMoveOnlyType<T>::value,
Vitaly Bukacbed2062015-08-17 12:54:05 -0700172 CallbackParamTraitsForMoveOnlyType<T>,
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800173 CallbackParamTraitsForNonMoveOnlyType<T>>::type {
Vitaly Bukacbed2062015-08-17 12:54:05 -0700174};
175
176template <typename T>
177struct CallbackParamTraitsForNonMoveOnlyType {
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800178 using ForwardType = const T&;
Vitaly Bukacbed2062015-08-17 12:54:05 -0700179};
180
181// Note that for array types, we implicitly add a const in the conversion. This
182// means that it is not possible to bind array arguments to functions that take
183// a non-const pointer. Trying to specialize the template based on a "const
184// T[n]" does not seem to match correctly, so we are stuck with this
185// restriction.
186template <typename T, size_t n>
187struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800188 using ForwardType = const T*;
Vitaly Bukacbed2062015-08-17 12:54:05 -0700189};
190
191// See comment for CallbackParamTraits<T[n]>.
192template <typename T>
193struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800194 using ForwardType = const T*;
Vitaly Bukacbed2062015-08-17 12:54:05 -0700195};
196
197// Parameter traits for movable-but-not-copyable scopers.
198//
199// Callback<>/Bind() understands movable-but-not-copyable semantics where
200// the type cannot be copied but can still have its state destructively
201// transferred (aka. moved) to another instance of the same type by calling a
202// helper function. When used with Bind(), this signifies transferal of the
203// object's state to the target function.
204//
205// For these types, the ForwardType must not be a const reference, or a
206// reference. A const reference is inappropriate, and would break const
207// correctness, because we are implementing a destructive move. A non-const
208// reference cannot be used with temporaries which means the result of a
209// function or a cast would not be usable with Callback<> or Bind().
210template <typename T>
211struct CallbackParamTraitsForMoveOnlyType {
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800212 using ForwardType = T;
Vitaly Bukacbed2062015-08-17 12:54:05 -0700213};
214
215// CallbackForward() is a very limited simulation of C++11's std::forward()
216// used by the Callback/Bind system for a set of movable-but-not-copyable
217// types. It is needed because forwarding a movable-but-not-copyable
218// argument to another function requires us to invoke the proper move
219// operator to create a rvalue version of the type. The supported types are
220// whitelisted below as overloads of the CallbackForward() function. The
221// default template compiles out to be a no-op.
222//
223// In C++11, std::forward would replace all uses of this function. However, it
Alex Vakulenko674f0eb2016-01-20 08:10:48 -0800224// is impossible to implement a general std::forward without C++11 due to a lack
Vitaly Bukacbed2062015-08-17 12:54:05 -0700225// of rvalue references.
226//
227// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
228// simulate std::forward() and forward the result of one Callback as a
229// parameter to another callback. This is to support Callbacks that return
230// the movable-but-not-copyable types whitelisted above.
231template <typename T>
Vitaly Buka8750b272015-08-18 18:39:08 -0700232typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(
233 T& t) {
Vitaly Bukacbed2062015-08-17 12:54:05 -0700234 return t;
235}
236
237template <typename T>
Vitaly Buka8750b272015-08-18 18:39:08 -0700238typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
239 T& t) {
Vitaly Bukacbed2062015-08-17 12:54:05 -0700240 return std::move(t);
241}
242
243} // namespace internal
244} // namespace base
245
246#endif // BASE_CALLBACK_INTERNAL_H_