mod impls;
pub mod iter;
mod raw;
use iter::RingBufIter;
use raw::RawRingBuffer;
use std::iter::{ExactSizeIterator, IntoIterator};
use std::ptr;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum Side {
Beginning,
End,
}
pub struct RingBuffer<T> {
buf: RawRingBuffer<T>,
len: usize,
cap: usize,
begin: usize,
end: usize,
}
impl<T> RingBuffer<T> {
fn ptr(&self) -> *mut T {
self.buf.ptr.as_ptr()
}
pub fn cap(&self) -> usize {
self.cap
}
pub fn len(&self) -> usize {
self.len
}
pub fn new(cap: usize) -> Self {
RingBuffer {
buf: RawRingBuffer::new(cap),
cap,
len: 0,
begin: 0,
end: cap - 1,
}
}
pub fn from_exact_size_iter<I, U>(iter: I) -> Self
where
I: IntoIterator<Item = T, IntoIter = U>,
U: ExactSizeIterator<Item = T>,
{
let iter = iter.into_iter();
let cap = iter.len();
let mut me = Self::new(cap);
for el in iter {
me.push(el);
}
me
}
pub fn from_iter_cap<I>(iter: I, cap: usize) -> (Self, Option<impl Iterator<Item = T>>)
where
I: IntoIterator<Item = T>,
{
let mut iter = iter.into_iter();
let mut me = Self::new(cap);
for el in iter.by_ref().take(cap) {
me.push(el);
}
let next = iter.next();
let remainder = if next.is_some() {
Some(next.into_iter().chain(iter))
} else {
None
};
(me, remainder)
}
pub fn push(&mut self, elem: T) -> Option<T> {
if self.is_full() {
unsafe {
let offset = self.ptr().add(self.begin);
let prev_val = ptr::read(offset);
ptr::write(offset, elem);
self.rotate(1, Side::End);
Some(prev_val)
}
} else {
let offset = (self.end + 1) % self.cap;
unsafe {
let offset = self.ptr().add(offset);
ptr::write(offset, elem);
}
self.grow(1, Side::End);
None
}
}
pub fn push_back(&mut self, elem: T) -> Option<T> {
if self.is_full() {
unsafe {
let offset = self.ptr().add(self.end);
let prev_val = ptr::read(offset);
ptr::write(offset, elem);
self.rotate(1, Side::Beginning);
Some(prev_val)
}
} else {
let offset = sub_rem(self.begin, 1, self.cap);
unsafe {
let offset = self.ptr().add(offset);
ptr::write(offset, elem);
}
self.grow(1, Side::Beginning);
None
}
}
pub fn pop(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let elem = unsafe {
let offset = self.ptr().add(self.end);
ptr::read(offset)
};
self.shrink(1, Side::End);
Some(elem)
}
pub fn pop_oldest(&mut self) -> Option<T> {
if self.is_empty() {
return None;
}
let elem = unsafe {
let offset = self.ptr().add(self.begin);
ptr::read(offset)
};
self.shrink(1, Side::Beginning);
Some(elem)
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn is_full(&self) -> bool {
self.len == self.cap
}
pub fn iter(&self) -> RingBufIter<T> {
RingBufIter::new(self)
}
pub fn justify(&mut self) {
use std::mem;
if self.len == 0 || self.begin == 0 {
return;
}
if mem::size_of::<T>() == 0 {
self.begin = 0;
self.end = self.len - 1;
return;
}
if self.end >= self.begin {
unsafe {
let src = self.buf.ptr.as_ptr().add(self.begin);
let dst = self.buf.ptr.as_ptr();
ptr::copy(src, dst, self.len);
self.begin = 0;
self.end = self.len - 1;
}
} else {
unsafe {
let ptr = self.buf.ptr.as_ptr();
let tmp_buf = RawRingBuffer::new(self.end + 1);
let tmp_ptr = tmp_buf.ptr.as_ptr();
ptr::copy_nonoverlapping(ptr, tmp_ptr, tmp_buf.cap);
let begin_size = self.cap - self.begin;
let begin = ptr.add(self.begin);
ptr::copy(begin, ptr, begin_size);
let end_ptr = ptr.add(begin_size);
ptr::copy_nonoverlapping(tmp_ptr, end_ptr, tmp_buf.cap);
self.begin = 0;
self.end = self.len - 1;
}
}
}
pub fn is_contiguous(&self) -> bool {
self.len == 0 || self.begin <= self.end
}
pub fn beginning(&self) -> Option<usize> {
if self.is_empty() {
None
} else {
Some(self.begin)
}
}
pub fn end(&self) -> Option<usize> {
if self.is_empty() {
None
} else {
Some(self.end)
}
}
pub fn is_justified(&self) -> bool {
self.begin == 0
}
pub fn resize(&mut self, new_cap: usize) {
assert!(
new_cap >= self.len,
"New capacity {} is smaller than current buffer size {}",
new_cap,
self.len
);
self.justify();
self.buf.resize(new_cap);
self.cap = new_cap;
}
pub fn shrink_to_fit(&mut self) {
self.resize(self.len);
}
fn shrink(&mut self, n: usize, side: Side) {
debug_assert!(n > 0, "Shrink by 0 (internal error)");
debug_assert_ne!(
self.len, 0,
"Attempting to shrink 0-size buffer (internal error)"
);
debug_assert!(
n <= self.len,
"Attempting to shrink more than our current size (internal error)"
);
self.len -= n;
if self.len == 0 {
self.end = self.cap - 1;
self.begin = 0;
} else {
match side {
Side::End => {
self.end = sub_rem(self.end, n, self.cap);
}
Side::Beginning => self.begin = (self.begin + n) % self.cap,
}
}
}
fn offset_backwards(&self, n: usize) -> usize {
sub_rem(self.end, n, self.cap)
}
fn grow(&mut self, n: usize, side: Side) {
debug_assert!(n > 0, "Growth by 0 (internal error)");
debug_assert!(
self.len + n <= self.cap,
"Growing buffer past capacity \
(this should never appear externally, this means internally calls were not \
properly split between grow and rotate, file a bug report)"
);
match side {
Side::End => {
self.end = (self.end + n) % self.cap;
self.len += n;
}
Side::Beginning => {
self.begin = sub_rem(self.begin, n, self.cap);
self.len += n;
}
}
}
fn rotate(&mut self, n: usize, side: Side) {
debug_assert!(n > 0, "Rotation of 0 (internal error)");
debug_assert!(self.is_full(), "Rotation when not full (internal error)");
match side {
Side::End => {
self.end = (self.end + n) % self.cap;
self.begin = (self.begin + n) % self.cap;
}
Side::Beginning => {
self.begin = sub_rem(self.begin, n, self.cap);
self.end = sub_rem(self.end, n, self.cap);
}
}
}
}
impl<T> RingBuffer<T>
where
T: PartialEq,
{
pub fn elem_equal(&self, other: &Self) -> bool {
self.len == other.len && self.iter().zip(other.iter()).all(|(e1, e2)| e1 == e2)
}
}
fn sub_rem(n: usize, sub: usize, div: usize) -> usize {
debug_assert!(n < div, "n ({}) should already be modulo div ({})", n, div);
debug_assert!(
sub <= div,
"sub_rem not meant to be used with sub ({}) > div ({})",
sub,
div
);
if sub <= n {
n - sub
} else {
div - (sub - n)
}
}
#[cfg(test)]
mod test {
#[test]
fn sub_rem() {
use super::sub_rem;
assert_eq!(sub_rem(4, 1, 5), 3);
assert_eq!(sub_rem(0, 1, 5), 4);
assert_eq!(sub_rem(2, 3, 5), 4);
assert_eq!(sub_rem(3, 3, 5), 0);
}
}