[Chromium] 闭包任务的创建

OnceCallback OnceClosure RepeatingCallback RepeatingClosure

Closure是给消息循环使用的内部任务,特点是返回值和参数都是void,不需要额外的运行环境,是一个完整的可以直接运行的闭包任务。

Callback是绑定闭包,用于绑定函数,自由使用的类型。

BindState

函数指针储存在BindState对象的functor_成员中,绑定的参数也存在这个对象中。

  // 真正的函数指针和调用bind时候传入的绑定参数
  Functor functor_;
  BoundArgsTuple bound_args_;

也就是说真正到执行函数的时候一定是需要BindState对象参与。

BindStateBase

其中的polymorphic_invoke_的成员变量存储了Invoker类型的静态方法RunOnce或者Run

using InvokeFuncStorage = void (*)(); // 临时转换用的万能存储用函数指针类型
InvokeFuncStorage polymorphic_invoke_; // BindStateBase持有这个

polymorphic_invoke_可以说是把BindState对象中存储的绑定的参数和执行时未绑定的参与合并然后调用函数指针的关键。

InvokeHelper

可以帮助探测方法的对象指针是否可用。是在Traits最终调用之前外包的最后一层

怎么把void(*)()模板函数和调用Bind的时候传入的函数指针关联起来

// callback.h
// RepeatingCallback
// 下面是组装好的闭包执行的代码,可以看出拿到了PolymorphicInvoke类型,绑定的参数存储在bind_state中
R Run(Args... args) const& {
    CHECK(!holder_.is_null());

    // Keep `bind_state` alive at least until after the invocation to ensure all
    // bound `Unretained` arguments remain protected by MiraclePtr.
    scoped_refptr<internal::BindStateBase> bind_state = holder_.bind_state();

    PolymorphicInvoke f =
        reinterpret_cast<PolymorphicInvoke>(holder_.polymorphic_invoke());
    return f(bind_state.get(), std::forward<Args>(args)...);
  }

PolymorphicInvoke类型如下所示,其中R是绑定闭包的返回值的类型,在传入的参数之前,还有一个BindStateBase类型的指针,下面的Args模板参数列表代表的是Run,函数执行的时候传入的补充参数

// Args are binded args
using PolymorphicInvoke = R (*)(internal::BindStateBase*,
                                  internal::PassingType<Args>...);

来源如下所示,是从BindStateBase中拿到的

using InvokeFuncStorage = void (*)(); // 临时转换用的万能存储用函数指针类型
InvokeFuncStorage polymorphic_invoke_; // BindStateBase持有这个

// 通过函数返回
InvokeFuncStorage polymorphic_invoke() const {
    return bind_state_->polymorphic_invoke_;
  }

但是polymorphic_invoke_是哪来的?其实它并非原本绑定的函数的函数指针,而是一层包装,这个包装的订一可以看BindImpl函数,这个包装的函数如下所示

// struct Invoker
// Invoker<Traits, StorageType, R(UnboundArgs...)>
static R RunOnce(BindStateBase* base,
                   PassingType<UnboundArgs>... unbound_args) {
    auto* const storage = static_cast<StorageType*>(base);
    return RunImpl(std::move(storage->functor_),
                   std::move(storage->bound_args_), Indices(),
                   std::forward<UnboundArgs>(unbound_args)...);
  }
 // 和RunOnce的区别可以看一下绑定参数的传递方式,Once是移动操作,这里是拷贝操作
  static R Run(BindStateBase* base, PassingType<UnboundArgs>... unbound_args) {
    auto* const storage = static_cast<const StorageType*>(base);
    return RunImpl(storage->functor_, storage->bound_args_, Indices(),
                   std::forward<UnboundArgs>(unbound_args)...);
  }

这里的storage->functor_有点像真正的函数指针,但是真正的函数指针是存在BindState类型里面的,这个storage的类型StorageType是什么来头,而且还用了static_cast类型转换,如果转换成BindState的话不应该使用这种转换才对。这得看这个Invoker类型的对象是怎么构造出来的

下面是绑定一个函数的时候的具体代码

template <typename Functor, typename... Args>
  static auto BindImpl(Functor&& functor, Args&&... args) {
    // There are a lot of variables and type aliases here. An example will be
    // illustrative. Assume we call:
    // ```
    //   struct S {
    //     double f(int, const std::string&);
    //   } s;
    //   int16_t i;
    //   BindOnce(&S::f, Unretained(&s), i);
    // ```
    // This means our template params are:
    // ```
    //   template <typename> class CallbackT = OnceCallback
    //   typename Functor = double (S::*)(int, const std::string&)
    //   typename... Args =
    //       UnretainedWrapper<S, unretained_traits::MayNotDangle>, int16_t
    // ```
    // And the implementation below is effectively:
    // ```
    //   using Traits = struct {
    //     using RunType = double(S*, int, const std::string&);
    //     static constexpr bool is_method = true;
    //     static constexpr bool is_nullable = true;
    //     static constexpr bool is_callback = false;
    //     static constexpr bool is_stateless = true;
    //     ...
    //   };
    //   using ValidatedUnwrappedTypes = struct {
    //     using Type = TypeList<S*, int16_t>;
    //     static constexpr bool value = true;
    //   };
    //   using BoundArgsList = TypeList<S*, int16_t>;
    //   using RunParamsList = TypeList<S*, int, const std::string&>;
    //   using BoundParamsList = TypeList<S*, int>;
    //   using ValidatedBindState = struct {
    //     using Type =
    //         BindState<double (S::*)(int, const std::string&),
    //                   UnretainedWrapper<S, unretained_traits::MayNotDangle>,
    //                   int16_t>;
    //     static constexpr bool value = true;
    //   };
    //   if constexpr (true) {
    //     using UnboundRunType = double(const std::string&);
    //     using CallbackType = OnceCallback<double(const std::string&)>;
    //     ...
    // ```
    using Traits = FunctorTraits<TransformToUnwrappedType<kIsOnce, Functor&&>,
                                 TransformToUnwrappedType<kIsOnce, Args&&>...>;
    if constexpr (TraitsAreInstantiable<Traits>::value) {
      using ValidatedUnwrappedTypes =
          ValidateUnwrappedTypeList<kIsOnce, Traits::is_method, Args&&...>;
      using BoundArgsList = TypeList<Args...>;
      using RunParamsList = ExtractArgs<typename Traits::RunType>;
      using BoundParamsList = TakeTypeListItem<sizeof...(Args), RunParamsList>;
      using ValidatedBindState =
          ValidateBindStateType<Traits::is_method, Traits::is_nullable,
                                Traits::is_callback, Functor, Args...>;
      // This conditional checks if each of the `args` matches to the
      // corresponding param of the target function. This check does not affect
      // the behavior of `Bind()`, but its error message should be more
      // readable.
      if constexpr (std::conjunction_v<
                        NotFunctionRef<Functor>, IsStateless<Traits>,
                        ValidatedUnwrappedTypes,
                        ParamsCanBeBound<
                            Traits::is_method,
                            std::make_index_sequence<sizeof...(Args)>,
                            BoundArgsList,
                            typename ValidatedUnwrappedTypes::Type,
                            BoundParamsList>,
                        ValidatedBindState>) {
        using UnboundRunType =
            MakeFunctionType<ExtractReturnType<typename Traits::RunType>,
                             DropTypeListItem<sizeof...(Args), RunParamsList>>;
        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.
        typename CallbackType::PolymorphicInvoke invoke_func;
        using Invoker =
            Invoker<Traits, typename ValidatedBindState::Type, UnboundRunType>;
        if constexpr (kIsOnce) {
          invoke_func = Invoker::RunOnce;
        } else {
          invoke_func = Invoker::Run;
        }
       // 可以看到这里传入了包装用的函数
        return CallbackType(ValidatedBindState::Type::Create(
            reinterpret_cast<BindStateBase::InvokeFuncStorage>(invoke_func),
            std::forward<Functor>(functor), std::forward<Args>(args)...));
      }
    }
  }

ValidatedBindState::Type这个类型萃取的结果都是BindState类型(根据计算结果,传入的模板参数不同)所以说。上面的storage->functor_就确实是真正的函数指针了。

模板元编程相关记录

如何萃取出函数的返回值和参数等内容

函数返回值和参数列表

// For most functors, the traits should not depend on how the functor is passed,
// so decay the functor.
template <typename Functor, typename... BoundArgs>
// This requirement avoids "implicit instantiation of undefined template" errors
// when the underlying `DecayedFunctorTraits<>` cannot be instantiated. Instead,
// this template will also not be instantiated, and the caller can detect and
// handle that.
  requires IsComplete<DecayedFunctorTraits<std::decay_t<Functor>, BoundArgs...>>
struct FunctorTraits<Functor, BoundArgs...>
    : DecayedFunctorTraits<std::decay_t<Functor>, BoundArgs...> {};
    
// Functions.
template <typename R, typename... Args, typename... BoundArgs>
struct DecayedFunctorTraits<R (*)(Args...), BoundArgs...> {
  using RunType = R(Args...);
  static constexpr bool is_method = false;
  static constexpr bool is_nullable = true;
  static constexpr bool is_callback = false;
  static constexpr bool is_stateless = true;

  template <typename Function, typename... RunArgs>
  static R Invoke(Function&& function, RunArgs&&... args) {
    return std::forward<Function>(function)(std::forward<RunArgs>(args)...);
  }
};

// Methods.
template <typename R,
          typename Receiver,
          typename... Args,
          typename... BoundArgs>
struct DecayedFunctorTraits<R (Receiver::*)(Args...), BoundArgs...> {
  using RunType = R(Receiver*, Args...);
  static constexpr bool is_method = true;
  static constexpr bool is_nullable = true;
  static constexpr bool is_callback = false;
  static constexpr bool is_stateless = true;

  template <typename Method, typename ReceiverPtr, typename... RunArgs>
  static R Invoke(Method method,
                  ReceiverPtr&& receiver_ptr,
                  RunArgs&&... args) {
    return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
  }
};

使用这个函数萃取,得到函数签名,重点关注RunType,针对不同的函数指针类型有不同的特化模板萃取出函数签名,例如上述代码中的普通函数和类型方法,对应两种特化。

这个代码把RunType定义为一个函数签名。这样就随时都可以取出返回值和参数列表。下述代码就可以完成这个操作。

// Implements `ExtractArgs` and `ExtractReturnType`.
template <typename Signature>
struct ExtractArgsImpl;

template <typename R, typename... Args>
struct ExtractArgsImpl<R(Args...)> {
  using ReturnType = R;
  using ArgsList = TypeList<Args...>;
};

根据传入的函数指针和绑定的参数,计算出剩余参数的模板参数列表

代码如下所示,RunType不用多说,上面解释过了,是函数签名,ExtractReturnType是萃取出函数签名的返回值类型,主要看一下DropTypeListItem这个是计算出未绑定的参数列表

using RunParamsList = ExtractArgs<typename Traits::RunType>;
using UnboundRunType =
            MakeFunctionType<ExtractReturnType<typename Traits::RunType>,
                             DropTypeListItem<sizeof...(Args), RunParamsList>>;

Args是绑定参数的模板参数列表,RunParamsList是整个函数签名的所有参数列表,DropTypeListItem是怎么计算出来的呢

// Implements `DropTypeListItem`.
template <size_t n, typename List>
  requires is_instantiation<TypeList, List>
struct DropTypeListItemImpl {
  using Type = List;
};

template <size_t n, typename T, typename... List>
  requires(n > 0)
struct DropTypeListItemImpl<n, TypeList<T, List...>>
    : DropTypeListItemImpl<n - 1, TypeList<List...>> {};

// A type-level function that drops `n` list items from a given `TypeList`.
template <size_t n, typename List>
using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;

这里是经典的模板参数列表展开,但是用到了size限制,计算出已经绑定的参数的个数,拆参数包的时候拆掉执行个数,留下的List就是我们需要的未绑定的参数列表了,其中requires是C++20的特性,可以用参数展开和参数个数为0的特化来做替换

template <size_t n, typename List>
struct DropTypeListItemImpl;

template <size_t n, typename T, typename... List>
struct DropTypeListItemImpl<n, TypeList<T, List...>>
    : DropTypeListItemImpl<n - 1, TypeList<List...>> {};

// specialization
template <typename T, typename... List>
struct DropTypeListItemImpl<0, TypeList<T, List...>> {
  using Type = TypeList<T, List...>;
};

template <>
struct DropTypeListItemImpl<0, TypeList<>> {
  using Type = TypeList<>;
};

template <size_t n, typename List>
using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
posted @ 2024-12-02 17:54  leno米雷  阅读(48)  评论(0)    收藏  举报