use std::{
usize, fmt::{ Debug, Formatter, Result as FmtResult },
ops::{
Index, IndexMut,
Range, RangeFrom, RangeTo, RangeInclusive, RangeToInclusive, RangeBounds, Bound,
Deref, DerefMut
}
};
#[cfg(feature = "fast_unsafe_code")]
use std::{ ptr, mem };
#[derive(Default)]
pub struct SliceQueue<T> {
backing: Vec<T>
}
impl<T> SliceQueue<T> {
pub fn new() -> Self {
SliceQueue{ backing: Vec::new() }
}
pub fn with_capacity(n: usize) -> Self {
SliceQueue{ backing: Vec::with_capacity(n) }
}
pub fn len(&self) -> usize {
self.backing.len()
}
pub fn is_empty(&self) -> bool {
self.backing.is_empty()
}
pub fn capacity(&self) -> usize {
self.backing.capacity()
}
pub fn reserve(&mut self, additional_element_count: usize) {
self.backing.reserve(additional_element_count)
}
pub fn shrink_opportunistic(&mut self) {
let half_capacity = if self.capacity() == 0 { 0 }
else { self.capacity() / 2 };
if self.len() > 4 && self.len() <= half_capacity { self.backing.shrink_to_fit() }
}
pub fn shrink_to_fit(&mut self) {
self.backing.shrink_to_fit()
}
pub fn pop(&mut self) -> Option<T> {
match self.is_empty() {
true => None,
false => {
let element = self.backing.remove(0);
self.shrink_opportunistic();
Some(element)
}
}
}
pub fn pop_n(&mut self, n: usize) -> Option<Vec<T>> {
if self.len() < n { return None }
#[cfg(feature = "fast_unsafe_code")]
let elements = unsafe {
let mut elements = Vec::with_capacity(n);
let remaining = self.len() - n;
ptr::copy_nonoverlapping(self.backing.as_ptr(), elements.as_mut_ptr(), n);
ptr::copy(self.backing[n..].as_ptr(), self.backing.as_mut_ptr(), remaining);
elements.set_len(n);
self.backing.set_len(remaining);
elements
};
#[cfg(not(feature = "fast_unsafe_code"))]
let elements = {
self.backing.drain(..n).collect()
};
self.shrink_opportunistic();
Some(elements)
}
pub fn pop_into(&mut self, dst: &mut[T]) {
assert!(self.len() >= dst.len(), "`dst` is larger than `self`");
let to_move = dst.len();
#[cfg(feature = "fast_unsafe_code")]
unsafe {
Self::replace_n(self.backing.as_ptr(), dst.as_mut_ptr(), to_move);
let remaining = self.len() - to_move;
ptr::copy(self.backing[to_move..].as_ptr(), self.backing.as_mut_ptr(), remaining);
self.backing.set_len(remaining);
}
#[cfg(not(feature = "fast_unsafe_code"))]
{
let (mut src, dst) = (self.backing.drain(..to_move), dst.iter_mut());
dst.for_each(|t| *t = src.next().unwrap());
}
self.shrink_opportunistic();
}
pub fn discard_n(&mut self, n: usize) {
assert!(self.len() >= n, "`n` is larger than the amount of elements in `self`");
#[cfg(feature = "fast_unsafe_code")]
unsafe {
let remaining = self.len() - n;
Self::replace_n(self.backing[n..].as_ptr(), self.backing.as_mut_ptr(), remaining);
self.backing.set_len(remaining);
}
#[cfg(not(feature = "fast_unsafe_code"))]
{
self.backing.drain(..n);
}
self.shrink_opportunistic();
}
pub fn peek(&self) -> Option<&T> {
self.backing.first()
}
pub fn peek_mut(&mut self) -> Option<&mut T> {
self.backing.first_mut()
}
pub fn peek_n(&self, n: usize) -> Option<&[T]> {
if self.len() < n { None }
else { Some(&self.backing[..n]) }
}
pub fn peek_n_mut(&mut self, n: usize) -> Option<&mut[T]> {
if self.len() < n { None }
else { Some(&mut self.backing[..n]) }
}
pub fn push(&mut self, element: T) {
self.backing.push(element)
}
pub fn push_n(&mut self, mut n: Vec<T>) {
self.backing.append(&mut n);
}
pub fn push_from(&mut self, src: &[T]) where T: Clone {
self.backing.extend_from_slice(src)
}
fn range_from_bounds(&self, bounds: impl RangeBounds<usize>) -> Range<usize> {
let start_included = match bounds.start_bound() {
Bound::Included(b) => *b,
Bound::Excluded(_) => unreachable!(),
Bound::Unbounded => 0
};
let end_excluded = match bounds.end_bound() {
Bound::Included(b) => if *b > usize::MIN { *b - 1 }
else { panic!("Index usize::MIN - 1 is invalid") },
Bound::Excluded(b) => *b,
Bound::Unbounded => self.backing.len()
};
start_included..end_excluded
}
#[cfg(feature = "fast_unsafe_code")]
unsafe fn replace_n(src: *const T, dst: *mut T, n: usize) {
if mem::needs_drop::<T>() {
let mut ptr = dst;
(0..n).for_each(|_| {
ptr.drop_in_place();
ptr = ptr.offset(1);
})
}
ptr::copy(src, dst, n);
}
}
impl<T: Debug> Debug for SliceQueue<T> {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
Debug::fmt(&**self, f)
}
}
impl<T> From<Vec<T>> for SliceQueue<T> {
fn from(vec: Vec<T>) -> Self {
SliceQueue { backing: vec }
}
}
impl<T> Clone for SliceQueue<T> where T: Clone {
fn clone(&self) -> Self {
SliceQueue { backing: self.backing.clone() }
}
}
macro_rules! impl_range_index {
($b:ty) => {
impl<T> Index<$b> for SliceQueue<T> {
type Output = [T];
fn index(&self, bounds: $b) -> &[T] {
&self.backing[self.range_from_bounds(bounds)]
}
}
impl<T> IndexMut<$b> for SliceQueue<T> {
fn index_mut(&mut self, bounds: $b) -> &mut [T] {
let range = self.range_from_bounds(bounds);
&mut self.backing[range]
}
}
};
}
impl_range_index!(Range<usize>);
impl_range_index!(RangeFrom<usize>);
impl_range_index!(RangeTo<usize>);
impl_range_index!(RangeInclusive<usize>);
impl_range_index!(RangeToInclusive<usize>);
impl<T> Index<usize> for SliceQueue<T> {
type Output = T;
fn index(&self, i: usize) -> &T {
&self.backing[i]
}
}
impl<T> IndexMut<usize> for SliceQueue<T> {
fn index_mut(&mut self, i: usize) -> &mut T {
&mut self.backing[i]
}
}
impl<T> Deref for SliceQueue<T> {
type Target = <Vec<T> as Deref>::Target;
fn deref(&self) -> &Self::Target {
self.backing.deref()
}
}
impl<T> DerefMut for SliceQueue<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.backing.deref_mut()
}
}
#[cfg(test)]
mod tests {
include!("tests.rs");
}