Bit-Masking Ring Buffer

Test Documentation Crates.io License

A fast ring buffer implementation with cheap and safe indexing written in Rust. It works by bit-masking an integer index to get the corresponding index in an array/vec whose length is a power of 2. This is best used when indexing the buffer with an isize value. Copies/reads with slices are implemented with memcpy. This is most useful for high performance algorithms such as audio DSP.

This crate has no consumer/producer logic, and is meant to be used as a raw data structure or a base for other data structures.

If your use case needs a buffer with a length that is not a power of 2, and the performance of indexing individual elements one at a time does not matter, then take a look at my crate [slice_ring_buf].

Installation

Add bit_mask_ring_buf as a dependency in your Cargo.toml: toml bit_mask_ring_buf = 0.4

Example

```rust use bitmaskring_buf::{BMRingBuf, BMRingBufRef};

// Create a ring buffer with type u32. The data will be // initialized with the default value (0 in this case). // The actual capacity will be set to the next highest // power of 2 if the given capacity is not already // a power of 2. let mut rb = BMRingBuf::::fromcapacity(3); asserteq!(rb.capacity(), 4);

// Read/write to buffer by indexing with an isize. rb[0] = 0; rb[1] = 1; rb[2] = 2; rb[3] = 3;

// Cheaply wrap when reading/writing outside of bounds. asserteq!(rb[-1], 3); asserteq!(rb[10], 2);

// Memcpy into slices at arbitrary isize indexes // and length. let mut readbuffer = [0u32; 7]; rb.readinto(&mut readbuffer, 2); asserteq!(read_buffer, [2, 3, 0, 1, 2, 3, 0]);

// Memcpy data from a slice into the ring buffer at // arbitrary isize indexes. Earlier data will not be // copied if it will be overwritten by newer data, // avoiding unecessary memcpy's. The correct placement // of the newer data will still be preserved. rb.writelatest(&[0, 2, 3, 4, 1], 0); asserteq!(rb[0], 1); asserteq!(rb[1], 2); asserteq!(rb[2], 3); assert_eq!(rb[3], 4);

// Read/write by retrieving slices directly. let (s1, s2) = rb.assliceslen(1, 4); asserteq!(s1, &[2, 3, 4]); asserteq!(s2, &[1]);

// Aligned/stack data may also be used. let mut stackdata = [0u32, 1, 2, 3]; let mut rbref = BMRingBufRef::new(&mut stackdata); rbref[-4] = 5; asserteq!(rbref[0], 5); asserteq!(rbref[1], 1); asserteq!(rbref[2], 2); asserteq!(rbref[3], 3);

// Get linear interpolation on floating point buffers. let mut rb = BMRingBuf::::fromcapacity(4); rb[0] = 0.0; rb[1] = 2.0; rb[2] = 4.0; rb[3] = 6.0; assert!((rb.lininterpf64(1.0) - 2.0).abs() <= f64::EPSILON); assert!((rb.lininterpf64(1.25) - 2.5).abs() <= f64::EPSILON); assert!((rb.lininterp_f64(3.75) - 1.5).abs() <= f64::EPSILON); ```