buffer:可增长的字节存储
Buffer 描述了初始化、添加、查询、容量和释放规则。
Wave Foundation
Buffer的含义
std::buffer::types 中的Buffer 有 data: ptr<u8>、len: i64 和 cap: i64。 len 是初始化和使用中的字节数,cap 是分配的总字节数。始终保持0 <= len <= cap。字符串 NUL 不会自动保证终止。
基本款API
| 模块 | 声明 | 意义 |
|---|---|---|
std::buffer::alloc |
buffer_init(out_buf: ptr<Buffer>, capacity: i64) -> i64 |
初始化新存储库。不要召回已拥有的缓冲区 |
| 相同模块 | buffer_free(buf: ptr<Buffer>) -> i64 |
解除分配。如果成功则为空 |
| 相同模块 | buffer_reserve(buf: ptr<Buffer>, required_cap: i64) -> i64 |
确保最低满负荷。 len 已维护 |
| 相同模块 | buffer_clear(buf: ptr<Buffer>) -> i64 |
维持容量且len=0 |
| 相同模块 | buffer_resize(buf: ptr<Buffer>, new_len: i64, value: u8) -> i64 |
更改长度,用value填充新字节 |
std::buffer::write |
buffer_push(buf: ptr<Buffer>, value: u8) -> i64 |
添加一个字节 |
| 相同模块 | buffer_append(buf: ptr<Buffer>, src: ptr<u8>, size: i64) -> i64 |
size复制并添加字节 |
| 相同模块 | buffer_append_str(buf: ptr<Buffer>, s: str) -> i64 |
添加不包括 NUL 的字符串字节 |
std::buffer::read |
buffer_get(buf: ptr<Buffer>, index: i64, out_value: ptr<u8>) -> i64 |
读取范围内的一个字节 |
状态返回 API 成功时返回 BUFFER_OK(0)。区分错误 INVALID、BOUNDS、OVERFLOW 和 ALLOC 与 std::buffer::error。该数字不解释为 OS errno。 buffer_new 将分配失败表示为空的Buffer,因此当需要区分失败时,请使用buffer_init。
运行示例
import("std::buffer::alloc")::{
Buffer, buffer_init, buffer_free
};
import("std::buffer::write")::{
buffer_append_str, buffer_push
};
import("std::buffer::read")::{
buffer_get
};
fun main() -> i32 {
var data: Buffer;
if (buffer_init(&data, 0) < 0) {
return 1;
}
if (buffer_append_str(&data, "Hi") < 0 || buffer_push(&data, 33) < 0) {
buffer_free(&data);
return 2;
}
var value: u8 = 0;
if (buffer_get(&data, 2, &value) < 0) {
buffer_free(&data);
return 3;
}
println("{} {}", data.len, value);
if (buffer_free(&data) < 0) {
return 4;
}
return 0;
}
执行结果:
3 33
将其保存为main.wave并以wavec run main.wave运行。初始容量为 0 并不是失败,而是有效的空缓冲区。在进一步处理过程中释放空间。
寿命和故障
增加缓冲区可以更改数据。在可能重新分配的操作之后,请勿使用先前借用的地址。复制 Buffer 结构不会重复其分配,因此请为该分配指定一个所有者。
如果失败,buffer_get不会更改输出参数。另一方面,便利函数buffer_at也将错误表示为0,因此使用buffer_get来区分实际的0字节和失败。通过直接更改公共字段来避免创建无效的len/cap。
分别观察长度和容量
reserve 释放存储空间,但不会增加 len。 resize 更改实际使用的长度并将扩展部分初始化为指定字节。 clear 仅将使用的长度设置为 0,允许重复使用分配。
将以下程序保存为main.wave并运行。它不依赖于容量的确切增长倍数;它只是确保您拥有所需的空间。
import("std::buffer::alloc")::{
Buffer,
buffer_init,
buffer_reserve,
buffer_resize,
buffer_clear,
buffer_free
};
fun main() -> i32 {
var data: Buffer;
if (buffer_init(&data, 0) < 0) {
return 1;
}
if (buffer_reserve(&data, 20) < 0) {
buffer_free(&data);
return 2;
}
println("reserved length={}", data.len);
if (buffer_resize(&data, 3, 7) < 0) {
buffer_free(&data);
return 3;
}
println("resized length={} first={}", data.len, deref data.data[0]);
if (buffer_clear(&data) < 0) {
buffer_free(&data);
return 4;
}
println("cleared length={}", data.len);
if (buffer_free(&data) < 0) {
return 5;
}
return 0;
}
执行结果:
reserved length=0
resized length=3 first=7
cleared length=0
当增加到resize时,我们传递了value=7,因此我们看到的所有三个新字节都是7。仅使用reserve保护的空间不会被读取为初始化数据。 cap 将保留在 clear 之后,并且可以再次添加到相同的 Buffer。
区分零字节和查找失败
buffer_get 返回状态并将实际字节写入作为输出参数。即使数据为0,也是正常成功。
import("std::buffer::alloc")::{Buffer, buffer_init, buffer_free};
import("std::buffer::write")::{buffer_push};
import("std::buffer::read")::{buffer_get};
import("std::buffer::error")::{BUFFER_ERR_BOUNDS};
fun main() -> i32 {
var data: Buffer;
if (buffer_init(&data, 0) < 0) {
return 1;
}
if (buffer_push(&data, 0) < 0) {
buffer_free(&data);
return 2;
}
var value: u8 = 99;
if (buffer_get(&data, 0, &value) < 0) {
buffer_free(&data);
return 3;
}
println("stored={}", value);
value = 99;
if (buffer_get(&data, 1, &value) == BUFFER_ERR_BOUNDS) {
println("outside, preserved={}", value);
}
if (buffer_free(&data) < 0) {
return 4;
}
return 0;
}
执行结果:
stored=0
outside, preserved=99
第一次命中为成功,读数为 0,第二次命中为出界失败。即使失败后仍保留value=99,也不意味着它是从缓冲区读取的值。请务必一起检查状态。
练习题:字节累加
要添加数字 0 到 9,请重复 buffer_push 并检查每个结果。将总和存储在i64中,并仅读取范围0 <= index < data.len。处理完缓冲区后,我们在成功和失败路径上调用buffer_free。
import("std::buffer::alloc")::{Buffer, buffer_init, buffer_free};
import("std::buffer::write")::{buffer_push};
fun main() -> i32 {
var data: Buffer;
if (buffer_init(&data, 0) < 0) {
return 1;
}
for (var value: i32 = 0; value < 10; value += 1) {
if (buffer_push(&data, value as u8) < 0) {
buffer_free(&data);
return 2;
}
}
var total: i64 = 0;
for (var index: i64 = 0; index < data.len; index += 1) {
total += deref data.data[index] as i64;
}
println("sum={}", total);
if (buffer_free(&data) < 0) {
return 3;
}
return 0;
}
执行结果:
sum=45