7个版本 (4个重大更新)

0.5.0 2024年6月28日
0.4.1 2024年6月17日
0.4.0 2024年5月28日
0.3.1 2024年5月24日
0.1.0 2024年2月23日

#181 in 数据结构

Download history 1623/week @ 2024-05-03 1805/week @ 2024-05-10 1681/week @ 2024-05-17 2194/week @ 2024-05-24 2109/week @ 2024-05-31 2125/week @ 2024-06-07 2178/week @ 2024-06-14 2401/week @ 2024-06-21 2265/week @ 2024-06-28 1889/week @ 2024-07-05 2534/week @ 2024-07-12 2587/week @ 2024-07-19 2557/week @ 2024-07-26 3632/week @ 2024-08-02 3706/week @ 2024-08-09 3605/week @ 2024-08-16

每月14,161次下载

MIT/Apache

180KB
4.5K SLoC

flatcontainer

Rust的扁平容器。

[dependencies]
flatcontainer = "0.4"

示例

use flatcontainer::FlatStack;

let r: Result<_, u16> = Ok("abc");
let mut c = FlatStack::default_impl::<Result<&str, u16>>();
c.copy(&r);
assert_eq!(r, c.get(0));

详细信息

flatcontainer是一个库,它提供将嵌套数据结构的集合扁平化到密集分配的抽象和实现。在其核心,一个Region特质描述了如何在内存中表示数据,并可选择提取原始数据的生命周期表示,这可能与调用者最初拥有的不同。

flatcontainer将容器的写入部分与其存储和读取接口解耦,以便向同一区域提供多种类型。例如,包含类似字符串的对象的区域,并且仅承诺访问&str,可以接受任何看起来像字符串的东西,即String&str以及这些类型的引用。区域写入部分应使用Push特质实现。

区域允许通过不可见索引访问数据,索引由调用者负责记忆。索引提供对区域特定数据表示的访问,尽管它可以被检查,但不应该以任何方式创建或修改。对于一个区域来说,索引是一个没有特定含义的不可见类型,除非区域有其他指定。

区域大致遵循两种模式:要么它们扩展到其他区域,要么它们作为终端节点并明确包含存储。一个[Result][ResultRegion]区域调度到ok和error区域,并使用其索引类型来区分查找值的位置。一个切片区域具有存储来记住索引切片,其中索引可用于在内部区域中查找数据的表示。

flatcontainer 提供了 FlatStack,这是一个如何实现支持添加额外元素和通过偏移量检索之前推入的元素的项集合的示例实现。它可以在许多只需要使用扁平数据表示的地方使用,但它留下了优化的潜力。具体来说,虽然索引是透明的,但它们遵循一个简单的结构,更有效的存储可以节省内存,而不是盲目地写下所有值。

所有区域实现都应被视为如何实现特定区域的示例,这些区域是根据类型的需求以及实际遇到的数据特征定制的。这个crate提供了一个 RegionPreference trait,让类型表达它们建议的区域,但用户可以选择不同的区域,只要它与要存储的类型兼容。例如,一个vector建议使用基于切片的区域,但客户端可能知道内部类型是可复制的,因此更好地使用不扇出到单个元素区域的基于切片的区域。

安全性

此crate安全使用,所有不安全代码都可以在本地解释。目前,这只涉及假设utf-8数据是正确的,这是构造上的事实。

特性

serde 特性控制类型是否实现支持序列化和反序列化数据。默认启用。

性能和设计考虑因素

flatcontainer 的一个目标是存储 O(n) 对象,分配少于 O(n),例如在 O(log n),或者在正确预分配大小的情况下,在常量分配中。它可以通过在内存中密集布局数据来实现这一点。这带来了好处和限制。它允许快速顺序访问,因为CPU可以预取数据,并且避免将不需要的数据加载到缓存中。减少分配数量可以限制与分配器的交谈。另一方面,区域是只添加的,复制一个值会破坏其原始形式。读取所有者数据需要复制或克隆。

flatcontainer的区域抽象要求用户存储索引。没有特定关于区域的了解,索引最好存储在向量中。在许多情况下,我们知道更多关于数据的信息,并且可以使用更好的方法来存储索引。

  • 存储切片的区域通常有一个看起来像 (start, end) 的索引。很容易观察到前一个元素的结束等于当前元素的开始,因此应该只存储一次。这可以将每个元素索引的大小从16字节减少到8字节。
  • 对于适合32位的索引值,我们只需要4字节内存。我们可以专门化一个容器,使用 u32 来存储小于 2^32 的值,而使用 u64 否则。
  • 存储固定大小元素的区域的索引通常看起来像步进数字,例如,0, 2, 4, 8, ...,我们可以通过记住步进和长度来使用常量内存表示。我们可以通过添加另一个计数器来扩展到存储等于最后一个步进的元素尾。这样的索引容器使用了0位限制!
  • 有关使用更少位存储索引的特殊化类型的类型,请参阅 offsets 模块。

Flatcontainer提供了一些这些概念的实施。为了合并相邻的起始-结束对,将一个区域包裹在一个ConsecutiveOffsetPairs区域中。它存储索引并以0, 1, 2, ...的密集序列呈现。

CollapseSequence区域会记住最后一个元素的索引,如果新元素与最后一个元素相同,它将返回上一个索引而不是存储相同的元素多次。这仅限于直接前驱,因为否则存储索引和扫描前一个元素将会太昂贵。

与列化的比较

Flatcontainer借鉴了columnation的几个想法。它使用区域的概念来抽象密集分配,同时仍然识别单个对象。columnation返回需要作为引用处理的所拥有的对象,而flatcontainer返回一个不可见的索引,该索引可以被区域转换为生命周期类型。columnation读取和写入相同的类型,这迫使用户在丢弃数据时必须小心。Flatcontainer避免了这些问题,因为索引不包含指向所拥有数据的指针。

Flatcontainer提供的性能与columnation相似,在某些情况下更快。对于存储字符串,flatcontainer提供了一个(start, end)的索引来将原始输入作为引用重建,而columnation返回一个所拥有的字符串,大致看起来像(pointer, size, capacity)。我们不需要在64位CPU上额外24字节,我们只有16字节。我们可以通过观察连续条目从上一个结束开始来将这16字节的额外开销减少到8字节。我们可以通过查看下一个元素的开始来重建结束,从而允许我们通过查看下一个元素的开始来重建结束。

许可证

根据您的选择,许可协议为Apache License,Version 2.0MIT许可证
除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交给此crate的贡献将根据上述条款进行双重许可,不附加任何额外的条款或条件。

依赖关系

~0.4–1MB
~22K SLoC