1use alloc::vec::Vec;
2
3cfg_digit!(
5 pub(crate) type BigDigit = u32;
6 pub(crate) type BigDigit = u64;
7);
8
9cfg_digit!(
12 pub(crate) type DoubleBigDigit = u64;
13 pub(crate) type DoubleBigDigit = u128;
14);
15
16pub(crate) const BITS: u8 = BigDigit::BITS as u8;
17pub(crate) const HALF_BITS: u8 = BITS / 2;
18pub(crate) const HALF: BigDigit = (1 << HALF_BITS) - 1;
19
20pub(crate) const MAX: BigDigit = BigDigit::MAX;
21const LO_MASK: DoubleBigDigit = MAX as DoubleBigDigit;
22
23#[inline]
24fn get_hi(n: DoubleBigDigit) -> BigDigit {
25 (n >> BITS) as BigDigit
26}
27#[inline]
28fn get_lo(n: DoubleBigDigit) -> BigDigit {
29 (n & LO_MASK) as BigDigit
30}
31
32#[inline]
34pub(crate) fn from_doublebigdigit(n: DoubleBigDigit) -> (BigDigit, BigDigit) {
35 (get_hi(n), get_lo(n))
36}
37
38#[inline]
40pub(crate) fn to_doublebigdigit(hi: BigDigit, lo: BigDigit) -> DoubleBigDigit {
41 DoubleBigDigit::from(lo) | (DoubleBigDigit::from(hi) << BITS)
42}
43
44pub(crate) enum BigDigits {
45 Inline(Option<BigDigit>),
46 Heap(Vec<BigDigit>),
47}
48
49impl BigDigits {
50 pub(crate) const ZERO: Self = BigDigits::Inline(None);
51 pub(crate) const ONE: Self = BigDigits::Inline(Some(1));
52
53 #[inline]
54 pub(crate) const fn from_digit(x: BigDigit) -> Self {
55 if x == 0 {
56 BigDigits::ZERO
57 } else {
58 BigDigits::Inline(Some(x))
59 }
60 }
61
62 #[inline]
63 pub(crate) fn from_slice(slice: &[BigDigit]) -> Self {
64 match slice {
65 &[] => BigDigits::ZERO,
66 &[x] => BigDigits::Inline(Some(x)),
67 xs => BigDigits::Heap(xs.to_vec()),
68 }
69 }
70
71 #[inline]
72 pub(crate) fn from_vec(xs: Vec<BigDigit>) -> Self {
73 BigDigits::Heap(xs)
74 }
75
76 #[inline]
77 pub(crate) fn clear(&mut self) {
78 match self {
79 BigDigits::Inline(x) => *x = None,
80 BigDigits::Heap(xs) => xs.clear(),
81 }
82 }
83
84 #[inline]
85 pub(crate) fn push(&mut self, y: BigDigit) {
86 match &mut *self {
87 BigDigits::Inline(x @ None) => *x = Some(y),
88 BigDigits::Inline(Some(x)) => *self = BigDigits::Heap([*x, y].to_vec()),
89 BigDigits::Heap(xs) => xs.push(y),
90 }
91 }
92
93 #[inline]
94 pub(crate) fn pop(&mut self) -> Option<BigDigit> {
95 match self {
96 BigDigits::Inline(x) => x.take(),
97 BigDigits::Heap(xs) => xs.pop(),
98 }
99 }
100
101 #[inline]
102 pub(crate) fn last(&self) -> Option<&BigDigit> {
103 match self {
104 BigDigits::Inline(x) => x.as_ref(),
105 BigDigits::Heap(xs) => xs.last(),
106 }
107 }
108
109 #[inline]
110 pub(crate) fn len(&self) -> usize {
111 match self {
112 BigDigits::Inline(None) => 0,
113 BigDigits::Inline(Some(_)) => 1,
114 BigDigits::Heap(xs) => xs.len(),
115 }
116 }
117
118 #[inline]
119 pub(crate) fn is_empty(&self) -> bool {
120 match self {
121 BigDigits::Inline(None) => true,
122 BigDigits::Inline(Some(_)) => false,
123 BigDigits::Heap(xs) => xs.is_empty(),
124 }
125 }
126
127 #[inline]
128 pub(crate) fn capacity(&self) -> usize {
129 match self {
130 BigDigits::Inline(_) => 1,
131 BigDigits::Heap(xs) => xs.capacity(),
132 }
133 }
134
135 #[inline]
136 pub(crate) fn shrink(&mut self) {
137 if let BigDigits::Heap(xs) = self {
138 if xs.len() < xs.capacity() / 2 {
139 match **xs {
140 [] => *self = BigDigits::ZERO,
141 [x] => *self = BigDigits::Inline(Some(x)),
142 _ => xs.shrink_to(xs.len() + 1),
143 }
144 }
145 }
146 }
147
148 #[inline]
150 pub(crate) fn is_normal(&self) -> bool {
151 match self {
152 BigDigits::Inline(Some(0)) => false,
153 BigDigits::Inline(_) => true,
154 BigDigits::Heap(xs) => !matches!(**xs, [.., 0]),
155 }
156 }
157
158 #[inline]
161 pub(crate) fn normalize(&mut self) {
162 match self {
163 BigDigits::Inline(x) => {
164 if let Some(0) = *x {
165 *x = None;
166 }
167 }
168 BigDigits::Heap(xs) => {
169 if let [.., 0] = **xs {
170 let len = xs.iter().rposition(|&d| d != 0).map_or(0, |i| i + 1);
171 xs.truncate(len);
172 }
173 if xs.len() < xs.capacity() / 2 {
174 match **xs {
175 [] => *self = BigDigits::ZERO,
176 [x] => *self = BigDigits::Inline(Some(x)),
177 _ => xs.shrink_to(xs.len() + 1),
178 }
179 }
180 }
181 }
182 }
183
184 #[inline]
185 pub(crate) fn truncate(&mut self, len: usize) {
186 match self {
187 BigDigits::Inline(x) => {
188 if len == 0 {
189 *x = None;
190 }
191 }
192 BigDigits::Heap(xs) => xs.truncate(len),
193 }
194 }
195
196 #[inline]
197 pub(crate) fn drain_front(&mut self, len: usize) {
198 match self {
199 BigDigits::Inline(x) => {
200 assert!(len <= 1);
201 if len == 1 {
202 *x = None;
203 }
204 }
205 BigDigits::Heap(xs) => {
206 xs.drain(..len);
207 }
208 }
209 }
210
211 pub(crate) fn reserve(&mut self, additional: usize) {
212 match &mut *self {
213 BigDigits::Inline(opt_x) => {
214 let capacity = usize::from(opt_x.is_some()) + additional;
215 if capacity > 1 {
216 let mut vec = Vec::with_capacity(capacity);
217 if let Some(x) = *opt_x {
218 vec.push(x);
219 }
220 *self = BigDigits::Heap(vec);
221 }
222 }
223 BigDigits::Heap(xs) => xs.reserve(additional),
224 }
225 }
226
227 pub(crate) fn resize(&mut self, len: usize, value: BigDigit) {
228 match &mut *self {
229 BigDigits::Inline(x) => match len {
230 0 => *x = None,
231 1 => {
232 if x.is_none() {
233 *x = Some(value);
234 }
235 }
236 _ => {
237 let mut xs = Vec::with_capacity(len);
238 if let Some(x) = *x {
239 xs.push(x);
240 }
241 xs.resize(len, value);
242 *self = BigDigits::Heap(xs);
243 }
244 },
245 BigDigits::Heap(xs) => xs.resize(len, value),
246 }
247 }
248
249 pub(crate) fn extend_from_slice(&mut self, ys: &[BigDigit]) {
250 match &mut *self {
251 BigDigits::Inline(None) => *self = BigDigits::from_slice(ys),
252 BigDigits::Inline(Some(x)) => {
253 let len = ys.len() + 1;
254 if len > 1 {
255 let mut xs = Vec::with_capacity(len);
256 xs.push(*x);
257 xs.extend_from_slice(ys);
258 *self = BigDigits::Heap(xs);
259 }
260 }
261 BigDigits::Heap(xs) => xs.extend_from_slice(ys),
262 }
263 }
264
265 pub(crate) fn extend<I>(&mut self, mut iter: I)
266 where
267 I: ExactSizeIterator<Item = BigDigit>,
268 {
269 match &mut *self {
270 BigDigits::Inline(x) => {
271 if x.is_none() {
272 match iter.next() {
273 Some(y) => *x = Some(y),
274 None => return,
275 }
276 }
277 if let Some(y) = iter.next() {
278 let len = iter.len().saturating_add(2);
279 let mut xs = Vec::with_capacity(len);
280 xs.push(x.unwrap());
281 xs.push(y);
282 xs.extend(iter);
283 *self = BigDigits::Heap(xs);
284 }
285 }
286 BigDigits::Heap(xs) => xs.extend(iter),
287 }
288 }
289}
290
291impl Clone for BigDigits {
292 #[inline]
293 fn clone(&self) -> Self {
294 match self {
295 BigDigits::Inline(x) => BigDigits::Inline(*x),
296 BigDigits::Heap(xs) => BigDigits::from_slice(xs),
297 }
298 }
299
300 #[inline]
301 fn clone_from(&mut self, source: &Self) {
302 match &mut *self {
303 BigDigits::Heap(xs) if xs.capacity() != 0 => {
305 xs.clear();
306 xs.extend_from_slice(source);
307 }
308 #[allow(clippy::assigning_clones)]
309 _ => *self = source.clone(),
310 }
311 }
312}
313
314impl core::ops::Deref for BigDigits {
315 type Target = [BigDigit];
316
317 #[inline]
318 fn deref(&self) -> &Self::Target {
319 match self {
320 BigDigits::Inline(None) => &[],
321 BigDigits::Inline(Some(x)) => core::slice::from_ref(x),
322 BigDigits::Heap(xs) => xs,
323 }
324 }
325}
326
327impl core::ops::DerefMut for BigDigits {
328 #[inline]
329 fn deref_mut(&mut self) -> &mut Self::Target {
330 match self {
331 BigDigits::Inline(None) => &mut [],
332 BigDigits::Inline(Some(x)) => core::slice::from_mut(x),
333 BigDigits::Heap(xs) => xs,
334 }
335 }
336}