diff --git a/Cargo.toml b/Cargo.toml index 6af07a7..a41a2f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,11 @@ experimental_write_impl = [] # small size without allocation. experimental_array_set = [] +# features that require rustc 1.40 +# use Vec::append if possible in TinyVec::append - 1.37 +# DoubleEndedIterator::nth_back - 1.40 +rustc_1_40 = [] + [badges] appveyor = { repository = "Lokathor/tinyvec" } travis-ci = { repository = "Lokathor/tinyvec" } diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 9843c64..72dcc39 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] tinyvec = { path = "..", features = ["alloc", "nightly_slice_partition_dedup"] } -arbitrary-model-tests = { git = "https://github.com/jakubadamw/arbitrary-model-tests" } +rutenspitz = "0.2" honggfuzz = "0.5.45" arbitrary = "0.2.0" better-panic = "0.2.0" diff --git a/src/arrayvec.rs b/src/arrayvec.rs index b039a0d..d5de521 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -92,7 +92,7 @@ macro_rules! array_vec { #[derive(Clone, Copy, Default)] pub struct ArrayVec { len: usize, - data: A, + pub(crate) data: A, } impl Deref for ArrayVec { @@ -146,17 +146,12 @@ impl ArrayVec { /// ``` #[inline] pub fn append(&mut self, other: &mut Self) { - let new_len = self.len() + other.len(); assert!( - new_len <= A::CAPACITY, + self.try_append(other).is_none(), "ArrayVec::append> total length {} exceeds capacity {}!", - new_len, + self.len() + other.len(), A::CAPACITY ); - - for item in other.drain(..) { - self.push(item); - } } /// Move all values from `other` into this vec. @@ -185,10 +180,13 @@ impl ArrayVec { return Some(other); } - for item in other.drain(..) { + let iter = other.iter_mut().map(take); + for item in iter { self.push(item); } + other.set_len(0); + return None; } @@ -266,39 +264,11 @@ impl ArrayVec { /// assert_eq!(av.as_slice(), &[]); /// ``` #[inline] - pub fn drain>( - &mut self, - range: R, - ) -> ArrayVecDrain<'_, A> { - use core::ops::Bound; - let start = match range.start_bound() { - Bound::Included(x) => *x, - Bound::Excluded(x) => x + 1, - Bound::Unbounded => 0, - }; - let end = match range.end_bound() { - Bound::Included(x) => x + 1, - Bound::Excluded(x) => *x, - Bound::Unbounded => self.len, - }; - assert!( - start <= end, - "ArrayVec::drain> Illegal range, {} to {}", - start, - end - ); - assert!( - end <= self.len, - "ArrayVec::drain> Range ends at {} but length is only {}!", - end, - self.len - ); - ArrayVecDrain { - parent: self, - target_start: start, - target_index: start, - target_end: end, - } + pub fn drain(&mut self, range: R) -> ArrayVecDrain<'_, A::Item> + where + R: RangeBounds, + { + ArrayVecDrain::new(self, range) } /// Clone each element of the slice into this `ArrayVec`. @@ -526,11 +496,14 @@ impl ArrayVec { /// ``` #[inline(always)] pub fn try_push(&mut self, val: A::Item) -> Option { - if self.len == A::CAPACITY { - return Some(val); - } + debug_assert!(self.len <= A::CAPACITY); - self.data.as_slice_mut()[self.len] = val; + let itemref = match self.data.as_slice_mut().get_mut(self.len) { + None => return Some(val), + Some(x) => x, + }; + + *itemref = val; self.len += 1; return None; } @@ -940,44 +913,6 @@ impl ArrayVec { } } -/// Draining iterator for [`ArrayVec`] -/// -/// See [`ArrayVec::drain`](ArrayVec::drain) -pub struct ArrayVecDrain<'p, A: Array> { - parent: &'p mut ArrayVec, - target_start: usize, - target_index: usize, - target_end: usize, -} -impl<'p, A: Array> Iterator for ArrayVecDrain<'p, A> { - type Item = A::Item; - #[inline] - fn next(&mut self) -> Option { - if self.target_index != self.target_end { - let out = take(&mut self.parent[self.target_index]); - self.target_index += 1; - Some(out) - } else { - None - } - } -} -impl<'p, A: Array> FusedIterator for ArrayVecDrain<'p, A> {} -impl<'p, A: Array> Drop for ArrayVecDrain<'p, A> { - #[inline] - fn drop(&mut self) { - // Changed because it was moving `self`, it's also more clear and the std - // does the same - self.for_each(drop); - // Implementation very similar to [`ArrayVec::remove`](ArrayVec::remove) - let count = self.target_end - self.target_start; - let targets: &mut [A::Item] = - &mut self.parent.deref_mut()[self.target_start..]; - targets.rotate_left(count); - self.parent.len -= count; - } -} - /// Splicing iterator for `ArrayVec` /// See [`ArrayVec::splice`](ArrayVec::::splice) pub struct ArrayVecSplice<'p, A: Array, I: Iterator> { @@ -1167,13 +1102,10 @@ impl Iterator for ArrayVecIterator { type Item = A::Item; #[inline] fn next(&mut self) -> Option { - if self.base < self.len { - let out = take(&mut self.data.as_slice_mut()[self.base]); - self.base += 1; - Some(out) - } else { - None - } + let slice = &mut self.data.as_slice_mut()[self.base..self.len]; + let itemref = slice.first_mut()?; + self.base += 1; + return Some(take(itemref)); } #[inline(always)] #[must_use] @@ -1187,18 +1119,39 @@ impl Iterator for ArrayVecIterator { } #[inline] fn last(mut self) -> Option { - Some(take(&mut self.data.as_slice_mut()[self.len])) + self.next_back() } #[inline] fn nth(&mut self, n: usize) -> Option { - let i = self.base + (n - 1); - if i < self.len { - let out = take(&mut self.data.as_slice_mut()[i]); - self.base = i + 1; - Some(out) - } else { - None + let slice = &mut self.data.as_slice_mut()[self.base..self.len]; + + if let Some(x) = slice.get_mut(n) { + self.base += n + 1; + return Some(take(x)); } + + self.base = self.len; + return None; + } +} + +impl DoubleEndedIterator for ArrayVecIterator { + #[inline] + fn next_back(&mut self) -> Option { + let slice = &mut self.data.as_slice_mut()[self.base..self.len]; + let item = slice.last_mut()?; + self.len -= 1; + return Some(take(item)); + } + #[cfg(feature = "rustc_1_40")] + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let slice = &mut self.data.as_slice_mut()[self.base..self.len]; + let n = slice.len().checked_sub(n + 1)?; + let item = &mut slice[n]; + self.len = n; + + return Some(take(item)); } } @@ -1496,7 +1449,9 @@ impl ArrayVec { pub fn drain_to_vec_and_reserve(&mut self, n: usize) -> Vec { let cap = n + self.len(); let mut v = Vec::with_capacity(cap); - v.extend(self.drain(..)); + let iter = self.iter_mut().map(take); + v.extend(iter); + self.set_len(0); return v; } diff --git a/src/arrayvec_drain.rs b/src/arrayvec_drain.rs new file mode 100644 index 0000000..62efb06 --- /dev/null +++ b/src/arrayvec_drain.rs @@ -0,0 +1,93 @@ +use super::*; + +use core::{ + ops::{Bound, RangeBounds}, + slice, +}; + +/// Draining iterator for [`ArrayVec`] +/// +/// See [`ArrayVec::drain`](ArrayVec::drain) +pub struct ArrayVecDrain<'a, T: 'a + Default> { + iter: slice::IterMut<'a, T>, +} + +impl<'a, T: 'a + Default> ArrayVecDrain<'a, T> { + pub(crate) fn new(arr: &'a mut ArrayVec, range: R) -> Self + where + A: Array, + R: RangeBounds, + { + let start = match range.start_bound() { + Bound::Unbounded => 0, + Bound::Included(&n) => n, + Bound::Excluded(&n) => n + 1, + }; + let end = match range.end_bound() { + Bound::Unbounded => arr.len(), + Bound::Included(&n) => n + 1, + Bound::Excluded(&n) => n, + }; + + assert!( + start <= end, + "ArrayVec::drain> Illegal range, {} to {}", + start, + end + ); + assert!( + end <= arr.len(), + "ArrayVec::drain> Range ends at {}, but length is only {}", + end, + arr.len() + ); + + let len = end - start; + let to_rotate = &mut arr[start..]; + to_rotate.rotate_left(len); + + let oldlen = arr.len(); + let newlen = oldlen - len; + arr.set_len(newlen); + let slice = &mut arr.data.as_slice_mut()[newlen..oldlen]; + let iter = slice.iter_mut(); + Self { iter } + } +} + +impl<'a, T: 'a + Default> DoubleEndedIterator for ArrayVecDrain<'a, T> { + fn next_back(&mut self) -> Option { + self.iter.next_back().map(take) + } + + #[cfg(feature = "rustc_1_40")] + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n).map(take) + } +} + +impl<'a, T: 'a + Default> Iterator for ArrayVecDrain<'a, T> { + type Item = T; + fn next(&mut self) -> Option { + self.iter.next().map(take) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n).map(take) + } + fn last(self) -> Option { + self.iter.last().map(take) + } + fn for_each(self, f: F) + where + F: FnMut(Self::Item), + { + self.iter.map(take).for_each(f) + } +} + +impl<'a, T: 'a + Default> FusedIterator for ArrayVecDrain<'a, T> {} +impl<'a, T: 'a + Default> ExactSizeIterator for ArrayVecDrain<'a, T> {} +/* No need to impl Drop! */ diff --git a/src/lib.rs b/src/lib.rs index 1fcc7da..9aea3cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,6 +89,9 @@ pub use arrayset::*; mod arrayvec; pub use arrayvec::*; +mod arrayvec_drain; +pub use arrayvec_drain::*; + mod slicevec; pub use slicevec::*; diff --git a/src/tinyvec.rs b/src/tinyvec.rs index d446c79..5661a95 100644 --- a/src/tinyvec.rs +++ b/src/tinyvec.rs @@ -280,14 +280,26 @@ impl TinyVec { impl TinyVec { /// Move all values from `other` into this vec. + #[cfg(feature = "rustc_1_40")] #[inline] pub fn append(&mut self, other: &mut Self) { self.reserve(other.len()); - let iter = other.drain(..); - match self { - TinyVec::Heap(h) => h.extend(iter), - TinyVec::Inline(a) => a.extend(iter), + /* Doing append should be faster, because it is effectively a memcpy */ + match (self, other) { + (TinyVec::Heap(sh), TinyVec::Heap(oh)) => sh.append(oh), + (TinyVec::Inline(a), TinyVec::Heap(h)) => a.extend(h.drain(..)), + (ref mut this, TinyVec::Inline(arr)) => this.extend(arr.drain(..)), + } + } + + /// Move all values from `other` into this vec. + #[cfg(not(feature = "rustc_1_40"))] + #[inline] + pub fn append(&mut self, other: &mut Self) { + match other { + TinyVec::Inline(a) => self.extend(a.drain(..)), + TinyVec::Heap(h) => self.extend(h.drain(..)), } } diff --git a/tests/arrayvec.rs b/tests/arrayvec.rs index 490fd96..68a7b7a 100644 --- a/tests/arrayvec.rs +++ b/tests/arrayvec.rs @@ -350,3 +350,59 @@ fn ArrayVec_splice() { av2.splice(1..=1, Some(4)); assert_eq!(av2, array_vec![1, 4, 3]); } + +#[test] +fn iter_last_nth() { + let mut av: ArrayVec<[i32; 10]> = Default::default(); + av.push(1); + av.push(2); + av.push(3); + av.push(4); + assert_eq!(av.len(), 4); + let mut iter = av.into_iter(); + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), None); + assert_eq!(iter.last(), None); + + let mut av: ArrayVec<[i32; 10]> = Default::default(); + av.push(1); + av.push(2); + av.push(3); + + assert_eq!(av.into_iter().nth(0), Some(1)); +} + +#[test] +#[cfg(feature = "rustc_1_40")] +fn reviter() { + let mut av: ArrayVec<[i32; 10]> = Default::default(); + av.push(1); + av.push(2); + av.push(3); + av.push(4); + + let mut iter = av.into_iter(); + + assert_eq!(iter.next(), Some(1)); + assert_eq!(iter.next_back(), Some(4)); + assert_eq!(iter.next(), Some(2)); + assert_eq!(iter.next_back(), Some(3)); + assert_eq!(iter.next(), None); + assert_eq!(iter.next_back(), None); + + let mut av: ArrayVec<[i32; 10]> = Default::default(); + av.push(1); + av.push(2); + av.push(3); + av.push(4); + + let mut iter = av.into_iter(); + + assert_eq!(iter.nth_back(0), Some(4)); + assert_eq!(iter.nth_back(2), Some(1)); + assert_eq!(iter.nth_back(0), None); + assert_eq!(iter.nth_back(99), None); +}