From 56cdcb1d7e60dbd52a28e9346b316356f227b3b2 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Thu, 9 Jan 2020 22:17:14 -0700 Subject: [PATCH] we're calling the ArrayishVec done for now I think --- Cargo.toml | 2 +- src/arrayish_vec.rs | 372 +++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 2 +- tests/basic_tests.rs | 44 ++--- 4 files changed, 389 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 18a2fd1..13be89e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ categories = ["data-structures", "no-std"] # not even std! [features] -default = ["extern_crate_alloc", "nightly_slice_partition_dedup"] +default = ["extern_crate_alloc"] # Provide additional types and impls related to the `alloc` crate. extern_crate_alloc = [] diff --git a/src/arrayish_vec.rs b/src/arrayish_vec.rs index 271d0a8..4e2886f 100644 --- a/src/arrayish_vec.rs +++ b/src/arrayish_vec.rs @@ -1,5 +1,22 @@ use super::*; +#[macro_export] +macro_rules! arr_vec { + ($array_type:ty) => { + { + let mut av: ArrayishVec<$array_type> = Default::default(); + av + } + }; + ($array_type:ty, $($elem:expr),*) => { + { + let mut av: ArrayishVec<$array_type> = Default::default(); + $( av.push($elem); )* + av + } + }; +} + #[repr(C)] #[derive(Clone, Copy, Default)] pub struct ArrayishVec { @@ -124,8 +141,60 @@ impl ArrayishVec { self.dedup_by(|a, b| key(a) == key(b)) } - // TODO(Vec): drain - // TODO(Vec): drain_filter #nightly + /// Creates a draining iterator that removes the specified range in the vector + /// and yields the removed items. + /// + /// ## Panics + /// * If the start is greater than the end + /// * If the end is past the edge of the vec. + /// + /// ## Example + /// ```rust + /// use tinyvec::*; + /// let mut av = arr_vec!([i32; 4], 1, 2, 3); + /// let av2: ArrayishVec<[i32; 4]> = av.drain(1..).collect(); + /// assert_eq!(av.as_slice(), &[1][..]); + /// assert_eq!(av2.as_slice(), &[2, 3][..]); + /// + /// av.drain(..); + /// assert_eq!(av.as_slice(), &[]); + /// ``` + #[inline] + pub fn drain>( + &mut self, + range: R, + ) -> ArrayishVecDrain<'_, 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, + Bound::Excluded(x) => x - 1, + Bound::Unbounded => self.len, + }; + assert!( + start <= end, + "ArrayishVec::drain> Illegal range, {} to {}", + start, + end + ); + assert!( + end <= self.len, + "ArrayishVec::drain> Range ends at {} but length is only {}!", + end, + self.len + ); + ArrayishVecDrain { + parent: self, + target_index: start, + target_count: end - start, + } + } + + // LATER(Vec): drain_filter #nightly https://github.com/rust-lang/rust/issues/43244 #[inline] pub fn extend_from_slice(&mut self, sli: &[A::Item]) @@ -156,7 +225,44 @@ impl ArrayishVec { } } - // TODO(Vec): insert + /// Inserts an item at the position given, moving all following elements +1 + /// index. + /// + /// ## Panics + /// * If `index` > `len` + /// + /// ## Example + /// ```rust + /// use tinyvec::*; + /// let mut av = arr_vec!([i32; 10], 1, 2, 3); + /// av.insert(1, 4); + /// assert_eq!(av.as_slice(), &[1, 4, 2, 3]); + /// av.insert(4, 5); + /// assert_eq!(av.as_slice(), &[1, 4, 2, 3, 5]); + /// ``` + #[inline] + pub fn insert(&mut self, index: usize, item: A::Item) { + use core::cmp::Ordering; + match index.cmp(&self.len) { + Ordering::Less => { + let targets: &mut [A::Item] = &mut self.as_mut_slice()[index..]; + let mut temp = item; + for target in targets.iter_mut() { + temp = replace(target, temp); + } + self.push(temp); + } + Ordering::Equal => { + self.push(item); + } + Ordering::Greater => { + panic!( + "ArrayishVec::insert> index {} is out of bounds {}", + index, self.len + ); + } + } + } #[inline(always)] #[must_use] @@ -198,14 +304,228 @@ impl ArrayishVec { } } - // TODO(Vec): remove - // TODO(Vec): remove_item - // TODO(Vec): resize (val that's clone) - // TODO(Vec): resize_with (fn that generates a new one each time) - // TODO(Vec): retain - // TODO(Vec): splice - // TODO(Vec): split_off - // TODO(Vec): swap_remove + /// Removes the item at `index`, shifting all others down by one index. + /// + /// Returns the removed element. + /// + /// ## Panics + /// + /// If the index is out of bounds. + /// + /// ## Example + /// + /// ```rust + /// use tinyvec::*; + /// let mut av = arr_vec!([i32; 4], 1, 2, 3); + /// assert_eq!(av.remove(1), 2); + /// assert_eq!(av.as_slice(), &[1, 3][..]); + /// ``` + #[inline] + pub fn remove(&mut self, index: usize) -> A::Item { + let targets: &mut [A::Item] = &mut self.deref_mut()[index..]; + let mut spare = A::Item::default(); + for target in targets.iter_mut().rev() { + spare = replace(target, spare); + } + self.len -= 1; + spare + } + + // NIGHTLY: remove_item, https://github.com/rust-lang/rust/issues/40062 + + /// Resize the vec to the new length. + /// + /// If it needs to be longer, it's filled with clones of the provided value. + /// If it needs to be shorter, it's truncated. + /// + /// ## Example + /// + /// ```rust + /// use tinyvec::*; + /// + /// let mut av = arr_vec!([&str; 10], "hello"); + /// av.resize(3, "world"); + /// assert_eq!(av.as_slice(), &["hello", "world", "world"][..]); + /// + /// let mut av = arr_vec!([i32; 10], 1, 2, 3, 4); + /// av.resize(2, 0); + /// assert_eq!(av.as_slice(), &[1, 2][..]); + /// ``` + #[inline] + pub fn resize(&mut self, new_len: usize, new_val: A::Item) + where + A::Item: Clone, + { + use core::cmp::Ordering; + match new_len.cmp(&self.len) { + Ordering::Less => self.truncate(new_len), + Ordering::Equal => (), + Ordering::Greater => { + while self.len < new_len { + self.push(new_val.clone()); + } + } + } + } + + /// Resize the vec to the new size. + /// + /// If it needs to be longer the length is simply increased (in constant + /// time), if it needs to be shorter then it's truncated. + /// + /// ## Example + /// + /// ```rust + /// use tinyvec::*; + /// + /// let mut av = arr_vec!([i32; 10], 1, 2, 3); + /// av.resize_default(5); + /// assert_eq!(av.as_slice(), &[1, 2, 3, 0, 0][..]); + /// + /// let mut av = arr_vec!([i32; 10], 1, 2, 3, 4); + /// av.resize_default(2); + /// assert_eq!(av.as_slice(), &[1, 2][..]); + /// ``` + #[inline] + pub fn resize_default(&mut self, new_len: usize) { + use core::cmp::Ordering; + match new_len.cmp(&self.len) { + Ordering::Less => self.truncate(new_len), + Ordering::Equal => (), + Ordering::Greater => self.len = new_len, + } + } + + /// Resize the vec to the new length. + /// + /// If it needs to be longer, it's filled with repeated calls to the provided + /// function. If it needs to be shorter, it's truncated. + /// + /// ## Example + /// + /// ```rust + /// use tinyvec::*; + /// + /// let mut av = arr_vec!([i32; 10], 1, 2, 3); + /// av.resize_with(5, Default::default); + /// assert_eq!(av.as_slice(), &[1, 2, 3, 0, 0][..]); + /// + /// let mut av = arr_vec!([i32; 10]); + /// let mut p = 1; + /// av.resize_with(4, || { + /// p *= 2; + /// p + /// }); + /// assert_eq!(av.as_slice(), &[2, 4, 8, 16][..]); + /// ``` + #[inline] + pub fn resize_with A::Item>( + &mut self, + new_len: usize, + mut f: F, + ) { + use core::cmp::Ordering; + match new_len.cmp(&self.len) { + Ordering::Less => self.truncate(new_len), + Ordering::Equal => (), + Ordering::Greater => { + while self.len < new_len { + self.push(f()); + } + } + } + } + + /// Walk the vec and keep only the elements that pass the predicate given. + /// + /// ## Example + /// + /// ```rust + /// use tinyvec::*; + /// + /// let mut av = arr_vec!([i32; 10], 1, 2, 3, 4); + /// av.retain(|&x| x % 2 == 0); + /// assert_eq!(av.as_slice(), &[2, 4][..]); + /// ``` + #[inline] + pub fn retain bool>(&mut self, mut acceptable: F) { + let mut i = 0; + while i < self.len { + if !acceptable(&self[i]) { + self.remove(i); + } + i += 1; + } + } + + // LATER(Vec): splice + + /// Splits the collection at the point given. + /// + /// * `[0, at)` stays in this vec + /// * `[at, len)` ends up in the new vec. + /// + /// ## Panics + /// * if at > len + /// + /// ## Example + /// + /// ```rust + /// use tinyvec::*; + /// let mut av = arr_vec!([i32; 4], 1, 2, 3); + /// let av2 = av.split_off(1); + /// assert_eq!(av.as_slice(), &[1][..]); + /// assert_eq!(av2.as_slice(), &[2, 3][..]); + /// ``` + #[inline] + pub fn split_off(&mut self, at: usize) -> Self + where + Self: Default, + { + if at > self.len { + panic!( + "ArrayishVec::split_off> at value {} exceeds length of {}", + at, self.len + ); + } + let mut new = Self::default(); + let moves = &mut self.as_mut_slice()[at..]; + let targets = new.data.slice_mut(); + for (m, t) in moves.iter_mut().zip(targets) { + replace(t, replace(m, A::Item::default())); + } + new.len = self.len - at; + self.len = at; + new + } + + /// Remove an element, swapping the end of the vec into its place. + /// + /// ## Panics + /// * If the index is out of bounds. + /// + /// ## Example + /// ```rust + /// use tinyvec::*; + /// let mut av = arr_vec!([&str; 4], "foo", "bar", "quack", "zap"); + /// + /// assert_eq!(av.swap_remove(1), "bar"); + /// assert_eq!(av.as_slice(), &["foo", "zap", "quack"][..]); + /// + /// assert_eq!(av.swap_remove(0), "foo"); + /// assert_eq!(av.as_slice(), &["quack", "zap"][..]); + /// ``` + #[inline] + pub fn swap_remove(&mut self, index: usize) -> A::Item { + assert!( + index < self.len, + "ArrayishVec::swap_remove> index {} is out of bounds {}", + index, + self.len + ); + let i = self.pop().unwrap(); + replace(&mut self[index], i) + } #[inline] pub fn truncate(&mut self, new_len: usize) { @@ -252,6 +572,36 @@ impl ArrayishVec { Err(val) } } + + // LATER: try_insert ? + + // LATER: try_remove ? +} + +// GoodFirstIssue: this entire type is correct but slow. +pub struct ArrayishVecDrain<'p, A: Arrayish> { + parent: &'p mut ArrayishVec, + target_index: usize, + target_count: usize, +} +// NIGHTLY: vec_drain_as_slice, https://github.com/rust-lang/rust/issues/58957 +impl<'p, A: Arrayish> Iterator for ArrayishVecDrain<'p, A> { + type Item = A::Item; + #[inline] + fn next(&mut self) -> Option { + if self.target_count > 0 { + let out = self.parent.remove(self.target_index); + self.target_count -= 1; + Some(out) + } else { + None + } + } +} +impl<'p, A: Arrayish> Drop for ArrayishVecDrain<'p, A> { + fn drop(&mut self) { + for _ in self {} + } } impl AsMut<[A::Item]> for ArrayishVec { diff --git a/src/lib.rs b/src/lib.rs index 9c36ea3..5442caf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use core::{ }, iter::{Extend, FromIterator, IntoIterator, Iterator}, mem::{needs_drop, replace}, - ops::{Deref, DerefMut, Index, IndexMut}, + ops::{Deref, DerefMut, Index, IndexMut, RangeBounds}, slice::SliceIndex, }; diff --git a/tests/basic_tests.rs b/tests/basic_tests.rs index 6c03891..4eca2dc 100644 --- a/tests/basic_tests.rs +++ b/tests/basic_tests.rs @@ -2,6 +2,18 @@ use tinyvec::*; +#[test] +fn test_a_vec() { + let mut expected: ArrayishVec<[i32; 4]> = Default::default(); + expected.push(1); + expected.push(2); + expected.push(3); + + let actual = arr_vec!([i32; 4], 1, 2, 3); + + assert_eq!(expected, actual); +} + #[test] fn ArrayishVec_push_pop() { let mut av: ArrayishVec<[i32; 4]> = Default::default(); @@ -75,11 +87,7 @@ fn ArrayishVec_formatting() { #[test] fn ArrayishVec_iteration() { - let mut av: ArrayishVec<[i32; 4]> = Default::default(); - av.push(10); - av.push(11); - av.push(12); - av.push(13); + let av = arr_vec!([i32; 4], 10, 11, 12, 13); let mut i = av.into_iter(); assert_eq!(i.next(), Some(10)); @@ -88,11 +96,7 @@ fn ArrayishVec_iteration() { assert_eq!(i.next(), Some(13)); assert_eq!(i.next(), None); - let mut av: ArrayishVec<[i32; 4]> = Default::default(); - av.push(10); - av.push(11); - av.push(12); - av.push(13); + let av = arr_vec!([i32; 4], 10, 11, 12, 13); let av2: ArrayishVec<[i32; 4]> = av.clone().into_iter().collect(); assert_eq!(av, av2); @@ -100,16 +104,20 @@ fn ArrayishVec_iteration() { #[test] fn ArrayishVec_append() { - let mut av: ArrayishVec<[i32; 10]> = Default::default(); - av.push(1); - av.push(2); - av.push(3); - let mut av2: ArrayishVec<[i32; 10]> = Default::default(); - av2.push(4); - av2.push(5); - av2.push(6); + let mut av = arr_vec!([i32; 8], 1, 2, 3); + let mut av2 = arr_vec!([i32; 8], 4, 5, 6); // av.append(&mut av2); assert_eq!(av.as_slice(), &[1_i32, 2, 3, 4, 5, 6]); assert_eq!(av2.as_slice(), &[]); } + +#[test] +fn ArrayishVec_remove() { + let mut av: ArrayishVec<[i32; 10]> = Default::default(); + av.push(1); + av.push(2); + av.push(3); + assert_eq!(av.remove(1), 2); + assert_eq!(&av[..], &[1, 3][..]); +}