blob: a8dcdfc7053c1713e6359eacdc343ce80881821a [file] [log] [blame]
[email protected]b38d3572011-02-15 01:27:381// 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_
[email protected]b38d3572011-02-15 01:27:387
8#include "base/bind_internal.h"
[email protected]b38d3572011-02-15 01:27:389
[email protected]24292642012-07-12 20:06:4010// -----------------------------------------------------------------------------
11// Usage documentation
12// -----------------------------------------------------------------------------
[email protected]b38d3572011-02-15 01:27:3813//
tzik703f1562016-09-02 07:36:5514// See //docs/callback.md for documentation.
[email protected]24292642012-07-12 20:06:4015//
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.
[email protected]b38d3572011-02-15 01:27:3824
25namespace base {
26
tzikae4202e2017-07-31 10:41:5427namespace internal {
28
29// IsOnceCallback<T> is a std::true_type if |T| is a OnceCallback.
30template <typename T>
31struct IsOnceCallback : std::false_type {};
32
33template <typename Signature>
34struct IsOnceCallback<OnceCallback<Signature>> : std::true_type {};
35
36// Asserts |Param| is constructible from |Unwrapped|. |Arg| is here just to
37// show it in the compile error message as a hint to fix the error.
38template <size_t i, typename Arg, typename Unwrapped, typename Param>
39struct AssertConstructible {
40 static_assert(std::is_constructible<Param, Unwrapped>::value,
41 "|Param| needs to be constructible from |Unwrapped| type. "
42 "The failing argument is passed as the |i|th parameter, whose "
43 "type is |Arg|, and delivered as |Unwrapped| into |Param|.");
44};
45
46// Takes three same-length TypeLists, and applies AssertConstructible for each
47// triples.
48template <typename Index,
49 typename ArgsList,
50 typename UnwrappedTypeList,
51 typename ParamsList>
52struct AssertBindArgsValidity;
53
54template <size_t... Ns,
55 typename... Args,
56 typename... Unwrapped,
57 typename... Params>
58struct AssertBindArgsValidity<IndexSequence<Ns...>,
59 TypeList<Args...>,
60 TypeList<Unwrapped...>,
61 TypeList<Params...>>
62 : AssertConstructible<Ns, Args, Unwrapped, Params>... {
63 static constexpr bool ok = true;
64};
65
66// The implementation of TransformToUnwrappedType below.
67template <RepeatMode, typename T>
68struct TransformToUnwrappedTypeImpl;
69
70template <typename T>
71struct TransformToUnwrappedTypeImpl<RepeatMode::Once, T> {
72 using StoredType = typename std::decay<T>::type;
73 using ForwardType = StoredType&&;
74 using Unwrapped = decltype(Unwrap(std::declval<ForwardType>()));
75};
76
77template <typename T>
78struct TransformToUnwrappedTypeImpl<RepeatMode::Repeating, T> {
79 using StoredType = typename std::decay<T>::type;
80 using ForwardType = const StoredType&;
81 using Unwrapped = decltype(Unwrap(std::declval<ForwardType>()));
82};
83
84// Transform |T| into `Unwrapped` type, which is passed to the target function.
85// Example:
86// In repeat_mode == RepeatMode::Once case,
87// `int&&` -> `int&&`,
88// `const int&` -> `int&&`,
89// `OwnedWrapper<int>&` -> `int*&&`.
90// In repeat_mode == RepeatMode::Repeating case,
91// `int&&` -> `const int&`,
92// `const int&` -> `const int&`,
93// `OwnedWrapper<int>&` -> `int* const &`.
94template <RepeatMode repeat_mode, typename T>
95using TransformToUnwrappedType =
96 typename TransformToUnwrappedTypeImpl<repeat_mode, T>::Unwrapped;
97
98// Transforms |Args| into `Unwrapped` types, and packs them into a TypeList.
99// If |is_method| is true, tries to dereference the first argument to support
100// smart pointers.
101template <RepeatMode repeat_mode, bool is_method, typename... Args>
102struct MakeUnwrappedTypeListImpl {
103 using Type = TypeList<TransformToUnwrappedType<repeat_mode, Args>...>;
104};
105
106// Performs special handling for this pointers.
107// Example:
108// int* -> int*,
109// std::unique_ptr<int> -> int*.
110template <RepeatMode repeat_mode, typename Receiver, typename... Args>
111struct MakeUnwrappedTypeListImpl<repeat_mode, true, Receiver, Args...> {
112 using UnwrappedReceiver = TransformToUnwrappedType<repeat_mode, Receiver>;
113 using Type = TypeList<decltype(&*std::declval<UnwrappedReceiver>()),
114 TransformToUnwrappedType<repeat_mode, Args>...>;
115};
116
117template <RepeatMode repeat_mode, bool is_method, typename... Args>
118using MakeUnwrappedTypeList =
119 typename MakeUnwrappedTypeListImpl<repeat_mode, is_method, Args...>::Type;
120
121} // namespace internal
122
tzik27d1e312016-09-13 05:28:59123// Bind as OnceCallback.
tzik401dd3672014-11-26 07:54:58124template <typename Functor, typename... Args>
tzik27d1e312016-09-13 05:28:59125inline OnceCallback<MakeUnboundRunType<Functor, Args...>>
126BindOnce(Functor&& functor, Args&&... args) {
tzikae4202e2017-07-31 10:41:54127 static_assert(
128 !internal::IsOnceCallback<typename std::decay<Functor>::type>() ||
129 (std::is_rvalue_reference<Functor&&>() &&
130 !std::is_const<typename std::remove_reference<Functor>::type>()),
131 "BindOnce requires non-const rvalue for OnceCallback binding."
132 " I.e.: base::BindOnce(std::move(callback)).");
133
134 // This block checks if each |args| matches to the corresponding params of the
135 // target function. This check does not affect the behavior of Bind, but its
136 // error message should be more readable.
137 using Helper = internal::BindTypeHelper<Functor, Args...>;
138 using FunctorTraits = typename Helper::FunctorTraits;
139 using BoundArgsList = typename Helper::BoundArgsList;
140 using UnwrappedArgsList =
141 internal::MakeUnwrappedTypeList<internal::RepeatMode::Once,
142 FunctorTraits::is_method, Args&&...>;
143 using BoundParamsList = typename Helper::BoundParamsList;
144 static_assert(
145 internal::AssertBindArgsValidity<MakeIndexSequence<Helper::num_bounds>,
146 BoundArgsList, UnwrappedArgsList,
147 BoundParamsList>::ok,
148 "The bound args need to be convertible to the target params.");
149
tzik99de02b2016-07-01 05:54:12150 using BindState = internal::MakeBindStateType<Functor, Args...>;
tzikcaf1d84b2016-06-28 12:22:21151 using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
tzikcaf1d84b2016-06-28 12:22:21152 using Invoker = internal::Invoker<BindState, UnboundRunType>;
tzik27d1e312016-09-13 05:28:59153 using CallbackType = OnceCallback<UnboundRunType>;
154
155 // Store the invoke func into PolymorphicInvoke before casting it to
156 // InvokeFuncStorage, so that we can ensure its type matches to
157 // PolymorphicInvoke, to which CallbackType will cast back.
158 using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
159 PolymorphicInvoke invoke_func = &Invoker::RunOnce;
160
161 using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
162 return CallbackType(new BindState(
163 reinterpret_cast<InvokeFuncStorage>(invoke_func),
164 std::forward<Functor>(functor),
165 std::forward<Args>(args)...));
166}
167
168// Bind as RepeatingCallback.
169template <typename Functor, typename... Args>
170inline RepeatingCallback<MakeUnboundRunType<Functor, Args...>>
171BindRepeating(Functor&& functor, Args&&... args) {
tzikae4202e2017-07-31 10:41:54172 static_assert(
173 !internal::IsOnceCallback<typename std::decay<Functor>::type>(),
174 "BindRepeating cannot bind OnceCallback. Use BindOnce with std::move().");
175
176 // This block checks if each |args| matches to the corresponding params of the
177 // target function. This check does not affect the behavior of Bind, but its
178 // error message should be more readable.
179 using Helper = internal::BindTypeHelper<Functor, Args...>;
180 using FunctorTraits = typename Helper::FunctorTraits;
181 using BoundArgsList = typename Helper::BoundArgsList;
182 using UnwrappedArgsList =
183 internal::MakeUnwrappedTypeList<internal::RepeatMode::Repeating,
184 FunctorTraits::is_method, Args&&...>;
185 using BoundParamsList = typename Helper::BoundParamsList;
186 static_assert(
187 internal::AssertBindArgsValidity<MakeIndexSequence<Helper::num_bounds>,
188 BoundArgsList, UnwrappedArgsList,
189 BoundParamsList>::ok,
190 "The bound args need to be convertible to the target params.");
191
tzik27d1e312016-09-13 05:28:59192 using BindState = internal::MakeBindStateType<Functor, Args...>;
193 using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
194 using Invoker = internal::Invoker<BindState, UnboundRunType>;
195 using CallbackType = RepeatingCallback<UnboundRunType>;
tzik1886c272016-09-08 05:45:38196
197 // Store the invoke func into PolymorphicInvoke before casting it to
198 // InvokeFuncStorage, so that we can ensure its type matches to
199 // PolymorphicInvoke, to which CallbackType will cast back.
200 using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
201 PolymorphicInvoke invoke_func = &Invoker::Run;
202
203 using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
204 return CallbackType(new BindState(
205 reinterpret_cast<InvokeFuncStorage>(invoke_func),
206 std::forward<Functor>(functor),
207 std::forward<Args>(args)...));
[email protected]fccef1552011-11-28 22:13:54208}
209
tzik27d1e312016-09-13 05:28:59210// Unannotated Bind.
211// TODO(tzik): Deprecate this and migrate to OnceCallback and
212// RepeatingCallback, once they get ready.
213template <typename Functor, typename... Args>
214inline Callback<MakeUnboundRunType<Functor, Args...>>
215Bind(Functor&& functor, Args&&... args) {
tzik07dbcfd2016-10-12 08:49:03216 return BindRepeating(std::forward<Functor>(functor),
217 std::forward<Args>(args)...);
tzik27d1e312016-09-13 05:28:59218}
219
[email protected]b38d3572011-02-15 01:27:38220} // namespace base
221
222#endif // BASE_BIND_H_