5 个版本 (重大变更)

0.5.0 2022 年 10 月 31 日
0.4.0 2021 年 9 月 19 日
0.3.0 2020 年 4 月 26 日
0.2.0 2020 年 4 月 21 日
0.1.0 2019 年 4 月 22 日

#1263文本处理

每月 36 次下载
4 个 Crates 中使用 (2 个直接使用)

MIT/Apache

45KB
531

六比特 - 一个用于小型打包字符串的 crate。

此 crate 提供了密集打包的 8 位、16 位、32 位、64 位和 128 位“小型字符串”,采用各种自定义脚本特定的每字符 6 位编码,以及 Unicode“统一字符集和顺序” (URO) 块中汉字的特殊每字符 15 位编码。

这种数据类型是一种底层优化,用于在处理大量小型字符串的系统(例如单个单词)中:您可以避免在堆上分配它们,将它们存储在字符串结构标题、NaN 盒或其他小型字面值类型中。

也许最有吸引力的是:您可以 将多个它们打包 到一个 SIMD 向量中,并一次性并行地对(例如搜索)多个此类字符串进行操作,作为一个单独的寄存器。向量寄存器正变得越来越强大。

当然,并非每个字符串都足够短以适应,也并非每个足够短的字符串都具有落在此 crate 提供的“代码页”之一的码点。因此,编码函数都是部分函数。但它们应该可以处理足够数量的字符串,使其变得有价值。

使用总结

编码通过附加到Iterator<char>EncodeSixbit特质来完成,因此您可以这样做:let enc = "hello".chars().encode_sixbit::<u64>()。如果出现失败(例如,字符串跨越页面或无法适应),您将获得一个带有详细信息的Err(EncodeError),否则将返回Ok(n),其中n是一个u64

解码是一个实现Iterator<char>DecodeSixbitIter迭代器,附加到各种打包类型上,允许您编写let s:String = someu64.decode_sixbit().collect(),或任何其他接受Iterator<char>的模式。

在某些情况下,您需要在将这些接口推送之前对“标准”Unicode文本进行规范化或分解。例如,韩文字符页仅包含兼容音节,因此您必须将标准韩文文本分解到该格式之前编码。同样,半角假名不太可能是标准日文文本到达的字符,而天城文字符串需要在与nuktas映射之前分解。这个crate不执行这些任务:它是一个构建块,而不是一个完整的解决方案。

代码页

这个crate生成的每个打包字符串都以一个小标签开始,指示字符串的“代码页”。这里的代码页是一组64个Unicode字符值,其余字符串的6位码被解释为(或者,在特殊情况下,是URO块)。不支持混合来自多个代码页的字符的字符串。再次强调,“单个单词”。

我尽我所能选择了代码页的内容,结合了脚本知识、猜测、咨询朋友和专家、查阅维基百科等,并受到以下约束。我愿意接受PR以改进它们以更好地捕捉特定脚本中的“许多单词”;因此,代码页的内容将在1.0版本发布之前有所变化,所以如果出于某种奇怪的原因您正在阅读此内容并决定使用这个crate并将值存储在稳定存储中,您应该将您的客户端锁定到crate的特定修订版,直到1.0发布。

约束

标签中空间有限,只能引用少量代码页;不是每个脚本都能通过,但幸运的是,只有少数几个脚本占用了世界上大部分文本。

我们希望避免浪费位,一个N位(模6)打包值的备用位数量会根据其大小而变化:8位、32位和128位值有2个备用位;16位和64位值有4个备用位。

在所有情况下都分配了中文的标签,但在32位、64位和128位值中只有15位码的非零序列有空间,所以只有这些宽度使用它;在8位或16位情况下,标签只是预留。

我们希望能够使用机器提供的整数比较对这些字符串进行排序,并且这种顺序与unicode代码点字典序字符串顺序相匹配(包括“短字符串排序在长字符串之前”)。这决定了标签值、代码库和编码字符串的正常形式。

设计

代码页来自(或在某些情况下,跨越)unicode块,标签按(初始)unicode块排序。每个代码页中的代码进一步按unicode代码点排序:每个代码页实际上是从1个或多个相应的unicode块的内容中的“可能有用的子序列”。遗憾的是,这意味着只有使用拉丁页面的字符串中才有数字(它还有下划线,额外一个空格,这在许多标识符库中很常见)。我尽量在可用块中包含一些额外的标点符号。由于混合页面也不可行,所以“补充”块大部分被避免。

一个脚本只有在有适合于63个代码点的“可能有用的子序列”的情况下才能工作(除非它是URO块)。每个页面的零代码保留为字符串终止符和填充值。编码长度小于其打包值容器的字符串将被左移,始终从最高有效编码位开始,尾随位全部置零(这并不意味着你可以编码nulls——这里的零意味着“字符串末尾”)。

高阶/2位标签可以在unicode范围内(按代码块顺序)分散的4个“主要”(最可能)脚本中选择。这些脚本在所有打包值中都可用

标签 页面内容
00 拉丁(带数字和下划线)
01 阿拉伯
10 德文
11 中文

当打包64位和16位值时,我们得到4个备用位用于标签,而不仅仅是2个。在这种情况下,因此有12个额外的脚本可用,为了简单起见,我们在值大小之间进行上舍和下舍,保持高阶位不变,并在下面添加2位,从主要脚本(再次,按unicode块顺序)之间的代码块范围中选取额外的脚本。

标签 页面内容
00 00 拉丁(带数字和下划线)
00 01 希腊
00 10 西里尔
00 11 希伯来
01 00 阿拉伯
01 01 预留
01 10 预留
01 11 预留
10 00 德文
10 01 预留
10 10 预留
10 11 韩文字符兼容字
11 00 中文
11 01 预留
11 10 预留
11 11 半角假名

预留的情况是我对这个unicode范围内可用的脚本了解不够,或者候选者用完了,或者两者都有。我可能在将来将它们分配给某物,或者“压缩”这些差距/重新分配4位代码,使它们的高位不是2位情况的高位,但我已经超过了我的实际水平的知识和经验,我认为简化设计选择比假装我能做得更好要好。欢迎补丁!

位的整体分配总结如下

打包类型 标签位 编码位 最大6位字符 最大15位字符
u128 2 126 21 8
u64 4 60 10 4
u32 2 30 5 2
u16 4 12 2 0
u8 2 6 1 0

许可证:MIT OR Apache-2.0

依赖关系

~92KB