LuaJIT 学习(5)—— string.buffer 库
文章目录
- Using the String Buffer Library
- Buffer Objects
- Buffer Method Overview
- Buffer Creation and Management
- `local buf = buffer.new([size [,options]]) local buf = buffer.new([options])`
- `buf = buf:reset()`
- `buf = buf:free()`
- Buffer Writers
- `buf = buf:put([str|num|obj] [,…])`
- `buf = buf:putf(format, …)`
- `buf = buf:putcdata(cdata, len)`FFI
- `buf = buf:set(str) `
- `buf = buf:set(cdata, len)`FFI
- `ptr, len = buf:reserve(size)`FFI
- `buf = buf:commit(used)`FFI
- Buffer Readers
- `len = #buf`
- `res = str|num|buf .. str|num|buf […]`
- `buf = buf:skip(len)`
- `str, … = buf:get([len|nil] [,…])`
- `str = buf:tostring() `
- `str = tostring(buf)`
- `ptr, len = buf:ref()`FFI
- Serialization of Lua Objects
- 例子:序列化 Lua 对象
- Error handling
- FFI caveats
- 例子说明:
The string buffer library allows high-performance manipulation of string-like data.
Unlike Lua strings, which are constants, string buffers are mutable sequences of 8-bit (binary-transparent) characters. Data can be stored, formatted and encoded into a string buffer and later converted, extracted or decoded.
The convenient string buffer API simplifies common string manipulation tasks, that would otherwise require creating many intermediate strings. String buffers improve performance by eliminating redundant memory copies, object creation, string interning and garbage collection overhead. In conjunction with the FFI library, they allow zero-copy operations.
The string buffer library also includes a high-performance serializer for Lua objects.
Using the String Buffer Library
The string buffer library is built into LuaJIT by default, but it’s not loaded by default. Add this to the start of every Lua file that needs one of its functions:
local buffer = require("string.buffer")
The convention for the syntax shown on this page is that buffer refers to the buffer library and buf refers to an individual buffer object.
Please note the difference between a Lua function call, e.g. buffer.new() (with a dot) and a Lua method call, e.g. buf:reset() (with a colon).
Buffer Objects
A buffer object is a garbage-collected Lua object. After creation with buffer.new(), it can (and should) be reused for many operations. When the last reference to a buffer object is gone, it will eventually be freed by the garbage collector, along with the allocated buffer space.
Buffers operate like a FIFO (first-in first-out) data structure. Data can be appended (written) to the end of the buffer and consumed (read) from the front of the buffer. These operations may be freely mixed.
The buffer space that holds the characters is managed automatically — it grows as needed and already consumed space is recycled. Use buffer.new(size) and buf:free(), if you need more control.
The maximum size of a single buffer is the same as the maximum size of a Lua string, which is slightly below two gigabytes. For huge data sizes, neither strings nor buffers are the right data structure — use the FFI library to directly map memory or files up to the virtual memory limit of your OS.
Buffer Method Overview
- The
buf:put*()-like methods append (write) characters to the end of the buffer. - The
buf:get*()-like methods consume (read) characters from the front of the buffer. - Other methods, like
buf:tostring()only read the buffer contents, but don’t change the buffer. - The
buf:set()method allows zero-copy consumption of a string or an FFI cdata object as a buffer. - The FFI-specific methods allow zero-copy read/write-style operations or modifying the buffer contents in-place. Please check the FFI caveats below, too.
- Methods that don’t need to return anything specific, return the buffer object itself as a convenience. This allows method chaining, e.g.:
buf:reset():encode(obj)orbuf:skip(len):get()
Buffer Creation and Management
local buf = buffer.new([size [,options]]) local buf = buffer.new([options])
Creates a new buffer object.
The optional size argument ensures a minimum initial buffer size. This is strictly an optimization when the required buffer size is known beforehand. The buffer space will grow as needed, in any case.
The optional table options sets various serialization options.
buf = buf:reset()
Reset (empty) the buffer. The allocated buffer space is not freed and may be reused.
buf = buf:free()
The buffer space of the buffer object is freed. The object itself remains intact, empty and may be reused.
Note: you normally don’t need to use this method. The garbage collector automatically frees the buffer space, when the buffer object is collected. Use this method, if you need to free the associated memory immediately.
Buffer Writers
buf = buf:put([str|num|obj] [,…])
Appends a string str, a number num or any object obj with a __tostring metamethod to the buffer. Multiple arguments are appended in the given order.
Appending a buffer to a buffer is possible and short-circuited internally. But it still involves a copy. Better combine the buffer writes to use a single buffer.
buf = buf:putf(format, …)
Appends the formatted arguments to the buffer. The format string supports the same options as string.format().
buf = buf:putcdata(cdata, len)FFI
Appends the given len number of bytes from the memory pointed to by the FFI cdata object to the buffer. The object needs to be convertible to a (constant) pointer.
buf = buf:set(str)
buf = buf:set(cdata, len)FFI
This method allows zero-copy consumption of a string or an FFI cdata object as a buffer. It stores a reference to the passed string str or the FFI cdata object in the buffer. Any buffer space originally allocated is freed. This is not an append operation, unlike the buf:put*() methods.
After calling this method, the buffer behaves as if buf:free():put(str) or buf:free():put(cdata, len) had been called. However, the data is only referenced and not copied, as long as the buffer is only consumed.
In case the buffer is written to later on, the referenced data is copied and the object reference is removed (copy-on-write semantics).
The stored reference is an anchor for the garbage collector and keeps the originally passed string or FFI cdata object alive.
ptr, len = buf:reserve(size)FFI
buf = buf:commit(used)FFI
The reserve method reserves at least size bytes of write space in the buffer. It returns an uint8_t * FFI cdata pointer ptr that points to this space.
The available length in bytes is returned in len. This is at least size bytes, but may be more to facilitate efficient buffer growth. You can either make use of the additional space or ignore len and only use size bytes.
The commit method appends the used bytes of the previously returned write space to the buffer data.
This pair of methods allows zero-copy use of C read-style APIs:
local MIN_SIZE = 65536
repeatlocal ptr, len = buf:reserve(MIN_SIZE)local n = C.read(fd, ptr, len)if n == 0 then break end -- EOF.if n < 0 then error("read error") endbuf:commit(n)
until false
The reserved write space is not initialized. At least the used bytes must be written to before calling the commit method. There’s no need to call the commit method, if nothing is added to the buffer (e.g. on error).
Buffer Readers
len = #buf
Returns the current length of the buffer data in bytes.
res = str|num|buf .. str|num|buf […]
The Lua concatenation operator .. also accepts buffers, just like strings or numbers. It always returns a string and not a buffer.
Note that although this is supported for convenience, this thwarts one of the main reasons to use buffers, which is to avoid string allocations. Rewrite it with buf:put() and buf:get().
Mixing this with unrelated objects that have a __concat metamethod may not work, since these probably only expect strings.
buf = buf:skip(len)
Skips (consumes) len bytes from the buffer up to the current length of the buffer data.
str, … = buf:get([len|nil] [,…])
Consumes the buffer data and returns one or more strings. If called without arguments, the whole buffer data is consumed. If called with a number, up to len bytes are consumed. A nil argument consumes the remaining buffer space (this only makes sense as the last argument). Multiple arguments consume the buffer data in the given order.
Note: a zero length or no remaining buffer data returns an empty string and not nil.
str = buf:tostring()
str = tostring(buf)
Creates a string from the buffer data, but doesn’t consume it. The buffer remains unchanged.
Buffer objects also define a __tostring metamethod. This means buffers can be passed to the global tostring() function and many other functions that accept this in place of strings. The important internal uses in functions like io.write() are short-circuited to avoid the creation of an intermediate string object.
ptr, len = buf:ref()FFI
Returns an uint8_t * FFI cdata pointer ptr that points to the buffer data. The length of the buffer data in bytes is returned in len.
The returned pointer can be directly passed to C functions that expect a buffer and a length. You can also do bytewise reads (local x = ptr[i]) or writes (ptr[i] = 0x40) of the buffer data.
In conjunction with the skip method, this allows zero-copy use of C write-style APIs:
repeatlocal ptr, len = buf:ref()if len == 0 then break endlocal n = C.write(fd, ptr, len)if n < 0 then error("write error") endbuf:skip(n)
until n >= len
Unlike Lua strings, buffer data is not implicitly zero-terminated. It’s not safe to pass ptr to C functions that expect zero-terminated strings. If you’re not using len, then you’re doing something wrong.
Serialization of Lua Objects
略过
例子:序列化 Lua 对象
local buffer = require("string.buffer")-- 创建一个元表
local mt1 = { __index = function(t, k) return "default" end }
local mt2 = { __index = function(t, k) return "another default" end }-- 创建需要序列化的表
local t1 = setmetatable({ key1 = "value1", key2 = "value2" }, mt1)
local t2 = setmetatable({ key1 = "value3", key2 = "value4" }, mt2)-- 定义字典和元表的数组
local dict = {"key1", "key2"}
local metatable = {mt1, mt2}-- 使用 buffer.new() 进行序列化
local buffer_obj = buffer.new({dict = dict,metatable = metatable
})-- 假设序列化后的数据为序列化函数 `encode()`
local serialized_data = buffer_obj:encode({t1, t2})-- 反序列化
local decoded_data = buffer_obj:decode(serialized_data)-- 访问解码后的数据
for _, tbl in ipairs(decoded_data) doprint(tbl.key1, tbl.key2)
end
Error handling
Many of the buffer methods can throw an error. Out-of-memory or usage errors are best caught with an outer wrapper for larger parts of code. There’s not much one can do after that, anyway.
OTOH, you may want to catch some errors individually. Buffer methods need to receive the buffer object as the first argument. The Lua colon-syntax obj:method() does that implicitly. But to wrap a method with pcall(), the arguments need to be passed like this:
local ok, err = pcall(buf.encode, buf, obj)
if not ok then-- Handle error in err.
end
FFI caveats
The string buffer library has been designed to work well together with the FFI library. But due to the low-level nature of the FFI library, some care needs to be taken:
First, please remember that FFI pointers are zero-indexed. The space returned by buf:reserve() and buf:ref() starts at the returned pointer and ends before len bytes after that.
I.e. the first valid index is ptr[0] and the last valid index is ptr[len-1]. If the returned length is zero, there’s no valid index at all. The returned pointer may even be NULL.
The space pointed to by the returned pointer is only valid as long as the buffer is not modified in any way (neither append, nor consume, nor reset, etc.). The pointer is also not a GC anchor for the buffer object itself.
Buffer data is only guaranteed to be byte-aligned. Casting the returned pointer to a data type with higher alignment may cause unaligned accesses. It depends on the CPU architecture whether this is allowed or not (it’s always OK on x86/x64 and mostly OK on other modern architectures).
FFI pointers or references do not count as GC anchors for an underlying object. E.g. an array allocated with ffi.new() is anchored by buf:set(array, len), but not by buf:set(array+offset, len). The addition of the offset creates a new pointer, even when the offset is zero. In this case, you need to make sure there’s still a reference to the original array as long as its contents are in use by the buffer.
例子说明:
- 正常的引用:当你使用
buf:set(array, len)时,这个array是一个通过 FFI 创建的数组,它会被作为buf的参数传递进去。在这种情况下,array被引用,并且只要buf依然存在并持有这个引用,array不会被垃圾回收器回收。这里array是一个“垃圾回收锚点”(GC anchor),即它会被垃圾回收器追踪。 - 添加偏移量后的情况:当你通过
array + offset创建一个新的指针时(即通过加偏移量来引用array中的某个元素),这时创建的是一个新的指针对象。即使offset为零,array + offset仍然会被视为一个新的指针。这个新的指针不会自动被垃圾回收器追踪,因为它并没有直接引用array。- 问题:这意味着,如果你只使用
array + offset(即偏移后的指针),垃圾回收器可能会认为原始的array对象不再被使用,最终回收掉array,即使buf仍然依赖于它的内容。这会导致访问已回收的内存,造成未定义行为或崩溃。
- 问题:这意味着,如果你只使用
Even though each LuaJIT VM instance is single-threaded (but you can create multiple VMs), FFI data structures can be accessed concurrently. Be careful when reading/writing FFI cdata from/to buffers to avoid concurrent accesses or modifications. In particular, the memory referenced by buf:set(cdata, len) must not be modified while buffer readers are working on it. Shared, but read-only memory mappings of files are OK, but only if the file does not change.
相关文章:
LuaJIT 学习(5)—— string.buffer 库
文章目录 Using the String Buffer LibraryBuffer ObjectsBuffer Method Overview Buffer Creation and Managementlocal buf buffer.new([size [,options]]) local buf buffer.new([options])buf buf:reset()buf buf:free() Buffer Writersbuf buf:put([str|num|obj] [,……...
qt介绍图表 charts 一
qt chartsj基于Q的Graphics View框架,其核心组件是QChartView和QChart.QChartView是一个显示图表的独立部件,基类为QGraphicsView.QChar类管理图表的序列,图例和轴示意图。 绘制一个cos和sin曲线图,效果如下 实现代码 #include…...
Transformer:GPT背后的造脑工程全解析(含手搓过程)
Transformer:GPT背后的"造脑工程"全解析(含手搓过程) Transformer 是人工智能领域的革命性架构,通过自注意力机制让模型像人类一样"全局理解"上下文关系。它摒弃传统循环结构,采用并行计算实现高…...
S32K144入门笔记(十):TRGMUX的初始化
目录 1. 概述 2. 代码配置 1. 概述 书接上回,TRGMUX本质上是一个多路选择开关,根据用户手册中的描述,它可以实现多个输入的选择输出,本篇文章将验证如何通过配置工具来生成初始化配置代码。 2. 代码配置 笔者通过配置TRGMUX实现…...
有了大模型为何还需要Agent智能体
一、什么是Agent? Agent(智能体) 是一种能感知环境、自主决策、执行动作的智能实体,当它与大语言模型(如通义千问QWen、GPT)结合时,形成一种**“增强型AI系统”**。其核心架构如下:…...
DNS主从服务器
1.1环境准备 作用系统IP主机名web 服务器redhat9.5192.168.33.8webDNS 主服务器redhat9.5192.168.33.18dns1DNS 从服务器redhat9.5192.168.33.28dns2客户端redhat9.5192.168.33.7client 1.2修改主机名和IP地址 web服务器 [rootweb-8 ~]# hostnamectl hostname web [rootweb-8…...
Flume详解——介绍、部署与使用
1. Flume 简介 Apache Flume 是一个专门用于高效地 收集、聚合、传输 大量日志数据的 分布式、可靠 的系统。它特别擅长将数据从各种数据源(如日志文件、消息队列等)传输到 HDFS、HBase、Kafka 等大数据存储系统。 特点: 可扩展࿱…...
一个简单的 **猜数字游戏** 的 C 语言例程
一个简单的 猜数字游戏 的 C 语言例程,代码包含详细注释,适合学习和练习基础语法: #include <stdio.h> #include <stdlib.h> #include <time.h> // 用于生成随机数种子int main() {int target, guess, attempts 0;srand…...
解决diffusers加载stablediffusion模型,输入prompt总是报错token数超出clip最大长度限制
1. StableDiffusion1.5 在加载huggingface中的扩散模型时,输入prompt总是会被报错超过clip的最大长度限制。 解决方案:使用compel库 from diffusers import AutoPipelineForText2Image import torch import pdb from compel import Compeldevice torc…...
mysql-查看binlog日志
mysql目前binlog_format默认是row格式, 找到binlog日志文件,通过命令查看 >mysqlbinlog binlog日志路径内容大致如下: /*!*/; # at 1163 #250317 14:13:43 server id 1 end_log_pos 1194 CRC32 0x09c8bcfd Xid 14 COMMIT/*!*…...
【Linux系列】文件压缩
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
微服务架构中10个常用的设计模式
在当今的微服务架构中,常见的十种设计模式,分别是服务发现模式、API网关模式、断路器模式、边车模式、负载均衡模式、Saga事务模式、CQRS模式、分片模式、分布式日志跟踪模式、熔断与降级模式 。其中,服务发现模式十分关键,通过…...
Vue3组件+leaflet,实现重叠marker的Popup切换显示
一、前言 GIS开发过程中,经常需要绘制marker,这些marker很大概率会有坐标相同导致的叠加问题,这种情况下会降低使用体验感。所以我们可以将叠加的marker的popup做一个分页效果,可以切换显示的marker。 二、技术要点 我们以leaf…...
将COCO格式的物体检测数据集划分训练集、验证集和测试集
目录 导入所需库 定义数据集路径 创建输出目录 读取JSON注释文件 随机打乱图像列表 计算划分大小 复制图像到相应文件夹 完整代码 导入所需库 我们需要以下Python库: os:处理文件路径。 json:读取和写入JSON文件。 numpyÿ…...
机器学习之距离度量方法
常见的距离度量方法及相关函数、图示如下: 1. 欧几里得距离(Euclidean Distance) 函数公式:对于两个 ( n ) 维向量 ( x = ( x 1 , x 2 , ⋯ ,...
3.1 在VisionPro脚本中添加CogGraphicLabel
本案例需要实现如下功能: 1.加载toolBlock 2.加载图片, 3.运行Block 4.VisionPro中添加脚本显示数值。 见下图:详细代码(C#以及visionPro)见下面链接: https://download.csdn.net/download/qq_340474…...
自动化APP测试APPium的元素等待
在使用Appium进行移动应用自动化测试时,有三种等待。 隐式等待driver.implicitly_wait() 显式等待(常用) time.sleep() 隐式等待(Implicit Wait) 应用场景: 当你希望对所有元素定位操作设置统一的超时…...
AI:Machine Learning Data Science
机器学习与数据科学 左侧 机器学习 Machine Learning 机器学习是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知…...
软件需求分类、需求获取(高软46)
系列文章目录 软件需求分类,需求获取 文章目录 系列文章目录前言一、软件需求二、获取需求三、真题总结 前言 本节讲明软件需求分类、需求获取的相关知识。 一、软件需求 二、获取需求 三、真题 总结 就是高软笔记,大佬请略过!...
vue3vue-elementPlus-admin框架中form组件的upload写法
dialog中write组件代码 let ImageList reactive<UploadFile[]>([])const formSchema reactive<FormSchema[]>([{field: ImageFiles,label: 现场图片,component: Upload,colProps: { span: 24 },componentProps: {limit: 5,action: PATH_URL /upload,headers: {…...
嵌入式Linux | 什么是 BootLoader、Linux 内核(kernel)、和文件系统?
01 什么是 BootLoader 呢? 它是个引导程序,也就是硬件复位以后第一个要执行的程序,它主要工作就是初始化操作系统运行的环境,比如说内存、定时器、缓冲器等,当这个工作做完以后,再把操作系统的代码加载…...
【ARM中R0寄存器】
ARM中R0寄存器 1 RO介绍1.1 R0 的主要作用1 函数返回值2 函数参数3 通用寄存器4 与其他寄存器的区别 1.2 示例 1 RO介绍 在ARM架构中,R0寄存器是一个通用寄存器;是16 个通用寄存器(R0 到 R15)中的第一个,通常用于存储…...
【JDK17】Jlink一秒生成精简的JRE
之前介绍了 Java17模块化的JDK,模块化后按需使用Jlink 用于精简生成 JRE 环境,这让快速的开发环境增强了编码的愉悦感。在实际生产环境中使用 mave 进行项目的构建,其次再是精简 JRE 缩小容器镜像体积,为实现一体化的流程…...
【第9章】亿级电商平台订单系统-整体技术架构设计
1-1 本章导学 课程主题:系统蓝图描绘与整体技术架构设计核心学习内容: ▶️ 订单系统的整体技术架构设计 ▶️ 架构设计核心方法论与实践应用本章核心内容架构 1. 技术预研 架构设计的基础支撑环节关键技术可行性分析与选型依据2. 整体技术架构设计方法与步骤 结构化设计方法…...
函数(函数的概念、库函数、自定义函数、形参和实参、return语句、数组做函数参数、嵌套调用和链式访问、函数的声明和定义、static和extern)
一、函数的概念 •C语⾔中的函数:⼀个完成某项特定的任务的⼀⼩段代码 •函数又被翻译为子函数(更准确) •在C语⾔中我们⼀般会⻅到两类函数:库函数 ⾃定义函数 二、库函数 1 .标准库和头文件 •C语⾔的国际标准ANSIC规定了⼀…...
AGI大模型(6):提示词模型进阶
1 零样本提示 如今,经过⼤量数据训练并调整指令的LLM能够执⾏零样本任务。 代码如下: from openai import OpenAI from dotenv import load_dotenv load_dotenv() # 初始化 OpenAI 服务。 client = OpenAI()prompt = """ 将⽂本分类为中性、负⾯或正⾯。 ⽂…...
ImGui 学习笔记(五) —— 字体文件加载问题
ImGui 加载字体文件的函数似乎存在编码问题,这一点可能跟源文件的编码也有关系,我目前源文件编码是 UTF-16。 当参数中包含中文字符时,ImGui 内部将字符转换为宽字符字符集时候,采用的 MultiByteToWideChar API 参数不太对&#…...
OpenCV计算摄影学(20)非真实感渲染之增强图像的细节函数detailEnhance()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 此滤波器增强特定图像的细节。 cv::detailEnhance用于增强图像的细节,通过结合空间域和频率域的处理,提升图像中特定细节…...
Android PC 要来了?Android 16 Beta3 出现 Enable desktop experience features 选项
在之前的 《Android 桌面窗口新功能推进》 我们就聊过,Google 就一直在努力改进 Android 的内置桌面模式,例如添加了适当的窗口标题、捕捉窗口的能力、悬停选项、窗口大小调整、最小化支持、app-to-web 等。 比如在搭载 Android 15 QPR 1 Beta 2 的 Pix…...
数据集格式转换——json2txt、xml2txt、txt2json【复制就能用】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏地址:YOLO11入门 + 改进涨点——点击即可跳转 欢迎订阅 目录 json2txt脚本 xml2txt txt2json...
