bind_internal.h cleanup: Use concepts and constexprs more.
Bug: none Change-Id: I7c840dbe6b405eefc5fc32a72cbaf1d3c7a61e09 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5113260 Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Peter Kasting <pkasting@chromium.org> Owners-Override: Lei Zhang <thestig@chromium.org> Auto-Submit: Peter Kasting <pkasting@chromium.org> Cr-Commit-Position: refs/heads/main@{#1238401}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f1ed67946e
commit
d077bb2075
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
@@ -123,7 +124,7 @@ class UnretainedWrapper {
|
|||||||
// This is enforced by `static_assert`s in `ParamCanBeBound`.
|
// This is enforced by `static_assert`s in `ParamCanBeBound`.
|
||||||
using GetPtrType = std::conditional_t<
|
using GetPtrType = std::conditional_t<
|
||||||
raw_ptr_traits::IsSupportedType<T>::value &&
|
raw_ptr_traits::IsSupportedType<T>::value &&
|
||||||
std::is_same_v<UnretainedTrait, unretained_traits::MayDangle>,
|
std::same_as<UnretainedTrait, unretained_traits::MayDangle>,
|
||||||
DanglingRawPtrType,
|
DanglingRawPtrType,
|
||||||
T*>;
|
T*>;
|
||||||
|
|
||||||
@@ -151,15 +152,15 @@ class UnretainedWrapper {
|
|||||||
private:
|
private:
|
||||||
// `ptr_` is either a `raw_ptr` or a regular C++ pointer.
|
// `ptr_` is either a `raw_ptr` or a regular C++ pointer.
|
||||||
template <typename U>
|
template <typename U>
|
||||||
|
requires std::same_as<T, U>
|
||||||
static GetPtrType GetInternal(U* ptr) {
|
static GetPtrType GetInternal(U* ptr) {
|
||||||
static_assert(std::is_same_v<T, U>);
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
template <typename U, RawPtrTraits Traits>
|
template <typename U, RawPtrTraits Traits>
|
||||||
|
requires std::same_as<T, U>
|
||||||
static GetPtrType GetInternal(const raw_ptr<U, Traits>& ptr) {
|
static GetPtrType GetInternal(const raw_ptr<U, Traits>& ptr) {
|
||||||
static_assert(std::is_same_v<T, U>);
|
if constexpr (std::same_as<UnretainedTrait,
|
||||||
if constexpr (std::is_same_v<UnretainedTrait,
|
unretained_traits::MayNotDangle>) {
|
||||||
unretained_traits::MayNotDangle>) {
|
|
||||||
ptr.ReportIfDangling();
|
ptr.ReportIfDangling();
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
@@ -182,7 +183,7 @@ class UnretainedWrapper {
|
|||||||
// It is allowable to convert `raw_ptr<T>` -> `T*`, but not in the other
|
// It is allowable to convert `raw_ptr<T>` -> `T*`, but not in the other
|
||||||
// direction. See the comment by `GetPtrType` describing for more details.
|
// direction. See the comment by `GetPtrType` describing for more details.
|
||||||
static_assert(std::is_pointer_v<GetPtrType> ||
|
static_assert(std::is_pointer_v<GetPtrType> ||
|
||||||
std::is_same_v<GetPtrType, StorageType>);
|
std::same_as<GetPtrType, StorageType>);
|
||||||
StorageType ptr_;
|
StorageType ptr_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -225,13 +226,13 @@ class UnretainedRefWrapper {
|
|||||||
private:
|
private:
|
||||||
// `ref_` is either a `raw_ref` or a regular C++ reference.
|
// `ref_` is either a `raw_ref` or a regular C++ reference.
|
||||||
template <typename U>
|
template <typename U>
|
||||||
|
requires std::same_as<T, U>
|
||||||
static T& GetInternal(U& ref) {
|
static T& GetInternal(U& ref) {
|
||||||
static_assert(std::is_same_v<T, U>);
|
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
template <typename U, RawPtrTraits Traits>
|
template <typename U, RawPtrTraits Traits>
|
||||||
|
requires std::same_as<T, U>
|
||||||
static T& GetInternal(const raw_ref<U, Traits>& ref) {
|
static T& GetInternal(const raw_ref<U, Traits>& ref) {
|
||||||
static_assert(std::is_same_v<T, U>);
|
|
||||||
// The ultimate goal is to crash when a callback is invoked with a
|
// The ultimate goal is to crash when a callback is invoked with a
|
||||||
// dangling pointer. This is checked here. For now, it is configured to
|
// dangling pointer. This is checked here. For now, it is configured to
|
||||||
// either crash, DumpWithoutCrashing or be ignored. This depends on the
|
// either crash, DumpWithoutCrashing or be ignored. This depends on the
|
||||||
@@ -265,6 +266,20 @@ class UnretainedRefWrapper {
|
|||||||
StorageType ref_;
|
StorageType ref_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Can't use `is_instantiation` to detect the unretained wrappers, since they
|
||||||
|
// have non-type template params.
|
||||||
|
template <template <typename, typename, RawPtrTraits> typename WrapperT,
|
||||||
|
typename T>
|
||||||
|
inline constexpr bool kIsUnretainedWrapper = false;
|
||||||
|
|
||||||
|
template <template <typename, typename, RawPtrTraits> typename WrapperT,
|
||||||
|
typename T,
|
||||||
|
typename UnretainedTrait,
|
||||||
|
RawPtrTraits PtrTraits>
|
||||||
|
inline constexpr bool
|
||||||
|
kIsUnretainedWrapper<WrapperT, WrapperT<T, UnretainedTrait, PtrTraits>> =
|
||||||
|
true;
|
||||||
|
|
||||||
// The class is used to wrap `UnretainedRefWrapper` when the latter is used as
|
// The class is used to wrap `UnretainedRefWrapper` when the latter is used as
|
||||||
// a method receiver (a reference on `this` argument). This is needed because
|
// a method receiver (a reference on `this` argument). This is needed because
|
||||||
// the internal callback mechanism expects the receiver to have the type
|
// the internal callback mechanism expects the receiver to have the type
|
||||||
@@ -393,7 +408,7 @@ decltype(auto) Unwrap(T&& o) {
|
|||||||
return Unwrapper<T>::Unwrap(std::forward<T>(o));
|
return Unwrapper<T>::Unwrap(std::forward<T>(o));
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
|
// `kIsWeakMethod` is a helper that determine if we are binding a WeakPtr<> to a
|
||||||
// method. It is used internally by Bind() to select the correct
|
// method. It is used internally by Bind() to select the correct
|
||||||
// InvokeHelper that will no-op itself in the event the WeakPtr<> for
|
// InvokeHelper that will no-op itself in the event the WeakPtr<> for
|
||||||
// the target object is invalidated.
|
// the target object is invalidated.
|
||||||
@@ -401,10 +416,11 @@ decltype(auto) Unwrap(T&& o) {
|
|||||||
// The first argument should be the type of the object that will be received by
|
// The first argument should be the type of the object that will be received by
|
||||||
// the method.
|
// the method.
|
||||||
template <bool is_method, typename... Args>
|
template <bool is_method, typename... Args>
|
||||||
struct IsWeakMethod : std::false_type {};
|
inline constexpr bool kIsWeakMethod = false;
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
struct IsWeakMethod<true, T, Args...> : IsWeakReceiver<T> {};
|
inline constexpr bool kIsWeakMethod<true, T, Args...> =
|
||||||
|
IsWeakReceiver<T>::value;
|
||||||
|
|
||||||
// Packs a list of types to hold them in a single type.
|
// Packs a list of types to hold them in a single type.
|
||||||
template <typename... Types>
|
template <typename... Types>
|
||||||
@@ -412,46 +428,32 @@ struct TypeList {};
|
|||||||
|
|
||||||
// Used for DropTypeListItem implementation.
|
// Used for DropTypeListItem implementation.
|
||||||
template <size_t n, typename List>
|
template <size_t n, typename List>
|
||||||
struct DropTypeListItemImpl;
|
requires is_instantiation<TypeList, List>
|
||||||
|
struct DropTypeListItemImpl {
|
||||||
|
using Type = List;
|
||||||
|
};
|
||||||
|
|
||||||
// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
|
|
||||||
template <size_t n, typename T, typename... List>
|
template <size_t n, typename T, typename... List>
|
||||||
|
requires(n > 0)
|
||||||
struct DropTypeListItemImpl<n, TypeList<T, List...>>
|
struct DropTypeListItemImpl<n, TypeList<T, List...>>
|
||||||
: DropTypeListItemImpl<n - 1, TypeList<List...>> {};
|
: DropTypeListItemImpl<n - 1, TypeList<List...>> {};
|
||||||
|
|
||||||
template <typename T, typename... List>
|
|
||||||
struct DropTypeListItemImpl<0, TypeList<T, List...>> {
|
|
||||||
using Type = TypeList<T, List...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct DropTypeListItemImpl<0, TypeList<>> {
|
|
||||||
using Type = TypeList<>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A type-level function that drops |n| list item from given TypeList.
|
// A type-level function that drops |n| list item from given TypeList.
|
||||||
template <size_t n, typename List>
|
template <size_t n, typename List>
|
||||||
using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
|
using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
|
||||||
|
|
||||||
// Used for TakeTypeListItem implementation.
|
// Used for TakeTypeListItem implementation.
|
||||||
template <size_t n, typename List, typename... Accum>
|
template <size_t n, typename List, typename... Accum>
|
||||||
struct TakeTypeListItemImpl;
|
requires is_instantiation<TypeList, List>
|
||||||
|
struct TakeTypeListItemImpl {
|
||||||
|
using Type = TypeList<Accum...>;
|
||||||
|
};
|
||||||
|
|
||||||
// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
|
|
||||||
template <size_t n, typename T, typename... List, typename... Accum>
|
template <size_t n, typename T, typename... List, typename... Accum>
|
||||||
|
requires(n > 0)
|
||||||
struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
|
struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
|
||||||
: TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
|
: TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
|
||||||
|
|
||||||
template <typename T, typename... List, typename... Accum>
|
|
||||||
struct TakeTypeListItemImpl<0, TypeList<T, List...>, Accum...> {
|
|
||||||
using Type = TypeList<Accum...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename... Accum>
|
|
||||||
struct TakeTypeListItemImpl<0, TypeList<>, Accum...> {
|
|
||||||
using Type = TypeList<Accum...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A type-level function that takes first |n| list item from given TypeList.
|
// A type-level function that takes first |n| list item from given TypeList.
|
||||||
// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
|
// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
|
||||||
// TypeList<A, B, C>.
|
// TypeList<A, B, C>.
|
||||||
@@ -477,9 +479,7 @@ struct MakeFunctionTypeImpl;
|
|||||||
|
|
||||||
template <typename R, typename... Args>
|
template <typename R, typename... Args>
|
||||||
struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
|
struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
|
||||||
// MSVC 2013 doesn't support Type Alias of function types.
|
using Type = R(Args...);
|
||||||
// Revisit this after we update it to newer version.
|
|
||||||
typedef R Type(Args...);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// A type-level function that constructs a function type that has |R| as its
|
// A type-level function that constructs a function type that has |R| as its
|
||||||
@@ -542,29 +542,26 @@ template <typename Callable>
|
|||||||
using ExtractCallableRunType =
|
using ExtractCallableRunType =
|
||||||
typename ExtractCallableRunTypeImpl<Callable>::Type;
|
typename ExtractCallableRunTypeImpl<Callable>::Type;
|
||||||
|
|
||||||
// IsCallableObject<Functor> is std::true_type if |Functor| has operator().
|
// IsCallableObject<Functor> is true if `Functor` has a non-overloaded
|
||||||
// Otherwise, it's std::false_type.
|
// `operator()`. This means it fails on some real callable objects, e.g. with
|
||||||
|
// templated or overloaded `operator()`s.
|
||||||
// Example:
|
// Example:
|
||||||
// IsCallableObject<void(*)()>::value is false.
|
// IsCallableObject<void(*)()> is false.
|
||||||
//
|
//
|
||||||
// struct Foo {};
|
// struct Foo {};
|
||||||
// IsCallableObject<void(Foo::*)()>::value is false.
|
// IsCallableObject<void(Foo::*)()> is false.
|
||||||
//
|
//
|
||||||
// int i = 0;
|
// int i = 0;
|
||||||
// auto f = [i] {};
|
// auto f = [i] {};
|
||||||
// IsCallableObject<decltype(f)>::value is false.
|
// IsCallableObject<decltype(f)> is false.
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
struct IsCallableObject : std::false_type {};
|
concept IsCallableObject = requires { &Functor::operator(); };
|
||||||
|
|
||||||
template <typename Callable>
|
// `HasRefCountedTypeAsRawPtr` is true when any of the `Args` is a raw pointer
|
||||||
requires requires { &Callable::operator(); }
|
// to a `RefCounted` type.
|
||||||
struct IsCallableObject<Callable> : std::true_type {};
|
|
||||||
|
|
||||||
// HasRefCountedTypeAsRawPtr inherits from true_type when any of the |Args| is a
|
|
||||||
// raw pointer to a RefCounted type.
|
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
struct HasRefCountedTypeAsRawPtr
|
concept HasRefCountedTypeAsRawPtr =
|
||||||
: std::disjunction<NeedsScopedRefptrButGetsRawPtr<Ts>...> {};
|
std::disjunction_v<NeedsScopedRefptrButGetsRawPtr<Ts>...>;
|
||||||
|
|
||||||
// ForceVoidReturn<>
|
// ForceVoidReturn<>
|
||||||
//
|
//
|
||||||
@@ -603,7 +600,7 @@ struct FunctorTraits;
|
|||||||
// // No non-static member variable and no virtual functions.
|
// // No non-static member variable and no virtual functions.
|
||||||
// };
|
// };
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
requires(IsCallableObject<Functor>::value)
|
requires IsCallableObject<Functor>
|
||||||
struct FunctorTraits<Functor> {
|
struct FunctorTraits<Functor> {
|
||||||
using RunType = ExtractCallableRunType<Functor>;
|
using RunType = ExtractCallableRunType<Functor>;
|
||||||
static constexpr bool is_method = false;
|
static constexpr bool is_method = false;
|
||||||
@@ -633,6 +630,10 @@ struct FunctorTraits<R (*)(Args...)> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename R, typename... Args>
|
||||||
|
struct FunctorTraits<R (*)(Args...) noexcept> : FunctorTraits<R (*)(Args...)> {
|
||||||
|
};
|
||||||
|
|
||||||
#if BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)
|
#if BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)
|
||||||
|
|
||||||
// For functions.
|
// For functions.
|
||||||
@@ -715,6 +716,10 @@ struct FunctorTraits<R (Receiver::*)(Args...)> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename R, typename Receiver, typename... Args>
|
||||||
|
struct FunctorTraits<R (Receiver::*)(Args...) noexcept>
|
||||||
|
: FunctorTraits<R (Receiver::*)(Args...)> {};
|
||||||
|
|
||||||
// For const methods.
|
// For const methods.
|
||||||
template <typename R, typename Receiver, typename... Args>
|
template <typename R, typename Receiver, typename... Args>
|
||||||
struct FunctorTraits<R (Receiver::*)(Args...) const> {
|
struct FunctorTraits<R (Receiver::*)(Args...) const> {
|
||||||
@@ -732,6 +737,10 @@ struct FunctorTraits<R (Receiver::*)(Args...) const> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename R, typename Receiver, typename... Args>
|
||||||
|
struct FunctorTraits<R (Receiver::*)(Args...) const noexcept>
|
||||||
|
: FunctorTraits<R (Receiver::*)(Args...) const> {};
|
||||||
|
|
||||||
#if BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)
|
#if BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)
|
||||||
|
|
||||||
// For __stdcall methods.
|
// For __stdcall methods.
|
||||||
@@ -746,23 +755,6 @@ struct FunctorTraits<R (__stdcall Receiver::*)(Args...) const>
|
|||||||
|
|
||||||
#endif // BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)
|
#endif // BUILDFLAG(IS_WIN) && !defined(ARCH_CPU_64_BITS)
|
||||||
|
|
||||||
#ifdef __cpp_noexcept_function_type
|
|
||||||
// noexcept makes a distinct function type in C++17.
|
|
||||||
// I.e. `void(*)()` and `void(*)() noexcept` are same in pre-C++17, and
|
|
||||||
// different in C++17.
|
|
||||||
template <typename R, typename... Args>
|
|
||||||
struct FunctorTraits<R (*)(Args...) noexcept> : FunctorTraits<R (*)(Args...)> {
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename R, typename Receiver, typename... Args>
|
|
||||||
struct FunctorTraits<R (Receiver::*)(Args...) noexcept>
|
|
||||||
: FunctorTraits<R (Receiver::*)(Args...)> {};
|
|
||||||
|
|
||||||
template <typename R, typename Receiver, typename... Args>
|
|
||||||
struct FunctorTraits<R (Receiver::*)(Args...) const noexcept>
|
|
||||||
: FunctorTraits<R (Receiver::*)(Args...) const> {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For IgnoreResults.
|
// For IgnoreResults.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
|
struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
|
||||||
@@ -941,10 +933,6 @@ struct Invoker<StorageType, R(UnboundArgs...)> {
|
|||||||
BoundArgsTuple&& bound,
|
BoundArgsTuple&& bound,
|
||||||
std::index_sequence<indices...> seq,
|
std::index_sequence<indices...> seq,
|
||||||
UnboundArgs&&... unbound_args) {
|
UnboundArgs&&... unbound_args) {
|
||||||
static constexpr bool is_method = MakeFunctorTraits<Functor>::is_method;
|
|
||||||
|
|
||||||
using DecayedArgsTuple = std::decay_t<BoundArgsTuple>;
|
|
||||||
|
|
||||||
#if BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
|
#if BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
|
||||||
RawPtrAsanBoundArgTracker raw_ptr_asan_bound_arg_tracker;
|
RawPtrAsanBoundArgTracker raw_ptr_asan_bound_arg_tracker;
|
||||||
raw_ptr_asan_bound_arg_tracker.AddArgs(
|
raw_ptr_asan_bound_arg_tracker.AddArgs(
|
||||||
@@ -952,9 +940,10 @@ struct Invoker<StorageType, R(UnboundArgs...)> {
|
|||||||
std::forward<UnboundArgs>(unbound_args)...);
|
std::forward<UnboundArgs>(unbound_args)...);
|
||||||
#endif // BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
|
#endif // BUILDFLAG(USE_ASAN_BACKUP_REF_PTR)
|
||||||
|
|
||||||
static constexpr bool is_weak_call =
|
using DecayedArgsTuple = std::decay_t<BoundArgsTuple>;
|
||||||
IsWeakMethod<is_method,
|
static constexpr bool kIsWeakCall =
|
||||||
std::tuple_element_t<indices, DecayedArgsTuple>...>();
|
kIsWeakMethod<MakeFunctorTraits<Functor>::is_method,
|
||||||
|
std::tuple_element_t<indices, DecayedArgsTuple>...>;
|
||||||
|
|
||||||
// Do not `Unwrap()` here, as that immediately triggers dangling pointer
|
// Do not `Unwrap()` here, as that immediately triggers dangling pointer
|
||||||
// detection. Dangling pointer detection should only be triggered if the
|
// detection. Dangling pointer detection should only be triggered if the
|
||||||
@@ -966,65 +955,56 @@ struct Invoker<StorageType, R(UnboundArgs...)> {
|
|||||||
// a memory safety error because protecting raw pointers usage with weak
|
// a memory safety error because protecting raw pointers usage with weak
|
||||||
// receivers (where the weak receiver usually own the pointed objects) is a
|
// receivers (where the weak receiver usually own the pointed objects) is a
|
||||||
// common and broadly used pattern in the codebase.
|
// common and broadly used pattern in the codebase.
|
||||||
return InvokeHelper<is_weak_call, R, indices...>::MakeItSo(
|
return InvokeHelper<kIsWeakCall, R, indices...>::MakeItSo(
|
||||||
std::forward<Functor>(functor), std::forward<BoundArgsTuple>(bound),
|
std::forward<Functor>(functor), std::forward<BoundArgsTuple>(bound),
|
||||||
std::forward<UnboundArgs>(unbound_args)...);
|
std::forward<UnboundArgs>(unbound_args)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Functor>
|
// Allow binding a method call with no receiver.
|
||||||
requires(FunctorTraits<Functor>::is_nullable)
|
// TODO(crbug.com/1511757): Remove or make safe.
|
||||||
constexpr bool IsNull(const Functor& functor) {
|
template <typename... Unused>
|
||||||
return !functor;
|
void VerifyMethodReceiver(Unused&&...) {}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Functor>
|
template <typename Receiver, typename... Unused>
|
||||||
requires(!FunctorTraits<Functor>::is_nullable)
|
void VerifyMethodReceiver(Receiver&& receiver, Unused&&...) {
|
||||||
constexpr bool IsNull(const Functor&) {
|
// Asserts that Callback is not the first owner of a ref-counted receiver.
|
||||||
return false;
|
if constexpr (IsPointerV<std::decay_t<Receiver>> &&
|
||||||
}
|
IsRefCountedType<RemovePointerT<std::decay_t<Receiver>>>) {
|
||||||
|
DCHECK(receiver);
|
||||||
|
|
||||||
// The base case of BanUnconstructedRefCountedReceiver that checks nothing.
|
// It's error prone to make the implicit first reference to ref-counted
|
||||||
template <typename Functor, typename... Unused>
|
// types. In the example below, base::BindOnce() would make the implicit
|
||||||
void BanUnconstructedRefCountedReceiver(Unused&&...) {}
|
// first reference to the ref-counted Foo. If PostTask() failed or the
|
||||||
|
// posted task ran fast enough, the newly created instance could be
|
||||||
// Asserts that Callback is not the first owner of a ref-counted receiver.
|
// destroyed before `oo` makes another reference.
|
||||||
template <typename Functor, typename Receiver, typename... Unused>
|
// Foo::Foo() {
|
||||||
requires(MakeFunctorTraits<Functor>::is_method &&
|
// base::ThreadPool::PostTask(FROM_HERE,
|
||||||
IsPointerV<std::decay_t<Receiver>> &&
|
// base::BindOnce(&Foo::Bar, this));
|
||||||
IsRefCountedType<RemovePointerT<std::decay_t<Receiver>>>)
|
// }
|
||||||
void BanUnconstructedRefCountedReceiver(Receiver&& receiver, Unused&&...) {
|
//
|
||||||
DCHECK(receiver);
|
// scoped_refptr<Foo> oo = new Foo();
|
||||||
|
//
|
||||||
// It's error prone to make the implicit first reference to ref-counted types.
|
// Hence, base::Bind{Once,Repeating}() refuses to create the first reference
|
||||||
// In the example below, base::BindOnce() would make the implicit first
|
// to ref-counted objects, and DCHECK()s otherwise. As above, that typically
|
||||||
// reference to the ref-counted Foo. If PostTask() failed or the posted task
|
// happens around PostTask() in their constructor, and such objects can be
|
||||||
// ran fast enough, the newly created instance could be destroyed before `oo`
|
// destroyed before `new` returns if the task resolves fast enough.
|
||||||
// makes another reference.
|
//
|
||||||
// Foo::Foo() {
|
// Instead of doing the above, please consider adding a static constructor,
|
||||||
// base::ThreadPool::PostTask(FROM_HERE, base::BindOnce(&Foo::Bar, this));
|
// and keep the first reference alive explicitly.
|
||||||
// }
|
// // static
|
||||||
//
|
// scoped_refptr<Foo> Foo::Create() {
|
||||||
// scoped_refptr<Foo> oo = new Foo();
|
// auto foo = base::WrapRefCounted(new Foo());
|
||||||
//
|
// base::ThreadPool::PostTask(FROM_HERE,
|
||||||
// Hence, base::Bind{Once,Repeating}() refuses to create the first reference
|
// base::BindOnce(&Foo::Bar, foo));
|
||||||
// to ref-counted objects, and DCHECK()s otherwise. As above, that typically
|
// return foo;
|
||||||
// happens around PostTask() in their constructor, and such objects can be
|
// }
|
||||||
// destroyed before `new` returns if the task resolves fast enough.
|
//
|
||||||
//
|
// Foo::Foo() {}
|
||||||
// Instead of doing the above, please consider adding a static constructor,
|
//
|
||||||
// and keep the first reference alive explicitly.
|
// scoped_refptr<Foo> oo = Foo::Create();
|
||||||
// // static
|
DCHECK(receiver->HasAtLeastOneRef());
|
||||||
// scoped_refptr<Foo> Foo::Create() {
|
}
|
||||||
// auto foo = base::WrapRefCounted(new Foo());
|
|
||||||
// base::ThreadPool::PostTask(FROM_HERE, base::BindOnce(&Foo::Bar, foo));
|
|
||||||
// return foo;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Foo::Foo() {}
|
|
||||||
//
|
|
||||||
// scoped_refptr<Foo> oo = Foo::Create();
|
|
||||||
DCHECK(receiver->HasAtLeastOneRef());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindState<>
|
// BindState<>
|
||||||
@@ -1033,20 +1013,18 @@ void BanUnconstructedRefCountedReceiver(Receiver&& receiver, Unused&&...) {
|
|||||||
template <typename Functor, typename... BoundArgs>
|
template <typename Functor, typename... BoundArgs>
|
||||||
struct BindState final : BindStateBase {
|
struct BindState final : BindStateBase {
|
||||||
private:
|
private:
|
||||||
|
using FunctorTraits = MakeFunctorTraits<Functor>;
|
||||||
using BoundArgsTuple = std::tuple<BoundArgs...>;
|
using BoundArgsTuple = std::tuple<BoundArgs...>;
|
||||||
using Traits = CallbackCancellationTraits<Functor, BoundArgsTuple>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename ForwardFunctor, typename... ForwardBoundArgs>
|
template <typename ForwardFunctor, typename... ForwardBoundArgs>
|
||||||
static BindState* Create(BindStateBase::InvokeFuncStorage invoke_func,
|
static BindState* Create(BindStateBase::InvokeFuncStorage invoke_func,
|
||||||
ForwardFunctor&& functor,
|
ForwardFunctor&& functor,
|
||||||
ForwardBoundArgs&&... bound_args) {
|
ForwardBoundArgs&&... bound_args) {
|
||||||
// Ban ref counted receivers that were not yet fully constructed to avoid
|
if constexpr (FunctorTraits::is_method) {
|
||||||
// a common pattern of racy situation.
|
VerifyMethodReceiver(bound_args...);
|
||||||
BanUnconstructedRefCountedReceiver<ForwardFunctor>(bound_args...);
|
}
|
||||||
|
return new BindState(invoke_func, std::forward<ForwardFunctor>(functor),
|
||||||
return new BindState(std::bool_constant<Traits::is_cancellable>(),
|
|
||||||
invoke_func, std::forward<ForwardFunctor>(functor),
|
|
||||||
std::forward<ForwardBoundArgs>(bound_args)...);
|
std::forward<ForwardBoundArgs>(bound_args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1054,41 +1032,45 @@ struct BindState final : BindStateBase {
|
|||||||
BoundArgsTuple bound_args_;
|
BoundArgsTuple bound_args_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr bool kIsNestedCallback =
|
using CancellationTraits =
|
||||||
MakeFunctorTraits<Functor>::is_callback;
|
CallbackCancellationTraits<Functor, BoundArgsTuple>;
|
||||||
|
|
||||||
template <typename ForwardFunctor, typename... ForwardBoundArgs>
|
template <typename ForwardFunctor, typename... ForwardBoundArgs>
|
||||||
explicit BindState(std::true_type,
|
requires CancellationTraits::is_cancellable
|
||||||
BindStateBase::InvokeFuncStorage invoke_func,
|
explicit BindState(BindStateBase::InvokeFuncStorage invoke_func,
|
||||||
ForwardFunctor&& functor,
|
ForwardFunctor&& functor,
|
||||||
ForwardBoundArgs&&... bound_args)
|
ForwardBoundArgs&&... bound_args)
|
||||||
: BindStateBase(invoke_func, &Destroy, &QueryCancellationTraits),
|
: BindStateBase(invoke_func, &Destroy, &QueryCancellationTraits),
|
||||||
functor_(std::forward<ForwardFunctor>(functor)),
|
functor_(std::forward<ForwardFunctor>(functor)),
|
||||||
bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
|
bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
|
||||||
// We check the validity of nested callbacks (e.g., Bind(callback, ...)) in
|
if constexpr (FunctorTraits::is_nullable) {
|
||||||
// release builds to avoid null pointers from ending up in posted tasks,
|
// We check the validity of nested callbacks (e.g., Bind(callback, ...))
|
||||||
// causing hard-to-diagnose crashes. Ideally we'd do this for all functors
|
// in release builds to avoid null pointers from ending up in posted
|
||||||
// here, but that would have a large binary size impact.
|
// tasks, causing hard-to-diagnose crashes. Ideally we'd do this for all
|
||||||
if constexpr (kIsNestedCallback) {
|
// functors here, but that would have a large binary size impact.
|
||||||
CHECK(!IsNull(functor_));
|
if constexpr (FunctorTraits::is_callback) {
|
||||||
} else {
|
CHECK(!!functor_);
|
||||||
DCHECK(!IsNull(functor_));
|
} else {
|
||||||
|
DCHECK(!!functor_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ForwardFunctor, typename... ForwardBoundArgs>
|
template <typename ForwardFunctor, typename... ForwardBoundArgs>
|
||||||
explicit BindState(std::false_type,
|
requires(!CancellationTraits::is_cancellable)
|
||||||
BindStateBase::InvokeFuncStorage invoke_func,
|
explicit BindState(BindStateBase::InvokeFuncStorage invoke_func,
|
||||||
ForwardFunctor&& functor,
|
ForwardFunctor&& functor,
|
||||||
ForwardBoundArgs&&... bound_args)
|
ForwardBoundArgs&&... bound_args)
|
||||||
: BindStateBase(invoke_func, &Destroy),
|
: BindStateBase(invoke_func, &Destroy),
|
||||||
functor_(std::forward<ForwardFunctor>(functor)),
|
functor_(std::forward<ForwardFunctor>(functor)),
|
||||||
bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
|
bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
|
||||||
// See above for CHECK/DCHECK rationale.
|
if constexpr (FunctorTraits::is_nullable) {
|
||||||
if constexpr (kIsNestedCallback) {
|
// See above for CHECK/DCHECK rationale.
|
||||||
CHECK(!IsNull(functor_));
|
if constexpr (FunctorTraits::is_callback) {
|
||||||
} else {
|
CHECK(!!functor_);
|
||||||
DCHECK(!IsNull(functor_));
|
} else {
|
||||||
|
DCHECK(!!functor_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1111,12 +1093,14 @@ struct BindState final : BindStateBase {
|
|||||||
// Helpers to do arg tuple expansion.
|
// Helpers to do arg tuple expansion.
|
||||||
template <size_t... indices>
|
template <size_t... indices>
|
||||||
bool IsCancelled(std::index_sequence<indices...>) const {
|
bool IsCancelled(std::index_sequence<indices...>) const {
|
||||||
return Traits::IsCancelled(functor_, std::get<indices>(bound_args_)...);
|
return CancellationTraits::IsCancelled(functor_,
|
||||||
|
std::get<indices>(bound_args_)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t... indices>
|
template <size_t... indices>
|
||||||
bool MaybeValid(std::index_sequence<indices...>) const {
|
bool MaybeValid(std::index_sequence<indices...>) const {
|
||||||
return Traits::MaybeValid(functor_, std::get<indices>(bound_args_)...);
|
return CancellationTraits::MaybeValid(functor_,
|
||||||
|
std::get<indices>(bound_args_)...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1169,8 +1153,7 @@ struct MakeBindStateTypeImpl<false, Functor, BoundArgs...> {
|
|||||||
// condition to be checked is always used as the default value of a template
|
// condition to be checked is always used as the default value of a template
|
||||||
// argument, so callers can simply instantiate the struct with no template
|
// argument, so callers can simply instantiate the struct with no template
|
||||||
// params to verify the condition.
|
// params to verify the condition.
|
||||||
template <bool v =
|
template <bool v = !HasRefCountedTypeAsRawPtr<std::decay_t<BoundArgs>...>>
|
||||||
!HasRefCountedTypeAsRawPtr<std::decay_t<BoundArgs>...>::value>
|
|
||||||
struct NoRawPtrsToRefCountedTypes {
|
struct NoRawPtrsToRefCountedTypes {
|
||||||
static constexpr bool value = [] {
|
static constexpr bool value = [] {
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -1227,8 +1210,7 @@ struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> {
|
|||||||
}();
|
}();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool v =
|
template <bool v = !HasRefCountedTypeAsRawPtr<std::decay_t<BoundArgs>...>>
|
||||||
!HasRefCountedTypeAsRawPtr<std::decay_t<BoundArgs>...>::value>
|
|
||||||
struct NoRawPtrsToRefCountedTypes {
|
struct NoRawPtrsToRefCountedTypes {
|
||||||
static constexpr bool value = [] {
|
static constexpr bool value = [] {
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -1254,24 +1236,6 @@ using MakeBindStateType =
|
|||||||
Functor,
|
Functor,
|
||||||
BoundArgs...>;
|
BoundArgs...>;
|
||||||
|
|
||||||
// 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.
|
// Transform |T| into `Unwrapped` type, which is passed to the target function.
|
||||||
// Example:
|
// Example:
|
||||||
// In is_once == true case,
|
// In is_once == true case,
|
||||||
@@ -1282,9 +1246,13 @@ struct TransformToUnwrappedTypeImpl<false, T> {
|
|||||||
// `int&&` -> `const int&`,
|
// `int&&` -> `const int&`,
|
||||||
// `const int&` -> `const int&`,
|
// `const int&` -> `const int&`,
|
||||||
// `OwnedWrapper<int>&` -> `int* const &`.
|
// `OwnedWrapper<int>&` -> `int* const &`.
|
||||||
template <bool is_once, typename T>
|
template <bool is_once,
|
||||||
|
typename T,
|
||||||
|
typename StoredType = std::decay_t<T>,
|
||||||
|
typename ForwardedType =
|
||||||
|
std::conditional_t<is_once, StoredType&&, const StoredType&>>
|
||||||
using TransformToUnwrappedType =
|
using TransformToUnwrappedType =
|
||||||
typename TransformToUnwrappedTypeImpl<is_once, T>::Unwrapped;
|
decltype(Unwrap(std::declval<ForwardedType>()));
|
||||||
|
|
||||||
// Converts `this` arguments to underlying pointer types. E.g.
|
// Converts `this` arguments to underlying pointer types. E.g.
|
||||||
// `int*` -> `int*`
|
// `int*` -> `int*`
|
||||||
@@ -1349,13 +1317,6 @@ struct MakeUnwrappedTypeList<is_once, true, Receiver, Args...> {
|
|||||||
static constexpr bool value = UnderlyingReceiver::value;
|
static constexpr bool value = UnderlyingReceiver::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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 {};
|
|
||||||
|
|
||||||
// IsUnretainedMayDangle is true if StorageType is of type
|
// IsUnretainedMayDangle is true if StorageType is of type
|
||||||
// `UnretainedWrapper<T, unretained_traits::MayDangle, PtrTraits>.
|
// `UnretainedWrapper<T, unretained_traits::MayDangle, PtrTraits>.
|
||||||
// Note that it is false for unretained_traits::MayDangleUntriaged.
|
// Note that it is false for unretained_traits::MayDangleUntriaged.
|
||||||
@@ -1377,11 +1338,10 @@ template <typename T,
|
|||||||
inline constexpr bool UnretainedAndRawPtrHaveCompatibleTraits<
|
inline constexpr bool UnretainedAndRawPtrHaveCompatibleTraits<
|
||||||
UnretainedWrapper<T, unretained_traits::MayDangle, PtrTraitsInUnretained>,
|
UnretainedWrapper<T, unretained_traits::MayDangle, PtrTraitsInUnretained>,
|
||||||
raw_ptr<T, PtrTraitsInReceiver>> =
|
raw_ptr<T, PtrTraitsInReceiver>> =
|
||||||
std::is_same_v<
|
std::same_as<typename UnretainedWrapper<T,
|
||||||
typename UnretainedWrapper<T,
|
unretained_traits::MayDangle,
|
||||||
unretained_traits::MayDangle,
|
PtrTraitsInUnretained>::GetPtrType,
|
||||||
PtrTraitsInUnretained>::GetPtrType,
|
raw_ptr<T, PtrTraitsInReceiver>>;
|
||||||
raw_ptr<T, PtrTraitsInReceiver>>;
|
|
||||||
|
|
||||||
// Helpers to make error messages slightly more readable.
|
// Helpers to make error messages slightly more readable.
|
||||||
template <int i>
|
template <int i>
|
||||||
@@ -1419,7 +1379,7 @@ struct BindArgument {
|
|||||||
template <typename StorageType>
|
template <typename StorageType>
|
||||||
struct StoredAs {
|
struct StoredAs {
|
||||||
static constexpr bool kBindArgumentCanBeCaptured =
|
static constexpr bool kBindArgumentCanBeCaptured =
|
||||||
std::is_constructible_v<StorageType, BoundAsType>;
|
std::constructible_from<StorageType, BoundAsType>;
|
||||||
|
|
||||||
// Note that this intentionally drops the const qualifier from
|
// Note that this intentionally drops the const qualifier from
|
||||||
// `BoundAsType`, to test if it *could* have been successfully bound if
|
// `BoundAsType`, to test if it *could* have been successfully bound if
|
||||||
@@ -1622,12 +1582,6 @@ struct ParamsCanBeBound<is_method,
|
|||||||
Params>...>;
|
Params>...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline constexpr bool kBindArgIsBasePassed = false;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline constexpr bool kBindArgIsBasePassed<PassedWrapper<T>> = true;
|
|
||||||
|
|
||||||
// Core implementation of Bind variants, which checks common preconditions
|
// Core implementation of Bind variants, which checks common preconditions
|
||||||
// before returning an appropriate callback.
|
// before returning an appropriate callback.
|
||||||
template <template <typename> class CallbackT>
|
template <template <typename> class CallbackT>
|
||||||
@@ -1708,7 +1662,8 @@ struct BindHelper {
|
|||||||
// using CallbackType = OnceCallback<double(const std::string&)>;
|
// using CallbackType = OnceCallback<double(const std::string&)>;
|
||||||
// ...
|
// ...
|
||||||
// ```
|
// ```
|
||||||
static constexpr bool kIsOnce = IsOnceCallback<CallbackT<void()>>::value;
|
static constexpr bool kIsOnce =
|
||||||
|
is_instantiation<OnceCallback, CallbackT<void()>>;
|
||||||
using FunctorTraits = MakeFunctorTraits<Functor>;
|
using FunctorTraits = MakeFunctorTraits<Functor>;
|
||||||
using UnwrappedArgsList =
|
using UnwrappedArgsList =
|
||||||
MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method, Args&&...>;
|
MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method, Args&&...>;
|
||||||
@@ -1756,27 +1711,24 @@ struct BindHelper {
|
|||||||
// extra bound arguments. We CHECK() the validity of callback to guard against
|
// extra bound arguments. We CHECK() the validity of callback to guard against
|
||||||
// null pointers accidentally ending up in posted tasks, causing hard-to-debug
|
// null pointers accidentally ending up in posted tasks, causing hard-to-debug
|
||||||
// crashes.
|
// crashes.
|
||||||
template <typename Signature>
|
|
||||||
requires(std::same_as<CallbackT<Signature>, OnceCallback<Signature>>)
|
// `OnceCallback` passed to `OnceCallback`, or `RepeatingCallback` passed to
|
||||||
static OnceCallback<Signature> Bind(OnceCallback<Signature> callback) {
|
// `RepeatingCallback`.
|
||||||
|
template <typename T>
|
||||||
|
requires is_instantiation<CallbackT, T>
|
||||||
|
static T Bind(T callback) {
|
||||||
CHECK(callback);
|
CHECK(callback);
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `RepeatingCallback` passed to `OnceCallback`. The opposite direction is
|
||||||
|
// intentionally not supported.
|
||||||
template <typename Signature>
|
template <typename Signature>
|
||||||
requires(std::same_as<CallbackT<Signature>, OnceCallback<Signature>>)
|
requires is_instantiation<CallbackT, OnceCallback<Signature>>
|
||||||
static OnceCallback<Signature> Bind(RepeatingCallback<Signature> callback) {
|
static OnceCallback<Signature> Bind(RepeatingCallback<Signature> callback) {
|
||||||
CHECK(callback);
|
CHECK(callback);
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Signature>
|
|
||||||
requires(std::same_as<CallbackT<Signature>, RepeatingCallback<Signature>>)
|
|
||||||
static RepeatingCallback<Signature> Bind(
|
|
||||||
RepeatingCallback<Signature> callback) {
|
|
||||||
CHECK(callback);
|
|
||||||
return callback;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Implementation of `BindOnce()`, which checks preconditions before handing off
|
// Implementation of `BindOnce()`, which checks preconditions before handing off
|
||||||
@@ -1784,7 +1736,7 @@ struct BindHelper {
|
|||||||
template <typename Functor, typename... Args>
|
template <typename Functor, typename... Args>
|
||||||
struct BindOnceHelper {
|
struct BindOnceHelper {
|
||||||
private:
|
private:
|
||||||
template <bool v = !IsOnceCallback<std::decay_t<Functor>>() ||
|
template <bool v = !is_instantiation<OnceCallback, std::decay_t<Functor>> ||
|
||||||
(std::is_rvalue_reference_v<Functor&&> &&
|
(std::is_rvalue_reference_v<Functor&&> &&
|
||||||
!std::is_const_v<std::remove_reference_t<Functor>>)>
|
!std::is_const_v<std::remove_reference_t<Functor>>)>
|
||||||
struct OnceCallbackFunctorIsConstRvalue {
|
struct OnceCallbackFunctorIsConstRvalue {
|
||||||
@@ -1795,7 +1747,8 @@ struct BindOnceHelper {
|
|||||||
}();
|
}();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool v = (... && !kBindArgIsBasePassed<std::decay_t<Args>>)>
|
template <bool v =
|
||||||
|
(... && !is_instantiation<PassedWrapper, std::decay_t<Args>>)>
|
||||||
struct NoBindArgIsBasePassed {
|
struct NoBindArgIsBasePassed {
|
||||||
static constexpr bool value = [] {
|
static constexpr bool value = [] {
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -1820,7 +1773,7 @@ struct BindOnceHelper {
|
|||||||
template <typename Functor, typename... Args>
|
template <typename Functor, typename... Args>
|
||||||
struct BindRepeatingHelper {
|
struct BindRepeatingHelper {
|
||||||
private:
|
private:
|
||||||
template <bool v = !IsOnceCallback<std::decay_t<Functor>>()>
|
template <bool v = !is_instantiation<OnceCallback, std::decay_t<Functor>>>
|
||||||
struct FunctorIsNotOnceCallback {
|
struct FunctorIsNotOnceCallback {
|
||||||
static constexpr bool value = [] {
|
static constexpr bool value = [] {
|
||||||
static_assert(v,
|
static_assert(v,
|
||||||
@@ -1853,14 +1806,11 @@ struct BindRepeatingHelper {
|
|||||||
// WeakPtr<Foo> oo = nullptr;
|
// WeakPtr<Foo> oo = nullptr;
|
||||||
// base::BindOnce(&Foo::bar, oo).Run();
|
// base::BindOnce(&Foo::bar, oo).Run();
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsWeakReceiver : std::false_type {};
|
struct IsWeakReceiver : std::bool_constant<is_instantiation<WeakPtr, T>> {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsWeakReceiver<std::reference_wrapper<T>> : IsWeakReceiver<T> {};
|
struct IsWeakReceiver<std::reference_wrapper<T>> : IsWeakReceiver<T> {};
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct IsWeakReceiver<WeakPtr<T>> : std::true_type {};
|
|
||||||
|
|
||||||
// An injection point to control how objects are checked for maybe validity,
|
// An injection point to control how objects are checked for maybe validity,
|
||||||
// which is an optimistic thread-safe check for full validity.
|
// which is an optimistic thread-safe check for full validity.
|
||||||
template <typename>
|
template <typename>
|
||||||
@@ -1882,39 +1832,14 @@ struct BindUnwrapTraits {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits>
|
|
||||||
struct BindUnwrapTraits<
|
|
||||||
internal::UnretainedWrapper<T, UnretainedTrait, PtrTraits>> {
|
|
||||||
static auto Unwrap(
|
|
||||||
const internal::UnretainedWrapper<T, UnretainedTrait, PtrTraits>& o) {
|
|
||||||
return o.get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename UnretainedTrait, RawPtrTraits PtrTraits>
|
|
||||||
struct BindUnwrapTraits<
|
|
||||||
internal::UnretainedRefWrapper<T, UnretainedTrait, PtrTraits>> {
|
|
||||||
static T& Unwrap(
|
|
||||||
const internal::UnretainedRefWrapper<T, UnretainedTrait, PtrTraits>& o) {
|
|
||||||
return o.get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct BindUnwrapTraits<internal::RetainedRefWrapper<T>> {
|
requires internal::kIsUnretainedWrapper<internal::UnretainedWrapper, T> ||
|
||||||
static T* Unwrap(const internal::RetainedRefWrapper<T>& o) { return o.get(); }
|
internal::kIsUnretainedWrapper<internal::UnretainedRefWrapper, T> ||
|
||||||
};
|
is_instantiation<internal::RetainedRefWrapper, T> ||
|
||||||
|
is_instantiation<internal::OwnedWrapper, T> ||
|
||||||
template <typename T, typename Deleter>
|
is_instantiation<internal::OwnedRefWrapper, T>
|
||||||
struct BindUnwrapTraits<internal::OwnedWrapper<T, Deleter>> {
|
struct BindUnwrapTraits<T> {
|
||||||
static T* Unwrap(const internal::OwnedWrapper<T, Deleter>& o) {
|
static decltype(auto) Unwrap(const T& o) { return o.get(); }
|
||||||
return o.get();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct BindUnwrapTraits<internal::OwnedRefWrapper<T>> {
|
|
||||||
static T& Unwrap(const internal::OwnedRefWrapper<T>& o) { return o.get(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -1940,8 +1865,8 @@ struct CallbackCancellationTraits {
|
|||||||
|
|
||||||
// Specialization for method bound to weak pointer receiver.
|
// Specialization for method bound to weak pointer receiver.
|
||||||
template <typename Functor, typename... BoundArgs>
|
template <typename Functor, typename... BoundArgs>
|
||||||
requires(internal::IsWeakMethod<internal::FunctorTraits<Functor>::is_method,
|
requires internal::kIsWeakMethod<internal::FunctorTraits<Functor>::is_method,
|
||||||
BoundArgs...>::value)
|
BoundArgs...>
|
||||||
struct CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>> {
|
struct CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>> {
|
||||||
static constexpr bool is_cancellable = true;
|
static constexpr bool is_cancellable = true;
|
||||||
|
|
||||||
@@ -1961,33 +1886,16 @@ struct CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Specialization for a nested bind.
|
// Specialization for a nested bind.
|
||||||
template <typename Signature, typename... BoundArgs>
|
template <typename Functor, typename... BoundArgs>
|
||||||
struct CallbackCancellationTraits<OnceCallback<Signature>,
|
requires is_instantiation<OnceCallback, Functor> ||
|
||||||
std::tuple<BoundArgs...>> {
|
is_instantiation<RepeatingCallback, Functor>
|
||||||
|
struct CallbackCancellationTraits<Functor, std::tuple<BoundArgs...>> {
|
||||||
static constexpr bool is_cancellable = true;
|
static constexpr bool is_cancellable = true;
|
||||||
|
|
||||||
template <typename Functor>
|
|
||||||
static bool IsCancelled(const Functor& functor, const BoundArgs&...) {
|
static bool IsCancelled(const Functor& functor, const BoundArgs&...) {
|
||||||
return functor.IsCancelled();
|
return functor.IsCancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Functor>
|
|
||||||
static bool MaybeValid(const Functor& functor, const BoundArgs&...) {
|
|
||||||
return MaybeValidTraits<Functor>::MaybeValid(functor);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Signature, typename... BoundArgs>
|
|
||||||
struct CallbackCancellationTraits<RepeatingCallback<Signature>,
|
|
||||||
std::tuple<BoundArgs...>> {
|
|
||||||
static constexpr bool is_cancellable = true;
|
|
||||||
|
|
||||||
template <typename Functor>
|
|
||||||
static bool IsCancelled(const Functor& functor, const BoundArgs&...) {
|
|
||||||
return functor.IsCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Functor>
|
|
||||||
static bool MaybeValid(const Functor& functor, const BoundArgs&...) {
|
static bool MaybeValid(const Functor& functor, const BoundArgs&...) {
|
||||||
return MaybeValidTraits<Functor>::MaybeValid(functor);
|
return MaybeValidTraits<Functor>::MaybeValid(functor);
|
||||||
}
|
}
|
||||||
|
@@ -1493,17 +1493,17 @@ TEST_F(BindTest, RepeatingWithoutPassed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BindTest, CapturelessLambda) {
|
TEST_F(BindTest, CapturelessLambda) {
|
||||||
EXPECT_FALSE(internal::IsCallableObject<void>::value);
|
EXPECT_FALSE(internal::IsCallableObject<void>);
|
||||||
EXPECT_FALSE(internal::IsCallableObject<int>::value);
|
EXPECT_FALSE(internal::IsCallableObject<int>);
|
||||||
EXPECT_FALSE(internal::IsCallableObject<void (*)()>::value);
|
EXPECT_FALSE(internal::IsCallableObject<void (*)()>);
|
||||||
EXPECT_FALSE(internal::IsCallableObject<void (NoRef::*)()>::value);
|
EXPECT_FALSE(internal::IsCallableObject<void (NoRef::*)()>);
|
||||||
|
|
||||||
auto f = [] {};
|
auto f = [] {};
|
||||||
EXPECT_TRUE(internal::IsCallableObject<decltype(f)>::value);
|
EXPECT_TRUE(internal::IsCallableObject<decltype(f)>);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
auto g = [i] { (void)i; };
|
auto g = [i] { (void)i; };
|
||||||
EXPECT_TRUE(internal::IsCallableObject<decltype(g)>::value);
|
EXPECT_TRUE(internal::IsCallableObject<decltype(g)>);
|
||||||
|
|
||||||
auto h = [](int, double) { return 'k'; };
|
auto h = [](int, double) { return 'k'; };
|
||||||
EXPECT_TRUE((std::is_same_v<char(int, double),
|
EXPECT_TRUE((std::is_same_v<char(int, double),
|
||||||
@@ -1535,9 +1535,9 @@ TEST_F(BindTest, EmptyFunctor) {
|
|||||||
int operator()() const { return 42; }
|
int operator()() const { return 42; }
|
||||||
};
|
};
|
||||||
|
|
||||||
EXPECT_TRUE(internal::IsCallableObject<NonEmptyFunctor>::value);
|
EXPECT_TRUE(internal::IsCallableObject<NonEmptyFunctor>);
|
||||||
EXPECT_TRUE(internal::IsCallableObject<EmptyFunctor>::value);
|
EXPECT_TRUE(internal::IsCallableObject<EmptyFunctor>);
|
||||||
EXPECT_TRUE(internal::IsCallableObject<EmptyFunctorConst>::value);
|
EXPECT_TRUE(internal::IsCallableObject<EmptyFunctorConst>);
|
||||||
EXPECT_EQ(42, BindOnce(EmptyFunctor()).Run());
|
EXPECT_EQ(42, BindOnce(EmptyFunctor()).Run());
|
||||||
EXPECT_EQ(42, BindOnce(EmptyFunctorConst()).Run());
|
EXPECT_EQ(42, BindOnce(EmptyFunctorConst()).Run());
|
||||||
EXPECT_EQ(42, BindRepeating(EmptyFunctorConst()).Run());
|
EXPECT_EQ(42, BindRepeating(EmptyFunctorConst()).Run());
|
||||||
|
@@ -854,9 +854,7 @@ of its implementation.
|
|||||||
namespace base {
|
namespace base {
|
||||||
|
|
||||||
template <typename Receiver>
|
template <typename Receiver>
|
||||||
struct IsWeakReceiver {
|
struct IsWeakReceiver : std::false_type {};
|
||||||
static constexpr bool value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Obj>
|
template <typename Obj>
|
||||||
struct BindUnwrapTraits {
|
struct BindUnwrapTraits {
|
||||||
|
@@ -124,9 +124,9 @@ auto MakeWGPUOnceCallback(CallbackType&& cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename FunctionType, typename... BoundParameters>
|
template <typename FunctionType, typename... BoundParameters>
|
||||||
requires(!base::internal::IsWeakMethod<
|
requires(!base::internal::kIsWeakMethod<
|
||||||
base::internal::MakeFunctorTraits<FunctionType>::is_method,
|
base::internal::MakeFunctorTraits<FunctionType>::is_method,
|
||||||
BoundParameters...>::value)
|
BoundParameters...>)
|
||||||
auto BindWGPUOnceCallback(FunctionType&& function,
|
auto BindWGPUOnceCallback(FunctionType&& function,
|
||||||
BoundParameters&&... bound_parameters) {
|
BoundParameters&&... bound_parameters) {
|
||||||
return MakeWGPUOnceCallback(
|
return MakeWGPUOnceCallback(
|
||||||
|
Reference in New Issue
Block a user