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] new() -> Self22 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] try_from(x: &[bigint::Limb]) -> Option<Self>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] set_len(&mut self, len: usize)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] len(&self) -> usize56 pub const fn len(&self) -> usize { 57 self.length as usize 58 } 59 60 /// If the vector is empty. 61 #[inline] is_empty(&self) -> bool62 pub const fn is_empty(&self) -> bool { 63 self.len() == 0 64 } 65 66 /// The number of items the vector can hold. 67 #[inline] capacity(&self) -> usize68 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] push_unchecked(&mut self, value: bigint::Limb)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] try_push(&mut self, value: bigint::Limb) -> Option<()>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] pop_unchecked(&mut self) -> bigint::Limb105 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] pop(&mut self) -> Option<bigint::Limb>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] extend_unchecked(&mut self, slc: &[bigint::Limb])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] try_extend(&mut self, slc: &[bigint::Limb]) -> Option<()>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()`. truncate_unchecked(&mut self, len: usize)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] resize_unchecked(&mut self, len: usize, value: bigint::Limb)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] try_resize(&mut self, len: usize, value: bigint::Limb) -> Option<()>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)] hi64(&self) -> (u64, bool)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)] from_u64(x: u64) -> Self221 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] normalize(&mut self)229 pub fn normalize(&mut self) { 230 bigint::normalize(self) 231 } 232 233 /// Get if the big integer is normalized. 234 #[inline] is_normalized(&self) -> bool235 pub fn is_normalized(&self) -> bool { 236 bigint::is_normalized(self) 237 } 238 239 /// AddAssign small integer. 240 #[inline] add_small(&mut self, y: bigint::Limb) -> Option<()>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] mul_small(&mut self, y: bigint::Limb) -> Option<()>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)] eq(&self, other: &Self) -> bool255 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] partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>266 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { 267 Some(bigint::compare(self, other)) 268 } 269 } 270 271 impl cmp::Ord for StackVec { 272 #[inline] cmp(&self, other: &Self) -> cmp::Ordering273 fn cmp(&self, other: &Self) -> cmp::Ordering { 274 bigint::compare(self, other) 275 } 276 } 277 278 impl ops::Deref for StackVec { 279 type Target = [bigint::Limb]; 280 #[inline] deref(&self) -> &[bigint::Limb]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 = self.data.as_ptr() as *const bigint::Limb; 286 slice::from_raw_parts(ptr, self.len()) 287 } 288 } 289 } 290 291 impl ops::DerefMut for StackVec { 292 #[inline] deref_mut(&mut self) -> &mut [bigint::Limb]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 = self.data.as_mut_ptr() as *mut bigint::Limb; 298 slice::from_raw_parts_mut(ptr, self.len()) 299 } 300 } 301 } 302 303 impl ops::MulAssign<&[bigint::Limb]> for StackVec { 304 #[inline] mul_assign(&mut self, rhs: &[bigint::Limb])305 fn mul_assign(&mut self, rhs: &[bigint::Limb]) { 306 bigint::large_mul(self, rhs).unwrap(); 307 } 308 } 309