| // 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); |
| } |