diff --git a/src/lib.rs b/src/lib.rs index e5ffc88..36e356b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,13 +120,14 @@ pub mod smallvec_v1; use core::{ fmt, iter::{DoubleEndedIterator, ExactSizeIterator, Extend, IntoIterator, Peekable}, + mem::MaybeUninit, ops::RangeBounds, result::Result as StdResult, }; use alloc::{ boxed::Box, - collections::{BinaryHeap, VecDeque}, + collections::{BinaryHeap, TryReserveError, VecDeque}, rc::Rc, string::String, vec::{self, Vec}, @@ -479,6 +480,28 @@ impl Vec1 { } } +impl_wrapper! { + base_bounds_macro = , + impl Vec1 { + fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>; + fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError>; + fn shrink_to(&mut self, min_capacity: usize) -> (); + fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit]; + } +} + +impl Vec1 +where + T: Clone, +{ + pub fn extend_from_within(&mut self, src: R) + where + R: RangeBounds, + { + self.0.extend_from_within(src); + } +} + impl Vec1 { /// Works like `&[u8].to_ascii_uppercase()` but returns a `Vec1` instead of a `Vec` pub fn to_ascii_uppercase(&self) -> Vec1 { @@ -1334,6 +1357,48 @@ mod test { assert_eq!(a, vec1![1u8, 2, 8, 3]); } + #[test] + fn try_reserve() { + let mut a = vec1![1u8, 2, 4, 3]; + a.try_reserve(100).unwrap(); + assert!(a.capacity() > 100); + a.try_reserve(usize::MAX).unwrap_err(); + } + + #[test] + fn try_reserve_exact() { + let mut a = vec1![1u8, 2, 4, 3]; + a.try_reserve_exact(124).unwrap(); + assert_eq!(a.capacity(), 128); + a.try_reserve(usize::MAX).unwrap_err(); + } + + #[test] + fn shrink_to() { + let mut a = Vec1::with_capacity(1, 16); + a.extend([2, 3, 4]); + a.shrink_to(16); + assert_eq!(a.capacity(), 16); + a.shrink_to(4); + assert_eq!(a.capacity(), 4); + a.shrink_to(1); + assert_eq!(a.capacity(), 4); + } + + #[test] + fn spare_capacity_mut() { + let mut a = Vec1::with_capacity(1, 16); + a.extend([2, 3, 4]); + assert_eq!(a.spare_capacity_mut().len(), 12); + } + + #[test] + fn extend_from_within() { + let mut a = vec1!["a", "b", "c", "d"]; + a.extend_from_within(1..3); + assert_eq!(a, ["a", "b", "c", "d", "b", "c"]); + } + mod AsMut { use crate::*; diff --git a/src/shared.rs b/src/shared.rs index ab4fc25..4d908d0 100644 --- a/src/shared.rs +++ b/src/shared.rs @@ -46,7 +46,7 @@ macro_rules! impl_wrapper { ( base_bounds_macro = $($tb:ident : $trait:ident)?, impl <$A:ident> $ty_name:ident<$A_:ident> { - $(fn $fn_name:ident(&$($m:ident)* $(, $param:ident: $tp:ty)*) -> $rt:ty);* + $(fn $fn_name:ident(&$($m:ident)* $(, $param:ident: $tp:ty)*) -> $rt:ty ;)* } ) => ( impl<$A> $ty_name<$A> @@ -300,6 +300,15 @@ macro_rules! shared_impl { /// The moment the last element would be removed this will instead fail, not removing /// the element. **All but the last element will have been removed anyway.** /// + /// # Panic Behavior + /// + /// The panic behavior is for now unspecified and might change without a + /// major version release. + /// + /// The current implementation does only delete non-retained elements at + /// the end of the `retain` function call. This might change in the future + /// matching `std`s behavior. + /// /// # Error /// /// If the last element would be removed instead of removing it a `Size0Error` is @@ -323,8 +332,54 @@ macro_rules! shared_impl { where F: FnMut(&$item_ty) -> bool { - // code is based on the code in the standard library, - // given a local instal of rust v1.50.0 source documentation in rustup: + self.retain_mut(|e| f(e)) + } + + /// Removes all elements except the ones which the predicate says need to be retained. + /// + /// The moment the last element would be removed this will instead fail, not removing + /// the element. **All other non retained elements will still be removed.** This means + /// you have to be more careful compared to `Vec::retain_mut` about how you modify + /// non retained elements in the closure. + /// + /// # Panic Behavior + /// + /// The panic behavior is for now unspecified and might change without a + /// major version release. + /// + /// The current implementation does only delete non-retained elements at + /// the end of the `retain` function call. This might change in the future + /// matching `std`s behavior. + /// + /// # Error + /// + /// If the last element would be removed instead of removing it a `Size0Error` is + /// returned. + /// + /// # Example + /// + /// Is for `Vec1` but similar code works with `SmallVec1`, too. + /// + /// ``` + /// # use vec1::vec1; + /// + /// let mut vec = vec1![1, 7, 8, 9, 10]; + /// vec.retain_mut(|v| { + /// *v += 2; + /// *v % 2 == 1 + /// }).unwrap(); + /// assert_eq!(vec, vec1![3, 9, 11]); + /// let Size0Error = vec.retain_mut(|_| false).unwrap_err(); + /// assert_eq!(vec.len(), 1); + /// assert_eq!(vec.last(), &11); + /// ``` + pub fn retain_mut(&mut self, mut f: F) -> Result<(), Size0Error> + where + F: FnMut(&mut $item_ty) -> bool + { + // Code is based on the code in the standard library, but not the newest version + // as the newest version uses unsafe optimizations. + // Given a local instal of rust v1.50.0 source documentation in rustup: // /share/doc/rust/html/src/alloc/vec.rs.html#1314-1334 let len = self.len(); let mut del = 0; @@ -332,7 +387,7 @@ macro_rules! shared_impl { let v = &mut **self; for i in 0..len { - if !f(&v[i]) { + if !f(&mut v[i]) { del += 1; } else if del > 0 { v.swap(i - del, i); @@ -551,7 +606,7 @@ macro_rules! shared_impl { fn insert(&mut self, idx: usize, val: $item_ty) -> (); fn len(&self) -> usize; fn capacity(&self) -> usize; - fn as_slice(&self) -> &[$item_ty] + fn as_slice(&self) -> &[$item_ty]; } } diff --git a/src/smallvec_v1.rs b/src/smallvec_v1.rs index 90ba13d..863b922 100644 --- a/src/smallvec_v1.rs +++ b/src/smallvec_v1.rs @@ -215,7 +215,7 @@ impl_wrapper! { fn grow(&mut self, len: usize) -> (); fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr>; fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr>; - fn try_grow(&mut self, len: usize) -> Result<(), CollectionAllocErr> + fn try_grow(&mut self, len: usize) -> Result<(), CollectionAllocErr>; } }