#pinned #fixed #constant-time #vec #array #split

orx-fixed-vec

具有固定容量和固定元素的效率高且常数时间访问的向量

40 个版本 (25 个稳定版本)

新版本 3.5.0 2024年8月22日
3.2.0 2024年7月25日
2.12.0 2024年6月28日
2.6.1 2024年3月24日
0.3.3 2023年9月8日

数据结构 中排名第 345

Download history 108/week @ 2024-05-03 228/week @ 2024-05-10 51/week @ 2024-05-17 21/week @ 2024-05-24 223/week @ 2024-05-31 34/week @ 2024-06-07 36/week @ 2024-06-14 19/week @ 2024-06-21 237/week @ 2024-06-28 33/week @ 2024-07-05 53/week @ 2024-07-12 472/week @ 2024-07-19 734/week @ 2024-07-26 811/week @ 2024-08-02 381/week @ 2024-08-09 143/week @ 2024-08-16

每月下载量 2,245
9 包中使用 (8 个直接使用)

MIT 协议

59KB
1K SLoC

orx-fixed-vec

orx-fixed-vec crate orx-fixed-vec documentation

具有固定容量和固定元素的效率高且常数时间访问的向量。

A. 动机

在许多情况下,固定元素是至关重要的。

  • 它在实现带有瘦引用的**高效、方便且安全的自引用集合**方面至关重要,详见 SelfRefCol 的详细信息,以及其特殊情况,如 LinkedList
  • 对于**并发**程序来说非常重要,因为它消除了与元素隐式地携带到不同内存位置相关的安全担忧。这有助于减少和解决并发的复杂性,并导致高效的并发数据结构。详见 ConcurrentIterConcurrentBagConcurrentOrderedBag,这些并发数据结构方便地建立在固定向量的固定元素保证之上。
  • 在允许**不可变推送**向量方面至关重要;即 ImpVec。当所需的集合是一个包或物品的容器,而不是具有集体意义时,这是一个非常有用的操作。在这种情况下,ImpVec 允许避免某些借用检查器复杂性、堆分配和宽指针,如 BoxRc 或等等。

B. 与 SplitVec 的比较

SplitVec 是另一个旨在实现相同目标但具有不同功能的 PinnedVec 实现。您可以在下表中进行比较。

FixedVec SplitVec
实现了 PinnedVec => 可以被 ImpVecSelfRefColConcurrentBag 等包装。 实现了 PinnedVec => 同样也可以被它们包装。
在创建时需要知道确切的容量。 可以使用任何关于所需容量的先验信息来创建。
不能超过容量增长;当在容量时调用 push 会引发恐慌。 可以动态增长。此外,它还提供了对如何增长的控制。
它只是 std::vec::Vec 的包装;因此,具有等效的性能。 性能优化的内置增长策略也具有与 std::vec::Vec 相当的性能。

在性能优化了 SplitVec 之后,它在性能方面现在可以与 std::vec::Vec 相媲美。这可能会使 SplitVec 成为优于 FixedVec 的主导选择。

C. 示例

C.1. 与 std::vec::Vec 相似的使用

FixedVec 中,大多数常见的 std::vec::Vec 操作都是可用的,并且具有相同的签名。

use orx_fixed_vec::prelude::*;

// capacity is not optional
let mut vec = FixedVec::new(4);

assert_eq!(4, vec.capacity());

vec.push(0);
assert!(!vec.is_full());
assert_eq!(3, vec.room());

vec.extend_from_slice(&[1, 2, 3]);
assert_eq!(vec, &[0, 1, 2, 3]);
assert!(vec.is_full());

// vec.push(42); // push would've panicked when vec.is_full()

vec[0] = 10;
assert_eq!(10, vec[0]);

vec.remove(0);
vec.insert(0, 0);

assert_eq!(6, vec.iter().sum());

assert_eq!(vec.clone(), vec);

let std_vec: Vec<_> = vec.into();
assert_eq!(&std_vec, &[0, 1, 2, 3]);

C.2. 固定元素

除非从向量中删除元素,否则已推送到 SplitVec 的元素的内存位置在显式更改之前不会更改。

use orx_fixed_vec::prelude::*;

let mut vec = FixedVec::new(100);

// push the first element
vec.push(42usize);
assert_eq!(vec, &[42]);

// let's get a pointer to the first element
let addr42 = &vec[0] as *const usize;

// let's push 99 new elements
for i in 1..100 {
    vec.push(i);
}

for i in 0..100 {
    assert_eq!(if i == 0 { 42 } else { i }, vec[i]);
}

// the memory location of the first element remains intact
assert_eq!(addr42, &vec[0] as *const usize);

// we can safely dereference it and read the correct value
// dereferencing is still unsafe for FixedVec,
// but the underlying guarantee will be used by wrappers such as ImpVec or SelfRefCol
assert_eq!(unsafe { *addr42 }, 42);

// the next push when `vec.is_full()` panics!
// vec.push(0);

D. 基准测试

由于 FixedVec 只是 std::vec::Vec 的包装,并增加了额外的固定元素保证;它预期具有等效的性能。这已在基准测试中得到测试和确认,基准测试可以在 benches 文件夹中找到。

许可证

此库在 MIT 许可证下授权。有关详细信息,请参阅 LICENSE。

依赖关系

~105KB