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