#circular-buffer #buffer #circular #zero-allocation #allocation #zero

rbl_circular_buffer

一个在Rust中实现的零分配、快速的循环缓冲区

3个版本

0.1.2 2020年7月25日
0.1.1 2020年7月25日
0.1.0 2020年7月25日

#17 in #zero-allocation


用于 2 crates

MIT 许可证

28KB
551

CircularBuffer

一个零依赖、零运行时分配的循环缓冲区。

这个crate提供了一个简单的循环缓冲区,在运行时不会进行任何分配。这个crate的主要关注点是正确性和性能。

循环缓冲区从不等待,如果缓冲区已满,它会覆盖第一个元素。

API非常简单,你创建缓冲区并指定缓冲区可以容纳多少个元素。然后你可以开始向其中推送元素。

use rbl_circular_buffer::*;

let mut buffer = CircularBuffer::new(3);
assert_eq!(0, buffer.len());

buffer.push(1);
assert_eq!(1, buffer.len());

buffer.push(2);
assert_eq!(2, buffer.len());

buffer.push(3);
assert_eq!(3, buffer.len());

// now the buffer is full, we can insert the next element, but it will overwrite the first one
buffer.push(4);
assert_eq!(3, buffer.len());

let v: Vec<u32> = buffer.collect();
assert_eq!(vec![2,3,4], v);

从缓冲区中读取元素有两种方式。

  1. CircularBuffer 实现了 Iterator 特性,你可以遍历它。
  2. CircularBuffer 提供了 .fill() 方法。

使用迭代器

迭代器会消耗缓冲区中的元素。

use rbl_circular_buffer::*;

let mut buffer = CircularBuffer::new(3);
buffer.push(1);
buffer.push(2);
buffer.push(3);

let mut sum = 0;
for element in &mut buffer {
    sum += element;
}
assert_eq!(1 + 2 + 3, sum);
assert_eq!(0, buffer.len());

填充向量

在性能要求高的应用中,迭代器可能不是一个好选择。

考虑线程之间的通信,每个线程都可以有一个 CircularBuffer 的引用,并在读取时获取锁。如果读取操作不够快,或者简单地元素太多,锁将被保持很长时间。另一种选择是填充一个向量。

use rbl_circular_buffer::*;

// let's make a bigger vector
let mut buffer = CircularBuffer::new(5);
for i in 1..=5 {
    buffer.push(i);
}

// with this vector we will remove the first 3 elements
let mut v = Vec::with_capacity(3);

buffer.fill(&mut v);
assert_eq!(vec![1, 2, 3], v);

// in the vector there are still 4 and 5
assert_eq!(2, buffer.len());

buffer.push(6);
buffer.push(7);
buffer.push(8);

// the fill avoid any allocation even in the vector to fill.
// if we remove one element, and refill, we will push only one element.
// this because `.fill()` does not allocate any memory.

v.remove(0);

buffer.fill(&mut v);

assert_eq!(vec![2, 3, 4], v);
assert_eq!(4, buffer.len())

无运行时依赖