[Chromium] 闭包任务的创建

news/2024/12/2 17:55:32/文章来源:https://www.cnblogs.com/lenomirei/p/18582187

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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/845533.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20222425 2024-2025-1 《网络与系统攻防技术》实验七实验报告

1.实验内容 本周学习内容:本周我们学了web安全的章节,首先我们了解了前端和后端技术,其次我们学习了一些web安全攻防的内容,例如SQL注入和XSS跨站脚本攻击、CSRF以及安全防范的内容。在实验的过程中我们学到了网络欺诈与防范技术。 2.实验过程 主机IP:192.168.35.1 kali(…

基于Bootstrap3的简单柱状图表插件

jchart是一款简单小巧的基于Bootstrap3.x的jquery柱状图表插件。该柱状图片表插件通过简单的设置,就可以生成非常漂亮的水平柱状图,并带有水平和垂直标签以及图表的头部和尾部。 在线演示 下载 使用方法 该jQuery柱状图插件可以通过javascript来调用,也可以直接使用HTML标…

编译OpenCV——jetson嵌入式平台

jetson嵌入式平台的系统为:ubuntu20.04 aarch64 不再研究Ubuntu x64上交叉编译ubuntu aarch64的OpenCV库,因为无法识别到arm的GTK导致编译不进去,最终imshow时会报如下错误:modules/highgui/src/window.cpp:611:error: (-2) The function is not implemented. Rebuild the …

Breakout pg walkthrough Intermediate

nmap ┌──(root㉿kali)-[~/lab] └─# nmap -p- -A 192.168.192.182 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-12-02 04:50 UTC Nmap scan report for 192.168.192.182 Host is up (0.071s latency). Not shown: 65533 closed tcp ports (reset) PORT STATE SE…

从开发者工具转型 AI 呼叫中心,这家 Voice Agent 公司已服务 100+客户

Retell.ai 的 5 位联创。(图:maginative.com)Retell AI 提供一个平台,用于构建和部署可进行自然、类人对话的 AI voice agent,赋能呼叫中心,替代或辅助人工座席。Retell AI 起初为构建 voice agent 产品的开发者提供 API,现已将重点转向为中型企业提供完整的 AI 呼叫中心…

实验5文档部分代码

实验一找到输入数据中的最大值和最小值 指向x[0]输出最大数 可以 实验二80 s1的内存大小和字符串长度 能 s1存储的内容是字符串"Learning makes me happy",而sizeof(s1)返回的是整个指针类型的大小\ 不能 在原始代码中,通过赋值的方式为s1分配内存空间,并初始化其…

IC Compiler II(ICC II)后端设计流程——超详细

Preface 本文中英文结合(学习一些专有名词),主要介绍ICC II软件进行后端设计的主要流程,在阅读之前需要对数字IC设计流程有一定的了解。 逻辑综合相关知识请查看:Synopsys逻辑综合及DesignCompiler的使用(想了解逻辑综合的可以看看这个,但内容较多) 数字IC设计整体流程…

迁移工具简介

迁移工具能有序、安全、便捷、轻松地将数字资产、服务、IT 资源及应用程序部分或完全迁移到天翼云,同时保证云上业务的可用性、安全性以及连续性。支持 x86、 ARM 同构服务器间迁移,覆盖多种主流操作系统、支持信创适配。本文分享自天翼云开发者社区《迁移工具简介》,作者:…

智慧园区算法视频分析服务器如何确保视频监控系统在极端天气下也能稳定运行?

在面对极端天气条件时,确保智慧园区算法视频分析服务器的稳定运行对于维持关键监控系统的连续性和数据安全性至关重要。以下是一系列措施,旨在保障视频监控系统在诸如暴雨、高温、暴雪等恶劣天气条件下的可靠性和有效性。通过实施这些策略,我们可以最大程度地减少极端天气对…

Docker常用应用之稍后阅读

1.简介 wallabag是一款开源的,可以自托管的稍后阅读工具。提供了浏览器插件和手机客户端,可以很方便的收藏文章用于稍后再看。 wallabag官网,wallabag github地址,wallabag dockerhub 2.部署 2.1.docker部署 cd /docker_data/ mkdir -p wallabag/data cd wallabag vi docke…

css 边框镶角

效果图:background: linear-gradient(to left, yellow, yellow) left top no-repeat,linear-gradient(to bottom, yellow, yellow) left top no-repeat,linear-gradient(to left, yellow, yellow) right top no-repeat,linear-gradient(to bottom, yellow, yellow) right top …

go语言常见cache库

摘自 https://zhuanlan.zhihu.com/p/624248354