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