#iterator #vec #memory #boxed #slice

无std small_iter

一个3指针迭代器,可以从Vec<T>Box<[T]>中移出数据

3次发布

0.1.2 2024年7月7日
0.1.1 2024年7月7日
0.1.0 2024年7月6日

数据结构中排名588

Download history 300/week @ 2024-07-06 16/week @ 2024-07-13 29/week @ 2024-07-27

每月下载345

MIT授权

15KB
224

一个3指针迭代器,可以从Vec<T>Box<[T]>中移出数据

文档链接

为什么?

如果您想迭代并从Vec<T>中移出项,您通常会调用.into_iter(),生成一个vec::IntoIter迭代器。(注意:即将到来的Box<[T]>IntoIterator实现也使用vec::IntoIter。)这对于大多数用例来说是可以的。

然而,存储大量vec::IntoIter迭代器可能对内存使用来说不是最优的。这是因为vec::IntoIter被表示为4个指针,这比仅用于单方向迭代时严格必要的多一个。

此crate提供了一个SmallIter类型,它被表示为3个指针。为了换取更小的尺寸,此类型不实现DoubleEndedIterator

用法

IntoSmallIterExt特质提供了into_small_iter()方法,它允许您从Vec<T>Box<[T]>生成SmallIter迭代器。

use small_iter::IntoSmallIterExt;

let v = vec![1, 2, 3];
let iter = v.into_small_iter();
let v2: Vec<_> = iter.collect();
assert_eq!(v2, vec![1, 2, 3]);

此crate节省空间的好处可能仅在您存储大量迭代器时相关。

use small_iter::{IntoSmallIterExt, SmallIter};

let v = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
let mut iters: Vec<SmallIter<i32>> = v.into_iter().map(|v| v.into_small_iter()).collect();
assert_eq!(iters[0].next(), Some(1));
assert_eq!(iters[1].next(), Some(3));
assert_eq!(iters[2].next(), Some(5));
assert_eq!(iters[0].next(), Some(2));
assert_eq!(iters[1].next(), Some(4));
assert_eq!(iters[2].next(), Some(6));

注意

对于Vec<T>,如果向量化器中存在剩余容量,调用into_small_iter将首先缩小分配以适应现有元素。根据分配器,这可能会导致重新分配。

另一方面,在Box<[T]>上调用into_small_iter是廉价的。

基准测试结果

我在Macbook Pro 2021上对以下工作负载进行了基准测试(这是该crate预期的工作负载类型):构建10万个迭代器,每个迭代器包含100个u8。然后,获取每个迭代器的第一个元素,然后是第二个,依此类推。

此工作负载以三种方式进行

  • 使用SmallIter(此crate)
    • 平均耗时20.4毫秒
  • 使用来自thin-vec crate的thin_vec::IntoIter
    • 平均耗时30.5毫秒
  • 使用std::vec::IntoIter
    • 平均耗时21.9毫秒

基准测试的源代码可以在这里找到。

Violin plot of the running times

无运行时依赖