#![no_std]
extern crate alloc;
use alloc::{
alloc::{alloc, handle_alloc_error, Layout},
boxed::Box,
};
use core::{
clone::Clone,
cmp::{Ord, Ordering},
fmt::Debug,
iter::Iterator,
mem::{transmute, MaybeUninit},
ops::{FnMut, Range},
ptr::copy,
slice,
};
#[derive(Debug)]
pub struct Ring<T>
where
T: Clone,
{
buf: Box<[MaybeUninit<T>]>,
oldest: usize,
fill: usize,
capacity: usize,
}
impl<T> Ring<T>
where
T: Clone,
{
pub fn new(n: usize) -> Self {
Self {
buf: Self::new_buf(n),
oldest: 0,
fill: 0,
capacity: n,
}
}
pub fn len(&self) -> usize {
self.fill
}
pub fn is_empty(&self) -> bool {
self.fill == 0
}
pub fn is_full(&self) -> bool {
self.fill == self.capacity
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn as_slice(&self) -> &[T] {
unsafe {
transmute::<&[MaybeUninit<T>], &[T]>(&self.buf[self.oldest..self.oldest + self.fill])
}
}
pub fn append(&mut self, value: T) {
if self.capacity == 0 {
return;
}
let newest = (self.oldest + self.fill) % self.capacity;
if self.fill == self.capacity {
unsafe {
self.buf[self.oldest].assume_init_drop();
self.buf[self.oldest + self.capacity].assume_init_drop();
}
self.oldest = (self.oldest + 1) % self.capacity;
} else {
self.fill += 1;
}
self.buf[newest].write(value.clone());
self.buf[newest + self.capacity].write(value);
}
pub fn prepend(&mut self, value: T) {
if self.capacity == 0 {
return;
}
self.oldest = (self.oldest + self.capacity - 1) % self.capacity;
if self.fill == self.capacity {
unsafe {
self.buf[self.oldest].assume_init_drop();
self.buf[self.oldest + self.capacity].assume_init_drop();
}
} else {
self.fill += 1;
}
self.buf[self.oldest].write(value.clone());
self.buf[self.oldest + self.capacity].write(value);
}
pub fn sort_by<F>(&mut self, compare: F)
where
F: FnMut(&T, &T) -> Ordering,
{
self.as_slice_mut().sort_unstable_by(compare);
self.duplicate();
}
pub fn sort_by_key<K, F>(&mut self, key: F)
where
F: FnMut(&T) -> K,
K: Ord,
{
self.as_slice_mut().sort_unstable_by_key(key);
self.duplicate();
}
pub fn insert_at(&mut self, index: usize, value: T) {
if index > self.fill {
panic!("Invalid index {index} for buffer with size {}", self.fill);
}
if self.fill == self.capacity {
if index == 0 {
return;
}
unsafe {
self.buf[self.oldest].assume_init_drop();
self.buf[self.oldest + self.capacity].assume_init_drop();
}
}
let src; let dst; let n; let insert; let lower; let upper;
if index > self.fill / 2 {
src = self.oldest + index;
dst = src + 1;
n = self.fill - index;
insert = src;
if self.capacity == self.fill {
self.oldest = (self.oldest + 1) % self.capacity;
} else {
self.fill += 1;
}
lower = src;
upper = dst + n;
} else {
if self.capacity == self.fill {
src = self.oldest + 1;
n = index - 1;
} else {
src = if self.oldest == 0 {
self.capacity
} else {
self.oldest
};
n = index;
self.fill += 1;
self.oldest = (self.oldest + self.capacity - 1) % self.capacity;
}
dst = src - 1;
insert = dst + n;
lower = dst;
upper = src + n;
}
if n > 0 {
unsafe { copy::<MaybeUninit<T>>(&self.buf[src], &mut self.buf[dst], n) };
if self.capacity <= lower {
unsafe {
copy::<MaybeUninit<T>>(
&self.buf[src - self.capacity],
&mut self.buf[dst - self.capacity],
n,
)
};
} else if self.capacity >= upper {
unsafe {
copy::<MaybeUninit<T>>(
&self.buf[src + self.capacity],
&mut self.buf[dst + self.capacity],
n,
)
};
} else {
let suffix = upper - self.capacity - 1;
let prefix = self.capacity - lower - 1;
let end = self.buf.len() - 1;
if dst > src {
unsafe {
copy::<MaybeUninit<T>>(&self.buf[0], &mut self.buf[1], suffix);
copy::<MaybeUninit<T>>(&self.buf[end], &mut self.buf[0], 1);
copy::<MaybeUninit<T>>(
&self.buf[end - prefix],
&mut self.buf[end - prefix + 1],
prefix,
);
}
} else {
unsafe {
copy::<MaybeUninit<T>>(
&self.buf[end - prefix + 1],
&mut self.buf[end - prefix],
prefix,
);
copy::<MaybeUninit<T>>(&self.buf[0], &mut self.buf[end], 1);
copy::<MaybeUninit<T>>(&self.buf[1], &mut self.buf[0], suffix);
}
}
}
}
self.buf[insert].write(value.clone());
self.buf[(insert + self.capacity) % self.buf.len()].write(value);
}
pub fn insert_by<F>(&mut self, value: T, mut compare: F)
where
F: FnMut(&T, &T) -> Ordering,
{
let idx = self
.as_slice()
.partition_point(|x| compare(x, &value) == Ordering::Less);
self.insert_at(idx, value);
}
pub fn insert_by_key<K, F>(&mut self, value: T, mut key: F)
where
F: FnMut(&T) -> K,
K: Ord,
{
let k = key(&value);
let idx = self.as_slice().partition_point(|x| key(x) < k);
self.insert_at(idx, value);
}
fn new_buf(n: usize) -> Box<[MaybeUninit<T>]> {
unsafe {
let layout = Layout::array::<T>(2 * n).expect("Invalid memory layout requested");
let ptr = alloc(layout);
if ptr.is_null() {
handle_alloc_error(layout);
}
Box::from_raw(slice::from_raw_parts_mut(
ptr.cast::<MaybeUninit<T>>(),
2 * n,
))
}
}
fn as_slice_mut(&mut self) -> &mut [T] {
unsafe {
transmute::<&mut [MaybeUninit<T>], &mut [T]>(
&mut self.buf[self.oldest..self.oldest + self.fill],
)
}
}
#[inline]
fn drop_and_replace_range(&mut self, src: Range<usize>, dst: Range<usize>) {
for (s, d) in Iterator::zip(src, dst) {
unsafe {
self.buf[d].assume_init_drop();
self.buf[d].write(self.buf[s].assume_init_ref().clone());
}
}
}
#[inline]
fn duplicate(&mut self) {
if self.oldest + self.fill <= self.capacity {
self.drop_and_replace_range(
self.oldest..self.oldest + self.fill,
self.oldest + self.capacity..self.oldest + self.fill + self.capacity,
);
} else {
self.drop_and_replace_range(
self.oldest..self.capacity,
self.oldest + self.capacity..2 * self.capacity,
);
let newest = (self.oldest + self.fill) % self.capacity;
self.drop_and_replace_range(self.capacity..self.oldest + self.fill, 0..newest);
}
}
}
impl<T> Ring<T>
where
T: Clone + Ord,
{
pub fn sort(&mut self) {
self.as_slice_mut().sort_unstable();
self.duplicate();
}
pub fn insert(&mut self, value: T) {
let idx = self.as_slice().partition_point(|x| x < &value);
self.insert_at(idx, value);
}
}
impl<T> Clone for Ring<T>
where
T: Clone,
{
fn clone(&self) -> Self {
let mut buf = Self::new_buf(self.capacity);
for idx in self.oldest..self.oldest + self.capacity {
let idx = idx % self.capacity;
unsafe {
buf[idx].write(self.buf[idx].assume_init_ref().clone());
buf[idx + self.capacity].write(self.buf[idx].assume_init_ref().clone());
}
}
Self {
buf,
oldest: self.oldest,
capacity: self.capacity,
fill: self.fill,
}
}
}
#[cfg(test)]
mod tests {
use super::Ring;
#[test]
fn test_new() {
let h = Ring::<u32>::new(3);
assert_eq!(h.oldest, 0);
assert_eq!(h.fill, 0);
assert_eq!(h.capacity, 3);
assert_eq!(h.buf.len(), 6);
}
#[test]
fn test_clone() {
let mut h = Ring::<i32>::new(3);
h.append(1);
h.prepend(2);
let h2 = h.clone();
assert_eq!(h2.oldest, 2);
assert_eq!(h2.fill, 2);
assert_eq!(h2.capacity, 3);
assert_eq!(unsafe { h2.buf[0].assume_init_ref() }, &1);
assert_eq!(unsafe { h2.buf[2].assume_init_ref() }, &2);
assert_eq!(unsafe { h2.buf[3].assume_init_ref() }, &1);
assert_eq!(unsafe { h2.buf[5].assume_init_ref() }, &2);
}
#[test]
fn test_len() {
let mut h = Ring::<i32>::new(3);
assert_eq!(h.len(), 0);
h.append(1);
assert_eq!(h.len(), 1);
h.prepend(2);
assert_eq!(h.len(), 2);
h.insert_at(0, 3);
assert_eq!(h.len(), 3);
h.insert(2);
assert_eq!(h.len(), 3);
}
#[test]
fn test_is_empty() {
assert!(Ring::<i32>::new(0).is_empty());
assert!(Ring::<[&str; 3]>::new(1).is_empty());
assert!(Ring::<&[f64]>::new(3).is_empty());
let mut h = Ring::<&[f64]>::new(3);
h.append(&[0.0, 1.0]);
assert!(!h.is_empty());
}
#[test]
fn test_is_full() {
assert!(Ring::<&[f64]>::new(0).is_full());
let mut h = Ring::<[&str; 3]>::new(1);
assert!(!h.is_full());
h.append(["a", "b", "c"]);
assert!(h.is_full());
let mut h = Ring::<i32>::new(3);
assert!(!h.is_full());
h.append(0);
assert!(!h.is_full());
h.append(1);
assert!(!h.is_full());
h.append(2);
assert!(h.is_full());
}
#[test]
fn test_append() {
let mut h = Ring::<u32>::new(3);
assert_eq!(h.len(), 0);
assert_eq!(h.as_slice(), &[]);
h.append(10);
assert_eq!(h.len(), 1);
assert_eq!(h.as_slice(), &[10]);
h.append(20);
assert_eq!(h.len(), 2);
assert_eq!(h.as_slice(), &[10, 20]);
h.append(30);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[10, 20, 30]);
h.append(40);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[20, 30, 40]);
}
#[test]
fn test_prepend() {
let mut h = Ring::<u32>::new(3);
assert_eq!(h.len(), 0);
assert_eq!(h.as_slice(), &[]);
assert_eq!(h.oldest, 0);
h.prepend(10);
assert_eq!(h.len(), 1);
assert_eq!(h.as_slice(), &[10]);
assert_eq!(h.oldest, 2);
h.prepend(20);
assert_eq!(h.len(), 2);
assert_eq!(h.as_slice(), &[20, 10]);
assert_eq!(h.oldest, 1);
h.prepend(30);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[30, 20, 10]);
assert_eq!(h.oldest, 0);
h.prepend(40);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[40, 30, 20]);
assert_eq!(h.oldest, 2);
}
#[test]
fn test_sort() {
let mut h = Ring::<u32>::new(5);
assert_eq!(h.len(), 0);
assert_eq!(h.as_slice(), &[]);
h.sort();
assert_eq!(h.len(), 0);
assert_eq!(h.as_slice(), &[]);
assert_eq!(h.oldest, 0);
h.append(20);
h.append(10);
h.append(30);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[20, 10, 30]);
h.sort();
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[10, 20, 30]);
assert_eq!(h.oldest, 0);
h.prepend(40);
h.append(0);
assert_eq!(h.len(), 5);
assert_eq!(h.as_slice(), &[40, 10, 20, 30, 0]);
h.sort();
assert_eq!(h.len(), 5);
assert_eq!(h.as_slice(), &[0, 10, 20, 30, 40]);
assert_eq!(h.oldest, 4);
}
#[test]
fn test_sort_by() {
let cmp = |a: &&str, b: &&str| a.len().cmp(&b.len());
let empty: &[&str] = &[];
let mut h = Ring::<&str>::new(5);
assert_eq!(h.len(), 0);
assert_eq!(h.as_slice(), empty);
h.sort_by(cmp);
assert_eq!(h.len(), 0);
assert_eq!(h.as_slice(), empty);
assert_eq!(h.oldest, 0);
h.append("abc");
h.append("d");
h.append("ef");
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["abc", "d", "ef"]);
h.sort_by(cmp);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["d", "ef", "abc"]);
assert_eq!(h.oldest, 0);
h.prepend("aaaa");
h.append("");
assert_eq!(h.len(), 5);
assert_eq!(h.as_slice(), &["aaaa", "d", "ef", "abc", ""]);
h.sort_by(cmp);
assert_eq!(h.len(), 5);
assert_eq!(h.as_slice(), &["", "d", "ef", "abc", "aaaa"]);
assert_eq!(h.oldest, 4);
}
#[test]
fn test_sort_by_key() {
let key = |a: &&str| a.len();
let empty: &[&str] = &[];
let mut h = Ring::<&str>::new(5);
assert_eq!(h.len(), 0);
assert_eq!(h.as_slice(), empty);
h.sort_by_key(key);
assert_eq!(h.len(), 0);
assert_eq!(h.as_slice(), empty);
assert_eq!(h.oldest, 0);
h.append("abc");
h.append("d");
h.append("ef");
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["abc", "d", "ef"]);
h.sort_by_key(key);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["d", "ef", "abc"]);
assert_eq!(h.oldest, 0);
h.prepend("aaaa");
h.append("");
assert_eq!(h.len(), 5);
assert_eq!(h.as_slice(), &["aaaa", "d", "ef", "abc", ""]);
h.sort_by_key(key);
assert_eq!(h.len(), 5);
assert_eq!(h.as_slice(), &["", "d", "ef", "abc", "aaaa"]);
assert_eq!(h.oldest, 4);
}
#[test]
fn test_insert() {
let mut h = Ring::<i32>::new(3);
h.insert(2);
assert_eq!(h.len(), 1);
assert_eq!(h.as_slice(), &[2]);
assert_eq!(h.oldest, 2);
h.insert(4);
assert_eq!(h.len(), 2);
assert_eq!(h.as_slice(), &[2, 4]);
assert_eq!(h.oldest, 2);
h.insert(1);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[1, 2, 4]);
assert_eq!(h.oldest, 1);
h.insert(0);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[1, 2, 4]);
assert_eq!(h.oldest, 1);
h.insert(5);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[2, 4, 5]);
assert_eq!(h.oldest, 2);
h.insert(3);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &[3, 4, 5]);
assert_eq!(h.oldest, 2);
}
#[test]
fn test_insert_by() {
let mut h = Ring::<&str>::new(3);
let cmp = |a: &&str, b: &&str| a.len().cmp(&b.len());
h.insert_by("wx", cmp);
assert_eq!(h.len(), 1);
assert_eq!(h.as_slice(), &["wx"]);
assert_eq!(h.oldest, 2);
h.insert_by("snarf", cmp);
assert_eq!(h.len(), 2);
assert_eq!(h.as_slice(), &["wx", "snarf"]);
assert_eq!(h.oldest, 2);
h.insert_by("z", cmp);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["z", "wx", "snarf"]);
assert_eq!(h.oldest, 1);
h.insert_by("", cmp);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["z", "wx", "snarf"]);
assert_eq!(h.oldest, 1);
h.insert_by("foobar", cmp);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["wx", "snarf", "foobar"]);
assert_eq!(h.oldest, 2);
h.insert_by("abc", cmp);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["abc", "snarf", "foobar"]);
assert_eq!(h.oldest, 2);
}
#[test]
fn test_insert_by_key() {
let mut h = Ring::<&str>::new(3);
let key = |a: &&str| a.len();
h.insert_by_key("wx", key);
assert_eq!(h.len(), 1);
assert_eq!(h.as_slice(), &["wx"]);
assert_eq!(h.oldest, 2);
h.insert_by_key("snarf", key);
assert_eq!(h.len(), 2);
assert_eq!(h.as_slice(), &["wx", "snarf"]);
assert_eq!(h.oldest, 2);
h.insert_by_key("z", key);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["z", "wx", "snarf"]);
assert_eq!(h.oldest, 1);
h.insert_by_key("", key);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["z", "wx", "snarf"]);
assert_eq!(h.oldest, 1);
h.insert_by_key("foobar", key);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["wx", "snarf", "foobar"]);
assert_eq!(h.oldest, 2);
h.insert_by_key("abc", key);
assert_eq!(h.len(), 3);
assert_eq!(h.as_slice(), &["abc", "snarf", "foobar"]);
assert_eq!(h.oldest, 2);
}
#[test]
fn test_insert_at_start() {
let mut h = Ring::<i32>::new(3);
h.insert_at(0, 1);
assert_eq!(h.as_slice(), &[1]);
assert_eq!(h.oldest, 2);
h.insert_at(0, 2);
assert_eq!(h.as_slice(), &[2, 1]);
assert_eq!(h.oldest, 1);
h.insert_at(0, 3);
assert_eq!(h.as_slice(), &[3, 2, 1]);
assert_eq!(h.oldest, 0);
h.insert_at(0, 4);
assert_eq!(h.as_slice(), &[3, 2, 1]);
assert_eq!(h.oldest, 0);
}
#[test]
fn test_insert_at_end() {
let mut h = Ring::<i32>::new(3);
h.insert_at(0, 1);
assert_eq!(h.as_slice(), &[1]);
assert_eq!(h.oldest, 2);
h.insert_at(1, 2);
assert_eq!(h.as_slice(), &[1, 2]);
assert_eq!(h.oldest, 2);
h.insert_at(2, 3);
assert_eq!(h.as_slice(), &[1, 2, 3]);
assert_eq!(h.oldest, 2);
h.insert_at(3, 4);
assert_eq!(h.as_slice(), &[2, 3, 4]);
assert_eq!(h.oldest, 0);
}
#[test]
fn test_insert_at_edge() {
let mut h = Ring::new(7);
h.append(5);
h.prepend(3);
h.prepend(2);
h.prepend(1);
assert_eq!(h.oldest, 4);
assert_eq!(h.fill, 4);
assert_eq!(h.as_slice(), &[1, 2, 3, 5]);
h.insert_at(3, 4);
assert_eq!(h.oldest, 4);
assert_eq!(h.fill, 5);
assert_eq!(h.as_slice(), &[1, 2, 3, 4, 5]);
}
#[test]
fn test_insert_not_full() {
let mut h = Ring::<i32>::new(7);
h.append(2);
h.append(3);
h.prepend(1);
h.prepend(0);
assert_eq!(h.oldest, 5);
assert_eq!(h.fill, 4);
assert_eq!(h.as_slice(), &[0, 1, 2, 3]);
let mut h2 = h.clone();
h2.insert_at(0, -1);
assert_eq!(h2.oldest, 4);
assert_eq!(h2.fill, 5);
assert_eq!(h2.as_slice(), &[-1, 0, 1, 2, 3]);
let mut h2 = h.clone();
h2.insert_at(1, -1);
assert_eq!(h2.oldest, 4);
assert_eq!(h2.fill, 5);
assert_eq!(h2.as_slice(), &[0, -1, 1, 2, 3]);
let mut h2 = h.clone();
h2.insert_at(2, -1);
assert_eq!(h2.oldest, 4);
assert_eq!(h2.fill, 5);
assert_eq!(h2.as_slice(), &[0, 1, -1, 2, 3]);
let mut h2 = h.clone();
h2.insert_at(3, -1);
assert_eq!(h2.oldest, 5);
assert_eq!(h2.fill, 5);
assert_eq!(h2.as_slice(), &[0, 1, 2, -1, 3]);
let mut h2 = h.clone();
h2.insert_at(4, -1);
assert_eq!(h2.oldest, 5);
assert_eq!(h2.fill, 5);
assert_eq!(h2.as_slice(), &[0, 1, 2, 3, -1]);
}
#[test]
fn test_insert_at_full() {
let mut h = Ring::new(4);
h.append(2);
h.append(4);
h.append(6);
h.append(8);
assert_eq!(h.oldest, 0);
assert_eq!(h.fill, 4);
assert_eq!(h.as_slice(), &[2, 4, 6, 8]);
h.insert_at(0, 1);
assert_eq!(h.oldest, 0);
assert_eq!(h.fill, 4);
assert_eq!(h.as_slice(), &[2, 4, 6, 8]);
h.insert_at(1, 3);
assert_eq!(h.oldest, 0);
assert_eq!(h.fill, 4);
assert_eq!(h.as_slice(), &[3, 4, 6, 8]);
h.insert_at(2, 5);
assert_eq!(h.oldest, 0);
assert_eq!(h.fill, 4);
assert_eq!(h.as_slice(), &[4, 5, 6, 8]);
}
#[test]
fn empty() {
let mut h = Ring::<&str>::new(0);
assert_eq!(h.fill, 0);
assert_eq!(h.capacity, 0);
assert_eq!(h.oldest, 0);
assert_eq!(h.buf.len(), 0);
assert!(h.is_empty());
assert!(h.is_full());
assert_eq!(h.len(), 0);
assert_eq!(h.capacity(), 0);
assert_eq!(h.as_slice(), &[] as &[&str]);
h.append("a");
assert!(h.is_empty());
h.prepend("a");
assert!(h.is_empty());
h.insert("a");
assert!(h.is_empty());
h.insert_at(0, "a");
assert!(h.is_empty());
h.insert_by("a", |a, b| a.len().cmp(&b.len()));
assert!(h.is_empty());
h.insert_by_key("a", |a| a.len());
assert!(h.is_empty());
h.sort();
assert!(h.is_empty());
h.sort_by(|a, b| a.len().cmp(&b.len()));
assert!(h.is_empty());
h.sort_by_key(|a| a.len());
assert!(h.is_empty());
}
}