use std::convert::TryInto;
#[cfg(test)]
mod tests;
#[derive(Copy)]
pub struct CircularBuffer<T> {
buffer: *mut T,
w: usize,
r: usize,
size: usize,
full: bool,
}
impl<T> CircularBuffer<T> {
pub fn new(size: usize) -> Self {
let size = size;
let type_size = std::mem::size_of::<T>();
let vector_size = type_size.checked_mul(size).unwrap();
let aligment = std::mem::align_of::<T>();
let layout = std::alloc::Layout::from_size_align(vector_size, aligment).unwrap();
let ptr = unsafe { std::alloc::alloc_zeroed(layout) };
CircularBuffer {
buffer: ptr.cast(),
w: 0,
r: 0,
size,
full: false,
}
}
pub fn len(&self) -> usize {
if self.full {
return self.size;
}
if self.w > self.r {
self.w - self.r
} else if self.w == self.r {
0
} else {
self.size - self.r + self.w
}
}
fn next_inc(&self, i: usize) -> usize {
(i + 1) % self.size
}
fn w_inc(&mut self) {
self.w = self.next_inc(self.w);
}
fn r_inc(&mut self) {
self.r = self.next_inc(self.r);
}
fn r_inc_of(&mut self, n: usize) {
self.r = (self.r + n) % self.size;
}
fn write(&mut self, value: T) {
let w_index = self.w;
self.w_inc();
unsafe {
self.buffer.add(w_index).write(value);
}
}
fn read(&mut self) -> T {
let r_index = self.r;
self.r_inc();
unsafe {
let ptr = self.buffer.add(r_index);
ptr.read()
}
}
fn drop(&mut self) {
unsafe {
let ptr = self.buffer.offset(self.w.try_into().unwrap());
std::ptr::drop_in_place(ptr);
}
}
pub fn push(&mut self, value: T) -> usize {
if self.full {
self.drop();
self.r_inc();
}
self.write(value);
if self.w == self.r {
self.full = true;
0
} else {
self.size - self.len()
}
}
pub fn fill(&mut self, return_vector: &mut Vec<T>) -> usize {
let mut i = 0;
while return_vector.capacity() - return_vector.len() > 0 {
match self.next() {
Some(element) => {
return_vector.push(element);
i += 1;
}
None => return i,
}
}
i
}
fn split_in_ranges(&self) -> (std::ops::Range<usize>, Option<std::ops::Range<usize>>) {
if self.r < self.w {
(self.r..self.w, None)
} else if self.r == self.w {
if self.full {
(self.r..self.size, Some(0..self.w))
} else {
(self.r..self.r, None)
}
} else {
(self.r..self.size, Some(0..self.w))
}
}
fn fill_vector_from_split(&mut self, range: std::ops::Range<usize>, vec: &mut Vec<T>) -> usize {
let sink_capacity = vec.capacity() - vec.len();
if sink_capacity == 0 {
return 0;
}
if range.len() == 0 {
return 0;
}
let to_push = if range.len() <= sink_capacity {
range
} else {
let mut r = range;
r.end = r.start + sink_capacity;
r
};
unsafe {
let ptr = vec.as_mut_ptr().add(vec.len());
std::ptr::copy_nonoverlapping(self.buffer.add(to_push.start), ptr, to_push.len());
vec.set_len(vec.len() + to_push.len());
}
self.r_inc_of(to_push.len());
self.full = false;
return to_push.len();
}
pub fn _fast_fill(&mut self, return_vector: &mut Vec<T>) -> usize {
if self.len() == 0 {
return 0;
}
let sink_capacity = return_vector.capacity() - return_vector.len();
if sink_capacity == 0 {
return 0;
}
let mut total_pushed = 0;
let (r1, r2) = self.split_in_ranges();
total_pushed += self.fill_vector_from_split(r1, return_vector);
if total_pushed == sink_capacity {
return total_pushed;
}
if let Some(r2) = r2 {
total_pushed += self.fill_vector_from_split(r2, return_vector)
}
total_pushed
}
}
impl<T: Clone> Clone for CircularBuffer<T> {
fn clone(&self) -> Self {
let mut new = CircularBuffer::new(self.size);
new.w = self.w;
new.r = self.r;
new.size = self.size; new.full = self.full;
let (r1, r2) = self.split_in_ranges();
for i in r1 {
unsafe {
let r_ptr = self.buffer.add(i);
let e0 = r_ptr.read();
let e1 = e0.clone();
std::mem::forget(e0);
let w_buffer = new.buffer as *mut T;
let w_ptr = w_buffer.add(i);
w_ptr.write(e1);
}
}
if let Some(r2) = r2 {
for i in r2 {
unsafe {
let r_ptr = self.buffer.add(i);
let e0 = r_ptr.read();
let e1 = e0.clone();
std::mem::forget(e0);
let w_buffer = new.buffer as *mut T;
let w_ptr = w_buffer.add(i);
w_ptr.write(e1);
}
}
}
new
}
}
impl<T> std::iter::Iterator for CircularBuffer<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match self.len() {
0 => None,
_ => {
self.full = false;
Some(self.read())
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len(), Some(self.len()))
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for CircularBuffer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.len() == 0 {
return write!(f, "CircularBuffer(<empty>)");
}
write!(f, "CircularBuffer(")?;
let mut fake_read = self.r;
let read = fake_read.try_into().unwrap();
let element = unsafe {
let ptr = self.buffer.offset(read);
ptr.read()
};
std::fmt::Debug::fmt(&element, f)?;
std::mem::forget(element);
fake_read = self.next_inc(fake_read);
while fake_read != self.w {
write!(f, ", ")?;
let read = fake_read.try_into().unwrap();
let element = unsafe {
let ptr = self.buffer.offset(read);
ptr.read()
};
std::fmt::Debug::fmt(&element, f)?;
std::mem::forget(element);
fake_read = self.next_inc(fake_read);
}
write!(
f,
") w: {:?}, r: {:?}, size: {:?}, full: {:?}",
self.w, self.r, self.size, self.full
)
}
}
impl<T: std::fmt::Display> std::fmt::Display for CircularBuffer<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.len() == 0 {
return write!(f, "CircularBuffer(<empty>)");
}
write!(f, "CircularBuffer(")?;
let mut fake_read = self.r;
let read = fake_read.try_into().unwrap();
let element = unsafe {
let ptr = self.buffer.offset(read);
ptr.read()
};
std::fmt::Display::fmt(&element, f)?;
std::mem::forget(element);
fake_read = self.next_inc(fake_read);
while fake_read != self.w {
write!(f, ", ")?;
let read = fake_read.try_into().unwrap();
let element = unsafe {
let ptr = self.buffer.offset(read);
ptr.read()
};
std::fmt::Display::fmt(&element, f)?;
std::mem::forget(element);
fake_read = self.next_inc(fake_read);
}
write!(f, ")")
}
}