| // SPDX-License-Identifier: GPL-2.0 | |
| //! Extensions to [`Vec`] for fallible allocations. | |
| use super::{AllocError, Flags}; | |
| use alloc::vec::Vec; | |
| /// Extensions to [`Vec`]. | |
| pub trait VecExt<T>: Sized { | |
| /// Creates a new [`Vec`] instance with at least the given capacity. | |
| /// | |
| /// # Examples | |
| /// | |
| /// ``` | |
| /// let v = Vec::<u32>::with_capacity(20, GFP_KERNEL)?; | |
| /// | |
| /// assert!(v.capacity() >= 20); | |
| /// # Ok::<(), Error>(()) | |
| /// ``` | |
| fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError>; | |
| /// Appends an element to the back of the [`Vec`] instance. | |
| /// | |
| /// # Examples | |
| /// | |
| /// ``` | |
| /// let mut v = Vec::new(); | |
| /// v.push(1, GFP_KERNEL)?; | |
| /// assert_eq!(&v, &[1]); | |
| /// | |
| /// v.push(2, GFP_KERNEL)?; | |
| /// assert_eq!(&v, &[1, 2]); | |
| /// # Ok::<(), Error>(()) | |
| /// ``` | |
| fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError>; | |
| /// Pushes clones of the elements of slice into the [`Vec`] instance. | |
| /// | |
| /// # Examples | |
| /// | |
| /// ``` | |
| /// let mut v = Vec::new(); | |
| /// v.push(1, GFP_KERNEL)?; | |
| /// | |
| /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?; | |
| /// assert_eq!(&v, &[1, 20, 30, 40]); | |
| /// | |
| /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?; | |
| /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]); | |
| /// # Ok::<(), Error>(()) | |
| /// ``` | |
| fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> | |
| where | |
| T: Clone; | |
| /// Ensures that the capacity exceeds the length by at least `additional` elements. | |
| /// | |
| /// # Examples | |
| /// | |
| /// ``` | |
| /// let mut v = Vec::new(); | |
| /// v.push(1, GFP_KERNEL)?; | |
| /// | |
| /// v.reserve(10, GFP_KERNEL)?; | |
| /// let cap = v.capacity(); | |
| /// assert!(cap >= 10); | |
| /// | |
| /// v.reserve(10, GFP_KERNEL)?; | |
| /// let new_cap = v.capacity(); | |
| /// assert_eq!(new_cap, cap); | |
| /// | |
| /// # Ok::<(), Error>(()) | |
| /// ``` | |
| fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError>; | |
| } | |
| impl<T> VecExt<T> for Vec<T> { | |
| fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> { | |
| let mut v = Vec::new(); | |
| <Self as VecExt<_>>::reserve(&mut v, capacity, flags)?; | |
| Ok(v) | |
| } | |
| fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> { | |
| <Self as VecExt<_>>::reserve(self, 1, flags)?; | |
| let s = self.spare_capacity_mut(); | |
| s[0].write(v); | |
| // SAFETY: We just initialised the first spare entry, so it is safe to increase the length | |
| // by 1. We also know that the new length is <= capacity because of the previous call to | |
| // `reserve` above. | |
| unsafe { self.set_len(self.len() + 1) }; | |
| Ok(()) | |
| } | |
| fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> | |
| where | |
| T: Clone, | |
| { | |
| <Self as VecExt<_>>::reserve(self, other.len(), flags)?; | |
| for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) { | |
| slot.write(item.clone()); | |
| } | |
| // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase | |
| // the length by the same amount. We also know that the new length is <= capacity because | |
| // of the previous call to `reserve` above. | |
| unsafe { self.set_len(self.len() + other.len()) }; | |
| Ok(()) | |
| } | |
| #[cfg(any(test, testlib))] | |
| fn reserve(&mut self, additional: usize, _flags: Flags) -> Result<(), AllocError> { | |
| Vec::reserve(self, additional); | |
| Ok(()) | |
| } | |
| #[cfg(not(any(test, testlib)))] | |
| fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> { | |
| let len = self.len(); | |
| let cap = self.capacity(); | |
| if cap - len >= additional { | |
| return Ok(()); | |
| } | |
| if core::mem::size_of::<T>() == 0 { | |
| // The capacity is already `usize::MAX` for SZTs, we can't go higher. | |
| return Err(AllocError); | |
| } | |
| // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size | |
| // is greater than `isize::MAX`. So the multiplication by two won't overflow. | |
| let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?); | |
| let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?; | |
| let (old_ptr, len, cap) = destructure(self); | |
| // We need to make sure that `ptr` is either NULL or comes from a previous call to | |
| // `krealloc_aligned`. A `Vec<T>`'s `ptr` value is not guaranteed to be NULL and might be | |
| // dangling after being created with `Vec::new`. Instead, we can rely on `Vec<T>`'s capacity | |
| // to be zero if no memory has been allocated yet. | |
| let ptr = if cap == 0 { | |
| core::ptr::null_mut() | |
| } else { | |
| old_ptr | |
| }; | |
| // SAFETY: `ptr` is valid because it's either NULL or comes from a previous call to | |
| // `krealloc_aligned`. We also verified that the type is not a ZST. | |
| let new_ptr = unsafe { super::allocator::krealloc_aligned(ptr.cast(), layout, flags) }; | |
| if new_ptr.is_null() { | |
| // SAFETY: We are just rebuilding the existing `Vec` with no changes. | |
| unsafe { rebuild(self, old_ptr, len, cap) }; | |
| Err(AllocError) | |
| } else { | |
| // SAFETY: `ptr` has been reallocated with the layout for `new_cap` elements. New cap | |
| // is greater than `cap`, so it continues to be >= `len`. | |
| unsafe { rebuild(self, new_ptr.cast::<T>(), len, new_cap) }; | |
| Ok(()) | |
| } | |
| } | |
| } | |
| #[cfg(not(any(test, testlib)))] | |
| fn destructure<T>(v: &mut Vec<T>) -> (*mut T, usize, usize) { | |
| let mut tmp = Vec::new(); | |
| core::mem::swap(&mut tmp, v); | |
| let mut tmp = core::mem::ManuallyDrop::new(tmp); | |
| let len = tmp.len(); | |
| let cap = tmp.capacity(); | |
| (tmp.as_mut_ptr(), len, cap) | |
| } | |
| /// Rebuilds a `Vec` from a pointer, length, and capacity. | |
| /// | |
| /// # Safety | |
| /// | |
| /// The same as [`Vec::from_raw_parts`]. | |
| #[cfg(not(any(test, testlib)))] | |
| unsafe fn rebuild<T>(v: &mut Vec<T>, ptr: *mut T, len: usize, cap: usize) { | |
| // SAFETY: The safety requirements from this function satisfy those of `from_raw_parts`. | |
| let mut tmp = unsafe { Vec::from_raw_parts(ptr, len, cap) }; | |
| core::mem::swap(&mut tmp, v); | |
| } |