#![cfg_attr(feature = "unstable", feature(test))]
use std::mem;
use std::ptr;
use std::slice;
use std::marker;
pub struct FixedVecDeque<T>
where
T: Array,
{
ptr: usize,
len: usize,
data: T,
}
impl<T> FixedVecDeque<T>
where
T: Array,
{
pub fn new() -> Self {
FixedVecDeque {
ptr: 0,
len: 0,
data: Self::data_from_default(),
}
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn is_full(&self) -> bool {
self.len == T::size()
}
pub fn len(&self) -> usize {
self.len
}
pub fn front(&self) -> Option<&T::Item> {
if self.is_empty() {
return None;
}
let front = T::wrap_sub(self.ptr, self.len);
Some(unsafe { self.buffer(front) })
}
pub fn front_mut(&mut self) -> Option<&mut T::Item> {
if self.is_empty() {
return None;
}
let front = T::wrap_sub(self.ptr, self.len);
Some(unsafe { self.buffer_mut(front) })
}
pub fn back(&self) -> Option<&T::Item> {
if self.is_empty() {
return None;
}
let back = T::wrap_sub(self.ptr, 1);
Some(unsafe { self.buffer(back) })
}
pub fn back_mut(&mut self) -> Option<&mut T::Item> {
if self.is_empty() {
return None;
}
let back = T::wrap_sub(self.ptr, 1);
Some(unsafe { self.buffer_mut(back) })
}
pub fn push_front(&mut self) -> &mut T::Item {
if self.len == T::size() {
self.ptr = T::wrap_sub(self.ptr, 1);
let front = self.ptr;
return unsafe { self.buffer_mut(front) };
}
self.len += 1;
let front = T::wrap_sub(self.ptr, self.len);
unsafe { self.buffer_mut(front) }
}
pub fn pop_front(&mut self) -> Option<&T::Item> {
if self.is_empty() {
return None;
}
let tail = T::wrap_sub(self.ptr, self.len);
self.len -= 1;
unsafe { Some(self.buffer(tail)) }
}
pub fn push_back(&mut self) -> &mut T::Item {
let head = self.ptr;
self.ptr = T::wrap_add(self.ptr, 1);
if self.len < T::size() {
self.len += 1;
}
unsafe { self.buffer_mut(head) }
}
pub fn pop_back(&mut self) -> Option<&T::Item> {
if self.is_empty() {
return None;
}
self.ptr = T::wrap_sub(self.ptr, 1);
self.len -= 1;
unsafe { Some(self.buffer(self.ptr)) }
}
pub fn iter<'a>(&'a self) -> Iter<'a, T> {
Iter {
data: self.data.ptr(),
start: T::wrap_sub(self.ptr, self.len),
end: self.ptr,
marker: marker::PhantomData,
}
}
#[inline]
pub fn clear(&mut self) {
self.ptr = 0;
self.len = 0;
}
#[inline]
pub fn as_mut_slices(&mut self) -> (&mut [T::Item], &mut [T::Item]) {
if self.is_full() {
let ptr = self.ptr;
let buf = unsafe { self.buffer_as_mut_slice() };
let (left, right) = buf.split_at(ptr);
return (right, left);
}
let head = self.ptr;
let tail = T::wrap_sub(self.ptr, self.len);
let buf = unsafe { self.buffer_as_mut_slice() };
RingSlices::ring_slices(buf, head, tail)
}
#[inline]
pub fn as_slices(&self) -> (&[T::Item], &[T::Item]) {
let buf = unsafe { self.buffer_as_slice() };
if self.len == T::size() {
let (left, right) = buf.split_at(self.ptr);
return (right, left);
}
let head = self.ptr;
let tail = T::wrap_sub(head, self.len);
RingSlices::ring_slices(buf, head, tail)
}
#[inline]
unsafe fn buffer_as_slice(&self) -> &[T::Item] {
slice::from_raw_parts(self.data.ptr(), T::size())
}
#[inline]
unsafe fn buffer_as_mut_slice(&mut self) -> &mut [T::Item] {
slice::from_raw_parts_mut(self.data.ptr_mut(), T::size())
}
#[inline]
unsafe fn buffer(&self, off: usize) -> &T::Item {
&*self.data.ptr().add(off)
}
#[inline]
unsafe fn buffer_mut<'a>(&'a mut self, off: usize) -> &'a mut T::Item {
&mut *self.data.ptr_mut().add(off)
}
fn data_from_default() -> T {
unsafe {
let mut data: T = mem::uninitialized();
let ptr = data.ptr_mut();
for o in 0..T::size() {
ptr::write(ptr.add(o), T::Item::default());
}
data
}
}
}
pub struct Iter<'a, T: 'a> where T: Array {
data: *const T::Item,
start: usize,
end: usize,
marker: marker::PhantomData<&'a ()>,
}
impl<'a, T: 'a> Iterator for Iter<'a, T>
where T: Array
{
type Item = &'a T::Item;
fn next(&mut self) -> Option<Self::Item> {
if self.start == self.end {
return None;
}
let item = self.start;
self.start = T::wrap_add(self.start, 1);
Some(unsafe { &* self.data.add(item) })
}
}
impl<'a, T: 'a> IntoIterator for &'a FixedVecDeque<T> where T: Array {
type Item = &'a T::Item;
type IntoIter = Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub unsafe trait Array {
type Item: Default;
fn size() -> usize;
fn ptr(&self) -> *const Self::Item;
fn ptr_mut(&mut self) -> *mut Self::Item;
#[inline]
fn wrap_add(idx: usize, addend: usize) -> usize {
(idx + addend) % Self::size()
}
#[inline]
fn wrap_sub(idx: usize, subtrahend: usize) -> usize {
if subtrahend > idx {
Self::size() - (subtrahend - idx)
} else {
idx - subtrahend
}
}
}
macro_rules! impl_array(
($($size:expr),+) => {
$(
unsafe impl<T> Array for [T; $size] where T: Default {
type Item = T;
fn size() -> usize { $size }
fn ptr(&self) -> *const T { self.as_ptr() }
fn ptr_mut(&mut self) -> *mut T { self.as_mut_ptr() }
}
)+
}
);
impl_array!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, 0x100,
0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000,
0x100000
);
trait RingSlices: Sized {
fn slice(self, from: usize, to: usize) -> Self;
fn split_at(self, i: usize) -> (Self, Self);
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<'a, T> RingSlices for &'a [T] {
fn slice(self, from: usize, to: usize) -> Self {
&self[from..to]
}
fn split_at(self, i: usize) -> (Self, Self) {
(*self).split_at(i)
}
}
impl<'a, T> RingSlices for &'a mut [T] {
fn slice(self, from: usize, to: usize) -> Self {
&mut self[from..to]
}
fn split_at(self, i: usize) -> (Self, Self) {
(*self).split_at_mut(i)
}
}
#[cfg(test)]
mod tests {
use super::{Array, FixedVecDeque};
use std::mem;
fn test_new<T>() -> FixedVecDeque<T>
where
T: Array + Default,
{
let fixed = FixedVecDeque::<T>::new();
assert_eq!(
mem::size_of::<T::Item>() * 4 + mem::size_of::<FixedVecDeque<[Zero; 1]>>(),
mem::size_of::<FixedVecDeque<[T::Item; 4]>>()
);
#[derive(Debug, Default, PartialEq, Eq)]
struct Zero {}
fixed
}
#[test]
fn test_push_back() {
let mut fixed = test_new::<[Foo; 4]>();
#[derive(Debug, Default, PartialEq, Eq)]
struct Foo {
data: u64,
}
fixed.push_back().data = 1;
fixed.push_back().data = 2;
assert_eq!(Some(&Foo { data: 1 }), fixed.pop_front());
assert_eq!(Some(&Foo { data: 2 }), fixed.pop_front());
assert_eq!(None, fixed.pop_front());
}
#[test]
fn test_unaligned_sizes() {
macro_rules! test_size {
($size:expr) => {
let mut buf = FixedVecDeque::<[u32; $size]>::new();
assert_eq!(buf.back(), None);
assert_eq!(buf.front(), None);
for i in 1..($size + 1) {
*buf.push_back() = i;
assert_eq!(buf.front(), Some(&1));
assert_eq!(buf.back(), Some(&i));
}
let mut buf = FixedVecDeque::<[u32; $size]>::new();
assert_eq!(buf.back(), None);
assert_eq!(buf.front(), None);
for i in 1..($size + 1) {
*buf.push_front() = i;
assert_eq!(buf.back(), Some(&1));
assert_eq!(buf.front(), Some(&i));
}
};
}
test_size!(0);
test_size!(1);
test_size!(2);
test_size!(3);
test_size!(4);
test_size!(5);
test_size!(6);
test_size!(7);
test_size!(8);
test_size!(9);
test_size!(10);
test_size!(11);
test_size!(12);
test_size!(13);
test_size!(14);
test_size!(15);
test_size!(16);
test_size!(20);
test_size!(24);
test_size!(32);
test_size!(36);
}
#[test]
fn test_drop() {
let mut a = 0;
let mut b = 0;
let mut c = 0;
{
let mut fixed = FixedVecDeque::<[Foo; 2]>::new();
fixed.push_back().value = Some(&mut a);
fixed.push_back().value = Some(&mut b);
fixed.push_back().value = Some(&mut c);
}
assert_eq!(a, 0);
assert_eq!(b, 1);
assert_eq!(c, 1);
#[derive(Default)]
struct Foo<'a> {
value: Option<&'a mut u32>,
}
impl<'a> Drop for Foo<'a> {
fn drop(&mut self) {
if let Some(v) = self.value.take() {
*v += 1;
}
}
}
}
}
#[cfg(all(feature = "unstable", test))]
mod benches {
extern crate test;
use super::FixedVecDeque;
#[bench]
fn bench_push_back_100(b: &mut test::Bencher) {
let mut deq = FixedVecDeque::<[BigStruct; 0x100]>::new();
b.iter(|| {
for i in 0..100 {
let big = deq.push_back();
big.fields[0] = i;
}
deq.clear();
})
}
#[bench]
fn bench_push_back_100_vec_deque(b: &mut test::Bencher) {
use std::collections::VecDeque;
let mut deq = VecDeque::new();
b.iter(|| {
for i in 0..100 {
let mut big = BigStruct::default();
big.fields[0] = i;
deq.push_back(big);
}
deq.clear();
})
}
pub struct BigStruct {
fields: [u64; 64],
}
impl Default for BigStruct {
fn default() -> Self {
let fields = [0u64; 64];
BigStruct {
fields,
}
}
}
}