use std::{slice as stdslice, mem};
use base::{u4lo, u4};
use pair::u4x2;
use slice::{self, NibSliceAligned, NibSliceAlignedMut, NibSliceFull, NibSliceNoR};
use common::{get_nib, set_nib, shift_left, shift_right};
#[derive(Clone)]
pub struct NibVec {
inner: Vec<u4x2>,
has_right_lo: bool,
}
impl NibVec {
pub fn new() -> Self {
NibVec { inner: Vec::new(), has_right_lo: true }
}
pub fn from_pair_vec(inner: Vec<u4x2>) -> Self {
NibVec { inner, has_right_lo: true }
}
pub fn from_byte_vec(inner: Vec<u8>) -> Self {
Self::from_pair_vec(unsafe { mem::transmute(inner) })
}
pub fn len(&self) -> usize {
(self.inner.len() >> 1).saturating_sub(!self.has_right_lo as usize)
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn capacity(&self) -> usize {
self.inner.capacity() >> 1
}
pub fn push<T: u4>(&mut self, nib: T) {
self.has_right_lo = !self.has_right_lo;
if self.has_right_lo {
self.inner.push(u4x2::from_hi(nib.to_u4hi()));
} else {
let i = self.inner.len() - 1;
self.inner[i].set_lo(nib);
}
}
pub fn insert<T: u4>(&mut self, index: usize, nib: T) {
if self.has_right_lo {
self.push(u4lo::from_lo(0));
}
shift_right(self.inner.as_mut_slice(), index);
set_nib(self.inner.as_mut_slice(), index, nib);
}
fn discard_at(&mut self, index: usize) {
shift_left(self.inner.as_mut_slice(), index);
self.has_right_lo = !self.has_right_lo;
if self.has_right_lo {
self.inner.pop();
}
}
pub fn remove<T: u4>(&mut self, index: usize) -> T {
let ret = get_nib(self.inner.as_slice(), index);
self.discard_at(index);
ret
}
pub fn pop<T: u4>(&mut self) -> Option<T> {
self.has_right_lo = !self.has_right_lo;
if self.has_right_lo {
Some(T::from_lo(self.inner[self.inner.len() - 1].lo().to_lo()))
} else {
self.inner.pop().map(|pair| T::from_hi(pair.hi().to_hi()))
}
}
pub fn clear(&mut self) {
self.inner.clear();
self.has_right_lo = true;
}
pub fn as_slice(&self) -> NibSliceAligned {
if self.has_right_lo {
NibSliceAligned::Even(unsafe { &*(&self.inner[..] as *const [u4x2] as *const NibSliceFull) })
} else {
NibSliceAligned::Odd(unsafe { &*(&self.inner[..] as *const [u4x2] as *const NibSliceNoR) })
}
}
pub fn as_mut_slice(&mut self) -> NibSliceAlignedMut {
if self.has_right_lo {
NibSliceAlignedMut::Even(unsafe { &mut *(&mut self.inner[..] as *mut [u4x2] as *mut NibSliceFull) })
} else {
NibSliceAlignedMut::Odd(unsafe { &mut *(&mut self.inner[..] as *mut [u4x2] as *mut NibSliceNoR) })
}
}
}
impl Default for NibVec {
fn default() -> Self {
NibVec::new()
}
}
impl slice::private::Sealed for NibVec {
#[inline(always)]
fn has_left_hi(&self) -> bool { true }
#[inline(always)]
fn has_right_lo(&self) -> bool { self.as_slice().has_right_lo() }
#[inline(always)]
fn iter(&self) -> stdslice::Iter<u4x2> { self.inner.iter() }
}
impl slice::private::SealedMut for NibVec {
#[inline(always)]
fn iter_mut(&mut self) -> stdslice::IterMut<u4x2> { self.inner.iter_mut() }
}
impl slice::NibSliceExt for NibVec {}
impl slice::NibSliceMutExt for NibVec {}