1.掩码简介
2.Linux C/C++源码实现常见命令mkdir
3.UE4-Slate源码学习(六)slate渲染Part2-Paint控件绘制
4.BitMask 位掩码浅析
5.bert源码解析
掩码简介
掩码,源码实质上是转掩一个二进制代码序列,它通过与目标字段进行位与操作,源码对输入的转掩位进行控制和筛选。这种操作在计算机编程中扮演着重要角色,源码主要用于数据处理和字段选择。转掩指标源码专栏
它的源码主要应用是通过位运算,如按位或(OR)和按位与(AND)等,转掩对源代码进行转换或处理。源码例如,转掩在ASCII码的源码处理中,掩码可以用来实现字符大小写的转掩转换。通过与特定掩码进行位与运算,源码可以保留需要的转掩字符信息,同时屏蔽或改变其他位,源码从而实现字符大小写的切换。
掩码操作直观且高效,常用于数据处理的各个环节,如数据校验、数据隐藏、字段提取等,是程序员在编程中的一项重要技能。通过巧妙运用掩码,可以简化复杂的数据处理过程,提高代码的可读性和效率。
Linux C/C++源码实现常见命令mkdir
Linux系统的结构由文件和目录构成。在使用过程中,我们经常需要创建目录来存储各类文件。此时,我们会使用Linux系统的内置命令mkdir,该命令用于在操作系统中创建目录或文件夹。本文将探讨如何使用具有不同命令行选项的mkdir命令及其代码实现。
mkdir命令代码实现
在Linux系统中,美聊Mei源码虽然可以使用rm命令删除目录,但首先需要使用mkdir命令来创建目录。下面是mkdir命令的实现方法:
编译运行:
my_mkdir将创建一个名为path的新目录。新目录的文件权限位将从模式初始化,mode参数的这些文件权限位将由进程的文件创建掩码修改。
mkdir代码实现相对简单,主要用于在Linux操作系统中创建目录。通过代码实现创建目录后,我们可以使用选项来查看其效果。
创建多目录
当需要创建多个目录时,只需指定要创建的目录名称。需要注意的是,在创建多个目录时,需要在目录名称之间添加空格。以下是一个创建多个目录的示例命令:
./my_mkdir aaa bbb ccc
创建父目录
./my_mkdir a/b
上述命令将在目录a中创建名为b的目录。如果目录a不存在,则会显示错误信息。
如果父目录不存在,可以使用-p选项创建它。如果目录a不存在,mkdir命令将创建目录a,并在目录a内创建一个名为b的目录。
如何在详细模式下创建目录?
我们可以使用-v选项以详细模式创建新目录。当使用此选项创建新目录时,它将在屏幕中生成以下详细输出。
总结
通过代码实现mkdir命令,并结合各种命令行选项使用。本文展示了mkdir命令的简单性和易用性。
UE4-Slate源码学习(六)slate渲染Part2-Paint控件绘制
上一篇文章介绍了绘制一个SWindow的初期步骤,即计算整个UI树的控件大小,为绘制做准备。文章随后深入探讨了绘制流程的临安到留下源码第二步,即执行FSlateApplication::PrivateDrawWindows()后,开始调用SWidget::Paint()函数,每个控件随后实现其虚函数OnPaint()。
在这一过程中,绘制参数被封装在FPaintArgs中,作为Paint和OnPaint过程中的关键引用参数。FSlateRHIRenderer与FSlateDrawBuffer是继承自FSlateRenderer的类,作为FSlateApplicationBase的全局变量,在构造时创建。在绘制过程中,通过GetDrawBuffer()函数可获取到FSlateDrawBuffer对象。
FSlateDrawBuffer实现了Slate的绘制缓冲区,内部封装了FSlateWindowElementList数组,用于存储多个SWindow下的绘制元素列表。每个SWindow通过AddWindowElementList()返回一个元素列表。
FSlateWindowElementList负载了SWindow内的所有图元信息,内部封装了FSlateDrawElement的数组,包含Cached和Uncached元素,以及SWindow的指针和用于渲染的批处理数据FSlateBatchData。
FSlateDrawElement是构建Slate渲染界面的基本块,封装了UI树节点控件需要渲染的相关信息,如渲染变换、位置、大小、层级ID、绘制效果等,以及后续渲染阶段需要的相关数据。
在Paint流程中,处理当前传入的SWindow和ChildWindows,首先判断窗口是否可见和是否最小化,然后从参数封装的OutDrawBuffer中获取WindowElementList。调用SWindow的游戏代理源码版本PaintWindow()函数开始绘制窗口,并最终返回所有子控件计算完的最大层级。接着,子窗口递归绘制。
PaintWindow()函数在绘制窗口时,首先调用SetHittestArea()设置点击区域,HittestGrid会判断窗口大小是否改变,若不变则仅更新窗口在屏幕中的位置。构造FPaintArgs参数后,将其封装到FSlateInvalidationContext中。
FSlateInvalidationRoot类的PaintInvalidationRoot()函数可以作为控件树的根节点或叶子节点(SInvalidationPanel),构建快速路径避免每次绘制都计算大小和Paint函数,有利于优化。本篇文章主要分析正常慢速路径调用流程,优化相关将另文分析。
PaintSlowPath()函数从SWindow开始调用Paint()函数,并定义LayerId从0开始作为参数,进行实际的绘制相关计算。
Paint()函数首先处理裁剪、透明度混合、坐标转换等代码。若SWidget包含NeedsTick掩码,则调用Tick函数,我们在日常开发中通过蓝图或lua使用Tick函数时即调用到这里,通过SObjectWidget::Tick调用到UUserWidget::NativeTick供实现Tick。构造FSlateWidgetPersistentState PersistentState作为SWidget的变量,表示Paint时的状态。
PersistentState.CachedElementHandle将当前SWidget存储到FSlateWindowElementList中的WidgetDrawStack数组中。
更新FPaintArgs中的父节点参数和继承可点击测试参数,判断点击测试状态,然后将当前SWidget添加到点击测试中。调用虚函数OnPaint,由控件自己实现。白宫网站源码下载
OnPaint()函数参数包括绘制参数引用、几何体、裁剪矩形、缓冲元素列表、层级、控件风格、父节点状态等。最后处理重绘标签、延迟绘制相关内容、UpdateWidgetProxy()根据缓存句柄更新快速路径中需要处理标记设置为Volatile不稳定状态的SWidget。
虚函数OnPaint()由子类自己实现,本文列举了SImage、SButton、SCompoundWidget和SConstraintCanvas的OnPaint()示例代码学习。
在SImage中,简单判断Brush是否存在以及BrushDrawType的类型,然后调用FSlateDrawElement::MakeBox将控件添加到缓冲区元素列表中。
SButton继承自SCompoundWidget,GetBorder()根据当前按钮状态返回ui中设置的Enabled、Press、Hover、Disabled等状态的Brush。
SCompoundWidget作为合成节点,有且只能有一个子节点,且在Paint时强制将子节点的LayerId+1,同时SCompoundWidget可以单独设置混合颜色和透明度,影响子节点。
SConstraintCanvas作为SWidget的基类对应UMG中常用的UCanvasPanel,通过ArrangeLayeredChildren()对孩子进行层级排序,并根据孩子的层级是否相同存储bool值在ChildLayers中。遍历所有孩子,判断是否开启新层级,递归调用Paint函数,最后返回最大层级。
SConstraintCanvas::ArrangeLayeredChildren函数中,获取设置bExplicitChildZOrder,表示可以将同层一次渲染,有利于提高渲染器批处理。对所有孩子排序,排序规则为FSortSlotsByZOrder。遍历所有孩子,判断可见性掩码、计算偏移、锚点、位置、拉伸缩放等,封装成FArrangedWidget存储到ArrangedChildren中,用于OnPaint时有序遍历。判断每个孩子ZOrder是否相同,相同则bNewLayer为false,大于LastZOrder则将bNewLayer设置为true,最终存储到ArrangedChildLayers中,用于OnPaint函数判断是否将layerId+1。
FSlateDrawElement::MakeBox()函数在OnPaint之后调用,将绘制控件的相关信息通过创建FSlateDrawElement绘制元素对象,添加到SWindow管理的FSlateWindowElementList元素列表中。创建Payload用于存储贴图等相关信息,根据控件Paint过程中的参数调用Element.Init初始化绘制元素,得到为该控件绘制创建的FSlateDrawElement对象。
总结整个Slate绘制流程的第二步,我们没有分析快速处理和优化细节,而是按照正常绘制流程分析代码。通过从PaintWindow开始遍历整个控件树,处理每个空间节点的Paint、OnPaint函数,最终目的是给每个控件创建一个FSlateDrawElement对象,存储渲染线程绘制所需的相关信息,并添加到FSlateWindowElementList中。理解了整个调用流程,整个过程较为清晰,本文基于UE4版本4..2。
BitMask 位掩码浅析
理解 BitMask 在代码中的应用,如在 React-DOM 源码中的检查掩码方法所示,其背后的逻辑和作用需从基础开始解读。首先,让我们深入探讨按位与运算的原理。
按位与运算,指的是对两个操作数进行二进制位的“与”运算,负数则以补码形式参与运算。运算遵循“两位同时为1,结果为1,否则为0”的规则。以示例说明,例如的二进制表示为,的二进制表示为,按位与运算结果为。
接着,我们探讨位掩码的用途。在OA系统中,假设功能包括增、删、改、查。用对象定义用户权限时,实现直观且清晰。然而,利用位掩码,我们能够以更紧凑的方式表示功能组合。比如,用整数的不同位表示不同的权限。
采用位掩码的益处在于,它有助于设置状态,并对状态进行高效查询、增加和清除操作。代码简洁性显著提升,且二进制运算速度极快。
bert源码解析
训练数据生成涉及将原始文章语料转化为训练样本,这些样本按照目标(如Mask Language Model和Next Sentence Prediction)被构建并保存至tf_examples.tfrecord文件。此过程的核心在于函数create_training_instances,它接受原始文章作为输入,输出为训练instance列表。在这一过程中,文章首先被分词,随后通过create_instances_from_document函数构建具体训练实例。构建实例流程如下:
确定最大序列长度后,Next Sentence Prediction任务被构建。选取文章的开始位置至结尾,确保生成的句子集长度至少等于最大序列长度。在此集合中随机挑选一个位置(a_end),将句子集分为两部分:前部分作为序列A,而后部分有%的概率成为序列B,剩余%则随机选择另一篇文章的句子集(总长度不小于「max_seq_length-序列A」),形成Next Sentence Prediction任务。
Mask language model任务构建通过将序列A和序列B组合成一个训练序列tokens,并对其进行掩码操作实现。掩码操作以token为单位,利用WordPiece进行分词,确保全词掩码模式下的整体性,无论是全掩码还是全不掩码。每个序列以masked_lm_prob(0.)概率进行掩码,对于被掩码的token,%情况下替换为[MASK],%保持不变,%则替换为词表中随机选择的单词。返回结果包括掩码操作后的序列、掩码token索引及真实值。
训练样本结构由上述处理后形成,每条样本包含经过掩码操作的序列、掩码token的索引及真实值。
分词器包括全词分词器(FullTokenizer),它首先使用BasicTokenizer进行基础分词,包括小写化、按空格和标点符号分词,以及中文的字符分词,随后使用WordpieceTokenizer基于词表文件对分词后的单词进行WordPiece分词。
模型结构从输入开始,经过BERT配置参数,包括WordEmbedding、初始化embedding_table、embedding_postprocessor等步骤,最终输出sequence和pooled out结果。WordEmbedding负责将输入token(input_ids)转换为其对应的embedding,包括token embedding、segment embedding和position embedding。embedding_postprocessor在得到的token embedding上加上position embedding和segment embedding,然后进行layer_norm和dropout处理。
Transformer Model中的attention mask根据input_mask构建,用于计算attention score。self attention过程包括query、key、value层的生成,query与key相乘得到attention score,经过归一化处理,并结合attention_mask和dropout,形成输出向量context_layer。随后是feed forward过程,包括两个网络层:中间层(intermediate_size,激活函数gelu)和输出层(hidden_size,无激活函数)。
sequence和pooled out分别代表最后一层的序列向量和[CLS]向量的全连接层输出,维度为hidden_size,激活函数为tanh。
训练过程基于BERT产生的序列向量和[CLS]向量,分别训练Mask Language Model和Next Sentence Prediction。Mask Language Model训练通过get_masked_lm_output函数,主要输入为序列向量、embedding table和mask token的位置及真实标签,输出为mask token的损失。Next Sentence Predication训练通过get_next_sentence_output函数,本质为一个二分类任务,通过全连接网络将[CLS]向量映射,计算交叉熵作为损失。