|
40 | 40 | //!
|
41 | 41 | //! When this feature is enabled, `SmallVec` works with any arrays of any size, not just a fixed
|
42 | 42 | //! list of sizes.
|
43 |
| -//! |
| 43 | +//! |
44 | 44 | //! ### `specialization`
|
45 | 45 | //!
|
46 | 46 | //! **This feature is unstable and requires a nightly build of the Rust toolchain.**
|
@@ -71,6 +71,7 @@ pub extern crate alloc;
|
71 | 71 | #[cfg(any(test, feature = "write"))]
|
72 | 72 | extern crate std;
|
73 | 73 |
|
| 74 | +use alloc::alloc::{Layout, LayoutErr}; |
74 | 75 | use alloc::boxed::Box;
|
75 | 76 | use alloc::{vec, vec::Vec};
|
76 | 77 | use core::borrow::{Borrow, BorrowMut};
|
@@ -200,9 +201,46 @@ impl<T: Clone> ExtendFromSlice<T> for Vec<T> {
|
200 | 201 | }
|
201 | 202 | }
|
202 | 203 |
|
| 204 | +/// Error type for APIs with fallible heap allocation |
| 205 | +#[derive(Debug)] |
| 206 | +pub enum CollectionAllocErr { |
| 207 | + /// Overflow `usize::MAX` or other error during size computation |
| 208 | + CapacityOverflow, |
| 209 | + /// The allocator return an error |
| 210 | + AllocErr { |
| 211 | + /// The layout that was passed to the allocator |
| 212 | + layout: Layout, |
| 213 | + }, |
| 214 | +} |
| 215 | + |
| 216 | +impl From<LayoutErr> for CollectionAllocErr { |
| 217 | + fn from(_: LayoutErr) -> Self { |
| 218 | + CollectionAllocErr::CapacityOverflow |
| 219 | + } |
| 220 | +} |
| 221 | + |
| 222 | +fn infallible<T>(result: Result<T, CollectionAllocErr>) -> T { |
| 223 | + match result { |
| 224 | + Ok(x) => x, |
| 225 | + Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), |
| 226 | + Err(CollectionAllocErr::AllocErr { layout }) => alloc::alloc::handle_alloc_error(layout), |
| 227 | + } |
| 228 | +} |
| 229 | + |
| 230 | +/// FIXME: use `Layout::array` when we require a Rust version where it’s stable |
| 231 | +/// https://github.com/rust-lang/rust/issues/55724 |
| 232 | +fn layout_array<T>(n: usize) -> Result<Layout, CollectionAllocErr> { |
| 233 | + let size = mem::size_of::<T>().checked_mul(n) |
| 234 | + .ok_or(CollectionAllocErr::CapacityOverflow)?; |
| 235 | + let align = mem::align_of::<T>(); |
| 236 | + Layout::from_size_align(size, align) |
| 237 | + .map_err(|_| CollectionAllocErr::CapacityOverflow) |
| 238 | +} |
| 239 | + |
203 | 240 | unsafe fn deallocate<T>(ptr: *mut T, capacity: usize) {
|
204 |
| - let _vec: Vec<T> = Vec::from_raw_parts(ptr, 0, capacity); |
205 |
| - // Let it drop. |
| 241 | + // This unwrap should succeed since the same did when allocating. |
| 242 | + let layout = layout_array::<T>(capacity).unwrap(); |
| 243 | + alloc::alloc::dealloc(ptr as *mut u8, layout) |
206 | 244 | }
|
207 | 245 |
|
208 | 246 | /// An iterator that removes the items from a `SmallVec` and yields them by value.
|
@@ -691,69 +729,100 @@ impl<A: Array> SmallVec<A> {
|
691 | 729 |
|
692 | 730 | /// Re-allocate to set the capacity to `max(new_cap, inline_size())`.
|
693 | 731 | ///
|
694 |
| - /// Panics if `new_cap` is less than the vector's length. |
| 732 | + /// Panics if `new_cap` is less than the vector's length |
| 733 | + /// or if the capacity computation overflows `usize`. |
695 | 734 | pub fn grow(&mut self, new_cap: usize) {
|
| 735 | + infallible(self.try_grow(new_cap)) |
| 736 | + } |
| 737 | + |
| 738 | + /// Re-allocate to set the capacity to `max(new_cap, inline_size())`. |
| 739 | + /// |
| 740 | + /// Panics if `new_cap` is less than the vector's length |
| 741 | + pub fn try_grow(&mut self, new_cap: usize) -> Result<(), CollectionAllocErr> { |
696 | 742 | unsafe {
|
697 | 743 | let (ptr, &mut len, cap) = self.triple_mut();
|
698 | 744 | let unspilled = !self.spilled();
|
699 | 745 | assert!(new_cap >= len);
|
700 | 746 | if new_cap <= self.inline_size() {
|
701 | 747 | if unspilled {
|
702 |
| - return; |
| 748 | + return Ok(()); |
703 | 749 | }
|
704 | 750 | self.data = SmallVecData::from_inline(MaybeUninit::uninit());
|
705 | 751 | ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
|
706 | 752 | self.capacity = len;
|
| 753 | + deallocate(ptr, cap); |
707 | 754 | } else if new_cap != cap {
|
708 |
| - let mut vec = Vec::with_capacity(new_cap); |
709 |
| - let new_alloc = vec.as_mut_ptr(); |
710 |
| - mem::forget(vec); |
711 |
| - ptr::copy_nonoverlapping(ptr, new_alloc, len); |
712 |
| - self.data = SmallVecData::from_heap(new_alloc, len); |
713 |
| - self.capacity = new_cap; |
| 755 | + let layout = layout_array::<A::Item>(new_cap)?; |
| 756 | + let new_alloc; |
714 | 757 | if unspilled {
|
715 |
| - return; |
| 758 | + new_alloc = NonNull::new(alloc::alloc::alloc(layout)) |
| 759 | + .ok_or(CollectionAllocErr::AllocErr { layout })? |
| 760 | + .cast() |
| 761 | + .as_ptr(); |
| 762 | + ptr::copy_nonoverlapping(ptr, new_alloc, len); |
| 763 | + } else { |
| 764 | + // This should never fail since the same succeeded |
| 765 | + // when previously allocating `ptr`. |
| 766 | + let old_layout = layout_array::<A::Item>(cap)?; |
| 767 | + |
| 768 | + let new_ptr = alloc::alloc::realloc(ptr as *mut u8, old_layout, layout.size()); |
| 769 | + new_alloc = NonNull::new(new_ptr) |
| 770 | + .ok_or(CollectionAllocErr::AllocErr { layout })? |
| 771 | + .cast() |
| 772 | + .as_ptr(); |
716 | 773 | }
|
717 |
| - } else { |
718 |
| - return; |
| 774 | + self.data = SmallVecData::from_heap(new_alloc, len); |
| 775 | + self.capacity = new_cap; |
719 | 776 | }
|
720 |
| - deallocate(ptr, cap); |
| 777 | + Ok(()) |
721 | 778 | }
|
722 | 779 | }
|
723 | 780 |
|
724 | 781 | /// Reserve capacity for `additional` more elements to be inserted.
|
725 | 782 | ///
|
726 | 783 | /// May reserve more space to avoid frequent reallocations.
|
727 | 784 | ///
|
728 |
| - /// If the new capacity would overflow `usize` then it will be set to `usize::max_value()` |
729 |
| - /// instead. (This means that inserting `additional` new elements is not guaranteed to be |
730 |
| - /// possible after calling this function.) |
| 785 | + /// Panics if the capacity computation overflows `usize`. |
731 | 786 | #[inline]
|
732 | 787 | pub fn reserve(&mut self, additional: usize) {
|
| 788 | + infallible(self.try_reserve(additional)) |
| 789 | + } |
| 790 | + |
| 791 | + /// Reserve capacity for `additional` more elements to be inserted. |
| 792 | + /// |
| 793 | + /// May reserve more space to avoid frequent reallocations. |
| 794 | + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { |
733 | 795 | // prefer triple_mut() even if triple() would work
|
734 | 796 | // so that the optimizer removes duplicated calls to it
|
735 | 797 | // from callers like insert()
|
736 | 798 | let (_, &mut len, cap) = self.triple_mut();
|
737 |
| - if cap - len < additional { |
738 |
| - let new_cap = len |
739 |
| - .checked_add(additional) |
740 |
| - .and_then(usize::checked_next_power_of_two) |
741 |
| - .unwrap_or(usize::max_value()); |
742 |
| - self.grow(new_cap); |
| 799 | + if cap - len >= additional { |
| 800 | + return Ok(()); |
743 | 801 | }
|
| 802 | + let new_cap = len |
| 803 | + .checked_add(additional) |
| 804 | + .and_then(usize::checked_next_power_of_two) |
| 805 | + .ok_or(CollectionAllocErr::CapacityOverflow)?; |
| 806 | + self.try_grow(new_cap) |
744 | 807 | }
|
745 | 808 |
|
746 | 809 | /// Reserve the minimum capacity for `additional` more elements to be inserted.
|
747 | 810 | ///
|
748 | 811 | /// Panics if the new capacity overflows `usize`.
|
749 | 812 | pub fn reserve_exact(&mut self, additional: usize) {
|
| 813 | + infallible(self.try_reserve_exact(additional)) |
| 814 | + } |
| 815 | + |
| 816 | + /// Reserve the minimum capacity for `additional` more elements to be inserted. |
| 817 | + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { |
750 | 818 | let (_, &mut len, cap) = self.triple_mut();
|
751 |
| - if cap - len < additional { |
752 |
| - match len.checked_add(additional) { |
753 |
| - Some(cap) => self.grow(cap), |
754 |
| - None => panic!("reserve_exact overflow"), |
755 |
| - } |
| 819 | + if cap - len >= additional { |
| 820 | + return Ok(()); |
756 | 821 | }
|
| 822 | + let new_cap = len |
| 823 | + .checked_add(additional) |
| 824 | + .ok_or(CollectionAllocErr::CapacityOverflow)?; |
| 825 | + self.try_grow(new_cap) |
757 | 826 | }
|
758 | 827 |
|
759 | 828 | /// Shrink the capacity of the vector as much as possible.
|
|
0 commit comments