OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This file contains utility functions and classes that help the | 5 // This file contains utility functions and classes that help the |
6 // implementation, and management of the Callback objects. | 6 // implementation, and management of the Callback objects. |
7 | 7 |
8 #ifndef BASE_CALLBACK_INTERNAL_H_ | 8 #ifndef BASE_CALLBACK_INTERNAL_H_ |
9 #define BASE_CALLBACK_INTERNAL_H_ | 9 #define BASE_CALLBACK_INTERNAL_H_ |
10 | 10 |
11 #include <stddef.h> | |
12 #include <memory> | |
13 #include <type_traits> | |
14 #include <vector> | |
15 | |
16 #include "base/atomic_ref_count.h" | 11 #include "base/atomic_ref_count.h" |
17 #include "base/base_export.h" | 12 #include "base/base_export.h" |
18 #include "base/callback_forward.h" | 13 #include "base/callback_forward.h" |
19 #include "base/macros.h" | 14 #include "base/macros.h" |
20 #include "base/memory/ref_counted.h" | 15 #include "base/memory/ref_counted.h" |
21 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
22 | 17 |
23 namespace base { | 18 namespace base { |
24 namespace internal { | 19 namespace internal { |
25 template <CopyMode copy_mode> | 20 template <CopyMode copy_mode> |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
110 CallbackBase& operator=(CallbackBase&& c); | 105 CallbackBase& operator=(CallbackBase&& c); |
111 protected: | 106 protected: |
112 explicit CallbackBase(BindStateBase* bind_state) | 107 explicit CallbackBase(BindStateBase* bind_state) |
113 : CallbackBase<CopyMode::MoveOnly>(bind_state) {} | 108 : CallbackBase<CopyMode::MoveOnly>(bind_state) {} |
114 ~CallbackBase() {} | 109 ~CallbackBase() {} |
115 }; | 110 }; |
116 | 111 |
117 extern template class CallbackBase<CopyMode::MoveOnly>; | 112 extern template class CallbackBase<CopyMode::MoveOnly>; |
118 extern template class CallbackBase<CopyMode::Copyable>; | 113 extern template class CallbackBase<CopyMode::Copyable>; |
119 | 114 |
120 // A helper template to determine if given type is non-const move-only-type, | |
121 // 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. | |
129 | |
130 template <typename T> struct IsMoveOnlyType { | |
131 // Types YesType and NoType are guaranteed such that sizeof(YesType) < | |
132 // sizeof(NoType). | |
133 using YesType = char; | |
134 struct NoType { YesType dummy[2]; }; | |
135 | |
136 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) && | |
143 !std::is_const<T>::value; | |
144 }; | |
145 | |
146 // Specialization of IsMoveOnlyType so that std::unique_ptr is still considered | |
147 // move-only, even without the sentinel member. | |
148 template <typename T, typename D> | |
149 struct 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. | |
154 template <typename T, typename Allocator> | |
155 struct IsMoveOnlyType<std::vector<T, Allocator>> : IsMoveOnlyType<T> {}; | |
156 | |
157 template <typename> | |
158 struct CallbackParamTraitsForMoveOnlyType; | |
159 | |
160 template <typename> | |
161 struct 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/compilat ion-error-with-variadic-templates | |
166 // | |
167 // This is a typetraits object that's used to take an argument type, and | |
168 // extract a suitable type for forwarding arguments. | |
169 template <typename T> | |
170 struct CallbackParamTraits | |
171 : std::conditional<IsMoveOnlyType<T>::value, | |
172 CallbackParamTraitsForMoveOnlyType<T>, | |
173 CallbackParamTraitsForNonMoveOnlyType<T>>::type { | |
174 }; | |
175 | |
176 template <typename T> | |
177 struct CallbackParamTraitsForNonMoveOnlyType { | |
178 using ForwardType = const T&; | |
179 }; | |
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. | |
186 template <typename T, size_t n> | |
187 struct CallbackParamTraitsForNonMoveOnlyType<T[n]> { | |
188 using ForwardType = const T*; | |
189 }; | |
190 | |
191 // See comment for CallbackParamTraits<T[n]>. | |
192 template <typename T> | |
193 struct CallbackParamTraitsForNonMoveOnlyType<T[]> { | |
194 using ForwardType = const T*; | |
195 }; | |
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(). | |
210 template <typename T> | |
211 struct CallbackParamTraitsForMoveOnlyType { | |
212 using ForwardType = T; | |
213 }; | |
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 | |
224 // is impossible to implement a general std::forward without C++11 due to a lack | |
225 // 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. | |
231 template <typename T> | |
232 typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward( | |
Nico
2016/03/10 21:54:50
Don't we lose this protection now? Or does std::fo
tzik
2016/03/14 08:49:42
Do you mean a protection to prevent moving non-mov
| |
233 T& t) { | |
234 return t; | |
235 } | |
236 | |
237 template <typename T> | |
238 typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward( | |
239 T& t) { | |
240 return std::move(t); | |
241 } | |
242 | |
243 } // namespace internal | 115 } // namespace internal |
244 } // namespace base | 116 } // namespace base |
245 | 117 |
246 #endif // BASE_CALLBACK_INTERNAL_H_ | 118 #endif // BASE_CALLBACK_INTERNAL_H_ |
OLD | NEW |