/src/mozilla-central/security/sandbox/chromium/base/bind.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef BASE_BIND_H_ |
6 | | #define BASE_BIND_H_ |
7 | | |
8 | | #include "base/bind_internal.h" |
9 | | |
10 | | // ----------------------------------------------------------------------------- |
11 | | // Usage documentation |
12 | | // ----------------------------------------------------------------------------- |
13 | | // |
14 | | // See //docs/callback.md for documentation. |
15 | | // |
16 | | // |
17 | | // ----------------------------------------------------------------------------- |
18 | | // Implementation notes |
19 | | // ----------------------------------------------------------------------------- |
20 | | // |
21 | | // If you're reading the implementation, before proceeding further, you should |
22 | | // read the top comment of base/bind_internal.h for a definition of common |
23 | | // terms and concepts. |
24 | | |
25 | | namespace base { |
26 | | |
27 | | namespace internal { |
28 | | |
29 | | // IsOnceCallback<T> is a std::true_type if |T| is a OnceCallback. |
30 | | template <typename T> |
31 | | struct IsOnceCallback : std::false_type {}; |
32 | | |
33 | | template <typename Signature> |
34 | | struct IsOnceCallback<OnceCallback<Signature>> : std::true_type {}; |
35 | | |
36 | | // Helper to assert that parameter |i| of type |Arg| can be bound, which means: |
37 | | // - |Arg| can be retained internally as |Storage|. |
38 | | // - |Arg| can be forwarded as |Unwrapped| to |Param|. |
39 | | template <size_t i, |
40 | | typename Arg, |
41 | | typename Storage, |
42 | | typename Unwrapped, |
43 | | typename Param> |
44 | | struct AssertConstructible { |
45 | | private: |
46 | | static constexpr bool param_is_forwardable = |
47 | | std::is_constructible<Param, Unwrapped>::value; |
48 | | // Unlike the check for binding into storage below, the check for |
49 | | // forwardability drops the const qualifier for repeating callbacks. This is |
50 | | // to try to catch instances where std::move()--which forwards as a const |
51 | | // reference with repeating callbacks--is used instead of base::Passed(). |
52 | | static_assert( |
53 | | param_is_forwardable || |
54 | | !std::is_constructible<Param, typename std::decay<Unwrapped>::type&&>::value, |
55 | | "Bound argument |i| is move-only but will be forwarded by copy. " |
56 | | "Ensure |Arg| is bound using base::Passed(), not std::move()."); |
57 | | static_assert( |
58 | | param_is_forwardable, |
59 | | "Bound argument |i| of type |Arg| cannot be forwarded as " |
60 | | "|Unwrapped| to the bound functor, which declares it as |Param|."); |
61 | | |
62 | | static constexpr bool arg_is_storable = |
63 | | std::is_constructible<Storage, Arg>::value; |
64 | | static_assert(arg_is_storable || |
65 | | !std::is_constructible<Storage, typename std::decay<Arg>::type&&>::value, |
66 | | "Bound argument |i| is move-only but will be bound by copy. " |
67 | | "Ensure |Arg| is mutable and bound using std::move()."); |
68 | | static_assert(arg_is_storable, |
69 | | "Bound argument |i| of type |Arg| cannot be converted and " |
70 | | "bound as |Storage|."); |
71 | | }; |
72 | | |
73 | | // Takes three same-length TypeLists, and applies AssertConstructible for each |
74 | | // triples. |
75 | | template <typename Index, |
76 | | typename Args, |
77 | | typename UnwrappedTypeList, |
78 | | typename ParamsList> |
79 | | struct AssertBindArgsValidity; |
80 | | |
81 | | template <size_t... Ns, |
82 | | typename... Args, |
83 | | typename... Unwrapped, |
84 | | typename... Params> |
85 | | struct AssertBindArgsValidity<IndexSequence<Ns...>, |
86 | | TypeList<Args...>, |
87 | | TypeList<Unwrapped...>, |
88 | | TypeList<Params...>> |
89 | | : AssertConstructible<Ns, Args, typename std::decay<Args>::type, Unwrapped, Params>... { |
90 | | static constexpr bool ok = true; |
91 | | }; |
92 | | |
93 | | // The implementation of TransformToUnwrappedType below. |
94 | | template <bool is_once, typename T> |
95 | | struct TransformToUnwrappedTypeImpl; |
96 | | |
97 | | template <typename T> |
98 | | struct TransformToUnwrappedTypeImpl<true, T> { |
99 | | using StoredType = typename std::decay<T>::type; |
100 | | using ForwardType = StoredType&&; |
101 | | using Unwrapped = decltype(Unwrap(std::declval<ForwardType>())); |
102 | | }; |
103 | | |
104 | | template <typename T> |
105 | | struct TransformToUnwrappedTypeImpl<false, T> { |
106 | | using StoredType = typename std::decay<T>::type; |
107 | | using ForwardType = const StoredType&; |
108 | | using Unwrapped = decltype(Unwrap(std::declval<ForwardType>())); |
109 | | }; |
110 | | |
111 | | // Transform |T| into `Unwrapped` type, which is passed to the target function. |
112 | | // Example: |
113 | | // In is_once == true case, |
114 | | // `int&&` -> `int&&`, |
115 | | // `const int&` -> `int&&`, |
116 | | // `OwnedWrapper<int>&` -> `int*&&`. |
117 | | // In is_once == false case, |
118 | | // `int&&` -> `const int&`, |
119 | | // `const int&` -> `const int&`, |
120 | | // `OwnedWrapper<int>&` -> `int* const &`. |
121 | | template <bool is_once, typename T> |
122 | | using TransformToUnwrappedType = |
123 | | typename TransformToUnwrappedTypeImpl<is_once, T>::Unwrapped; |
124 | | |
125 | | // Transforms |Args| into `Unwrapped` types, and packs them into a TypeList. |
126 | | // If |is_method| is true, tries to dereference the first argument to support |
127 | | // smart pointers. |
128 | | template <bool is_once, bool is_method, typename... Args> |
129 | | struct MakeUnwrappedTypeListImpl { |
130 | | using Type = TypeList<TransformToUnwrappedType<is_once, Args>...>; |
131 | | }; |
132 | | |
133 | | // Performs special handling for this pointers. |
134 | | // Example: |
135 | | // int* -> int*, |
136 | | // std::unique_ptr<int> -> int*. |
137 | | template <bool is_once, typename Receiver, typename... Args> |
138 | | struct MakeUnwrappedTypeListImpl<is_once, true, Receiver, Args...> { |
139 | | using UnwrappedReceiver = TransformToUnwrappedType<is_once, Receiver>; |
140 | | using Type = TypeList<decltype(&*std::declval<UnwrappedReceiver>()), |
141 | | TransformToUnwrappedType<is_once, Args>...>; |
142 | | }; |
143 | | |
144 | | template <bool is_once, bool is_method, typename... Args> |
145 | | using MakeUnwrappedTypeList = |
146 | | typename MakeUnwrappedTypeListImpl<is_once, is_method, Args...>::Type; |
147 | | |
148 | | } // namespace internal |
149 | | |
150 | | // Bind as OnceCallback. |
151 | | template <typename Functor, typename... Args> |
152 | | inline OnceCallback<MakeUnboundRunType<Functor, Args...>> |
153 | | BindOnce(Functor&& functor, Args&&... args) { |
154 | | static_assert( |
155 | | !internal::IsOnceCallback<typename std::decay<Functor>::type>() || |
156 | | (std::is_rvalue_reference<Functor&&>() && |
157 | | !std::is_const<typename std::remove_reference<Functor>::type>()), |
158 | | "BindOnce requires non-const rvalue for OnceCallback binding." |
159 | | " I.e.: base::BindOnce(std::move(callback))."); |
160 | | |
161 | | // This block checks if each |args| matches to the corresponding params of the |
162 | | // target function. This check does not affect the behavior of Bind, but its |
163 | | // error message should be more readable. |
164 | | using Helper = internal::BindTypeHelper<Functor, Args...>; |
165 | | using FunctorTraits = typename Helper::FunctorTraits; |
166 | | using BoundArgsList = typename Helper::BoundArgsList; |
167 | | using UnwrappedArgsList = |
168 | | internal::MakeUnwrappedTypeList<true, FunctorTraits::is_method, |
169 | | Args&&...>; |
170 | | using BoundParamsList = typename Helper::BoundParamsList; |
171 | | static_assert(internal::AssertBindArgsValidity< |
172 | | MakeIndexSequence<Helper::num_bounds>, BoundArgsList, |
173 | | UnwrappedArgsList, BoundParamsList>::ok, |
174 | | "The bound args need to be convertible to the target params."); |
175 | | |
176 | | using BindState = internal::MakeBindStateType<Functor, Args...>; |
177 | | using UnboundRunType = MakeUnboundRunType<Functor, Args...>; |
178 | | using Invoker = internal::Invoker<BindState, UnboundRunType>; |
179 | | using CallbackType = OnceCallback<UnboundRunType>; |
180 | | |
181 | | // Store the invoke func into PolymorphicInvoke before casting it to |
182 | | // InvokeFuncStorage, so that we can ensure its type matches to |
183 | | // PolymorphicInvoke, to which CallbackType will cast back. |
184 | | using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke; |
185 | | PolymorphicInvoke invoke_func = &Invoker::RunOnce; |
186 | | |
187 | | using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage; |
188 | | return CallbackType(new BindState( |
189 | | reinterpret_cast<InvokeFuncStorage>(invoke_func), |
190 | | std::forward<Functor>(functor), |
191 | | std::forward<Args>(args)...)); |
192 | | } |
193 | | |
194 | | // Bind as RepeatingCallback. |
195 | | template <typename Functor, typename... Args> |
196 | | inline RepeatingCallback<MakeUnboundRunType<Functor, Args...>> |
197 | 0 | BindRepeating(Functor&& functor, Args&&... args) { |
198 | 0 | static_assert( |
199 | 0 | !internal::IsOnceCallback<typename std::decay<Functor>::type>(), |
200 | 0 | "BindRepeating cannot bind OnceCallback. Use BindOnce with std::move()."); |
201 | 0 |
|
202 | 0 | // This block checks if each |args| matches to the corresponding params of the |
203 | 0 | // target function. This check does not affect the behavior of Bind, but its |
204 | 0 | // error message should be more readable. |
205 | 0 | using Helper = internal::BindTypeHelper<Functor, Args...>; |
206 | 0 | using FunctorTraits = typename Helper::FunctorTraits; |
207 | 0 | using BoundArgsList = typename Helper::BoundArgsList; |
208 | 0 | using UnwrappedArgsList = |
209 | 0 | internal::MakeUnwrappedTypeList<false, FunctorTraits::is_method, |
210 | 0 | Args&&...>; |
211 | 0 | using BoundParamsList = typename Helper::BoundParamsList; |
212 | 0 | static_assert(internal::AssertBindArgsValidity< |
213 | 0 | MakeIndexSequence<Helper::num_bounds>, BoundArgsList, |
214 | 0 | UnwrappedArgsList, BoundParamsList>::ok, |
215 | 0 | "The bound args need to be convertible to the target params."); |
216 | 0 |
|
217 | 0 | using BindState = internal::MakeBindStateType<Functor, Args...>; |
218 | 0 | using UnboundRunType = MakeUnboundRunType<Functor, Args...>; |
219 | 0 | using Invoker = internal::Invoker<BindState, UnboundRunType>; |
220 | 0 | using CallbackType = RepeatingCallback<UnboundRunType>; |
221 | 0 |
|
222 | 0 | // Store the invoke func into PolymorphicInvoke before casting it to |
223 | 0 | // InvokeFuncStorage, so that we can ensure its type matches to |
224 | 0 | // PolymorphicInvoke, to which CallbackType will cast back. |
225 | 0 | using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke; |
226 | 0 | PolymorphicInvoke invoke_func = &Invoker::Run; |
227 | 0 |
|
228 | 0 | using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage; |
229 | 0 | return CallbackType(new BindState( |
230 | 0 | reinterpret_cast<InvokeFuncStorage>(invoke_func), |
231 | 0 | std::forward<Functor>(functor), |
232 | 0 | std::forward<Args>(args)...)); |
233 | 0 | } |
234 | | |
235 | | // Unannotated Bind. |
236 | | // TODO(tzik): Deprecate this and migrate to OnceCallback and |
237 | | // RepeatingCallback, once they get ready. |
238 | | template <typename Functor, typename... Args> |
239 | | inline Callback<MakeUnboundRunType<Functor, Args...>> |
240 | 0 | Bind(Functor&& functor, Args&&... args) { |
241 | 0 | return BindRepeating(std::forward<Functor>(functor), |
242 | 0 | std::forward<Args>(args)...); |
243 | 0 | } |
244 | | |
245 | | // Special cases for binding to a base::Callback without extra bound arguments. |
246 | | template <typename Signature> |
247 | | OnceCallback<Signature> BindOnce(OnceCallback<Signature> closure) { |
248 | | return closure; |
249 | | } |
250 | | |
251 | | template <typename Signature> |
252 | | RepeatingCallback<Signature> BindRepeating( |
253 | | RepeatingCallback<Signature> closure) { |
254 | | return closure; |
255 | | } |
256 | | |
257 | | template <typename Signature> |
258 | | Callback<Signature> Bind(Callback<Signature> closure) { |
259 | | return closure; |
260 | | } |
261 | | |
262 | | } // namespace base |
263 | | |
264 | | #endif // BASE_BIND_H_ |