Crate strider [] [src]

useful for stepping (variable step) a window (variable size) through a streaming (possibly infinite) series of values while avoiding unnecessary memory allocations

essential in computing the short-time fourier transform and other data/signal processing methods.

to use add strider = "0.1.1" to the [dependencies] section of your Cargo.toml and call extern crate strider; in your code.

example

following is a program that reads a stream of chars from stdin. it writes every consecutive sequence of WINDOW_SIZE chars that is STEP_SIZE apart to stdout. for the input of ABCDEFGHIJK it produces the output ABCDCDEFEFGHGHIJ. it uses constant memory and does no allocations after the initial ones. you should be able to grasp the idea and adapt it to your needs.

use std::io;
use std::io::{Write, Read};

extern crate strider;
use strider::{SliceRing, SliceRingImpl};

fn main() {
    const WINDOW_SIZE: usize = 4;
    const STEP_SIZE: usize = 2;

    let mut ring = SliceRingImpl::<u8>::new();
    let mut input_buffer: &mut [u8] = &mut [0; 20];
    let mut window_buffer: &mut [u8] = &mut [0; WINDOW_SIZE];

    loop {
        let input_count = io::stdin().read(input_buffer).unwrap();
        // leave the loop when we reach end of file
        if input_count == 0 { break; }

        // add elements to the back of the ring
        ring.push_many_back(&input_buffer[..input_count]);
        // read as long as we can read windows of length `WINDOW_SIZE`
        while WINDOW_SIZE <= ring.len() {
            ring.read_many_front(window_buffer);
            io::stdout().write(window_buffer).unwrap();
            // do a step by dropping the first `STEP_SIZE` elements in ring
            ring.drop_many_front(STEP_SIZE);
        }
    }
}

overview

memory

these operations read from and writes to buffers that you control.

performance

strider::SliceRing is implemented by std::collections::VecDeque and strider::SliceRingImpl. strider::SliceRingImpl is an optimized implementation of strider::SliceRing that is 2 to 6 times faster than the implementation using std::collections::VecDeque. see the benchmarks.

two backing buffer types: one simple for illustration one optimized for performance benchmarked against each other

often you want to do deque operations on multiple values at once. operations implemented on std::collections::VecDeque as well as an optimized implementation.

windowing the equivalent of 1 minute of 44100 hz audio samples with a window_size of 1024 and step_size of 512 only takes a few (6) milliseconds and constant memory of about

this is probably what you want

sliding-window uses a std::collections::VecDeque under the hood.

will double in size only when full.

for the common case this allocates memory once, maybe twice and is done with it.

fast

performance

optimized for and restricted to working on multiple things at once. which it can do faster.

performance is relative. so instead of claiming that this is fast, we'll instead prove that it is much faster than a naive implementation building on std::collections::VecDeque.

reads integers from stdin and without any memory allocations (past the initial).

Macros

test_slice_ring!

macro containing a test run that is used to test and benchmark different implementations of the SliceRing trait

Structs

SliceRingImpl

readable area starts at first_readable and goes until next_writable. next_writable is one after the last readable and not readable.

Traits

SliceRing

ringbuffer operations on slices