diff options
Diffstat (limited to 'third_party/rust/minimal-lexical/src/stackvec.rs')
-rw-r--r-- | third_party/rust/minimal-lexical/src/stackvec.rs | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/third_party/rust/minimal-lexical/src/stackvec.rs b/third_party/rust/minimal-lexical/src/stackvec.rs new file mode 100644 index 0000000000..d9bc259555 --- /dev/null +++ b/third_party/rust/minimal-lexical/src/stackvec.rs @@ -0,0 +1,308 @@ +//! Simple stack-allocated vector. + +#![cfg(not(feature = "alloc"))] +#![doc(hidden)] + +use crate::bigint; +use core::{cmp, mem, ops, ptr, slice}; + +/// Simple stack vector implementation. +#[derive(Clone)] +pub struct StackVec { + /// The raw buffer for the elements. + data: [mem::MaybeUninit<bigint::Limb>; bigint::BIGINT_LIMBS], + /// The number of elements in the array (we never need more than u16::MAX). + length: u16, +} + +#[allow(clippy::new_without_default)] +impl StackVec { + /// Construct an empty vector. + #[inline] + pub const fn new() -> Self { + Self { + length: 0, + data: [mem::MaybeUninit::uninit(); bigint::BIGINT_LIMBS], + } + } + + /// Construct a vector from an existing slice. + #[inline] + pub fn try_from(x: &[bigint::Limb]) -> Option<Self> { + let mut vec = Self::new(); + vec.try_extend(x)?; + Some(vec) + } + + /// Sets the length of a vector. + /// + /// This will explicitly set the size of the vector, without actually + /// modifying its buffers, so it is up to the caller to ensure that the + /// vector is actually the specified size. + /// + /// # Safety + /// + /// Safe as long as `len` is less than `BIGINT_LIMBS`. + #[inline] + pub unsafe fn set_len(&mut self, len: usize) { + // Constant is `u16::MAX` for older Rustc versions. + debug_assert!(len <= 0xffff); + debug_assert!(len <= bigint::BIGINT_LIMBS); + self.length = len as u16; + } + + /// The number of elements stored in the vector. + #[inline] + pub const fn len(&self) -> usize { + self.length as usize + } + + /// If the vector is empty. + #[inline] + pub const fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// The number of items the vector can hold. + #[inline] + pub const fn capacity(&self) -> usize { + bigint::BIGINT_LIMBS as usize + } + + /// Append an item to the vector, without bounds checking. + /// + /// # Safety + /// + /// Safe if `self.len() < self.capacity()`. + #[inline] + pub unsafe fn push_unchecked(&mut self, value: bigint::Limb) { + debug_assert!(self.len() < self.capacity()); + // SAFETY: safe, capacity is less than the current size. + unsafe { + ptr::write(self.as_mut_ptr().add(self.len()), value); + self.length += 1; + } + } + + /// Append an item to the vector. + #[inline] + pub fn try_push(&mut self, value: bigint::Limb) -> Option<()> { + if self.len() < self.capacity() { + // SAFETY: safe, capacity is less than the current size. + unsafe { self.push_unchecked(value) }; + Some(()) + } else { + None + } + } + + /// Remove an item from the end of a vector, without bounds checking. + /// + /// # Safety + /// + /// Safe if `self.len() > 0`. + #[inline] + pub unsafe fn pop_unchecked(&mut self) -> bigint::Limb { + debug_assert!(!self.is_empty()); + // SAFETY: safe if `self.length > 0`. + // We have a trivial drop and copy, so this is safe. + self.length -= 1; + unsafe { ptr::read(self.as_mut_ptr().add(self.len())) } + } + + /// Remove an item from the end of the vector and return it, or None if empty. + #[inline] + pub fn pop(&mut self) -> Option<bigint::Limb> { + if self.is_empty() { + None + } else { + // SAFETY: safe, since `self.len() > 0`. + unsafe { Some(self.pop_unchecked()) } + } + } + + /// Add items from a slice to the vector, without bounds checking. + /// + /// # Safety + /// + /// Safe if `self.len() + slc.len() <= self.capacity()`. + #[inline] + pub unsafe fn extend_unchecked(&mut self, slc: &[bigint::Limb]) { + let index = self.len(); + let new_len = index + slc.len(); + debug_assert!(self.len() + slc.len() <= self.capacity()); + let src = slc.as_ptr(); + // SAFETY: safe if `self.len() + slc.len() <= self.capacity()`. + unsafe { + let dst = self.as_mut_ptr().add(index); + ptr::copy_nonoverlapping(src, dst, slc.len()); + self.set_len(new_len); + } + } + + /// Copy elements from a slice and append them to the vector. + #[inline] + pub fn try_extend(&mut self, slc: &[bigint::Limb]) -> Option<()> { + if self.len() + slc.len() <= self.capacity() { + // SAFETY: safe, since `self.len() + slc.len() <= self.capacity()`. + unsafe { self.extend_unchecked(slc) }; + Some(()) + } else { + None + } + } + + /// Truncate vector to new length, dropping any items after `len`. + /// + /// # Safety + /// + /// Safe as long as `len <= self.capacity()`. + unsafe fn truncate_unchecked(&mut self, len: usize) { + debug_assert!(len <= self.capacity()); + self.length = len as u16; + } + + /// Resize the buffer, without bounds checking. + /// + /// # Safety + /// + /// Safe as long as `len <= self.capacity()`. + #[inline] + pub unsafe fn resize_unchecked(&mut self, len: usize, value: bigint::Limb) { + debug_assert!(len <= self.capacity()); + let old_len = self.len(); + if len > old_len { + // We have a trivial drop, so there's no worry here. + // Just, don't set the length until all values have been written, + // so we don't accidentally read uninitialized memory. + + // SAFETY: safe if `len < self.capacity()`. + let count = len - old_len; + for index in 0..count { + unsafe { + let dst = self.as_mut_ptr().add(old_len + index); + ptr::write(dst, value); + } + } + self.length = len as u16; + } else { + // SAFETY: safe since `len < self.len()`. + unsafe { self.truncate_unchecked(len) }; + } + } + + /// Try to resize the buffer. + /// + /// If the new length is smaller than the current length, truncate + /// the input. If it's larger, then append elements to the buffer. + #[inline] + pub fn try_resize(&mut self, len: usize, value: bigint::Limb) -> Option<()> { + if len > self.capacity() { + None + } else { + // SAFETY: safe, since `len <= self.capacity()`. + unsafe { self.resize_unchecked(len, value) }; + Some(()) + } + } + + // HI + + /// Get the high 64 bits from the vector. + #[inline(always)] + pub fn hi64(&self) -> (u64, bool) { + bigint::hi64(self) + } + + // FROM + + /// Create StackVec from u64 value. + #[inline(always)] + pub fn from_u64(x: u64) -> Self { + bigint::from_u64(x) + } + + // MATH + + /// Normalize the integer, so any leading zero values are removed. + #[inline] + pub fn normalize(&mut self) { + bigint::normalize(self) + } + + /// Get if the big integer is normalized. + #[inline] + pub fn is_normalized(&self) -> bool { + bigint::is_normalized(self) + } + + /// AddAssign small integer. + #[inline] + pub fn add_small(&mut self, y: bigint::Limb) -> Option<()> { + bigint::small_add(self, y) + } + + /// MulAssign small integer. + #[inline] + pub fn mul_small(&mut self, y: bigint::Limb) -> Option<()> { + bigint::small_mul(self, y) + } +} + +impl PartialEq for StackVec { + #[inline] + #[allow(clippy::op_ref)] + fn eq(&self, other: &Self) -> bool { + use core::ops::Deref; + self.len() == other.len() && self.deref() == other.deref() + } +} + +impl Eq for StackVec { +} + +impl cmp::PartialOrd for StackVec { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { + Some(bigint::compare(self, other)) + } +} + +impl cmp::Ord for StackVec { + #[inline] + fn cmp(&self, other: &Self) -> cmp::Ordering { + bigint::compare(self, other) + } +} + +impl ops::Deref for StackVec { + type Target = [bigint::Limb]; + #[inline] + fn deref(&self) -> &[bigint::Limb] { + // SAFETY: safe since `self.data[..self.len()]` must be initialized + // and `self.len() <= self.capacity()`. + unsafe { + let ptr = self.data.as_ptr() as *const bigint::Limb; + slice::from_raw_parts(ptr, self.len()) + } + } +} + +impl ops::DerefMut for StackVec { + #[inline] + fn deref_mut(&mut self) -> &mut [bigint::Limb] { + // SAFETY: safe since `self.data[..self.len()]` must be initialized + // and `self.len() <= self.capacity()`. + unsafe { + let ptr = self.data.as_mut_ptr() as *mut bigint::Limb; + slice::from_raw_parts_mut(ptr, self.len()) + } + } +} + +impl ops::MulAssign<&[bigint::Limb]> for StackVec { + #[inline] + fn mul_assign(&mut self, rhs: &[bigint::Limb]) { + bigint::large_mul(self, rhs).unwrap(); + } +} |