//! //! ### TODO //! //! * Are zero-sized-types properly covered? //! * reserve_exact //! * IntoIterator //! * impl From/Into-traits? //! * index ranges use traits::*; use qindex_multi::MultiIndexable; use alloc::raw_vec::RawVec; use core::array::FixedSizeArray; use rustc_serialize::{self, Encodable, Decodable}; use std::borrow::{Borrow, BorrowMut}; use std::fmt::{self, Debug}; use std::hash::{self, Hash}; use std::iter::FromIterator; use std::ops::{Deref, DerefMut, Index, IndexMut}; use std::{cmp, slice, mem, ptr}; enum SmallVecData where A: FixedSizeArray, { Inline(A), Heap(RawVec), } #[unsafe_no_drop_flag] pub struct SmallVec where A: FixedSizeArray, { len: usize, data: SmallVecData, } impl SmallVec where A: FixedSizeArray, { pub fn inline_capacity() -> usize { mem::size_of::() / mem::size_of::() } pub fn from_fixed(array: A) -> Self { SmallVec{ len: Self::inline_capacity(), data: SmallVecData::Inline(array), } } /// Panics if _spilled_ or length doesn't match capacity. pub fn into_fixed(self) -> A { assert!(!self.spilled()); assert!(self.len() == self.capacity()); let ret = unsafe { ptr::read(self.as_ptr() as *const A) }; mem::forget(self); ret } pub fn new() -> Self { let mut ret = Self::from_fixed(unsafe { mem::uninitialized() }); ret.len = 0; ret } /// Note that this might defeat the actual purpose of a `SmallVec`. pub fn with_capacity(cap: usize) -> Self { let mut ret = Self::new(); if cap > Self::inline_capacity() { ret.reserve(cap); } ret } pub fn spilled(&self) -> bool { match self.data { SmallVecData::Inline(_) => false, SmallVecData::Heap(_) => true, } } pub unsafe fn set_len(&mut self, len: usize){ self.len = len; } pub fn len(&self) -> usize { self.len } #[inline] pub fn as_slice(&self) -> &[T] { match &self.data { &SmallVecData::Inline(ref array) => unsafe { slice::from_raw_parts(array as *const A as *const T, self.len) }, &SmallVecData::Heap(ref raw_vec) => unsafe { slice::from_raw_parts(raw_vec.ptr(), self.len) }, } } #[inline] pub fn as_mut_slice(&mut self) -> &mut [T] { match &mut self.data { &mut SmallVecData::Inline(ref mut array) => unsafe { slice::from_raw_parts_mut(array as *const A as *mut T, self.len) }, &mut SmallVecData::Heap(ref raw_vec) => unsafe { slice::from_raw_parts_mut(raw_vec.ptr() as *mut _, self.len) }, } } pub fn as_ptr(&self) -> *const T { self.as_slice().as_ptr() } pub fn as_mut_ptr(&mut self) -> *mut T { self.as_mut_slice().as_mut_ptr() } pub fn capacity(&self) -> usize { if mem::size_of::() == 0 { return !0; } match self.data { SmallVecData::Inline(_) => Self::inline_capacity(), SmallVecData::Heap(ref raw_vec) => raw_vec.cap(), } } pub fn reserve(&mut self, additional: usize){ if mem::size_of::() == 0 { return } if !self.spilled() { // Move data from inline to heap. let old_ptr = self.as_mut_ptr(); let raw_vec: RawVec = RawVec::with_capacity(self.len + additional); unsafe { ptr::copy_nonoverlapping(old_ptr, raw_vec.ptr() as *mut _, self.len); ptr::write(&mut self.data, SmallVecData::Heap(raw_vec)); } } else { match &mut self.data { &mut SmallVecData::Heap(ref mut raw_vec) => { raw_vec.reserve(self.len, additional); } _ => unreachable!(), } } } pub fn insert(&mut self, idx: usize, val: T){ let len = self.len; assert!(idx <= len); if idx == self.capacity() { self.reserve(1) } unsafe { let ptr = self.as_mut_ptr().offset(idx as isize); ptr::copy(ptr, ptr.offset(1), len - idx); ptr::write(ptr, val); } self.len += 1; } pub fn remove(&mut self, idx: usize) -> T { let len = self.len; assert!(idx < len); unsafe { let ptr = self.as_mut_ptr().offset(idx as isize); let ret = ptr::read(ptr); ptr::copy(ptr.offset(1), ptr, len - idx - 1); self.len -= 1; ret } } pub fn clear(&mut self) { for idx in 0..self.len { unsafe { ptr::read(self.as_ptr().offset(idx as isize)); } } self.len = 0; } fn needs_drop(&self) -> bool { self.len != mem::POST_DROP_USIZE } } impl Drop for SmallVec where A: FixedSizeArray, { fn drop(&mut self){ if self.needs_drop() { self.clear(); if !self.spilled() { unsafe { ptr::write(&mut self.data, SmallVecData::Heap(RawVec::new())); } } } } } // ++++++++++++++++++++ QCollect-stuff ++++++++++++++++++++ // impl -> trait impl impl ImmutableCollection for SmallVec where A: FixedSizeArray, { fn len(&self) -> usize { (*self).len() } } impl MutableCollection for SmallVec where A: FixedSizeArray, {} // impl -> trait impl impl GrowableCollection for SmallVec where A: FixedSizeArray, { fn capacity(&self) -> usize { (*self).capacity() } fn reserve(&mut self, additional: usize){ (*self).reserve(additional) } fn reserve_exact(&mut self, additional: usize){ (*self).reserve(additional) } fn clear(&mut self){ (*self).clear(); } } // impl -> trait impl impl<'a, T: 'a, A> ImmutableSequenceTypes<'a, T> for SmallVec where A: FixedSizeArray, { type Iter = slice::Iter<'a, T>; } // impl -> trait impl impl ImmutableSequence for SmallVec where A: FixedSizeArray, { fn get<'a>(&'a self, idx: usize) -> Option<>::Output> { self.as_slice().get(idx) } fn iter<'a>(&'a self) -> >::Iter { self.as_slice().iter() } } // impl -> trait impl impl<'a, T: 'a, A> MutableSequenceTypes<'a, T> for SmallVec where A: FixedSizeArray, { type IterMut = slice::IterMut<'a, T>; } // impl -> trait impl impl MutableSequence for SmallVec where A: FixedSizeArray, { fn get_mut<'a>(&'a mut self, idx: usize) -> Option<&mut T> //FIXME_REMOVE where Self: ImmutableSequenceTypes<'a, T, Output = &'a T> { self.as_mut_slice().get_mut(idx) } fn iter_mut<'a>(&'a mut self) -> >::IterMut //FIXME_REMOVE where Self: ImmutableSequenceTypes<'a, T, Output = &'a T> { self.as_mut_slice().iter_mut() } fn swap(&mut self, a: usize, b: usize){ self.as_mut_slice().swap(a, b); } fn sort_by(&mut self, compare: F) where F: FnMut(&T, &T) -> cmp::Ordering { self.as_mut_slice().sort_by(compare); } } // impl -> trait impl impl GrowableSequence for SmallVec where A: FixedSizeArray, { fn insert(&mut self, idx: usize, val: T){ (*self).insert(idx, val); } fn remove(&mut self, idx: usize) -> T { (*self).remove(idx) } } // trait defaults -> impl impl SmallVec where A: FixedSizeArray, { pub fn push(&mut self, val: T){ //FIXME uncomment after we removed 'static-bounds //GrowableSequence::push(self, val); let len = self.len(); self.insert(len, val); } pub fn pop(&mut self) -> Option { //FIXME uncomment after we removed 'static-bounds //GrowableSequence::pop(self) let len = self.len(); if len == 0 { None } else { Some(self.remove(len - 1)) } } } // ++++++++++++++++++++ Iteration-stuff ++++++++++++++++++++ impl FromIterator for SmallVec where A: FixedSizeArray, { fn from_iter(iterable: I) -> Self where I: IntoIterator { let iter = iterable.into_iter(); let mut ret = SmallVec::new(); Extend::extend(&mut ret, iter); ret } } impl Extend for SmallVec where A: FixedSizeArray, { fn extend(&mut self, iterable: I) where I: IntoIterator { // FIXME uncomment after we removed 'static-bounds //extend_sequence(self, iterable) let iter = iterable.into_iter(); iter.size_hint().1.map(|len|{ let space = self.capacity() - self.len(); if len > space { self.reserve(len - space); } }); for val in iter { self.push(val); } } } impl<'a, T, A> IntoIterator for &'a SmallVec where A: FixedSizeArray, { type Item = &'a T; type IntoIter = slice::Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { self.as_slice().iter() } } impl<'a, T, A> IntoIterator for &'a mut SmallVec where A: FixedSizeArray, { type Item = &'a mut T; type IntoIter = slice::IterMut<'a, T>; fn into_iter(self) -> Self::IntoIter { self.as_mut_slice().iter_mut() } } /* TODO pub use std::vec::IntoIter; impl IntoIterator for SmallVec where A: FixedSizeArray, { type Item = T; type IntoIter = IntoIter; fn into_iter(mut self) -> Self::IntoIter { let vec = if !self.spilled() { let mut vec: Vec = Vec::with_capacity(self.capacity()); unsafe { ptr::copy_nonoverlapping(self.as_mut_ptr(), vec.as_mut_ptr(), self.len); } vec } else { unsafe { Vec::from_raw_parts(self.as_mut_ptr(), self.len, self.capacity()) } }; vec.into_iter() } }*/ // ++++++++++++++++++++ Index-trait ++++++++++++++++++++ impl Index for SmallVec where A: FixedSizeArray, { type Output = T; fn index(&self, idx: usize) -> &Self::Output { &self.as_slice()[idx] } } impl IndexMut for SmallVec where A: FixedSizeArray, { fn index_mut(&mut self, idx: usize) -> &mut Self::Output { &mut self.as_mut_slice()[idx] } } // TODO index ranges unsafe impl MultiIndexable for SmallVec where A: FixedSizeArray, {} // ++++++++++++++++++++ StdPrelude-traits ++++++++++++++++++++ impl Clone for SmallVec where A: FixedSizeArray, T: Clone, { fn clone(&self) -> Self { SmallVec::from_iter(self.as_slice().iter().cloned()) } fn clone_from(&mut self, src: &Self){ self.clear(); Extend::extend(self, src.as_slice().iter().cloned()); } } impl Default for SmallVec where A: FixedSizeArray, { fn default() -> Self { Self::new() } } impl Deref for SmallVec where A: FixedSizeArray, { type Target = [T]; fn deref(&self) -> &Self::Target { self.as_slice() } } impl DerefMut for SmallVec where A: FixedSizeArray, { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_slice() } } impl PartialEq for SmallVec where Rhs: Borrow<[T]>, T: PartialEq, A: FixedSizeArray, { fn eq(&self, other: &Rhs) -> bool { self.as_slice() == other.borrow() } } impl Eq for SmallVec where T: Eq, A: FixedSizeArray, {} impl PartialOrd for SmallVec where Rhs: Borrow<[T]>, T: PartialOrd, A: FixedSizeArray, { fn partial_cmp(&self, other: &Rhs) -> Option { self.as_slice().partial_cmp(other.borrow()) } } impl Ord for SmallVec where T: Ord, A: FixedSizeArray, { fn cmp(&self, other: &Self) -> cmp::Ordering { self.as_slice().cmp(other.as_slice()) } } // ++++++++++++++++++++ StdLib-traits ++++++++++++++++++++ impl Borrow<[T]> for SmallVec where A: FixedSizeArray, { fn borrow(&self) -> &[T] { self.as_slice() } } impl BorrowMut<[T]> for SmallVec where A: FixedSizeArray, { fn borrow_mut(&mut self) -> &mut [T] { self.as_mut_slice() } } impl<'a, T, A> From<&'a [T]> for SmallVec where T: Clone, A: FixedSizeArray, { fn from(src: &'a [T]) -> Self { Self::from_iter(src.iter().cloned()) } } impl Hash for SmallVec where T: Hash, A: FixedSizeArray, { fn hash(&self, state: &mut H) where H: hash::Hasher { self.as_slice().hash(state) } } impl Debug for SmallVec where T: Debug, A: FixedSizeArray, { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { self.as_slice().fmt(formatter) } } // ++++++++++++++++++++ Serialization-traits ++++++++++++++++++++ impl Encodable for SmallVec where T: Encodable, A: FixedSizeArray, { fn encode(&self, e: &mut E) -> Result<(), E::Error> where E: rustc_serialize::Encoder { self.as_slice().encode(e) } } impl Decodable for SmallVec where T: Decodable, A: FixedSizeArray, { fn decode(d: &mut D) -> Result where D: rustc_serialize::Decoder { d.read_seq(|d, len| { let mut v = Self::with_capacity(len); for i in 0..len { v.push(try!(d.read_seq_elt(i, |d| T::decode(d)))); } Ok(v) }) } } // ++++++++++++++++++++ Tests ++++++++++++++++++++ #[test] fn push_n_spill_n_pop(){ let mut v = SmallVec::::new(); v.push(1); v.push(2); assert!(!v.spilled()); v.push(3); assert!(v.spilled()); v.push(4); assert_eq!(v.pop().unwrap(), 4); assert_eq!(v.pop().unwrap(), 3); assert_eq!(v.pop().unwrap(), 2); assert_eq!(v.pop().unwrap(), 1); assert!(v.spilled()); } #[test] fn clone(){ let mut v = SmallVec::::new(); Extend::extend(&mut v, vec![1, 2, 3, 4, 5]); let cloned = v.clone(); assert_eq!(cloned.len(), 5); assert!(cloned.spilled()); v.pop(); let cloned = v.clone(); assert_eq!(cloned.len(), 4); assert!(!cloned.spilled()); }