22个版本
新 0.3.3 | 2024年8月23日 |
---|---|
0.3.2 | 2024年6月4日 |
0.3.1 | 2023年2月14日 |
0.2.6 | 2023年1月25日 |
0.1.13 | 2022年8月21日 |
#139 在 数据结构
2,753 每月下载量
用于 10 个 crate(5个直接使用)
145KB
3.5K SLoC
Sokoban
连续字节数组中的紧凑、高效数据结构。
基准测试
根据简单的基准测试,Sokoban数据结构的原始性能与Rust标准库相当,但略慢。
test bench_tests::bench_sokoban_avl_tree_insert_1000_u128 ... bench: 134,301 ns/iter (+/- 4,033)
test bench_tests::bench_sokoban_avl_tree_insert_1000_u128_stack ... bench: 134,135 ns/iter (+/- 3,620)
test bench_tests::bench_sokoban_avl_tree_insert_20000_u128 ... bench: 2,744,853 ns/iter (+/- 158,364)
test bench_tests::bench_sokoban_avl_tree_remove_u128 ... bench: 355,992 ns/iter (+/- 22,770)
test bench_tests::bench_sokoban_critbit_insert_1000_u128 ... bench: 90,306 ns/iter (+/- 590)
test bench_tests::bench_sokoban_critbit_insert_1000_u128_stack ... bench: 76,819 ns/iter (+/- 661)
test bench_tests::bench_sokoban_critbit_insert_20000_u128 ... bench: 2,839,050 ns/iter (+/- 207,241)
test bench_tests::bench_sokoban_critbit_remove_1000_u128 ... bench: 97,366 ns/iter (+/- 6,124)
test bench_tests::bench_sokoban_hash_map_insert_1000_u128 ... bench: 46,828 ns/iter (+/- 1,928)
test bench_tests::bench_sokoban_hash_map_insert_1000_u128_stack ... bench: 46,686 ns/iter (+/- 1,691)
test bench_tests::bench_sokoban_hash_map_insert_20000_u128 ... bench: 1,492,742 ns/iter (+/- 43,362)
test bench_tests::bench_sokoban_hash_map_remove_1000_u128 ... bench: 59,896 ns/iter (+/- 1,782)
test bench_tests::bench_sokoban_red_black_tree_insert_1000_u128 ... bench: 69,574 ns/iter (+/- 8,581)
test bench_tests::bench_sokoban_red_black_tree_insert_1000_u128_stack ... bench: 66,057 ns/iter (+/- 8,853)
test bench_tests::bench_sokoban_red_black_tree_insert_20000_u128 ... bench: 1,905,406 ns/iter (+/- 25,546)
test bench_tests::bench_sokoban_red_black_tree_remove_1000_u128 ... bench: 128,889 ns/iter (+/- 13,508)
test bench_tests::bench_std_btree_map_insert_1000_u128 ... bench: 51,353 ns/iter (+/- 10,240)
test bench_tests::bench_std_btree_map_insert_20000_u128 ... bench: 1,535,224 ns/iter (+/- 21,645)
test bench_tests::bench_std_btree_map_remove_1000_u128 ... bench: 131,879 ns/iter (+/- 19,325)
test bench_tests::bench_std_hash_map_insert_1000_u128 ... bench: 38,775 ns/iter (+/- 237)
test bench_tests::bench_std_hash_map_insert_20000_u128 ... bench: 797,904 ns/iter (+/- 10,719)
test bench_tests::bench_std_hash_map_remove_1000_u128 ... bench: 57,452 ns/iter (+/- 364)
为什么是紧凑数据结构?
对于大多数应用来说,没有必要超出Rust标准库来寻找数据结构。然而,当应用程序具有有限的或昂贵的内存,并且由于性能瓶颈而受到影响时,程序员通常会需要设计定制的解决方案来处理这些约束。这类约束在高频交易、嵌入式系统和区块链开发中相当常见。
这就是Sokoban的用武之地:一个专门设计用来简化此类问题的数据结构库。
泛型节点分配器
几乎所有数据结构都可以用某种类型的节点和边连接的图来表示。`node-allocator`模块实现了一个用于连续缓冲区的原始节点分配数据结构。缓冲区中的每个条目必须包含相同的基本类型的对象。每个条目还将有一个固定数量的寄存器,这些寄存器包含有关当前节点的元数据。这些寄存器通常被解释为图边。
#[repr(C)]
#[derive(Copy, Clone)]
pub struct NodeAllocator<
T: Default + Copy + Clone + Pod + Zeroable,
const MAX_SIZE: usize,
const NUM_REGISTERS: usize,
> {
/// Size of the allocator
pub size: u64,
/// Furthest index of the allocator
bump_index: u32,
/// Buffer index of the first element in the free list
free_list_head: u32,
pub nodes: [Node<NUM_REGISTERS, T>; MAX_SIZE],
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Node<T: Copy + Clone + Pod + Zeroable + Default, const NUM_REGISTERS: usize> {
/// Arbitrary registers (generally used for pointers)
/// Note: Register 0 is ALWAYS used for the free list
registers: [u32; NUM_REGISTERS],
value: T,
}
模板化的`NodeAllocator`对象是一个灵活的原始数据结构,用于实现更复杂类型。以下是使用`NodeAllocator`实现双向链表的示例:
// Register aliases
pub const PREV: u32 = 0;
pub const NEXT: u32 = 1;
#[derive(Copy, Clone)]
pub struct DLL<T: Default + Copy + Clone + Pod + Zeroable, const MAX_SIZE: usize> {
pub head: u32,
pub tail: u32,
allocator: NodeAllocator<T, MAX_SIZE, 2>,
}
DLL实际上只是一个具有每个节点2个寄存器的节点分配器。这些寄存器代表DLL节点的`prev`和`next`指针。创建和删除边的逻辑是特定于类型的,但分配器结构提供了一种实现具有此属性(树和图)的任意类型的接口。
依赖项
~0.5–1MB
~21K SLoC