diff --git a/lib.rs b/lib.rs index e4e3765..47b55d3 100644 --- a/lib.rs +++ b/lib.rs @@ -5,8 +5,10 @@ //! Small vectors in various sizes. These store a certain number of elements inline and fall back //! to the heap for larger allocations. +use std::borrow::{Borrow, BorrowMut}; use std::cmp; use std::fmt; +use std::hash::{Hash, Hasher}; use std::iter::{IntoIterator, FromIterator}; use std::mem; use std::ops; @@ -51,11 +53,11 @@ unsafe fn deallocate(ptr: *mut T, capacity: usize) { // Let it drop. } -pub struct SmallVecMoveIterator<'a, T: 'a> { +pub struct Drain<'a, T: 'a> { iter: slice::IterMut<'a,T>, } -impl<'a, T: 'a> Iterator for SmallVecMoveIterator<'a,T> { +impl<'a, T: 'a> Iterator for Drain<'a,T> { type Item = T; #[inline] @@ -69,9 +71,30 @@ impl<'a, T: 'a> Iterator for SmallVecMoveIterator<'a,T> { } } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { + #[inline] + fn next_back(&mut self) -> Option { + match self.iter.next_back() { + None => None, + Some(reference) => { + unsafe { + Some(ptr::read(reference)) + } + } + } + } } -impl<'a, T: 'a> Drop for SmallVecMoveIterator<'a,T> { +impl<'a, T> ExactSizeIterator for Drain<'a, T> { } + +impl<'a, T: 'a> Drop for Drain<'a,T> { fn drop(&mut self) { // Destroy the remaining elements. for _ in self.by_ref() {} @@ -83,6 +106,15 @@ enum SmallVecData { Heap { ptr: *mut A::Item, capacity: usize }, } +impl SmallVecData { + fn ptr_mut(&mut self) -> *mut A::Item { + match *self { + Inline { ref mut array } => array.ptr_mut(), + Heap { ptr, .. } => ptr, + } + } +} + unsafe impl Send for SmallVecData {} unsafe impl Sync for SmallVecData {} @@ -137,22 +169,16 @@ impl SmallVec { } } - /// NB: For efficiency reasons (avoiding making a second copy of the inline elements), this - /// actually clears out the original array instead of moving it. - /// FIXME: Rename this to `drain`? It’s more like `Vec::drain` than `Vec::into_iter`. - pub fn into_iter<'a>(&'a mut self) -> SmallVecMoveIterator<'a, A::Item> { + pub fn drain(&mut self) -> Drain { unsafe { let current_len = self.len(); self.set_len(0); - let ptr = match self.data { - Inline { ref mut array } => array.ptr_mut(), - Heap { ptr, .. } => ptr, - }; + let ptr = self.data.ptr_mut(); let slice = slice::from_raw_parts_mut(ptr, current_len); - SmallVecMoveIterator { + Drain { iter: slice.iter_mut(), } } @@ -305,16 +331,48 @@ impl ops::Deref for SmallVec { impl ops::DerefMut for SmallVec { #[inline] fn deref_mut(&mut self) -> &mut [A::Item] { - let ptr = match self.data { - Inline { ref mut array } => array.ptr_mut(), - Heap { ptr, .. } => ptr, - }; + let ptr = self.data.ptr_mut(); unsafe { slice::from_raw_parts_mut(ptr, self.len) } } } +impl AsRef<[A::Item]> for SmallVec { + #[inline] + fn as_ref(&self) -> &[A::Item] { + self + } +} + +impl AsMut<[A::Item]> for SmallVec { + #[inline] + fn as_mut(&mut self) -> &mut [A::Item] { + self + } +} + +impl Borrow<[A::Item]> for SmallVec { + #[inline] + fn borrow(&self) -> &[A::Item] { + self + } +} + +impl BorrowMut<[A::Item]> for SmallVec { + #[inline] + fn borrow_mut(&mut self) -> &mut [A::Item] { + self + } +} + +impl<'a, A: Array> From<&'a [A::Item]> for SmallVec where A::Item: Clone { + #[inline] + fn from(slice: &'a [A::Item]) -> SmallVec { + slice.into_iter().cloned().collect() + } +} + macro_rules! impl_index { ($index_type: ty, $output_type: ty) => { impl ops::Index<$index_type> for SmallVec { @@ -361,8 +419,8 @@ impl FromIterator for SmallVec { } } -impl SmallVec { - pub fn extend>(&mut self, iterable: I) { +impl Extend for SmallVec { + fn extend>(&mut self, iterable: I) { let iter = iterable.into_iter(); let (lower_size_bound, _) = iter.size_hint(); @@ -443,8 +501,101 @@ impl Ord for SmallVec where A::Item: Ord { } } +impl Hash for SmallVec where A::Item: Hash { + fn hash(&self, state: &mut H) { + (**self).hash(state) + } +} + unsafe impl Send for SmallVec where A::Item: Send {} +pub struct IntoIter { + data: SmallVecData, + current: usize, + end: usize, +} + +impl Drop for IntoIter { + fn drop(&mut self) { + for _ in self { } + } +} + +impl Iterator for IntoIter { + type Item = A::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.current == self.end { + None + } + else { + unsafe { + let current = self.current as isize; + self.current += 1; + Some(ptr::read(self.data.ptr_mut().offset(current))) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = self.end - self.current; + (size, Some(size)) + } +} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + if self.current == self.end { + None + } + else { + unsafe { + self.end -= 1; + Some(ptr::read(self.data.ptr_mut().offset(self.end as isize))) + } + } + } +} + +impl ExactSizeIterator for IntoIter { } + +impl IntoIterator for SmallVec { + type IntoIter = IntoIter; + type Item = A::Item; + fn into_iter(mut self) -> Self::IntoIter { + let len = self.len(); + unsafe { + // Only grab the `data` field, the `IntoIter` type handles dropping of the elements + let data = ptr::read(&mut self.data); + mem::forget(self); + IntoIter { + data: data, + current: 0, + end: len, + } + } + } +} + +impl<'a, A: Array> IntoIterator for &'a SmallVec { + type IntoIter = slice::Iter<'a, A::Item>; + type Item = &'a A::Item; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, A: Array> IntoIterator for &'a mut SmallVec { + type IntoIter = slice::IterMut<'a, A::Item>; + type Item = &'a mut A::Item; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} + // TODO: Remove these and its users. /// Deprecated alias to ease transition from an earlier version. @@ -563,6 +714,32 @@ pub mod tests { assert!(Some(SmallVec::<[&u32; 2]>::new()).is_some()); } + #[test] + fn drain() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.drain().collect::>(), &[3]); + + // spilling the vec + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.drain().collect::>(), &[3, 4, 5]); + } + + #[test] + fn drain_rev() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.drain().rev().collect::>(), &[3]); + + // spilling the vec + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.drain().rev().collect::>(), &[5, 4, 3]); + } + #[test] fn into_iter() { let mut v: SmallVec<[u8; 2]> = SmallVec::new(); @@ -570,12 +747,80 @@ pub mod tests { assert_eq!(v.into_iter().collect::>(), &[3]); // spilling the vec + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); v.push(3); v.push(4); v.push(5); assert_eq!(v.into_iter().collect::>(), &[3, 4, 5]); } + #[test] + fn into_iter_rev() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.into_iter().rev().collect::>(), &[3]); + + // spilling the vec + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.into_iter().rev().collect::>(), &[5, 4, 3]); + } + + #[test] + fn into_iter_drop() { + use std::cell::Cell; + + struct DropCounter<'a>(&'a Cell); + + impl<'a> Drop for DropCounter<'a> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.into_iter(); + assert_eq!(cell.get(), 1); + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + assert!(v.into_iter().next().is_some()); + assert_eq!(cell.get(), 2); + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + assert!(v.into_iter().next().is_some()); + assert_eq!(cell.get(), 3); + } + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + { + let mut it = v.into_iter(); + assert!(it.next().is_some()); + assert!(it.next_back().is_some()); + } + assert_eq!(cell.get(), 3); + } + } + #[test] fn test_capacity() { let mut v: SmallVec<[u8; 2]> = SmallVec::new(); @@ -669,4 +914,89 @@ pub mod tests { assert!(b < c); assert!(c > b); } + + #[test] + fn test_hash() { + use std::hash::{Hash, SipHasher}; + + { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let b = [1, 2]; + a.extend(b.iter().cloned()); + let mut hasher = SipHasher::new(); + assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher)); + } + { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let b = [1, 2, 11, 12]; + a.extend(b.iter().cloned()); + let mut hasher = SipHasher::new(); + assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher)); + } + } + + #[test] + fn test_as_ref() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.as_ref(), [1]); + a.push(2); + assert_eq!(a.as_ref(), [1, 2]); + a.push(3); + assert_eq!(a.as_ref(), [1, 2, 3]); + } + + #[test] + fn test_as_mut() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.as_mut(), [1]); + a.push(2); + assert_eq!(a.as_mut(), [1, 2]); + a.push(3); + assert_eq!(a.as_mut(), [1, 2, 3]); + a.as_mut()[1] = 4; + assert_eq!(a.as_mut(), [1, 4, 3]); + } + + #[test] + fn test_borrow() { + use std::borrow::Borrow; + + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.borrow(), [1]); + a.push(2); + assert_eq!(a.borrow(), [1, 2]); + a.push(3); + assert_eq!(a.borrow(), [1, 2, 3]); + } + + #[test] + fn test_borrow_mut() { + use std::borrow::BorrowMut; + + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.borrow_mut(), [1]); + a.push(2); + assert_eq!(a.borrow_mut(), [1, 2]); + a.push(3); + assert_eq!(a.borrow_mut(), [1, 2, 3]); + BorrowMut::<[u32]>::borrow_mut(&mut a)[1] = 4; + assert_eq!(a.borrow_mut(), [1, 4, 3]); + } + + #[test] + fn test_from() { + assert_eq!(&SmallVec::<[u32; 2]>::from(&[1][..])[..], [1]); + assert_eq!(&SmallVec::<[u32; 2]>::from(&[1, 2, 3][..])[..], [1, 2, 3]); + } + + #[test] + fn test_exact_size_iterator() { + let mut vec = SmallVec::<[u32; 2]>::from(&[1, 2, 3][..]); + assert_eq!(vec.clone().into_iter().len(), 3); + assert_eq!(vec.drain().len(), 3); + } }