| 1 | //! Simple stack-allocated vector. |
| 2 | |
| 3 | #![cfg (not(feature = "alloc" ))] |
| 4 | #![doc (hidden)] |
| 5 | |
| 6 | use crate::bigint; |
| 7 | use core::{cmp, mem, ops, ptr, slice}; |
| 8 | |
| 9 | /// Simple stack vector implementation. |
| 10 | #[derive (Clone)] |
| 11 | pub struct StackVec { |
| 12 | /// The raw buffer for the elements. |
| 13 | data: [mem::MaybeUninit<bigint::Limb>; bigint::BIGINT_LIMBS], |
| 14 | /// The number of elements in the array (we never need more than u16::MAX). |
| 15 | length: u16, |
| 16 | } |
| 17 | |
| 18 | #[allow (clippy::new_without_default)] |
| 19 | impl StackVec { |
| 20 | /// Construct an empty vector. |
| 21 | #[inline ] |
| 22 | pub const fn new() -> Self { |
| 23 | Self { |
| 24 | length: 0, |
| 25 | data: [mem::MaybeUninit::uninit(); bigint::BIGINT_LIMBS], |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | /// Construct a vector from an existing slice. |
| 30 | #[inline ] |
| 31 | pub fn try_from(x: &[bigint::Limb]) -> Option<Self> { |
| 32 | let mut vec = Self::new(); |
| 33 | vec.try_extend(x)?; |
| 34 | Some(vec) |
| 35 | } |
| 36 | |
| 37 | /// Sets the length of a vector. |
| 38 | /// |
| 39 | /// This will explicitly set the size of the vector, without actually |
| 40 | /// modifying its buffers, so it is up to the caller to ensure that the |
| 41 | /// vector is actually the specified size. |
| 42 | /// |
| 43 | /// # Safety |
| 44 | /// |
| 45 | /// Safe as long as `len` is less than `BIGINT_LIMBS`. |
| 46 | #[inline ] |
| 47 | pub unsafe fn set_len(&mut self, len: usize) { |
| 48 | // Constant is `u16::MAX` for older Rustc versions. |
| 49 | debug_assert!(len <= 0xffff); |
| 50 | debug_assert!(len <= bigint::BIGINT_LIMBS); |
| 51 | self.length = len as u16; |
| 52 | } |
| 53 | |
| 54 | /// The number of elements stored in the vector. |
| 55 | #[inline ] |
| 56 | pub const fn len(&self) -> usize { |
| 57 | self.length as usize |
| 58 | } |
| 59 | |
| 60 | /// If the vector is empty. |
| 61 | #[inline ] |
| 62 | pub const fn is_empty(&self) -> bool { |
| 63 | self.len() == 0 |
| 64 | } |
| 65 | |
| 66 | /// The number of items the vector can hold. |
| 67 | #[inline ] |
| 68 | pub const fn capacity(&self) -> usize { |
| 69 | bigint::BIGINT_LIMBS as usize |
| 70 | } |
| 71 | |
| 72 | /// Append an item to the vector, without bounds checking. |
| 73 | /// |
| 74 | /// # Safety |
| 75 | /// |
| 76 | /// Safe if `self.len() < self.capacity()`. |
| 77 | #[inline ] |
| 78 | pub unsafe fn push_unchecked(&mut self, value: bigint::Limb) { |
| 79 | debug_assert!(self.len() < self.capacity()); |
| 80 | // SAFETY: safe, capacity is less than the current size. |
| 81 | unsafe { |
| 82 | ptr::write(self.as_mut_ptr().add(self.len()), value); |
| 83 | self.length += 1; |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | /// Append an item to the vector. |
| 88 | #[inline ] |
| 89 | pub fn try_push(&mut self, value: bigint::Limb) -> Option<()> { |
| 90 | if self.len() < self.capacity() { |
| 91 | // SAFETY: safe, capacity is less than the current size. |
| 92 | unsafe { self.push_unchecked(value) }; |
| 93 | Some(()) |
| 94 | } else { |
| 95 | None |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | /// Remove an item from the end of a vector, without bounds checking. |
| 100 | /// |
| 101 | /// # Safety |
| 102 | /// |
| 103 | /// Safe if `self.len() > 0`. |
| 104 | #[inline ] |
| 105 | pub unsafe fn pop_unchecked(&mut self) -> bigint::Limb { |
| 106 | debug_assert!(!self.is_empty()); |
| 107 | // SAFETY: safe if `self.length > 0`. |
| 108 | // We have a trivial drop and copy, so this is safe. |
| 109 | self.length -= 1; |
| 110 | unsafe { ptr::read(self.as_mut_ptr().add(self.len())) } |
| 111 | } |
| 112 | |
| 113 | /// Remove an item from the end of the vector and return it, or None if empty. |
| 114 | #[inline ] |
| 115 | pub fn pop(&mut self) -> Option<bigint::Limb> { |
| 116 | if self.is_empty() { |
| 117 | None |
| 118 | } else { |
| 119 | // SAFETY: safe, since `self.len() > 0`. |
| 120 | unsafe { Some(self.pop_unchecked()) } |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | /// Add items from a slice to the vector, without bounds checking. |
| 125 | /// |
| 126 | /// # Safety |
| 127 | /// |
| 128 | /// Safe if `self.len() + slc.len() <= self.capacity()`. |
| 129 | #[inline ] |
| 130 | pub unsafe fn extend_unchecked(&mut self, slc: &[bigint::Limb]) { |
| 131 | let index = self.len(); |
| 132 | let new_len = index + slc.len(); |
| 133 | debug_assert!(self.len() + slc.len() <= self.capacity()); |
| 134 | let src = slc.as_ptr(); |
| 135 | // SAFETY: safe if `self.len() + slc.len() <= self.capacity()`. |
| 136 | unsafe { |
| 137 | let dst = self.as_mut_ptr().add(index); |
| 138 | ptr::copy_nonoverlapping(src, dst, slc.len()); |
| 139 | self.set_len(new_len); |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | /// Copy elements from a slice and append them to the vector. |
| 144 | #[inline ] |
| 145 | pub fn try_extend(&mut self, slc: &[bigint::Limb]) -> Option<()> { |
| 146 | if self.len() + slc.len() <= self.capacity() { |
| 147 | // SAFETY: safe, since `self.len() + slc.len() <= self.capacity()`. |
| 148 | unsafe { self.extend_unchecked(slc) }; |
| 149 | Some(()) |
| 150 | } else { |
| 151 | None |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | /// Truncate vector to new length, dropping any items after `len`. |
| 156 | /// |
| 157 | /// # Safety |
| 158 | /// |
| 159 | /// Safe as long as `len <= self.capacity()`. |
| 160 | unsafe fn truncate_unchecked(&mut self, len: usize) { |
| 161 | debug_assert!(len <= self.capacity()); |
| 162 | self.length = len as u16; |
| 163 | } |
| 164 | |
| 165 | /// Resize the buffer, without bounds checking. |
| 166 | /// |
| 167 | /// # Safety |
| 168 | /// |
| 169 | /// Safe as long as `len <= self.capacity()`. |
| 170 | #[inline ] |
| 171 | pub unsafe fn resize_unchecked(&mut self, len: usize, value: bigint::Limb) { |
| 172 | debug_assert!(len <= self.capacity()); |
| 173 | let old_len = self.len(); |
| 174 | if len > old_len { |
| 175 | // We have a trivial drop, so there's no worry here. |
| 176 | // Just, don't set the length until all values have been written, |
| 177 | // so we don't accidentally read uninitialized memory. |
| 178 | |
| 179 | // SAFETY: safe if `len < self.capacity()`. |
| 180 | let count = len - old_len; |
| 181 | for index in 0..count { |
| 182 | unsafe { |
| 183 | let dst = self.as_mut_ptr().add(old_len + index); |
| 184 | ptr::write(dst, value); |
| 185 | } |
| 186 | } |
| 187 | self.length = len as u16; |
| 188 | } else { |
| 189 | // SAFETY: safe since `len < self.len()`. |
| 190 | unsafe { self.truncate_unchecked(len) }; |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | /// Try to resize the buffer. |
| 195 | /// |
| 196 | /// If the new length is smaller than the current length, truncate |
| 197 | /// the input. If it's larger, then append elements to the buffer. |
| 198 | #[inline ] |
| 199 | pub fn try_resize(&mut self, len: usize, value: bigint::Limb) -> Option<()> { |
| 200 | if len > self.capacity() { |
| 201 | None |
| 202 | } else { |
| 203 | // SAFETY: safe, since `len <= self.capacity()`. |
| 204 | unsafe { self.resize_unchecked(len, value) }; |
| 205 | Some(()) |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | // HI |
| 210 | |
| 211 | /// Get the high 64 bits from the vector. |
| 212 | #[inline (always)] |
| 213 | pub fn hi64(&self) -> (u64, bool) { |
| 214 | bigint::hi64(self) |
| 215 | } |
| 216 | |
| 217 | // FROM |
| 218 | |
| 219 | /// Create StackVec from u64 value. |
| 220 | #[inline (always)] |
| 221 | pub fn from_u64(x: u64) -> Self { |
| 222 | bigint::from_u64(x) |
| 223 | } |
| 224 | |
| 225 | // MATH |
| 226 | |
| 227 | /// Normalize the integer, so any leading zero values are removed. |
| 228 | #[inline ] |
| 229 | pub fn normalize(&mut self) { |
| 230 | bigint::normalize(self) |
| 231 | } |
| 232 | |
| 233 | /// Get if the big integer is normalized. |
| 234 | #[inline ] |
| 235 | pub fn is_normalized(&self) -> bool { |
| 236 | bigint::is_normalized(self) |
| 237 | } |
| 238 | |
| 239 | /// AddAssign small integer. |
| 240 | #[inline ] |
| 241 | pub fn add_small(&mut self, y: bigint::Limb) -> Option<()> { |
| 242 | bigint::small_add(self, y) |
| 243 | } |
| 244 | |
| 245 | /// MulAssign small integer. |
| 246 | #[inline ] |
| 247 | pub fn mul_small(&mut self, y: bigint::Limb) -> Option<()> { |
| 248 | bigint::small_mul(self, y) |
| 249 | } |
| 250 | } |
| 251 | |
| 252 | impl PartialEq for StackVec { |
| 253 | #[inline ] |
| 254 | #[allow (clippy::op_ref)] |
| 255 | fn eq(&self, other: &Self) -> bool { |
| 256 | use core::ops::Deref; |
| 257 | self.len() == other.len() && self.deref() == other.deref() |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | impl Eq for StackVec { |
| 262 | } |
| 263 | |
| 264 | impl cmp::PartialOrd for StackVec { |
| 265 | #[inline ] |
| 266 | fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { |
| 267 | Some(bigint::compare(self, y:other)) |
| 268 | } |
| 269 | } |
| 270 | |
| 271 | impl cmp::Ord for StackVec { |
| 272 | #[inline ] |
| 273 | fn cmp(&self, other: &Self) -> cmp::Ordering { |
| 274 | bigint::compare(self, y:other) |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | impl ops::Deref for StackVec { |
| 279 | type Target = [bigint::Limb]; |
| 280 | #[inline ] |
| 281 | fn deref(&self) -> &[bigint::Limb] { |
| 282 | // SAFETY: safe since `self.data[..self.len()]` must be initialized |
| 283 | // and `self.len() <= self.capacity()`. |
| 284 | unsafe { |
| 285 | let ptr: *const u64 = self.data.as_ptr() as *const bigint::Limb; |
| 286 | slice::from_raw_parts(data:ptr, self.len()) |
| 287 | } |
| 288 | } |
| 289 | } |
| 290 | |
| 291 | impl ops::DerefMut for StackVec { |
| 292 | #[inline ] |
| 293 | fn deref_mut(&mut self) -> &mut [bigint::Limb] { |
| 294 | // SAFETY: safe since `self.data[..self.len()]` must be initialized |
| 295 | // and `self.len() <= self.capacity()`. |
| 296 | unsafe { |
| 297 | let ptr: *mut u64 = self.data.as_mut_ptr() as *mut bigint::Limb; |
| 298 | slice::from_raw_parts_mut(data:ptr, self.len()) |
| 299 | } |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | impl ops::MulAssign<&[bigint::Limb]> for StackVec { |
| 304 | #[inline ] |
| 305 | fn mul_assign(&mut self, rhs: &[bigint::Limb]) { |
| 306 | bigint::large_mul(self, y:rhs).unwrap(); |
| 307 | } |
| 308 | } |
| 309 | |