From df6f237f80ab0d30b28608ddb51922b240ece57b Mon Sep 17 00:00:00 2001 From: John Ericson Date: Wed, 7 Jul 2021 00:11:34 -0400 Subject: [PATCH 1/8] alloc: add some try_* methods Rust-for-Linux needs Based off of https://github.com/Rust-for-Linux/linux/commit/487d7578bd036ba57b0998d7af69e0bdcc595da8 --- library/alloc/src/collections/mod.rs | 17 ++ library/alloc/src/lib.rs | 1 + library/alloc/src/raw_vec.rs | 104 +++++++-- library/alloc/src/slice.rs | 97 +++++++- library/alloc/src/str.rs | 17 ++ library/alloc/src/string.rs | 4 +- library/alloc/src/sync.rs | 64 ++++- library/alloc/src/vec/mod.rs | 296 ++++++++++++++++++++++-- library/alloc/src/vec/spec_extend.rs | 83 +++++++ library/std/src/collections/hash/map.rs | 4 +- 10 files changed, 645 insertions(+), 42 deletions(-) diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 1ea135a2aed82..c9e1b88d1fafd 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -52,7 +52,11 @@ pub use linked_list::LinkedList; #[doc(no_inline)] pub use vec_deque::VecDeque; +#[cfg(not(no_global_oom_handling))] +use crate::alloc::handle_alloc_error; use crate::alloc::{Layout, LayoutError}; +#[cfg(not(no_global_oom_handling))] +use crate::raw_vec::capacity_overflow; use core::fmt::Display; /// The error type for `try_reserve` methods. @@ -106,6 +110,19 @@ pub enum TryReserveErrorKind { }, } +#[cfg(not(no_global_oom_handling))] +impl TryReserveError { + /// Panic, or worse, according to the global handlers for each case. + pub(crate) fn handle(self) -> ! { + match self { + TryReserveErrorKind::CapacityOverflow => capacity_overflow(), + TryReserveErrorKind::AllocError { layout, non_exhaustive: () } => { + handle_alloc_error(layout) + } + } + } +} + #[unstable( feature = "try_reserve_kind", reason = "Uncertain how much info should be exposed", diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 1bb257acff76a..d9400c1022f46 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -109,6 +109,7 @@ #![feature(iter_advance_by)] #![feature(iter_zip)] #![feature(layout_for_ptr)] +#![feature(more_fallible_allocation_methods)] #![feature(maybe_uninit_extra)] #![feature(maybe_uninit_slice)] #![cfg_attr(test, feature(new_uninit))] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 3d38e73305a37..9720f52cb646c 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -93,6 +93,16 @@ impl RawVec { Self::with_capacity_in(capacity, Global) } + /// Tries to create a `RawVec` (on the system heap) with exactly the + /// capacity and alignment requirements for a `[T; capacity]`. This is + /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is + /// zero-sized. Note that if `T` is zero-sized this means you will + /// *not* get a `RawVec` with the requested capacity. + #[inline] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + /// Like `with_capacity`, but guarantees the buffer is zeroed. #[cfg(not(any(no_global_oom_handling, test)))] #[must_use] @@ -100,6 +110,25 @@ impl RawVec { pub fn with_capacity_zeroed(capacity: usize) -> Self { Self::with_capacity_zeroed_in(capacity, Global) } + + /// Like `try_with_capacity`, but guarantees a successfully allocated buffer is zeroed. + #[inline] + pub fn try_with_capacity_zeroed(capacity: usize) -> Result { + Self::try_with_capacity_zeroed_in(capacity, Global) + } + + /// Reconstitutes a `RawVec` from a pointer and capacity. + /// + /// # Safety + /// + /// The `ptr` must be allocated (on the system heap), and with the given `capacity`. + /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit + /// systems). ZST vectors may have a capacity up to `usize::MAX`. + /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed. + #[inline] + pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self { + unsafe { Self::from_raw_parts_in(ptr, capacity, Global) } + } } impl RawVec { @@ -132,6 +161,13 @@ impl RawVec { Self::allocate_in(capacity, AllocInit::Uninitialized, alloc) } + /// Like `try_with_capacity`, but parameterized over the choice of + /// allocator for the returned `RawVec`. + #[inline] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc) + } + /// Like `with_capacity_zeroed`, but parameterized over the choice /// of allocator for the returned `RawVec`. #[cfg(not(no_global_oom_handling))] @@ -140,6 +176,21 @@ impl RawVec { Self::allocate_in(capacity, AllocInit::Zeroed, alloc) } + /// Like `with_capacity_zeroed`, but parameterized over the choice + /// of allocator for the returned `RawVec`. + #[inline] + pub fn try_with_capacity_zeroed_in(capacity: usize, alloc: A) -> Result { + Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc) + } + + /// Converts a `Box<[T]>` into a `RawVec`. + pub fn from_box(slice: Box<[T], A>) -> Self { + unsafe { + let (slice, alloc) = Box::into_raw_with_allocator(slice); + RawVec::from_raw_parts_in(slice.as_mut_ptr(), slice.len(), alloc) + } + } + /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. /// /// Note that this will correctly reconstitute any `cap` changes @@ -168,33 +219,38 @@ impl RawVec { #[cfg(not(no_global_oom_handling))] fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { + match Self::try_allocate_in(capacity, init, alloc) { + Ok(r) => r, + Err(e) => e.handle(), + } + } + + fn try_allocate_in( + capacity: usize, + init: AllocInit, + alloc: A, + ) -> Result { if mem::size_of::() == 0 { - Self::new_in(alloc) + Ok(Self::new_in(alloc)) } else { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. - let layout = match Layout::array::(capacity) { - Ok(layout) => layout, - Err(_) => capacity_overflow(), - }; - match alloc_guard(layout.size()) { - Ok(_) => {} - Err(_) => capacity_overflow(), - } + let layout = match Layout::array::(capacity)?; + match alloc_guard(layout.size())?; let result = match init { AllocInit::Uninitialized => alloc.allocate(layout), AllocInit::Zeroed => alloc.allocate_zeroed(layout), }; let ptr = match result { Ok(ptr) => ptr, - Err(_) => handle_alloc_error(layout), + Err(_) => return Err(TryReserveErrorKind::AllocError { layout, non_exhaustive: () }), }; - Self { + Ok(Self { ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }, cap: Self::capacity_from_bytes(ptr.len()), alloc, - } + }) } } @@ -349,7 +405,29 @@ impl RawVec { /// Aborts on OOM. #[cfg(not(no_global_oom_handling))] pub fn shrink_to_fit(&mut self, amount: usize) { - handle_reserve(self.shrink(amount)); + handle_reserve(self.try_shrink_to_fit(amount)); + } + + /// Tries to shrink the allocation down to the specified amount. If the given amount + /// is 0, actually completely deallocates. + /// + /// # Panics + /// + /// Panics if the given amount is *larger* than the current capacity. + pub fn try_shrink_to_fit(&mut self, amount: usize) -> Result<(), TryReserveError> { + assert!(amount <= self.capacity(), "Tried to shrink to a larger capacity"); + + let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; + let new_size = amount * mem::size_of::(); + + let ptr = unsafe { + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + self.alloc + .shrink(ptr, layout, new_layout) + .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? + }; + self.set_ptr(ptr); + Ok(()) } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index ae730be0d25a5..5cd17127452dc 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -93,11 +93,11 @@ use core::mem::size_of; use core::ptr; use crate::alloc::Allocator; -#[cfg(not(no_global_oom_handling))] use crate::alloc::Global; #[cfg(not(no_global_oom_handling))] use crate::borrow::ToOwned; use crate::boxed::Box; +use crate::collections::TryReserveError; use crate::vec::Vec; #[unstable(feature = "slice_range", issue = "76393")] @@ -157,6 +157,7 @@ mod hack { use core::alloc::Allocator; use crate::boxed::Box; + use crate::collections::TryReserveError; use crate::vec::Vec; // We shouldn't add inline attribute to this since this is used in @@ -176,6 +177,14 @@ mod hack { T::to_vec(s, alloc) } + #[inline] + pub fn try_to_vec( + s: &[T], + alloc: A, + ) -> Result, TryReserveError> { + T::try_to_vec(s, alloc) + } + #[cfg(not(no_global_oom_handling))] pub trait ConvertVec { fn to_vec(s: &[Self], alloc: A) -> Vec @@ -183,6 +192,12 @@ mod hack { Self: Sized; } + pub trait TryConvertVec { + fn try_to_vec(s: &[Self], alloc: A) -> Result, TryReserveError> + where + Self: Sized; + } + #[cfg(not(no_global_oom_handling))] impl ConvertVec for T { #[inline] @@ -235,6 +250,45 @@ mod hack { v } } + + impl TryConvertVec for T { + #[inline] + default fn try_to_vec( + s: &[Self], + alloc: A, + ) -> Result, TryReserveError> { + struct DropGuard<'a, T, A: Allocator> { + vec: &'a mut Vec, + num_init: usize, + } + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + #[inline] + fn drop(&mut self) { + // SAFETY: + // items were marked initialized in the loop below + unsafe { + self.vec.set_len(self.num_init); + } + } + } + let mut vec = Vec::try_with_capacity_in(s.len(), alloc)?; + let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; + let slots = guard.vec.spare_capacity_mut(); + // .take(slots.len()) is necessary for LLVM to remove bounds checks + // and has better codegen than zip. + for (i, b) in s.iter().enumerate().take(slots.len()) { + guard.num_init = i; + slots[i].write(b.clone()); + } + core::mem::forget(guard); + // SAFETY: + // the vec was allocated and initialized above to at least this length. + unsafe { + vec.set_len(s.len()); + } + Ok(vec) + } + } } #[lang = "slice_alloc"] @@ -474,6 +528,24 @@ impl [T] { self.to_vec_in(Global) } + /// Tries to copy `self` into a new `Vec`. + /// + /// # Examples + /// + /// ``` + /// let s = [10, 40, 30]; + /// let x = s.try_to_vec().unwrap(); + /// // Here, `s` and `x` can be modified independently. + /// ``` + #[inline] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_to_vec(&self) -> Result, TryReserveError> + where + T: Clone, + { + self.try_to_vec_in(Global) + } + /// Copies `self` into a new `Vec` with an allocator. /// /// # Examples @@ -498,6 +570,29 @@ impl [T] { hack::to_vec(self, alloc) } + /// Tries to copy `self` into a new `Vec` with an allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let s = [10, 40, 30]; + /// let x = s.try_to_vec_in(System).unwrap(); + /// // Here, `s` and `x` can be modified independently. + /// ``` + #[inline] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_to_vec_in(&self, alloc: A) -> Result, TryReserveError> + where + T: Clone, + { + // N.B., see the `hack` module in this file for more details. + hack::try_to_vec(self, alloc) + } + /// Converts `self` into a vector without clones or allocation. /// /// The resulting vector can be converted back into a box via diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 104f5556566f4..24131d8550f97 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -36,6 +36,7 @@ use core::unicode::conversions; use crate::borrow::ToOwned; use crate::boxed::Box; +use crate::collections::TryReserveError; use crate::slice::{Concat, Join, SliceIndex}; use crate::string::String; use crate::vec::Vec; @@ -582,6 +583,22 @@ impl str { // make_ascii_lowercase() preserves the UTF-8 invariant. unsafe { String::from_utf8_unchecked(bytes) } } + + /// Tries to create a `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s: &str = "a"; + /// let ss: String = s.try_to_owned().unwrap(); + /// ``` + #[inline] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_to_owned(&self) -> Result { + unsafe { Ok(String::from_utf8_unchecked(self.as_bytes().try_to_vec()?)) } + } } /// Converts a boxed slice of bytes to a boxed string slice without checking diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 4f926d99c6dbc..e984ec9d354fe 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -46,9 +46,9 @@ use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; use core::fmt; use core::hash; +use core::iter::FusedIterator; #[cfg(not(no_global_oom_handling))] -use core::iter::FromIterator; -use core::iter::{from_fn, FusedIterator}; +use core::iter::{from_fn, FromIterator}; #[cfg(not(no_global_oom_handling))] use core::ops::Add; #[cfg(not(no_global_oom_handling))] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 733a898b285ac..81dee9de8a14e 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -34,10 +34,10 @@ use crate::alloc::{box_free, WriteCloneIntoRaw}; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; +use crate::collections::TryReserveError; use crate::rc::is_dangling; #[cfg(not(no_global_oom_handling))] use crate::string::String; -#[cfg(not(no_global_oom_handling))] use crate::vec::Vec; #[cfg(test)] @@ -1203,11 +1203,23 @@ impl Arc<[T]> { #[cfg(not(no_global_oom_handling))] unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> { unsafe { - Self::allocate_for_layout( - Layout::array::(len).unwrap(), - |layout| Global.allocate(layout), + match Self::try_allocate_for_slice(len) { + Ok(r) => r, + Err(e) => e.handle(), + } + } + } + + /// Tries to allocate an `ArcInner<[T]>` with the given length. + unsafe fn try_allocate_for_slice(len: usize) -> Result<*mut ArcInner<[T]>, TryReserveError> { + unsafe { + let layout = Layout::array::(len)?; + Self::try_allocate_for_layout( + layout, + |l| Global.allocate(l), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>, ) + .map_err(|_| TryReserveErrorKind::AllocError { layout, non_exhaustive: () }) } } @@ -1217,11 +1229,23 @@ impl Arc<[T]> { #[cfg(not(no_global_oom_handling))] unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { unsafe { - let ptr = Self::allocate_for_slice(v.len()); + match Self::try_copy_from_slice(v) { + Ok(r) => r, + Err(e) => e.handle(), + } + } + } + + /// Tries to copy elements from slice into newly allocated Arc<\[T\]> + /// + /// Unsafe because the caller must either take ownership or bind `T: Copy`. + unsafe fn try_copy_from_slice(v: &[T]) -> Result, TryReserveError> { + unsafe { + let ptr = Self::try_allocate_for_slice(v.len())?; ptr::copy_nonoverlapping(v.as_ptr(), &mut (*ptr).data as *mut [T] as *mut T, v.len()); - Self::from_ptr(ptr) + Ok(Self::from_ptr(ptr)) } } @@ -2467,14 +2491,36 @@ impl From> for Arc<[T]> { /// assert_eq!(&[1, 2, 3], &shared[..]); /// ``` #[inline] - fn from(mut v: Vec) -> Arc<[T]> { + fn from(v: Vec) -> Arc<[T]> { + match Arc::try_from_vec(v) { + Ok(r) => r, + Err(e) => e.handle(), + } + } +} + +// Avoid `error: specializing impl repeats parameter` implementing `TryFrom`. +impl Arc<[T]> { + /// Tries to allocate a reference-counted slice and move `v`'s items into it. + /// + /// # Example + /// + /// ``` + /// # use std::sync::Arc; + /// let unique: Vec = vec![1, 2, 3]; + /// let shared: Arc<[i32]> = Arc::try_from(unique).unwrap(); + /// assert_eq!(&[1, 2, 3], &shared[..]); + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + #[inline] + pub fn try_from_vec(mut v: Vec) -> Result { unsafe { - let arc = Arc::copy_from_slice(&v); + let arc = Arc::try_copy_from_slice(&v)?; // Allow the Vec to free its memory, but not destroy its contents v.set_len(0); - arc + Ok(arc) } } } diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 88bde6e8ce481..0b371611fd020 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + //! A contiguous growable array type with heap-allocated contents, written //! `Vec`. //! @@ -144,6 +146,7 @@ mod spec_from_iter; #[cfg(not(no_global_oom_handling))] use self::spec_extend::SpecExtend; +use self::spec_extend::TrySpecExtend; #[cfg(not(no_global_oom_handling))] mod spec_extend; @@ -470,6 +473,49 @@ impl Vec { Self::with_capacity_in(capacity, Global) } + /// Tries to construct a new, empty `Vec` with the specified capacity. + /// + /// The vector will be able to hold exactly `capacity` elements without + /// reallocating. If `capacity` is 0, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// *capacity* specified, the vector will have a zero *length*. For an + /// explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// + /// # Examples + /// + /// ``` + /// let mut vec = Vec::try_with_capacity(10).unwrap(); + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.push(i); + /// } + /// assert_eq!(vec.len(), 10); + /// assert_eq!(vec.capacity(), 10); + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); + /// assert_eq!(vec.len(), 11); + /// assert!(vec.capacity() >= 11); + /// + /// let mut result = Vec::try_with_capacity(usize::MAX); + /// assert!(result.is_err()); + /// ``` + #[inline] + #[doc(alias = "malloc")] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + /// Creates a `Vec` directly from the raw components of another vector. /// /// # Safety @@ -609,6 +655,53 @@ impl Vec { Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 } } + /// Tries to construct a new, empty `Vec` with the specified capacity + /// with the provided allocator. + /// + /// The vector will be able to hold exactly `capacity` elements without + /// reallocating. If `capacity` is 0, the vector will not allocate. + /// + /// It is important to note that although the returned vector has the + /// *capacity* specified, the vector will have a zero *length*. For an + /// explanation of the difference between length and capacity, see + /// *[Capacity and reallocation]*. + /// + /// [Capacity and reallocation]: #capacity-and-reallocation + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let mut vec = Vec::try_with_capacity_in(10, System).unwrap(); + /// + /// // The vector contains no items, even though it has capacity for more + /// assert_eq!(vec.len(), 0); + /// assert_eq!(vec.capacity(), 10); + /// + /// // These are all done without reallocating... + /// for i in 0..10 { + /// vec.push(i); + /// } + /// assert_eq!(vec.len(), 10); + /// assert_eq!(vec.capacity(), 10); + /// + /// // ...but this may make the vector reallocate + /// vec.push(11); + /// assert_eq!(vec.len(), 11); + /// assert!(vec.capacity() >= 11); + /// + /// let mut result = Vec::try_with_capacity_in(usize::MAX, System); + /// assert!(result.is_err()); + /// ``` + #[inline] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { + Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 }) + } + /// Creates a `Vec` directly from the raw components of another vector. /// /// # Safety @@ -932,12 +1025,37 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { + match self.try_shrink_to_fit() { + Ok(r) => r, + Err(e) => e.handle(), + } + } + + /// Tries to shrink the capacity of the vector as much as possible. + /// + /// It will drop down as close as possible to the length but the allocator + /// may still inform the vector that there is space for a few more elements. + /// + /// # Examples + /// + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3]); + /// assert_eq!(vec.capacity(), 10); + /// vec.try_shrink_to_fit().unwrap(); + /// assert!(vec.capacity() >= 3); + /// ``` + #[doc(alias = "realloc")] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_shrink_to_fit(&mut self) -> Result<(), TryReserveError> { // The capacity is never less than the length, and there's nothing to do when - // they are equal, so we can avoid the panic case in `RawVec::shrink_to_fit` + // they are equal, so we can avoid the panic case in `RawVec::try_shrink_to_fit` // by only calling it with a greater capacity. - if self.capacity() > self.len { - self.buf.shrink_to_fit(self.len); + if self.capacity() <= self.len { + return Ok(()); } + + self.buf.try_shrink_to_fit(self.len) } /// Shrinks the capacity of the vector with a lower bound. @@ -992,13 +1110,45 @@ impl Vec { /// ``` #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_boxed_slice(mut self) -> Box<[T], A> { + pub fn into_boxed_slice(self) -> Box<[T], A> { + match self.try_into_boxed_slice() { + Ok(r) => r, + Err(e) => e.handle(), + } + } + + /// Tries to convert the vector into [`Box<[T]>`][owned slice]. + /// + /// Note that this will drop any excess capacity. + /// + /// [owned slice]: Box + /// + /// # Examples + /// + /// ``` + /// let v = vec![1, 2, 3]; + /// + /// let slice = v.try_into_boxed_slice().unwrap(); + /// ``` + /// + /// Any excess capacity is removed: + /// + /// ``` + /// let mut vec = Vec::with_capacity(10); + /// vec.extend([1, 2, 3]); + /// + /// assert_eq!(vec.capacity(), 10); + /// let slice = vec.try_into_boxed_slice().unwrap(); + /// assert_eq!(slice.into_vec().capacity(), 3); + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_into_boxed_slice(mut self) -> Result, TryReserveError> { unsafe { - self.shrink_to_fit(); + self.try_shrink_to_fit()?; let me = ManuallyDrop::new(self); let buf = ptr::read(&me.buf); let len = me.len(); - buf.into_box(len).assume_init() + Ok(buf.into_box(len).assume_init()) } } @@ -1723,8 +1873,24 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, value: T) { - // This will panic or abort if we would allocate > isize::MAX bytes - // or if the length increment would overflow for zero-sized types. + match self.try_push(value) { + Ok(r) => r, + Err(e) => e.handle(), + } + } + + /// Tries to append an element to the back of a collection. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1, 2]; + /// vec.try_push(3).unwrap(); + /// assert_eq!(vec, [1, 2, 3]); + /// ``` + #[inline] + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_push(&mut self, value: T) -> Result<(), TryReserveError> { if self.len == self.buf.capacity() { self.buf.reserve_for_push(self.len); } @@ -1733,6 +1899,7 @@ impl Vec { ptr::write(end, value); self.len += 1; } + Ok(()) } /// Removes the last element from a vector and returns it, or [`None`] if it @@ -1787,11 +1954,23 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[inline] unsafe fn append_elements(&mut self, other: *const [T]) { + unsafe { + match self.try_append_elements(other) { + Ok(r) => r, + Err(e) => e.handle(), + } + } + } + + /// Tries to append elements to `Self` from other buffer. + #[inline] + unsafe fn try_append_elements(&mut self, other: *const [T]) -> Result<(), TryReserveError> { let count = unsafe { (*other).len() }; - self.reserve(count); + self.try_reserve(count)?; let len = self.len(); unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) }; self.len += count; + Ok(()) } /// Creates a draining iterator that removes the specified range in the vector @@ -2196,6 +2375,44 @@ impl Vec { } } + /// Tries to resize the `Vec` in-place so that `len` is equal to `new_len`. + /// + /// If `new_len` is greater than `len`, the `Vec` is extended by the + /// difference, with each additional slot filled with `value`. + /// If `new_len` is less than `len`, the `Vec` is simply truncated. + /// + /// This method requires `T` to implement [`Clone`], + /// in order to be able to clone the passed value. + /// If you need more flexibility (or want to rely on [`Default`] instead of + /// [`Clone`]), use [`Vec::resize_with`]. + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec!["hello"]; + /// vec.try_resize(3, "world").unwrap(); + /// assert_eq!(vec, ["hello", "world", "world"]); + /// + /// let mut vec = vec![1, 2, 3, 4]; + /// vec.try_resize(2, 0).unwrap(); + /// assert_eq!(vec, [1, 2]); + /// + /// let mut vec = vec![42]; + /// let result = vec.try_resize(usize::MAX, 0); + /// assert!(result.is_err()); + /// ``` + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_resize(&mut self, new_len: usize, value: T) -> Result<(), TryReserveError> { + let len = self.len(); + + if new_len > len { + self.try_extend_with(new_len - len, ExtendElement(value)) + } else { + self.truncate(new_len); + Ok(()) + } + } + /// Clones and appends all elements in a slice to the `Vec`. /// /// Iterates over the slice `other`, clones each element, and then appends @@ -2221,6 +2438,30 @@ impl Vec { self.spec_extend(other.iter()) } + /// Tries to clone and append all elements in a slice to the `Vec`. + /// + /// Iterates over the slice `other`, clones each element, and then appends + /// it to this `Vec`. The `other` vector is traversed in-order. + /// + /// Note that this function is same as [`extend`] except that it is + /// specialized to work with slices instead. If and when Rust gets + /// specialization this function will likely be deprecated (but still + /// available). + /// + /// # Examples + /// + /// ``` + /// let mut vec = vec![1]; + /// vec.try_extend_from_slice(&[2, 3, 4]).unwrap(); + /// assert_eq!(vec, [1, 2, 3, 4]); + /// ``` + /// + /// [`extend`]: Vec::extend + #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] + pub fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> { + self.try_spec_extend(other.iter()) + } + /// Copies elements from `src` range to the end of the vector. /// /// # Panics @@ -2298,8 +2539,20 @@ impl T> ExtendWith for ExtendFunc { impl Vec { #[cfg(not(no_global_oom_handling))] /// Extend the vector by `n` values, using the given generator. - fn extend_with>(&mut self, n: usize, mut value: E) { - self.reserve(n); + fn extend_with>(&mut self, n: usize, value: E) { + match self.try_extend_with(n, value) { + Ok(r) => r, + Err(e) => e.handle(), + } + } + + /// Try to extend the vector by `n` values, using the given generator. + fn try_extend_with>( + &mut self, + n: usize, + mut value: E, + ) -> Result<(), TryReserveError> { + self.try_reserve(n)?; unsafe { let mut ptr = self.as_mut_ptr().add(self.len()); @@ -2323,6 +2576,7 @@ impl Vec { } // len set by scope guard + Ok(()) } } } @@ -2635,7 +2889,19 @@ impl Vec { // leaf method to which various SpecFrom/SpecExtend implementations delegate when // they have no further optimizations to apply #[cfg(not(no_global_oom_handling))] - fn extend_desugared>(&mut self, mut iterator: I) { + fn extend_desugared>(&mut self, iterator: I) { + match self.try_extend_desugared(iterator) { + Ok(r) => r, + Err(e) => e.handle(), + } + } + + // leaf method to which various SpecFrom/SpecExtend implementations delegate when + // they have no further optimizations to apply + fn try_extend_desugared>( + &mut self, + mut iterator: I, + ) -> Result<(), TryReserveError> { // This is the case for a general iterator. // // This function should be the moral equivalent of: @@ -2647,16 +2913,16 @@ impl Vec { let len = self.len(); if len == self.capacity() { let (lower, _) = iterator.size_hint(); - self.reserve(lower.saturating_add(1)); + self.try_reserve(lower.saturating_add(1))?; } unsafe { ptr::write(self.as_mut_ptr().add(len), element); - // Since next() executes user code which can panic we have to bump the length - // after each step. // NB can't overflow since we would have had to alloc the address space self.set_len(len + 1); } } + + Ok(()) } /// Creates a splicing iterator that replaces the specified range in the vector diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index c3b4534096de5..6773e2ddb1cce 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -1,4 +1,5 @@ use crate::alloc::Allocator; +use crate::vec::TryReserveError; use core::iter::TrustedLen; use core::ptr::{self}; use core::slice::{self}; @@ -6,10 +7,17 @@ use core::slice::{self}; use super::{IntoIter, SetLenOnDrop, Vec}; // Specialization trait used for Vec::extend +#[cfg(not(no_global_oom_handling))] pub(super) trait SpecExtend { fn spec_extend(&mut self, iter: I); } +// Specialization trait used for Vec::try_extend +pub(super) trait TrySpecExtend { + fn try_spec_extend(&mut self, iter: I) -> Result<(), TryReserveError>; +} + +#[cfg(not(no_global_oom_handling))] impl SpecExtend for Vec where I: Iterator, @@ -19,6 +27,16 @@ where } } +impl TrySpecExtend for Vec +where + I: Iterator, +{ + default fn try_spec_extend(&mut self, iter: I) -> Result<(), TryReserveError> { + self.try_extend_desugared(iter) + } +} + +#[cfg(not(no_global_oom_handling))] impl SpecExtend for Vec where I: TrustedLen, @@ -57,6 +75,39 @@ where } } +impl TrySpecExtend for Vec +where + I: TrustedLen, +{ + default fn try_spec_extend(&mut self, iterator: I) -> Result<(), TryReserveError> { + // This is the case for a TrustedLen iterator. + let (low, high) = iterator.size_hint(); + if let Some(additional) = high { + debug_assert_eq!( + low, + additional, + "TrustedLen iterator's size hint is not exact: {:?}", + (low, high) + ); + self.try_reserve(additional)?; + unsafe { + let mut ptr = self.as_mut_ptr().add(self.len()); + let mut local_len = SetLenOnDrop::new(&mut self.len); + iterator.for_each(move |element| { + ptr::write(ptr, element); + ptr = ptr.offset(1); + // NB can't overflow since we would have had to alloc the address space + local_len.increment_len(1); + }); + } + Ok(()) + } else { + Err(TryReserveErrorKind::CapacityOverflow) + } + } +} + +#[cfg(not(no_global_oom_handling))] impl SpecExtend> for Vec { fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { @@ -66,6 +117,17 @@ impl SpecExtend> for Vec { } } +impl TrySpecExtend> for Vec { + fn try_spec_extend(&mut self, mut iterator: IntoIter) -> Result<(), TryReserveError> { + unsafe { + self.try_append_elements(iterator.as_slice() as _)?; + } + iterator.ptr = iterator.end; + Ok(()) + } +} + +#[cfg(not(no_global_oom_handling))] impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec where I: Iterator, @@ -76,6 +138,17 @@ where } } +impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec +where + I: Iterator, + T: Clone, +{ + default fn try_spec_extend(&mut self, iterator: I) -> Result<(), TryReserveError> { + self.try_spec_extend(iterator.cloned()) + } +} + +#[cfg(not(no_global_oom_handling))] impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec where T: Copy, @@ -85,3 +158,13 @@ where unsafe { self.append_elements(slice) }; } } + +impl<'a, T: 'a, A: Allocator + 'a> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec +where + T: Copy, +{ + fn try_spec_extend(&mut self, iterator: slice::Iter<'a, T>) -> Result<(), TryReserveError> { + let slice = iterator.as_slice(); + unsafe { self.try_append_elements(slice) } + } +} diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index ce34e235f5d6a..e7c947ea73d48 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -3011,10 +3011,10 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, #[inline] pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { match err { - hashbrown::TryReserveError::CapacityOverflow => { + hashbrown::TryReserveErrorKind::CapacityOverflow => { TryReserveErrorKind::CapacityOverflow.into() } - hashbrown::TryReserveError::AllocError { layout } => { + hashbrown::TryReserveErrorKind::AllocError { layout } => { TryReserveErrorKind::AllocError { layout, non_exhaustive: () }.into() } } From 759cc38e825d29eb255056a44aa25e487a039901 Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Mon, 6 Dec 2021 15:33:48 +0800 Subject: [PATCH 2/8] Fix some ovbious error Signed-off-by: Xuanwo --- library/alloc/src/collections/mod.rs | 9 ++++++++- library/alloc/src/raw_vec.rs | 22 ++++++++++++++++------ library/alloc/src/sync.rs | 21 +++++++++++++++++---- library/alloc/src/vec/spec_extend.rs | 3 ++- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index c9e1b88d1fafd..8aa126adef1c5 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -114,7 +114,7 @@ pub enum TryReserveErrorKind { impl TryReserveError { /// Panic, or worse, according to the global handlers for each case. pub(crate) fn handle(self) -> ! { - match self { + match self.kind { TryReserveErrorKind::CapacityOverflow => capacity_overflow(), TryReserveErrorKind::AllocError { layout, non_exhaustive: () } => { handle_alloc_error(layout) @@ -135,6 +135,13 @@ impl From for TryReserveError { } } +impl From for TryReserveError { + #[inline] + fn from(_: LayoutError) -> Self { + TryReserveError::from(TryReserveErrorKind::CapacityOverflow) + } +} + #[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")] impl From for TryReserveErrorKind { /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 9720f52cb646c..4abd31bb07a89 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -235,15 +235,17 @@ impl RawVec { } else { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. - let layout = match Layout::array::(capacity)?; - match alloc_guard(layout.size())?; + let layout = Layout::array::(capacity)?; + alloc_guard(layout.size())?; let result = match init { AllocInit::Uninitialized => alloc.allocate(layout), AllocInit::Zeroed => alloc.allocate_zeroed(layout), }; let ptr = match result { Ok(ptr) => ptr, - Err(_) => return Err(TryReserveErrorKind::AllocError { layout, non_exhaustive: () }), + Err(_) => { + return Err(TryReserveError::from(AllocError { layout, non_exhaustive: () })) + } }; Ok(Self { @@ -282,7 +284,11 @@ impl RawVec { /// This will always be `usize::MAX` if `T` is zero-sized. #[inline(always)] pub fn capacity(&self) -> usize { - if mem::size_of::() == 0 { usize::MAX } else { self.cap } + if mem::size_of::() == 0 { + usize::MAX + } else { + self.cap + } } /// Returns a shared reference to the allocator backing this `RawVec`. @@ -390,7 +396,11 @@ impl RawVec { len: usize, additional: usize, ) -> Result<(), TryReserveError> { - if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) } + if self.needs_to_grow(len, additional) { + self.grow_exact(len, additional) + } else { + Ok(()) + } } /// Shrinks the allocation down to the specified amount. If the given amount @@ -591,6 +601,6 @@ fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { // ensure that the code generation related to these panics is minimal as there's // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] -fn capacity_overflow() -> ! { +pub fn capacity_overflow() -> ! { panic!("capacity overflow"); } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 81dee9de8a14e..fdd2757323da3 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -34,7 +34,7 @@ use crate::alloc::{box_free, WriteCloneIntoRaw}; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; -use crate::collections::TryReserveError; +use crate::collections::{TryReserveError, TryReserveErrorKind}; use crate::rc::is_dangling; #[cfg(not(no_global_oom_handling))] use crate::string::String; @@ -960,7 +960,11 @@ impl Arc { let cnt = this.inner().weak.load(SeqCst); // If the weak count is currently locked, the value of the // count was 0 just before taking the lock. - if cnt == usize::MAX { 0 } else { cnt - 1 } + if cnt == usize::MAX { + 0 + } else { + cnt - 1 + } } /// Gets the number of strong (`Arc`) pointers to this allocation. @@ -1219,7 +1223,12 @@ impl Arc<[T]> { |l| Global.allocate(l), |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>, ) - .map_err(|_| TryReserveErrorKind::AllocError { layout, non_exhaustive: () }) + .map_err(|_| { + TryReserveError::from(TryReserveErrorKind::AllocError { + layout, + non_exhaustive: (), + }) + }) } } @@ -1937,7 +1946,11 @@ impl Weak { #[must_use] #[stable(feature = "weak_counts", since = "1.41.0")] pub fn strong_count(&self) -> usize { - if let Some(inner) = self.inner() { inner.strong.load(SeqCst) } else { 0 } + if let Some(inner) = self.inner() { + inner.strong.load(SeqCst) + } else { + 0 + } } /// Gets an approximation of the number of `Weak` pointers pointing to this diff --git a/library/alloc/src/vec/spec_extend.rs b/library/alloc/src/vec/spec_extend.rs index 6773e2ddb1cce..db24cbaf88c21 100644 --- a/library/alloc/src/vec/spec_extend.rs +++ b/library/alloc/src/vec/spec_extend.rs @@ -1,4 +1,5 @@ use crate::alloc::Allocator; +use crate::collections::TryReserveErrorKind; use crate::vec::TryReserveError; use core::iter::TrustedLen; use core::ptr::{self}; @@ -102,7 +103,7 @@ where } Ok(()) } else { - Err(TryReserveErrorKind::CapacityOverflow) + Err(TryReserveError::from(TryReserveErrorKind::CapacityOverflow)) } } } From 6c564f9e65f4009796ef94e0bb1b127802ec63cb Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Mon, 6 Dec 2021 15:36:18 +0800 Subject: [PATCH 3/8] Fix missing piece Signed-off-by: Xuanwo --- library/alloc/src/slice.rs | 1 + library/alloc/src/sync.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 5cd17127452dc..c897482436675 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -93,6 +93,7 @@ use core::mem::size_of; use core::ptr; use crate::alloc::Allocator; +#[cfg(not(no_global_oom_handling))] use crate::alloc::Global; #[cfg(not(no_global_oom_handling))] use crate::borrow::ToOwned; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index fdd2757323da3..01a27f317b600 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -38,6 +38,7 @@ use crate::collections::{TryReserveError, TryReserveErrorKind}; use crate::rc::is_dangling; #[cfg(not(no_global_oom_handling))] use crate::string::String; +#[cfg(not(no_global_oom_handling))] use crate::vec::Vec; #[cfg(test)] From a794efe50883c007ed4b5fe9bc44107f56ce3c0d Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Mon, 6 Dec 2021 15:39:14 +0800 Subject: [PATCH 4/8] Update library/std/src/collections/hash/map.rs --- library/std/src/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index e7c947ea73d48..1bfe7c49029a0 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -3011,7 +3011,7 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, #[inline] pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { match err { - hashbrown::TryReserveErrorKind::CapacityOverflow => { + hashbrown::TryReserveError::CapacityOverflow => { TryReserveErrorKind::CapacityOverflow.into() } hashbrown::TryReserveErrorKind::AllocError { layout } => { From 3ef0a2eaec22c76524cd15ca3c3582a9381ea0b2 Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Mon, 6 Dec 2021 15:39:19 +0800 Subject: [PATCH 5/8] Update library/std/src/collections/hash/map.rs --- library/std/src/collections/hash/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 1bfe7c49029a0..ce34e235f5d6a 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -3014,7 +3014,7 @@ pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReser hashbrown::TryReserveError::CapacityOverflow => { TryReserveErrorKind::CapacityOverflow.into() } - hashbrown::TryReserveErrorKind::AllocError { layout } => { + hashbrown::TryReserveError::AllocError { layout } => { TryReserveErrorKind::AllocError { layout, non_exhaustive: () }.into() } } From bdd26c5606e15fd28f073b67ab54cd17e6104ac0 Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Wed, 15 Dec 2021 15:11:56 +0800 Subject: [PATCH 6/8] Fix warning Signed-off-by: Xuanwo --- library/alloc/src/collections/mod.rs | 7 ------- library/alloc/src/raw_vec.rs | 27 +++++++-------------------- library/alloc/src/sync.rs | 17 ++++++----------- library/alloc/src/vec/mod.rs | 2 -- 4 files changed, 13 insertions(+), 40 deletions(-) diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 8aa126adef1c5..e3aeae4e47fbe 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -135,13 +135,6 @@ impl From for TryReserveError { } } -impl From for TryReserveError { - #[inline] - fn from(_: LayoutError) -> Self { - TryReserveError::from(TryReserveErrorKind::CapacityOverflow) - } -} - #[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")] impl From for TryReserveErrorKind { /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 4abd31bb07a89..2df7d45afbee6 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -183,14 +183,6 @@ impl RawVec { Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc) } - /// Converts a `Box<[T]>` into a `RawVec`. - pub fn from_box(slice: Box<[T], A>) -> Self { - unsafe { - let (slice, alloc) = Box::into_raw_with_allocator(slice); - RawVec::from_raw_parts_in(slice.as_mut_ptr(), slice.len(), alloc) - } - } - /// Converts the entire buffer into `Box<[MaybeUninit]>` with the specified `len`. /// /// Note that this will correctly reconstitute any `cap` changes @@ -235,7 +227,10 @@ impl RawVec { } else { // We avoid `unwrap_or_else` here because it bloats the amount of // LLVM IR generated. - let layout = Layout::array::(capacity)?; + let layout = match Layout::array::(capacity) { + Ok(layout) => layout, + Err(_) => return Err(TryReserveError::from(CapacityOverflow)), + }; alloc_guard(layout.size())?; let result = match init { AllocInit::Uninitialized => alloc.allocate(layout), @@ -244,7 +239,7 @@ impl RawVec { let ptr = match result { Ok(ptr) => ptr, Err(_) => { - return Err(TryReserveError::from(AllocError { layout, non_exhaustive: () })) + return Err(TryReserveError::from(AllocError { layout, non_exhaustive: () })); } }; @@ -284,11 +279,7 @@ impl RawVec { /// This will always be `usize::MAX` if `T` is zero-sized. #[inline(always)] pub fn capacity(&self) -> usize { - if mem::size_of::() == 0 { - usize::MAX - } else { - self.cap - } + if mem::size_of::() == 0 { usize::MAX } else { self.cap } } /// Returns a shared reference to the allocator backing this `RawVec`. @@ -396,11 +387,7 @@ impl RawVec { len: usize, additional: usize, ) -> Result<(), TryReserveError> { - if self.needs_to_grow(len, additional) { - self.grow_exact(len, additional) - } else { - Ok(()) - } + if self.needs_to_grow(len, additional) { self.grow_exact(len, additional) } else { Ok(()) } } /// Shrinks the allocation down to the specified amount. If the given amount diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 3367303d5d4ba..6bef6c2e1bbad 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -961,11 +961,7 @@ impl Arc { let cnt = this.inner().weak.load(SeqCst); // If the weak count is currently locked, the value of the // count was 0 just before taking the lock. - if cnt == usize::MAX { - 0 - } else { - cnt - 1 - } + if cnt == usize::MAX { 0 } else { cnt - 1 } } /// Gets the number of strong (`Arc`) pointers to this allocation. @@ -1218,7 +1214,10 @@ impl Arc<[T]> { /// Tries to allocate an `ArcInner<[T]>` with the given length. unsafe fn try_allocate_for_slice(len: usize) -> Result<*mut ArcInner<[T]>, TryReserveError> { unsafe { - let layout = Layout::array::(len)?; + let layout = match Layout::array::(len) { + Ok(layout) => layout, + Err(_) => return Err(TryReserveError::from(TryReserveErrorKind::CapacityOverflow)), + }; Self::try_allocate_for_layout( layout, |l| Global.allocate(l), @@ -1947,11 +1946,7 @@ impl Weak { #[must_use] #[stable(feature = "weak_counts", since = "1.41.0")] pub fn strong_count(&self) -> usize { - if let Some(inner) = self.inner() { - inner.strong.load(SeqCst) - } else { - 0 - } + if let Some(inner) = self.inner() { inner.strong.load(SeqCst) } else { 0 } } /// Gets an approximation of the number of `Weak` pointers pointing to this diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f9f63c71fa979..930ad567c1f5f 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! A contiguous growable array type with heap-allocated contents, written //! `Vec`. //! From d1126e0e1d58e8f6aaf9a2349a05e6884c1df626 Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Wed, 15 Dec 2021 15:31:35 +0800 Subject: [PATCH 7/8] Fix build Signed-off-by: Xuanwo --- library/alloc/src/boxed.rs | 20 ++++++++------------ library/alloc/src/raw_vec.rs | 35 ++++++----------------------------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ab41f5646e5e5..1c207639f412a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -626,12 +626,10 @@ impl Box<[T]> { #[inline] pub fn try_new_uninit_slice(len: usize) -> Result]>, AllocError> { unsafe { - let layout = match Layout::array::>(len) { - Ok(l) => l, - Err(_) => return Err(AllocError), - }; - let ptr = Global.allocate(layout)?; - Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) + match RawVec::try_with_capacity(len) { + Ok(raw) => Ok(raw.into_box(len)), + Err(_) => Err(AllocError), + } } } @@ -658,12 +656,10 @@ impl Box<[T]> { #[inline] pub fn try_new_zeroed_slice(len: usize) -> Result]>, AllocError> { unsafe { - let layout = match Layout::array::>(len) { - Ok(l) => l, - Err(_) => return Err(AllocError), - }; - let ptr = Global.allocate_zeroed(layout)?; - Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len)) + match RawVec::try_with_capacity_zeroed(len) { + Ok(raw) => Ok(raw.into_box(len)), + Err(_) => Err(AllocError), + } } } } diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 2df7d45afbee6..3c6baaef8925d 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -98,6 +98,8 @@ impl RawVec { /// equivalent to calling `RawVec::new` when `capacity` is `0` or `T` is /// zero-sized. Note that if `T` is zero-sized this means you will /// *not* get a `RawVec` with the requested capacity. + #[cfg(not(any(no_global_oom_handling, test)))] + #[must_use] #[inline] pub fn try_with_capacity(capacity: usize) -> Result { Self::try_with_capacity_in(capacity, Global) @@ -112,23 +114,12 @@ impl RawVec { } /// Like `try_with_capacity`, but guarantees a successfully allocated buffer is zeroed. + #[cfg(not(any(no_global_oom_handling, test)))] + #[must_use] #[inline] pub fn try_with_capacity_zeroed(capacity: usize) -> Result { Self::try_with_capacity_zeroed_in(capacity, Global) } - - /// Reconstitutes a `RawVec` from a pointer and capacity. - /// - /// # Safety - /// - /// The `ptr` must be allocated (on the system heap), and with the given `capacity`. - /// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit - /// systems). ZST vectors may have a capacity up to `usize::MAX`. - /// If the `ptr` and `capacity` come from a `RawVec`, then this is guaranteed. - #[inline] - pub unsafe fn from_raw_parts(ptr: *mut T, capacity: usize) -> Self { - unsafe { Self::from_raw_parts_in(ptr, capacity, Global) } - } } impl RawVec { @@ -178,6 +169,8 @@ impl RawVec { /// Like `with_capacity_zeroed`, but parameterized over the choice /// of allocator for the returned `RawVec`. + #[cfg(not(any(no_global_oom_handling, test)))] + #[must_use] #[inline] pub fn try_with_capacity_zeroed_in(capacity: usize, alloc: A) -> Result { Self::try_allocate_in(capacity, AllocInit::Zeroed, alloc) @@ -496,22 +489,6 @@ impl RawVec { self.set_ptr(ptr); Ok(()) } - - fn shrink(&mut self, amount: usize) -> Result<(), TryReserveError> { - assert!(amount <= self.capacity(), "Tried to shrink to a larger capacity"); - - let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; - let new_size = amount * mem::size_of::(); - - let ptr = unsafe { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc - .shrink(ptr, layout, new_layout) - .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })? - }; - self.set_ptr(ptr); - Ok(()) - } } // This function is outside `RawVec` to minimize compile times. See the comment From 770559e807e1b1dc78a0685187713e5c07db0494 Mon Sep 17 00:00:00 2001 From: Xuanwo Date: Wed, 15 Dec 2021 16:34:18 +0800 Subject: [PATCH 8/8] Fix test Signed-off-by: Xuanwo --- library/alloc/src/slice.rs | 3 +++ library/alloc/src/str.rs | 2 ++ library/alloc/src/sync.rs | 4 +++- library/alloc/src/vec/mod.rs | 20 ++++++++++++++++++-- library/alloc/tests/lib.rs | 1 + 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index c897482436675..be3e4e48c8eab 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -534,6 +534,8 @@ impl [T] { /// # Examples /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let s = [10, 40, 30]; /// let x = s.try_to_vec().unwrap(); /// // Here, `s` and `x` can be modified independently. @@ -577,6 +579,7 @@ impl [T] { /// /// ``` /// #![feature(allocator_api)] + /// #![feature(more_fallible_allocation_methods)] /// /// use std::alloc::System; /// diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index e176f1cea5bc2..17cfbacf2b9eb 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -599,6 +599,8 @@ impl str { /// Basic usage: /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let s: &str = "a"; /// let ss: String = s.try_to_owned().unwrap(); /// ``` diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 6bef6c2e1bbad..5e4201cf62b88 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2515,9 +2515,11 @@ impl Arc<[T]> { /// # Example /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// # use std::sync::Arc; /// let unique: Vec = vec![1, 2, 3]; - /// let shared: Arc<[i32]> = Arc::try_from(unique).unwrap(); + /// let shared: Arc<[i32]> = Arc::try_from_vec(unique).unwrap(); /// assert_eq!(&[1, 2, 3], &shared[..]); /// ``` #[unstable(feature = "more_fallible_allocation_methods", issue = "86942")] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 930ad567c1f5f..3879714683c7c 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -486,6 +486,8 @@ impl Vec { /// # Examples /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let mut vec = Vec::try_with_capacity(10).unwrap(); /// /// // The vector contains no items, even though it has capacity for more @@ -504,7 +506,7 @@ impl Vec { /// assert_eq!(vec.len(), 11); /// assert!(vec.capacity() >= 11); /// - /// let mut result = Vec::try_with_capacity(usize::MAX); + /// let result = Vec::::try_with_capacity(usize::MAX); /// assert!(result.is_err()); /// ``` #[inline] @@ -670,8 +672,10 @@ impl Vec { /// /// ``` /// #![feature(allocator_api)] + /// #![feature(more_fallible_allocation_methods)] /// /// use std::alloc::System; + /// use alloc::collections::TryReserveError; /// /// let mut vec = Vec::try_with_capacity_in(10, System).unwrap(); /// @@ -691,7 +695,7 @@ impl Vec { /// assert_eq!(vec.len(), 11); /// assert!(vec.capacity() >= 11); /// - /// let mut result = Vec::try_with_capacity_in(usize::MAX, System); + /// let result: Result, TryReserveError> = Vec::try_with_capacity_in(usize::MAX, System); /// assert!(result.is_err()); /// ``` #[inline] @@ -1037,6 +1041,8 @@ impl Vec { /// # Examples /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let mut vec = Vec::with_capacity(10); /// vec.extend([1, 2, 3]); /// assert_eq!(vec.capacity(), 10); @@ -1124,6 +1130,8 @@ impl Vec { /// # Examples /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let v = vec![1, 2, 3]; /// /// let slice = v.try_into_boxed_slice().unwrap(); @@ -1132,6 +1140,8 @@ impl Vec { /// Any excess capacity is removed: /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let mut vec = Vec::with_capacity(10); /// vec.extend([1, 2, 3]); /// @@ -1882,6 +1892,8 @@ impl Vec { /// # Examples /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let mut vec = vec![1, 2]; /// vec.try_push(3).unwrap(); /// assert_eq!(vec, [1, 2, 3]); @@ -2387,6 +2399,8 @@ impl Vec { /// # Examples /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let mut vec = vec!["hello"]; /// vec.try_resize(3, "world").unwrap(); /// assert_eq!(vec, ["hello", "world", "world"]); @@ -2449,6 +2463,8 @@ impl Vec { /// # Examples /// /// ``` + /// #![feature(more_fallible_allocation_methods)] + /// /// let mut vec = vec![1]; /// vec.try_extend_from_slice(&[2, 3, 4]).unwrap(); /// assert_eq!(vec, [1, 2, 3, 4]); diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 68e48348b076e..718f8817e7681 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -26,6 +26,7 @@ #![feature(const_default_impls)] #![feature(const_trait_impl)] #![feature(const_str_from_utf8)] +#![feature(more_fallible_allocation_methods)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher};