use core::{
iter::{FromIterator, FusedIterator},
mem,
};
use tinyvec::Array;
#[derive(Debug)]
pub struct ArrayDeque<A: Array> {
ring_buffer: A,
head: usize,
tail: usize,
len: usize,
}
impl<A: Array> Default for ArrayDeque<A> {
#[inline]
fn default() -> Self {
Self::new()
}
}
#[inline]
fn wrap_index(index: isize, size: isize) -> usize {
let base = index % size;
if base < 0 {
(size + base) as usize
} else {
base as usize
}
}
#[inline]
fn wrap_add(index: usize, add: usize, size: usize) -> usize {
wrap_index((index as isize).wrapping_add(add as isize), size as isize)
}
#[inline]
fn wrap_sub(index: usize, sub: usize, size: usize) -> usize {
wrap_index((index as isize).wrapping_sub(sub as isize), size as isize)
}
impl<A: Array> ArrayDeque<A> {
#[inline]
#[must_use]
pub fn new() -> Self {
Self {
ring_buffer: A::default(),
head: 0,
tail: 0,
len: 0,
}
}
#[inline]
#[must_use]
pub fn capacity() -> usize {
A::CAPACITY
}
#[inline]
fn count(tail: usize, head: usize, size: usize) -> usize {
wrap_sub(head, tail, size)
}
#[inline]
pub fn len(&self) -> usize {
self.len
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub fn is_full(&self) -> bool {
self.len == Self::capacity()
}
#[inline]
pub fn try_push_back(&mut self, element: A::Item) -> Result<(), A::Item> {
if self.is_full() {
return Err(element);
}
let head = self.head;
self.head = wrap_add(self.head, 1, Self::capacity());
self.ring_buffer.as_slice_mut()[head] = element;
self.len += 1;
Ok(())
}
#[inline]
pub fn push_back(&mut self, element: A::Item) {
if let Err(_) = self.try_push_back(element) {
panic!("<ArrayDeque> Unable to push element onto ArrayDeque, since it is full");
}
}
#[inline]
pub fn try_push_front(&mut self, element: A::Item) -> Result<(), A::Item> {
if self.is_full() {
return Err(element);
}
self.tail = wrap_sub(self.tail, 1, Self::capacity());
self.ring_buffer.as_slice_mut()[self.tail] = element;
self.len += 1;
Ok(())
}
#[inline]
pub fn push_front(&mut self, element: A::Item) {
if let Err(_) = self.try_push_front(element) {
panic!("<ArrayDeque> Unable to push element onto ArrayDeque, since it is full");
}
}
#[inline]
pub fn pop_back(&mut self) -> Option<A::Item> {
if self.is_empty() {
None
} else {
self.head = wrap_sub(self.head, 1, Self::capacity());
self.len -= 1;
Some(mem::take(&mut self.ring_buffer.as_slice_mut()[self.head]))
}
}
#[inline]
pub fn pop_front(&mut self) -> Option<A::Item> {
if self.is_empty() {
None
} else {
let tail = self.tail;
self.tail = wrap_add(self.tail, 1, Self::capacity());
self.len -= 1;
Some(mem::take(&mut self.ring_buffer.as_slice_mut()[tail]))
}
}
#[inline]
pub fn get(&self, index: usize) -> Option<&A::Item> {
if index < self.len() {
self.ring_buffer
.as_slice()
.get(wrap_add(self.tail, index, Self::capacity()))
} else {
None
}
}
#[inline]
pub fn get_mut(&mut self, index: usize) -> Option<&mut A::Item> {
if index < self.len() {
let i = wrap_add(self.tail, index, Self::capacity());
self.ring_buffer.as_slice_mut().get_mut(i)
} else {
None
}
}
#[inline]
pub fn is_contiguous(&self) -> bool {
self.tail <= self.head
}
#[inline]
pub fn as_slices(&self) -> (&[A::Item], &[A::Item]) {
RingSlices::ring_slices(self.ring_buffer.as_slice(), self.head, self.tail)
}
#[inline]
pub fn as_mut_slices(&mut self) -> (&mut [A::Item], &mut [A::Item]) {
RingSlices::ring_slices(self.ring_buffer.as_slice_mut(), self.head, self.tail)
}
#[inline]
pub fn truncate(&mut self, len: usize) {
if len > self.len() {
return;
}
let num_dropped = self.len() - len;
let (front, back) = self.as_mut_slices();
let front_dropped = core::cmp::min(num_dropped, front.len());
front.iter_mut().take(front_dropped).for_each(|f| {
mem::take(f);
});
let back_drop = num_dropped - front_dropped;
back.iter_mut().take(back_drop).for_each(|b| {
mem::take(b);
});
self.head = wrap_sub(self.head, num_dropped, Self::capacity());
}
#[inline]
pub fn clear(&mut self) {
self.truncate(0);
}
#[inline]
pub fn iter(&self) -> Iter<'_, A> {
Iter {
ring_buffer: self.ring_buffer.as_slice(),
tail: self.tail,
head: self.tail,
}
}
#[inline]
pub fn append(&mut self, other: &mut Self) -> Result<(), ()> {
if self.len() + other.len() > Self::capacity() {
Err(())
} else {
while let Some(item) = other.pop_front() { self.push_back(item); }
Ok(())
}
}
#[inline]
pub fn back(&self) -> Option<&A::Item> { self.get(self.len - 1) }
#[inline]
pub fn back_mut(&mut self) -> Option<&mut A::Item> { self.get_mut(self.len - 1) }
#[inline]
pub fn front(&self) -> Option<&A::Item> { self.get(0) }
#[inline]
pub fn front_mut(&mut self) -> Option<&mut A::Item> { self.get_mut(0) }
#[inline]
pub fn contains(&self, item: &A::Item) -> bool where A::Item: PartialEq {
let (front, back) = self.as_slices();
front.contains(item) || back.contains(item)
}
}
impl<A: Array> Clone for ArrayDeque<A>
where
A::Item: Clone,
{
#[inline]
fn clone(&self) -> Self {
self.iter().cloned().collect()
}
}
impl<A: Array> FromIterator<A::Item> for ArrayDeque<A> {
#[inline]
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = A::Item>,
{
let mut ad = ArrayDeque::new();
ad.extend(iter);
ad
}
}
impl<A: Array> Extend<A::Item> for ArrayDeque<A> {
#[inline]
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = A::Item>,
{
iter.into_iter().for_each(|item| self.push_back(item));
}
}
#[derive(Clone)]
pub struct Iter<'a, A: Array + 'a> {
ring_buffer: &'a [A::Item],
tail: usize,
head: usize,
}
impl<'a, A: Array> Iterator for Iter<'a, A> {
type Item = &'a A::Item;
#[inline]
fn next(&mut self) -> Option<&'a A::Item> {
if self.tail == self.head {
None
} else {
let tail = self.tail;
self.tail = wrap_add(self.tail, 1, self.ring_buffer.len());
Some(&self.ring_buffer[tail])
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = ArrayDeque::<A>::count(self.tail, self.head, self.ring_buffer.len());
(len, Some(len))
}
}
impl<'a, A: Array> DoubleEndedIterator for Iter<'a, A> {
#[inline]
fn next_back(&mut self) -> Option<&'a A::Item> {
if self.tail == self.head {
None
} else {
self.head = wrap_sub(self.head, 1, self.ring_buffer.len());
Some(&self.ring_buffer[self.head])
}
}
}
impl<'a, A: Array> ExactSizeIterator for Iter<'a, A> {}
impl<A: Array> FusedIterator for Iter<'_, A> {}
trait RingSlices: Sized {
fn slice(self, from: usize, to: usize) -> Self;
fn split_at(self, i: usize) -> (Self, Self);
#[inline]
fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) {
let contiguous = tail <= head;
if contiguous {
let (empty, buf) = buf.split_at(0);
(buf.slice(tail, head), empty)
} else {
let (mid, right) = buf.split_at(tail);
let (left, _) = mid.split_at(head);
(right, left)
}
}
}
impl<T> RingSlices for &[T] {
#[inline]
fn slice(self, from: usize, to: usize) -> Self {
&self[from..to]
}
#[inline]
fn split_at(self, i: usize) -> (Self, Self) {
(*self).split_at(i)
}
}
impl<T> RingSlices for &mut [T] {
#[inline]
fn slice(self, from: usize, to: usize) -> Self {
&mut self[from..to]
}
#[inline]
fn split_at(self, i: usize) -> (Self, Self) {
(*self).split_at_mut(i)
}
}
#[test]
fn test_index_wrap() {
assert_eq!(wrap_index(1, 10), 1);
assert_eq!(wrap_index(13, 10), 3);
assert_eq!(wrap_index(10, 10), 0);
assert_eq!(wrap_add(9, 2, 10), 1);
assert_eq!(wrap_add(5, 2, 10), 7);
assert_eq!(wrap_sub(1, 6, 10), 5, "subtraction test");
}