pub struct RingBuffer<T> { /* private fields */ }Expand description
A fixed-sized collection meant to hold a limited horizon of generic data. When filled to capacity, older data will be overwritten.
Indexing and iterating over this collection will start from the most recent
element (assuming you primarily use push,
however all iterators implement ExactSizeIterator and
DoubleEndedIterator, so they can be trivially traversed backwards with
the rev method.
Be aware that the Eq and PartialEq implementations for this struct do not care
about buffer rotation (where in the ring a sequence starts), but they do check if two
buffers have the same capacity. So two buffers with the sequence [1,2,3] may not compare
as equal if one can hold 10 elements and one can hold 20. If you want to compare these, a
convenience method called elem_equal is provided.
Implementations§
Source§impl<T> RingBuffer<T>
impl<T> RingBuffer<T>
Sourcepub fn cap(&self) -> usize
pub fn cap(&self) -> usize
The capacity of the buffer, this is the most data this buffer can store before it starts overwriting older entries.
Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
The length of the buffer. This is the number
of elements currently stores. When len and cap
are equal, the buffer will begin overwriting older
entries.
Sourcepub fn new(cap: usize) -> Self
pub fn new(cap: usize) -> Self
Creates a new RingBuffer at the given capacity,
this buffer will not grow without explicit calls to
resize.
Sourcepub fn from_exact_size_iter<I, U>(iter: I) -> Selfwhere
I: IntoIterator<Item = T, IntoIter = U>,
U: ExactSizeIterator<Item = T>,
pub fn from_exact_size_iter<I, U>(iter: I) -> Selfwhere
I: IntoIterator<Item = T, IntoIter = U>,
U: ExactSizeIterator<Item = T>,
Creates a new RingBuffer that exactly fits
the data in the provided iterator. It must have an exact
size or we cannot intuit the capacity.
use simple_ringbuf::RingBuffer;;
let buf = RingBuffer::from_exact_size_iter(vec![1,2,3]);
assert!(buf.is_justified());
let mut cmp = RingBuffer::new(3);
cmp.push(1);
cmp.push(2);
cmp.push(3);
assert_eq!(buf, cmp);Sourcepub fn from_iter_cap<I>(
iter: I,
cap: usize,
) -> (Self, Option<impl Iterator<Item = T>>)where
I: IntoIterator<Item = T>,
pub fn from_iter_cap<I>(
iter: I,
cap: usize,
) -> (Self, Option<impl Iterator<Item = T>>)where
I: IntoIterator<Item = T>,
Creates a new RingBuffer with capacity cap that fills itself with
at most cap elements from the provided iterator. If any of the iterator is
left over at the end, an iterator yielding those elements will be returned.
use simple_ringbuf::RingBuffer;;
let (buf, rem) = RingBuffer::from_iter_cap(vec![1,2,3], 2);
assert!(buf.is_justified());
let mut cmp = RingBuffer::new(2);
cmp.push(1);
cmp.push(2);
assert_eq!(buf, cmp);
assert!(rem.is_some());
let rem = rem.unwrap();
assert_eq!(vec![3], rem.collect::<Vec<_>>());Sourcepub fn push(&mut self, elem: T) -> Option<T>
pub fn push(&mut self, elem: T) -> Option<T>
Pushes an element onto the collection. This is intended to be the primary means of using this as a log/undo buffer.
If the buffer is full, this will overwrite the element at buf[len-1], which is the “oldest”
element if you generally use the collection as designed.
If this method overwrites an existing element it will return it, otherwise it will
return None.
use simple_ringbuf::RingBuffer;;
let mut buf = RingBuffer::new(3);
buf.push(1);
buf.push(2);
buf.push(3);
assert_eq!(buf[0], 3);
assert_eq!(buf[1], 2);
assert_eq!(buf[2], 1);
let el = buf.push(10);
assert_eq!(el, Some(1));
assert_eq!(buf[0], 10);
assert_eq!(buf[1], 3);
assert_eq!(buf[2], 2);Sourcepub fn push_back(&mut self, elem: T) -> Option<T>
pub fn push_back(&mut self, elem: T) -> Option<T>
Pushes an element as if it were the first element added. If the buffer
is full, this will overwrite the element at buf[0], which is the most
recently added element (if you use the collection as designed defaulting to
push in most cases).
This is not intended to be the primary method of adding data, but rather reinserting an element you’ve removed or otherwise rewinding history.
If this method overwrites an existing element, it will return it. Otherwise it will
return None.
use simple_ringbuf::RingBuffer;;
let mut buf = RingBuffer::new(3);
buf.push(1);
buf.push(2);
buf.push(3);
assert_eq!(buf[0], 3);
assert_eq!(buf[1], 2);
assert_eq!(buf[2], 1);
let el = buf.push(10);
assert!(el.is_some());
let el = el.unwrap();
let el = buf.push_back(el);
assert_eq!(el, Some(10));
assert_eq!(buf[0], 3);
assert_eq!(buf[1], 2);
assert_eq!(buf[2], 1);Sourcepub fn pop(&mut self) -> Option<T>
pub fn pop(&mut self) -> Option<T>
Removes the most recently added element from the collection and returns it, shrinking the buffer from the end.
Note that if you’ve been using push_back this won’t
be the most recently added element per se, but rather the element at
the end of the collection (aka at buf[0]).
use simple_ringbuf::RingBuffer;
let mut buf = RingBuffer::new(5);
buf.push(5);
buf.push(10);
buf.push(20);
assert_eq!(buf.pop(), Some(20));
assert_eq!(buf.len(), 2);Sourcepub fn pop_oldest(&mut self) -> Option<T>
pub fn pop_oldest(&mut self) -> Option<T>
Removes the oldest element from the collection and returns it, shrinking the buffer from the beginning.
Note that if you’ve been using push_back this won’t be the oldest
element per se, but rather the element at the [beginning] (buf[len-1]).
use simple_ringbuf::RingBuffer;
let mut buf = RingBuffer::new(5);
buf.push(5);
buf.push(10);
buf.push(20);
assert_eq!(buf.pop_oldest(), Some(5));
assert_eq!(buf.len(), 2);Sourcepub fn is_full(&self) -> bool
pub fn is_full(&self) -> bool
Determines whether the buffer is filled to capacity, if this is true, any subsequent writes will overwrite the oldest element.
Sourcepub fn iter(&self) -> RingBufIter<'_, T> ⓘ
pub fn iter(&self) -> RingBufIter<'_, T> ⓘ
Returns an iterator over this buffer.
Sourcepub fn justify(&mut self)
pub fn justify(&mut self)
Forces a buffer to be “justified”.
This means the first element is at the beginning of
the actual underlying buffer. Once a buffer gets full, or if you frequently use pop_oldest,
this will rarely be true.
Justifying a buffer is largely useful for internal operations such as resize, but may
be useful if you require the elements to be in a contiguous memory block for some reason.
use simple_ringbuf::RingBuffer;
let mut buf = RingBuffer::new(5);
buf.push(19);
buf.push(26);
buf.push(113);
assert!(buf.is_justified());
// Buf now has a gap
buf.pop_oldest();
assert!( !buf.is_justified() );
buf.justify();
assert!(buf.is_justified());Sourcepub fn is_contiguous(&self) -> bool
pub fn is_contiguous(&self) -> bool
Determines if a buffer is “contiguous” if
the end of the buffer is after the beginning in
the internal memory layout. That is beginning < end.
This likely isn’t useful in most cases, but if you want to do unsafe hacky things, or
make sure the buffer is contiguous before iterating for, e.g., cache reasons
you may decide to call this before deciding whether to call justify. (This likely
won’t have any appreciable effect on speed, especially while iterating in the default order).
An empty buffer is always contiguous.
Sourcepub fn beginning(&self) -> Option<usize>
pub fn beginning(&self) -> Option<usize>
Shows where in the internal buffer the current data begins,
not particularly useful but here for convenience. This will return
None when the buffer is empty. Note that due to how indexing works,
this is buf[end], buf[0] will yield the newest element added.
Sourcepub fn end(&self) -> Option<usize>
pub fn end(&self) -> Option<usize>
Shows where in the internal buffer the current data ends,
not particularly useful but here for convenience. This will return
None when the buffer is empty. Note that due to how indexing works,
this is buf[0], buf[end] will yield the oldest element added.
Sourcepub fn is_justified(&self) -> bool
pub fn is_justified(&self) -> bool
Determines if the buffer is “justified”,
this means the first element is at the beginning of
the actual underlying buffer. Once a buffer gets full, or if you frequently use pop_oldest,
this will rarely be true.
An empty buffer is always justified.
use simple_ringbuf::RingBuffer;
let mut buf = RingBuffer::new(5);
buf.push(19);
buf.push(26);
buf.push(113);
assert!(buf.is_justified());
buf.pop();
assert!(buf.is_justified());
// Buf now has a gap
buf.pop_oldest();
assert!( !buf.is_justified() );
// Empty buffer
buf.pop();
assert!(buf.is_justified());This is largely useful for internal operations such as resize.
If you really need to check for something that will aid, e.g., iteration
speed, or you want to do unsafe hacky things, is_contiguous is probably
closer to what you want.
Sourcepub fn resize(&mut self, new_cap: usize)
pub fn resize(&mut self, new_cap: usize)
Resizes the buffer such that it can hold more or fewer total elements. This will panic is the capacity underflows the current length.
The new buffer will be justified.
use simple_ringbuf::RingBuffer;
let mut buf = RingBuffer::new(5);
buf.push(2);
buf.push(3);
buf.resize(2);
assert_eq!(buf.cap(), 2);
buf.pop_oldest();
buf.resize(9);
assert_eq!(buf.cap(), 9);
assert_eq!(buf.len(), 1);
assert!(buf.is_justified());pub fn shrink_to_fit(&mut self)
Source§impl<T> RingBuffer<T>where
T: PartialEq,
impl<T> RingBuffer<T>where
T: PartialEq,
Sourcepub fn elem_equal(&self, other: &Self) -> bool
pub fn elem_equal(&self, other: &Self) -> bool
Performs an element-wise comparison between two different-capacity buffers.
If your buffers are the same size you probably just want ==.
use simple_ringbuf::RingBuffer;
let mut buf = RingBuffer::new(5);
buf.push(1);
buf.push(2);
buf.push(3);
let mut buf2 = RingBuffer::new(10);
buf2.push(1);
buf2.push(2);
buf2.push(3);
assert_ne!(buf, buf2); // Not the same!
assert!(buf.elem_equal(&buf2)); // This works though