diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-09-01 11:08:40 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2021-10-01 12:16:21 +0000 |
commit | 03c549e0392f92c02536d3f86d5e1d8dfa3435ac (patch) | |
tree | fe49d170a929b34ba82cd10db1a0bd8e3760fa4b /chromium/base/bind_internal.h | |
parent | 5d013f5804a0d91fcf6c626b2d6fb6eca5c845b0 (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.h | 292 |
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_ |