summaryrefslogtreecommitdiffstats
path: root/chromium/base/bind_internal.h
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-09-01 11:08:40 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-01 12:16:21 +0000
commit03c549e0392f92c02536d3f86d5e1d8dfa3435ac (patch)
treefe49d170a929b34ba82cd10db1a0bd8e3760fa4b /chromium/base/bind_internal.h
parent5d013f5804a0d91fcf6c626b2d6fb6eca5c845b0 (diff)
BASELINE: Update Chromium to 91.0.4472.160
Change-Id: I0def1f08a2412aeed79a9ab95dd50eb5c3f65f31 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/base/bind_internal.h')
-rw-r--r--chromium/base/bind_internal.h292
1 files changed, 279 insertions, 13 deletions
diff --git a/chromium/base/bind_internal.h b/chromium/base/bind_internal.h
index 1434e416067..a7aba35bb6c 100644
--- a/chromium/base/bind_internal.h
+++ b/chromium/base/bind_internal.h
@@ -118,6 +118,17 @@ class OwnedWrapper {
std::unique_ptr<T, Deleter> ptr_;
};
+template <typename T>
+class OwnedRefWrapper {
+ public:
+ explicit OwnedRefWrapper(const T& t) : t_(t) {}
+ explicit OwnedRefWrapper(T&& t) : t_(std::move(t)) {}
+ T& get() const { return t_; }
+
+ private:
+ mutable T t_;
+};
+
// PassedWrapper is a copyable adapter for a scoper that ignores const.
//
// It is needed to get around the fact that Bind() takes a const reference to
@@ -135,7 +146,7 @@ class OwnedWrapper {
//
// Two notes:
// 1) PassedWrapper supports any type that has a move constructor, however
-// the type will need to be specifically whitelisted in order for it to be
+// the type will need to be specifically allowed in order for it to be
// bound to a Callback. We guard this explicitly at the call of Passed()
// to make for clear errors. Things not given to Passed() will be forwarded
// and stored by value which will not work for general move-only types.
@@ -865,7 +876,7 @@ struct BindState final : BindStateBase {
private:
static constexpr bool is_nested_callback =
- internal::MakeFunctorTraits<Functor>::is_callback;
+ MakeFunctorTraits<Functor>::is_callback;
template <typename ForwardFunctor, typename... ForwardBoundArgs>
explicit BindState(std::true_type,
@@ -958,6 +969,267 @@ using MakeBindStateType =
Functor,
BoundArgs...>::Type;
+// Returns a RunType of bound functor.
+// E.g. MakeUnboundRunType<R(A, B, C), A, B> is evaluated to R(C).
+template <typename Functor, typename... BoundArgs>
+using MakeUnboundRunType =
+ typename BindTypeHelper<Functor, BoundArgs...>::UnboundRunType;
+
+// The implementation of TransformToUnwrappedType below.
+template <bool is_once, typename T>
+struct TransformToUnwrappedTypeImpl;
+
+template <typename T>
+struct TransformToUnwrappedTypeImpl<true, T> {
+ using StoredType = std::decay_t<T>;
+ using ForwardType = StoredType&&;
+ using Unwrapped = decltype(Unwrap(std::declval<ForwardType>()));
+};
+
+template <typename T>
+struct TransformToUnwrappedTypeImpl<false, T> {
+ using StoredType = std::decay_t<T>;
+ 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;
+
+// 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 {};
+
+// Helpers to make error messages slightly more readable.
+template <int i>
+struct BindArgument {
+ template <typename ForwardingType>
+ struct ForwardedAs {
+ template <typename FunctorParamType>
+ struct ToParamWithType {
+ static constexpr bool kCanBeForwardedToBoundFunctor =
+ std::is_constructible<FunctorParamType, ForwardingType>::value;
+
+ // If the bound type can't be forwarded then test if `FunctorParamType` is
+ // a non-const lvalue reference and a reference to the unwrapped type
+ // *could* have been successfully forwarded.
+ static constexpr bool kNonConstRefParamMustBeWrapped =
+ kCanBeForwardedToBoundFunctor ||
+ !(std::is_lvalue_reference<FunctorParamType>::value &&
+ !std::is_const<std::remove_reference_t<FunctorParamType>>::value &&
+ std::is_convertible<std::decay_t<ForwardingType>&,
+ FunctorParamType>::value);
+
+ // Note that this intentionally drops the const qualifier from
+ // `ForwardingType`, to test if it *could* have been successfully
+ // forwarded if `Passed()` had been used.
+ static constexpr bool kMoveOnlyTypeMustUseBasePassed =
+ kCanBeForwardedToBoundFunctor ||
+ !std::is_constructible<FunctorParamType,
+ std::decay_t<ForwardingType>&&>::value;
+ };
+ };
+
+ template <typename BoundAsType>
+ struct BoundAs {
+ template <typename StorageType>
+ struct StoredAs {
+ static constexpr bool kBindArgumentCanBeCaptured =
+ std::is_constructible<StorageType, BoundAsType>::value;
+ // Note that this intentionally drops the const qualifier from
+ // `BoundAsType`, to test if it *could* have been successfully bound if
+ // `std::move()` had been used.
+ static constexpr bool kMoveOnlyTypeMustUseStdMove =
+ kBindArgumentCanBeCaptured ||
+ !std::is_constructible<StorageType,
+ std::decay_t<BoundAsType>&&>::value;
+ };
+ };
+};
+
+// 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 <int i,
+ typename Arg,
+ typename Storage,
+ typename Unwrapped,
+ typename Param>
+struct AssertConstructible {
+ private:
+ // With `BindRepeating`, there are two decision points for how to handle a
+ // move-only type:
+ //
+ // 1. Whether the move-only argument should be moved into the internal
+ // `BindState`. Either `std::move()` or `Passed` is sufficient to trigger
+ // move-only semantics.
+ // 2. Whether or not the bound, move-only argument should be moved to the
+ // bound functor when invoked. When the argument is bound with `Passed`,
+ // invoking the callback will destructively move the bound, move-only
+ // argument to the bound functor. In contrast, if the argument is bound
+ // with `std::move()`, `RepeatingCallback` will attempt to call the bound
+ // functor with a constant reference to the bound, move-only argument. This
+ // will fail if the bound functor accepts that argument by value, since the
+ // argument cannot be copied. It is this latter case that this
+ // static_assert aims to catch.
+ //
+ // In contrast, `BindOnce()` only has one decision point. Once a move-only
+ // type is captured by value into the internal `BindState`, the bound,
+ // move-only argument will always be moved to the functor when invoked.
+ // Failure to use std::move will simply fail the `kMoveOnlyTypeMustUseStdMove`
+ // assert below instead.
+ //
+ // Note: `Passed()` is a legacy of supporting move-only types when repeating
+ // callbacks were the only callback type. A `RepeatingCallback` with a
+ // `Passed()` argument is really a `OnceCallback` and should eventually be
+ // migrated.
+ static_assert(
+ BindArgument<i>::template ForwardedAs<Unwrapped>::
+ template ToParamWithType<Param>::kMoveOnlyTypeMustUseBasePassed,
+ "base::BindRepeating() argument is a move-only type. Use base::Passed() "
+ "instead of std::move() to transfer ownership from the callback to the "
+ "bound functor.");
+ static_assert(
+ BindArgument<i>::template ForwardedAs<Unwrapped>::
+ template ToParamWithType<Param>::kNonConstRefParamMustBeWrapped,
+ "Bound argument for non-const reference parameter must be wrapped in "
+ "std::ref() or base::OwnedRef().");
+ static_assert(
+ BindArgument<i>::template ForwardedAs<Unwrapped>::
+ template ToParamWithType<Param>::kCanBeForwardedToBoundFunctor,
+ "Type mismatch between bound argument and bound functor's parameter.");
+
+ static_assert(BindArgument<i>::template BoundAs<Arg>::template StoredAs<
+ Storage>::kMoveOnlyTypeMustUseStdMove,
+ "Attempting to bind a move-only type. Use std::move() to "
+ "transfer ownership to the created callback.");
+ // In practice, this static_assert should be quite rare as the storage type
+ // is deduced from the arguments passed to `BindOnce()`/`BindRepeating()`.
+ static_assert(
+ BindArgument<i>::template BoundAs<Arg>::template StoredAs<
+ Storage>::kBindArgumentCanBeCaptured,
+ "Cannot capture argument: is the argument copyable or movable?");
+};
+
+// 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<std::index_sequence<Ns...>,
+ TypeList<Args...>,
+ TypeList<Unwrapped...>,
+ TypeList<Params...>>
+ : AssertConstructible<Ns, Args, std::decay_t<Args>, Unwrapped, Params>... {
+ static constexpr bool ok = true;
+};
+
+template <typename T>
+struct AssertBindArgIsNotBasePassed : public std::true_type {};
+
+template <typename T>
+struct AssertBindArgIsNotBasePassed<PassedWrapper<T>> : public std::false_type {
+};
+
+// Used below in BindImpl to determine whether to use Invoker::Run or
+// Invoker::RunOnce.
+// Note: Simply using `kIsOnce ? &Invoker::RunOnce : &Invoker::Run` does not
+// work, since the compiler needs to check whether both expressions are
+// well-formed. Using `Invoker::Run` with a OnceCallback triggers a
+// static_assert, which is why the ternary expression does not compile.
+// TODO(crbug.com/752720): Remove this indirection once we have `if constexpr`.
+template <typename Invoker>
+constexpr auto GetInvokeFunc(std::true_type) {
+ return Invoker::RunOnce;
+}
+
+template <typename Invoker>
+constexpr auto GetInvokeFunc(std::false_type) {
+ return Invoker::Run;
+}
+
+template <template <typename> class CallbackT,
+ typename Functor,
+ typename... Args>
+decltype(auto) BindImpl(Functor&& functor, Args&&... args) {
+ // 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.
+ static constexpr bool kIsOnce = IsOnceCallback<CallbackT<void()>>::value;
+ using Helper = BindTypeHelper<Functor, Args...>;
+ using FunctorTraits = typename Helper::FunctorTraits;
+ using BoundArgsList = typename Helper::BoundArgsList;
+ using UnwrappedArgsList =
+ MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method, Args&&...>;
+ using BoundParamsList = typename Helper::BoundParamsList;
+ static_assert(
+ AssertBindArgsValidity<std::make_index_sequence<Helper::num_bounds>,
+ BoundArgsList, UnwrappedArgsList,
+ BoundParamsList>::ok,
+ "The bound args need to be convertible to the target params.");
+
+ using BindState = MakeBindStateType<Functor, Args...>;
+ using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
+ using Invoker = Invoker<BindState, UnboundRunType>;
+ using CallbackType = CallbackT<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 =
+ GetInvokeFunc<Invoker>(bool_constant<kIsOnce>());
+
+ using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
+ return CallbackType(BindState::Create(
+ reinterpret_cast<InvokeFuncStorage>(invoke_func),
+ std::forward<Functor>(functor), std::forward<Args>(args)...));
+}
+
} // namespace internal
// An injection point to control |this| pointer behavior on a method invocation.
@@ -1007,11 +1279,6 @@ struct BindUnwrapTraits<internal::UnretainedWrapper<T>> {
};
template <typename T>
-struct BindUnwrapTraits<std::reference_wrapper<T>> {
- static T& Unwrap(std::reference_wrapper<T> o) { return o.get(); }
-};
-
-template <typename T>
struct BindUnwrapTraits<internal::RetainedRefWrapper<T>> {
static T* Unwrap(const internal::RetainedRefWrapper<T>& o) { return o.get(); }
};
@@ -1024,6 +1291,11 @@ struct BindUnwrapTraits<internal::OwnedWrapper<T, Deleter>> {
};
template <typename T>
+struct BindUnwrapTraits<internal::OwnedRefWrapper<T>> {
+ static T& Unwrap(const internal::OwnedRefWrapper<T>& o) { return o.get(); }
+};
+
+template <typename T>
struct BindUnwrapTraits<internal::PassedWrapper<T>> {
static T Unwrap(const internal::PassedWrapper<T>& o) { return o.Take(); }
};
@@ -1102,12 +1374,6 @@ struct CallbackCancellationTraits<RepeatingCallback<Signature>,
}
};
-// Returns a RunType of bound functor.
-// E.g. MakeUnboundRunType<R(A, B, C), A, B> is evaluated to R(C).
-template <typename Functor, typename... BoundArgs>
-using MakeUnboundRunType =
- typename internal::BindTypeHelper<Functor, BoundArgs...>::UnboundRunType;
-
} // namespace base
#endif // BASE_BIND_INTERNAL_H_