2 个版本
| 0.5.1 | 2021 年 1 月 14 日 |
|---|---|
| 0.5.0 | 2021 年 1 月 10 日 |
1936 在 数据结构
用于 pui
275KB
5K SLoC
pui-arena
一套非常高效、非常可定制的区域,尽可能减少边界检查。
许可协议:MIT/Apache-2.0
lib.rs:
一套非常高效、非常可定制的区域,尽可能减少边界检查。
pui-arena 提供了一套集合,允许你在至少平均情况下以 O(1) 的时间复杂度插入和删除项目,以 O(1) 的时间复杂度访问元素。它还提供了避免 ABA 问题 所需的工具。
你可以将 pui-arena 中的集合视为一个 HashMap/BTreeMap,其中区域管理键,并提供了一种非常高效的方式来访问元素。
为什么选择 pui-arena 而不是其他替代方案
pui-arena 允许你在可能的情况下最小化开销,并完全自定义区域。这允许你根据如何使用 api 来使用类似 slab 或 slotmap 的 api。 (还有由 slab 和 slotmap 特性控制的特性门控的新类型,实现了这两个包的类似接口)。
如果你使用 pui/scoped 特性,那么你也可以完全消除边界检查,这可以在性能敏感的区域中节省大量性能。
pui-arena 还提供了比竞争对手更多的功能,例如为版本化区域提供空缺条目 api,以及所有区域的 drain_filter。
选择 sparse、hop 或 dense
您可以在相应的模块文档中了解每个模块的工作细节。
性能特性
速度
pui-arena中的所有集合允许您
- 以摊销时间复杂度
O(1)插入元素 - 以
O(1)删除/访问元素 - 确保除非调用
remove,否则键值永远不会被失效
内存
对于每个Arena<T, _, V>,其中V: Version,内存开销如下
sparseArena- 每个槽位size_of(V) + max(size_of(T), size_of(usize))hopArena- 每个槽位size_of(V) + max(size_of(T), 3 * size_of(usize))denseArena- 每个槽位size_of(V) + size_of(usize),以及每个值size_of(usize) + size_of(T)
实现细节
此crate的核心是Version特质、ArenaKey特质和BuildArenaKey特质。
Version指定了集合的行为。pui-arena提供了三个实现,更多详情请见Version
DefaultVersion- 确保所有由
insert生成的键都是唯一的 - 由一个
u32支持,因此对于小值可能会浪费空间- 技术上来说,如果项目被插入/删除多次,槽位将被“泄漏”,迭代性能可能会降低,但这种情况不太可能发生,除非相同的槽位被重复使用超过20亿次
- 确保所有由
TinyVersion-- 确保所有由
insert生成的键都是唯一的 - 由一个
u8支持,如果项目被插入/删除多次,槽位将被“泄漏”,迭代性能可能会降低
- 确保所有由
Unversioned-insert生成的键不必保证是唯一的- 槽位永远不会被“泄漏”
ArenaKey 用于指定键在区域中的行为。 pui-arena 提供了多种实现。请参见 ArenaKey 以获取详细信息。
usize- 允许直接访问给定的槽位,不考虑其版本- 注意:当我说“不考虑其版本”时,它仍然会检查槽位是否已被占用,但没有方法来检查一个值是否被重新插入到同一个槽位
Key<K, _>- 允许通过K访问指定的槽位,并在提供值之前检查槽位的生成K可以是这里列出的其他键之一(除了ScopedKey)
TrustedIndex- 允许直接访问给定的槽位,不考虑其版本- 省略了边界检查,但构造时是不安全的
- 应该小心使用这个功能,如果确实需要使用,最好使用
pui功能并使用pui_vec::Id。它是安全的,并且也保证了边界检查的省略
ScopedKey<'_, _>- 只允许访问范围区域(否则与Key相同)
通过 pui 功能启用
pui_vec::Id- 允许直接访问给定的槽位,不考虑其版本- 省略了边界检查
BuildArenaKey 指定了区域应该如何创建键,除了 TrustedIndex 之外,该包提供的所有 ArenaKey 实现也实现了 BuildArenaKey
自定义区域
您可以使用 newtype 宏或功能: slab、slotmap 或 scoped 来创建区域的新类型。
slab- 提供了与slab包 相似的 API- 使用
usize键和Unversioned槽位
- 使用
slotmap- 提供了与slab包 相似的 API- 使用
Key<usize>键和DefaultVersion插槽
- 使用
scoped- 提供使用pui_core::scoped以省略边界检查的新类型竞技场- 使用
scoped::ScopedKey<'_, _>键,并对版本进行泛型化
- 使用
newtype- 创建具有base模块结构的系列新类型竞技场- 这些竞技场省略了边界检查,转而进行 ID 检查,这更便宜,并且根据你的底层 ID,甚至可以完全不检查!(见
pui_core::scalar_allocator详细信息)
- 这些竞技场省略了边界检查,转而进行 ID 检查,这更便宜,并且根据你的底层 ID,甚至可以完全不检查!(见
// Because the backing id type is `()`, there are no bounds checks when using
// this arena!
pui_arena::newtype! {
struct MyCustomArena;
}
let my_sparse_arena = sparse::Arena::new();
let my_dense_arena = dense::Arena::new();
let my_hop_arena = hop::Arena::new();
变成了类似下面的东西
pui_core::scalar_allocator! {
struct MyCustomArena;
}
mod sparse {
pub(super) Arena(pub(super) pui_arena::base::sparse::Arena<...>);
/// more type aliases here
}
mod dense {
pub(super) Arena(pub(super) pui_arena::base::dense::Arena<...>);
/// more type aliases here
}
mod hop {
pub(super) Arena(pub(super) pui_arena::base::hop::Arena<...>);
/// more type aliases here
}
let my_sparse_arena = sparse::Arena::new();
let my_dense_arena = dense::Arena::new();
let my_hop_arena = hop::Arena::new();
其中每个 Arena 新类型都有一个简化的 API 和更好的错误信息。