官方库 · std 与 host
先说清一件事:Loment 语言本身没有标准库。语言里只有内建函数(alloc / load8 / str_* / syscall4 那一组,二十来个),没有 String、没有 Vec、没有 HashMap。下面这些是一个库——和你能写的那个库是同一种东西,只是它是官方维护的。
所以它没有特权:依赖一样从源码的 use 来,身份一样是内容哈希,选版一样只有「版本最大」一条规则。它是库系统的第一个大用户,也是Lompi 的第一个大输入。
127 个模块这个数不是估的:一个包入口 std.lomt,里面 127 条 use,加上它自己就是 128 个文件。
为什么是两个包,不是一个
| 包 | 内容 | 发不发 syscall |
|---|---|---|
std · 0.1.0 |
127 个模块:数值、容器、文本、摘要、压缩、编解码、图像、时间 | 一个都不发 |
host · 0.1.0 |
7 个模块:argv · dir · fs · io · log · stat · 包入口 |
发(getdents64 / openat / newfstatat 这类) |
依赖方向是单向的:host → std → numfmt,反不过来。这条方向是刻意的,不是碰巧——裸机、无宿主、或者只想要一段 CRC 的消费者,只依赖 std,不会把 getdents64 和目录遍历一起拖进二进制。基础内建之外最底下的那一层是 numfmt(整数转文本),它上面才长别的。
一句话:把「需要操作系统的」和「不需要的」分成两个包,是为了让后者能去没有操作系统的地方。
怎么用它
消费方在源码里写依赖——没有别的清单要维护。库里公开的名字带前缀(math_gcd / crc32_str / out_str),因为发射出来的符号名是平的,一个单元里顶层名字必须唯一。
module consumer
use std
fn _start() {
let b: ptr = alloc(256);
let o: u32 = 0;
o = out_str(b, o, "gcd=");
o = out_dec(b, o, math_gcd(12, 18) as u64);
...
}
use,以及名字形式的搜索只认仓库相对的四个根——于是装在用户机器上(没有仓库)时 use std 一个都找不到。Pre1 把这两条都改了:条数上限提到 300(超了报 E020),搜索改成三层(① <项目根>/deps/ ② 工具链自带的 store ③ 内置四根)。但
use std 仍然编不过。拿装好的 Pre2 实测:它找得到 std(名字写错是立刻报「找不到或有歧义」的,写 std 不报),然后真的把整个包装进来——耗时 9 分 4 秒(同一台机器上一个普通文件的 check 是 0.088 秒)——最后以一片错误收场:合并出来的单元里有重复的顶层名字(E13,std 的模块共用 mem / wide,就是菱形),另有一批元数与类型不符(E3 / E1)。所以结论分两半:找得到是 Pre1 修好的;合得起来不是——那一条还在。实际用法照旧:按需
use 具体模块;要整体消费就交给 python tools/loment.py lib materialize,它走去重加物化,而不是把 127 个模块硬拼成一个单元。
模块索引
下面每一行的说明都来自那个模块自己文件头的第一行,不是概括出来的。
数值:整数、浮点、大数
math | 整数数学 |
intmath | 整数数论(gcd / lcm / isqrt / powmod / invmod / 素性 / 试除分解) |
num | 整数打包、上下界与夹取 |
numfmt | 纯数字格式化(整数 → 文本)——整棵树最底下的一层 |
round | 取整语义(浮点四种模式 + 整数除法 / 倍数) |
comb | 组合数学(阶乘 / 二项式 / 排列 / 卡特兰 / 斯特林) |
f64 | 双精度浮点算术(IEEE 754,软实现) |
f64bits | IEEE 754 双精度的位级视图 |
f64conv | 整数 ↔ 浮点,以及单精度 ↔ 双精度 |
f64fmt | 浮点的十进制文本(dtoa) |
mathf | 浮点超越函数(sqrt / exp / log / 三角) |
fixed | 定点小数(i64,六位小数) |
rational | 精确分数(有理数)算术 |
bigint | 任意精度无符号整数 |
bigdec | 十进制定点大数(系数 + 标度) |
wide | 64 位之上的算术(128 位积、128/64 除、跨字移位、位计数) |
matrix | 稠密矩阵(i64,行主序) |
stats | 基本统计量(均值 / 方差 / 中位数 / 分位数 / 直方图 / 相关系数) |
noise | 定点值噪声 / Perlin 噪声 / 分形叠加(fbm) |
interp | 定点插值与缓动(t 是千分比 0..1024) |
rand | 确定性伪随机(xorshift) |
rng | 确定性伪随机(splitmix64 播种 + xoshiro256** 生成 + 无偏取模 + 洗牌) |
内存、缓冲与容器
mem | 多字节读写与块操作 |
endian | 字节序读写与翻转 |
bit | 位操作 |
atomics | 原子操作:有什么、缺什么、缺的怎么替 |
arena | 基于调用方缓冲的 bump 分配器 |
mall | 空闲块分配器(在调用方给的 arena 上) |
pool | 定长对象池(slab) |
memdbg | 分配记账与哨兵 |
buf | 有容量检查的字节构建器 |
vec | u32 动态数组(调用方持有缓冲) |
deque | 双端队列(环形缓冲) |
ring | 环形缓冲(FIFO,调用方持有数组) |
ilist | 侵入式双向链表(节点池在调用方的缓冲里) |
map | 开放寻址哈希表(u64 → u64) |
mapstr | 字符串键哈希表(字节串 → u64) |
set | 哈希集合(u64) |
lru | LRU 缓存(开放寻址哈希 + 双向链表,节点用下标不用指针) |
trie | 前缀树(字节串键) |
bst | 二叉搜索树(有序映射,节点池在调用方的缓冲里) |
heap | 二叉最小堆(优先队列) |
bitset | 位图(调用方持有字节缓冲) |
flags | 位标志集合(通用小位集工具) |
bloom | 布隆过滤器(位数组 + k 个哈希) |
intern | 字符串驻留(string interning) |
unionfind | 并查集(不相交集合;按秩合并 + 路径压缩) |
fenwick | 树状数组 / BIT(单点加 + 前缀和) |
graph | 图的基础表示与遍历 |
shortest | 最短路:Dijkstra / Bellman-Ford / Floyd-Warshall |
mst | 最小生成树:Kruskal 与 Prim |
文本与字符串
utf8 | UTF-8 编解码与码点计数 |
char | 字节分类与大小写 |
case | Unicode 简单大小写映射与不区分大小写比较 |
text | 字节段的比较与查找 |
split | 按分隔符切分 |
trim | 去空白 |
quote | 转义与反转义 |
line | 按行遍历 |
bufio | 缓冲读:行切分 + 环形缓冲 |
parse | 文本 → 整数 |
path | 路径切分 |
glob | glob 通配匹配(* ? [...] \),含路径语义 |
search | 文本搜索:朴素 / KMP / Boyer-Moore-Horspool |
hash | 非加密哈希 |
hashx | 非加密哈希(FNV-1a / xxHash32)+ 一致性哈希环 |
fmt | 对齐与填充 |
table | 对齐表格渲染(列宽 + 填充 + 分隔线) |
width | 终端里的显示宽度(东亚宽度) |
wrap | 按显示宽度折行(word wrap) |
word | 排版语义上的「词」(word segmentation) |
sort | u32 数组排序(原地) |
bsearch | 已排序 u32 数组上的二分 |
udiff | 行级差异(LCS + 统一 diff) |
摘要、校验与压缩
sha256 | SHA-256(FIPS 180-4) |
sha1 | SHA-1(FIPS 180-4) |
sha512 | SHA-512(FIPS 180-4) |
md5 | MD5(RFC 1321) |
hmac | HMAC(RFC 2104) |
kdf | 密钥派生(PBKDF2 与 HKDF,都基于 HMAC-SHA256) |
crc32 | CRC-32(IEEE 802.3,反射多项式 0xEDB88320) |
crc32c | CRC-32 的几种参数 |
crc16 | CRC-16 的几种常见参数 |
adler32 | Adler-32 |
sum | 加法族校验和(Fletcher / 反码和 / 字节和 / 异或) |
deflate | DEFLATE 压缩(RFC 1951) |
inflate | DEFLATE 解压(RFC 1951) |
zlibc | zlib(RFC 1950)容器:头 + DEFLATE 数据 + 大端 Adler-32 |
lzss | LZSS(滑动窗口 + 长度 / 距离对) |
huffman | 霍夫曼编码:频率表 → 码长 → 规范码 |
rle | 行程编码(RLE)的两种常见形态 |
编解码与格式(全部游标式读取)
这一组有一个共同点:值留在原文里,不建树。读取是游标式的——你拿着原文和一个位置往前走,而不是先把整个文档变成一个对象图。没有 DOM,因为建 DOM 要分配,而这个语言的空间是调用方给的。
base64 | Base64(标准字母表,带 = 填充) |
base32 | Base32(RFC 4648,字母表 A-Z2-7) |
base58 | Base58(Bitcoin 字母表) |
base85 | Base85(Z85 字母表,4 字节 → 5 字符) |
hex | 十六进制编解码与转储 |
hexdump | 十六进制转储(hexdump -C / xxd 风格) |
url | URL 百分号编码 / 解码 + 查询串取值 |
varint | LEB128 变长整数 + zigzag |
jsn | JSON 读取(游标式,不建 DOM) |
cbor | CBOR 读取(RFC 8949,游标式) |
mpk | MessagePack 读取(游标式) |
asn1 | ASN.1 DER 读取(游标式) |
toml | TOML 读取(游标式) |
ini | INI / 键值配置文件 |
csv | CSV 字段的读写(RFC 4180 的那套引号规则) |
ansi | ANSI 转义序列(SGR / 光标 / 屏幕)+ 流解析 |
图像与终端
raster | 像素缓冲:填充 / 矩形 / 直线 / 圆 |
blit | 位块传送:拷贝 / alpha 混合 / 缩放 / 着色 / 颜色键 |
font | 8×8 点阵字体与文字绘制 |
bmp | BMP 读写(只做未压缩 24/32 位) |
png | PNG 容器:签名 / 块遍历 / IHDR / 扫描线反滤波 |
qoi | QOI 图像格式(Quite Ok Image,规范 v1.0) |
tui | 终端界面:单元格网格 + 差异渲染 + 画框 |
时间、系统与其他
civil | 公历日期 / 时间的纯整数换算 |
clock | 时间的文本表示与时长算术 |
assert | 断言与定位 |
out | 游标式输出层(可移植层) |
once | 一次性初始化(赢家选举 + 三态迁移) |
spin | ticket 锁 / 有界自旋等待 / 计数信号量 / latch |
coro | 可恢复的状态机(不是有独立栈的协程) |
sched | 数据驱动的合作式调度表(不是抢占式调度器) |
perm | 权限位 ↔ rwxr-xr-x 文本 |
proc | /proc/self/* 的解析 |
env | 环境块 / argv 的解析(\0 分隔的连续字节区) |
fwalk | linux_dirent64 记录的解析与路径拼接 |
tmpf | 临时文件名的生成(没有 mkdir/unlink/getpid 时怎么不撞名) |
std | 包入口(把 127 个模块拉进同一个单元) |
宿主层 · host
io | Loment 的第一个库:宿主侧 IO 与字节原语 |
fs | 整文件读写(在 io 之上) |
argv | 进程启动参数 |
dir | 目录遍历(getdents64) |
stat | 文件元信息(newfstatat) |
log | 工具链那套诊断行的约定 |
几条贯穿全库的约定
- 公开名字带模块前缀 ——
hex_*、crc32_*、math_*、out_*。因为发射的符号名是平的、一个单元里顶层名字必须唯一,前缀是这条约束的纪律,不是命名癖好。 - 容器不收自己的账 ——
vec/arena/bst/pool/ring/bitset一律由调用方持有缓冲。bump 堆只有 64 KiB,库自己分配会把上限摊到每一个使用者身上。 - 格式读取是游标式的 ——
jsn/cbor/mpk/asn1/toml都不建树。同一个理由:建树要分配。 - 先定义后使用 —— 语言要求如此。
hex.lomt里hex_val排在hex_decode前面,那不是风格,是编译器会拦。 - 名字里有「不是」的东西会写明 ——
coro的文件头第一句就是「不是有独立栈的协程」,sched是「不是抢占式调度器」。免得有人按名字想当然。
pub fn 上面那行 /// 是文档注释,loment doc FILE 会把它们抽出来。写一个 Loment 库 讲的是一个库该怎么组织,Lompi 讲的是怎么把它解析、发锁、物化。