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