|
2 | 2 |
|
3 | 3 | //! Extensions to [`Vec`] for fallible allocations.
|
4 | 4 |
|
5 |
| -use alloc::{collections::TryReserveError, vec::Vec}; |
| 5 | +use super::Flags; |
| 6 | +use alloc::{alloc::AllocError, vec::Vec}; |
6 | 7 | use core::result::Result;
|
7 | 8 |
|
8 | 9 | /// Extensions to [`Vec`].
|
9 | 10 | pub trait VecExt<T>: Sized {
|
10 | 11 | /// Creates a new [`Vec`] instance with at least the given capacity.
|
11 |
| - fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError>; |
| 12 | + /// |
| 13 | + /// # Examples |
| 14 | + /// |
| 15 | + /// ``` |
| 16 | + /// let v = Vec::<u32>::with_capacity(20, GFP_KERNEL)?; |
| 17 | + /// |
| 18 | + /// assert!(v.capacity() >= 20); |
| 19 | + /// # Ok::<(), Error>(()) |
| 20 | + /// ``` |
| 21 | + fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError>; |
12 | 22 |
|
13 | 23 | /// Appends an element to the back of the [`Vec`] instance.
|
14 |
| - fn try_push(&mut self, v: T) -> Result<(), TryReserveError>; |
| 24 | + /// |
| 25 | + /// # Examples |
| 26 | + /// |
| 27 | + /// ``` |
| 28 | + /// let mut v = Vec::new(); |
| 29 | + /// v.push(1, GFP_KERNEL)?; |
| 30 | + /// assert_eq!(&v, &[1]); |
| 31 | + /// |
| 32 | + /// v.push(2, GFP_KERNEL)?; |
| 33 | + /// assert_eq!(&v, &[1, 2]); |
| 34 | + /// # Ok::<(), Error>(()) |
| 35 | + /// ``` |
| 36 | + fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError>; |
15 | 37 |
|
16 | 38 | /// Pushes clones of the elements of slice into the [`Vec`] instance.
|
17 |
| - fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> |
| 39 | + /// |
| 40 | + /// # Examples |
| 41 | + /// |
| 42 | + /// ``` |
| 43 | + /// let mut v = Vec::new(); |
| 44 | + /// v.push(1, GFP_KERNEL)?; |
| 45 | + /// |
| 46 | + /// v.extend_from_slice(&[20, 30, 40], GFP_KERNEL)?; |
| 47 | + /// assert_eq!(&v, &[1, 20, 30, 40]); |
| 48 | + /// |
| 49 | + /// v.extend_from_slice(&[50, 60], GFP_KERNEL)?; |
| 50 | + /// assert_eq!(&v, &[1, 20, 30, 40, 50, 60]); |
| 51 | + /// # Ok::<(), Error>(()) |
| 52 | + /// ``` |
| 53 | + fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> |
18 | 54 | where
|
19 | 55 | T: Clone;
|
| 56 | + |
| 57 | + /// Ensures that the capacity exceeds the length by at least `additional` elements. |
| 58 | + /// |
| 59 | + /// # Examples |
| 60 | + /// |
| 61 | + /// ``` |
| 62 | + /// let mut v = Vec::new(); |
| 63 | + /// v.push(1, GFP_KERNEL)?; |
| 64 | + /// |
| 65 | + /// v.reserve(10, GFP_KERNEL)?; |
| 66 | + /// let cap = v.capacity(); |
| 67 | + /// assert!(cap >= 10); |
| 68 | + /// |
| 69 | + /// v.reserve(10, GFP_KERNEL)?; |
| 70 | + /// let new_cap = v.capacity(); |
| 71 | + /// assert_eq!(new_cap, cap); |
| 72 | + /// |
| 73 | + /// # Ok::<(), Error>(()) |
| 74 | + /// ``` |
| 75 | + fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError>; |
20 | 76 | }
|
21 | 77 |
|
22 | 78 | impl<T> VecExt<T> for Vec<T> {
|
23 |
| - fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> { |
| 79 | + fn with_capacity(capacity: usize, flags: Flags) -> Result<Self, AllocError> { |
24 | 80 | let mut v = Vec::new();
|
25 |
| - v.try_reserve(capacity)?; |
| 81 | + <Self as VecExt<_>>::reserve(&mut v, capacity, flags)?; |
26 | 82 | Ok(v)
|
27 | 83 | }
|
28 | 84 |
|
29 |
| - fn try_push(&mut self, v: T) -> Result<(), TryReserveError> { |
30 |
| - if let Err(retry) = self.push_within_capacity(v) { |
31 |
| - self.try_reserve(1)?; |
32 |
| - let _ = self.push_within_capacity(retry); |
33 |
| - } |
| 85 | + fn push(&mut self, v: T, flags: Flags) -> Result<(), AllocError> { |
| 86 | + <Self as VecExt<_>>::reserve(self, 1, flags)?; |
| 87 | + let s = self.spare_capacity_mut(); |
| 88 | + s[0].write(v); |
| 89 | + |
| 90 | + // SAFETY: We just initialised the first spare entry, so it is safe to increase the length |
| 91 | + // by 1. We also know that the new length is <= capacity because of the previous call to |
| 92 | + // `reserve` above. |
| 93 | + unsafe { self.set_len(self.len() + 1) }; |
34 | 94 | Ok(())
|
35 | 95 | }
|
36 | 96 |
|
37 |
| - fn try_extend_from_slice(&mut self, other: &[T]) -> Result<(), TryReserveError> |
| 97 | + fn extend_from_slice(&mut self, other: &[T], flags: Flags) -> Result<(), AllocError> |
38 | 98 | where
|
39 | 99 | T: Clone,
|
40 | 100 | {
|
41 |
| - self.try_reserve(other.len())?; |
42 |
| - for item in other { |
43 |
| - self.try_push(item.clone())?; |
| 101 | + <Self as VecExt<_>>::reserve(self, other.len(), flags)?; |
| 102 | + for (slot, item) in core::iter::zip(self.spare_capacity_mut(), other) { |
| 103 | + slot.write(item.clone()); |
44 | 104 | }
|
45 | 105 |
|
| 106 | + // SAFETY: We just initialised the `other.len()` spare entries, so it is safe to increase |
| 107 | + // the length by the same amount. We also know that the new length is <= capacity because |
| 108 | + // of the previous call to `reserve` above. |
| 109 | + unsafe { self.set_len(self.len() + other.len()) }; |
| 110 | + Ok(()) |
| 111 | + } |
| 112 | + |
| 113 | + #[cfg(any(test, testlib))] |
| 114 | + fn reserve(&mut self, additional: usize, _flags: Flags) -> Result<(), AllocError> { |
| 115 | + Vec::reserve(self, additional); |
46 | 116 | Ok(())
|
47 | 117 | }
|
| 118 | + |
| 119 | + #[cfg(not(any(test, testlib)))] |
| 120 | + fn reserve(&mut self, additional: usize, flags: Flags) -> Result<(), AllocError> { |
| 121 | + let len = self.len(); |
| 122 | + let cap = self.capacity(); |
| 123 | + |
| 124 | + if cap - len >= additional { |
| 125 | + return Ok(()); |
| 126 | + } |
| 127 | + |
| 128 | + if core::mem::size_of::<T>() == 0 { |
| 129 | + // The capacity is already `usize::MAX` for SZTs, we can't go higher. |
| 130 | + return Err(AllocError); |
| 131 | + } |
| 132 | + |
| 133 | + // We know cap is <= `isize::MAX` because `Layout::array` fails if the resulting byte size |
| 134 | + // is greater than `isize::MAX`. So the multiplication by two won't overflow. |
| 135 | + let new_cap = core::cmp::max(cap * 2, len.checked_add(additional).ok_or(AllocError)?); |
| 136 | + let layout = core::alloc::Layout::array::<T>(new_cap).map_err(|_| AllocError)?; |
| 137 | + |
| 138 | + let (ptr, len, cap) = destructure(self); |
| 139 | + |
| 140 | + // SAFETY: `ptr` is valid because it's either NULL or comes from a previous call to |
| 141 | + // `krealloc_aligned`. We also verified that the type is not a ZST. |
| 142 | + let new_ptr = unsafe { super::allocator::krealloc_aligned(ptr.cast(), layout, flags) }; |
| 143 | + if new_ptr.is_null() { |
| 144 | + // SAFETY: We are just rebuilding the existing `Vec` with no changes. |
| 145 | + unsafe { rebuild(self, ptr, len, cap) }; |
| 146 | + Err(AllocError) |
| 147 | + } else { |
| 148 | + // SAFETY: `ptr` has been reallocated with the layout for `new_cap` elements. New cap |
| 149 | + // is greater than `cap`, so it continues to be >= `len`. |
| 150 | + unsafe { rebuild(self, new_ptr.cast::<T>(), len, new_cap) }; |
| 151 | + Ok(()) |
| 152 | + } |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +#[cfg(not(any(test, testlib)))] |
| 157 | +fn destructure<T>(v: &mut Vec<T>) -> (*mut T, usize, usize) { |
| 158 | + let mut tmp = Vec::new(); |
| 159 | + core::mem::swap(&mut tmp, v); |
| 160 | + let mut tmp = core::mem::ManuallyDrop::new(tmp); |
| 161 | + let len = tmp.len(); |
| 162 | + let cap = tmp.capacity(); |
| 163 | + (tmp.as_mut_ptr(), len, cap) |
| 164 | +} |
| 165 | + |
| 166 | +/// Rebuilds a `Vec` from a pointer, length, and capacity. |
| 167 | +/// |
| 168 | +/// # Safety |
| 169 | +/// |
| 170 | +/// The same as [`Vec::from_raw_parts`]. |
| 171 | +#[cfg(not(any(test, testlib)))] |
| 172 | +unsafe fn rebuild<T>(v: &mut Vec<T>, ptr: *mut T, len: usize, cap: usize) { |
| 173 | + // SAFETY: The safety requirements from this function satisfy those of `from_raw_parts`. |
| 174 | + let mut tmp = unsafe { Vec::from_raw_parts(ptr, len, cap) }; |
| 175 | + core::mem::swap(&mut tmp, v); |
48 | 176 | }
|
0 commit comments