diff --git a/Cargo.toml b/Cargo.toml index 0e8f13a..29f8147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smallvec" -version = "1.4.0" +version = "1.4.1" edition = "2018" authors = ["Simon Sapin "] license = "MIT/Apache-2.0" diff --git a/lib.rs b/lib.rs index ba39f43..e0d7541 100644 --- a/lib.rs +++ b/lib.rs @@ -205,7 +205,7 @@ impl ExtendFromSlice for Vec { } /// Error type for APIs with fallible heap allocation -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub enum CollectionAllocErr { /// Overflow `usize::MAX` or other error during size computation CapacityOverflow, @@ -221,23 +221,33 @@ impl From for CollectionAllocErr { CollectionAllocErr::CapacityOverflow } } +impl CollectionAllocErr { + #[cold] + #[inline(never)] + fn bail(&self) -> ! { + match self { + CollectionAllocErr::CapacityOverflow => panic!("capacity overflow"), + CollectionAllocErr::AllocErr { layout } => alloc::alloc::handle_alloc_error(*layout), + } + } +} +#[inline] fn infallible(result: Result) -> T { match result { Ok(x) => x, - Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr { layout }) => alloc::alloc::handle_alloc_error(layout), + Err(ref err) => err.bail(), } } /// FIXME: use `Layout::array` when we require a Rust version where it’s stable /// https://github.com/rust-lang/rust/issues/55724 fn layout_array(n: usize) -> Result { - let size = mem::size_of::().checked_mul(n) + let size = mem::size_of::() + .checked_mul(n) .ok_or(CollectionAllocErr::CapacityOverflow)?; let align = mem::align_of::(); - Layout::from_size_align(size, align) - .map_err(|_| CollectionAllocErr::CapacityOverflow) + Layout::from_size_align(size, align).map_err(|_| CollectionAllocErr::CapacityOverflow) } unsafe fn deallocate(ptr: *mut T, capacity: usize) { @@ -800,8 +810,19 @@ impl SmallVec { // from callers like insert() let (_, &mut len, cap) = self.triple_mut(); if cap - len >= additional { - return Ok(()); + Ok(()) + } else { + self.try_reserve_cold(len, additional) } + } + + #[cold] + #[inline(never)] + fn try_reserve_cold( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), CollectionAllocErr> { let new_cap = len .checked_add(additional) .and_then(usize::checked_next_power_of_two) @@ -817,11 +838,23 @@ impl SmallVec { } /// Reserve the minimum capacity for `additional` more elements to be inserted. + #[inline] pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { let (_, &mut len, cap) = self.triple_mut(); if cap - len >= additional { - return Ok(()); + Ok(()) + } else { + self.try_reserve_exact_cold(len, additional) } + } + + #[cold] + #[inline(never)] + fn try_reserve_exact_cold( + &mut self, + len: usize, + additional: usize, + ) -> Result<(), CollectionAllocErr> { let new_cap = len .checked_add(additional) .ok_or(CollectionAllocErr::CapacityOverflow)?; @@ -1782,7 +1815,9 @@ impl<'a> Drop for SetLenOnDrop<'a> { #[cfg(feature = "const_generics")] unsafe impl Array for [T; N] { type Item = T; - fn size() -> usize { N } + fn size() -> usize { + N + } } #[cfg(not(feature = "const_generics"))] @@ -1805,13 +1840,15 @@ impl_array!( ); /// Convenience trait for constructing a `SmallVec` -pub trait ToSmallVec { +pub trait ToSmallVec { /// Construct a new `SmallVec` from a slice. fn to_smallvec(&self) -> SmallVec; } -impl ToSmallVec for [A::Item] - where A::Item: Copy { +impl ToSmallVec for [A::Item] +where + A::Item: Copy, +{ #[inline] fn to_smallvec(&self) -> SmallVec { SmallVec::from_slice(self)