cw_bigint/biguint/
convert.rs

1use super::{biguint_from_vec, BigUint, ToBigUint};
2
3use crate::big_digit::{self, BigDigit};
4use crate::std_alloc::Vec;
5use crate::ParseBigIntError;
6#[cfg(has_try_from)]
7use crate::TryFromBigIntError;
8
9#[cfg(has_try_from)]
10use core::convert::TryFrom;
11use core::mem;
12use core::str::FromStr;
13use num_integer::Integer;
14use num_traits::{FromPrimitive, Num, PrimInt, ToPrimitive, Zero};
15
16/// Find last set bit
17/// fls(0) == 0, fls(u32::MAX) == 32
18fn fls<T: PrimInt>(v: T) -> u8 {
19    mem::size_of::<T>() as u8 * 8 - v.leading_zeros() as u8
20}
21
22fn ilog2<T: PrimInt>(v: T) -> u8 {
23    fls(v) - 1
24}
25
26impl FromStr for BigUint {
27    type Err = ParseBigIntError;
28
29    #[inline]
30    fn from_str(s: &str) -> Result<BigUint, ParseBigIntError> {
31        BigUint::from_str_radix(s, 10)
32    }
33}
34
35// Convert from a power of two radix (bits == ilog2(radix)) where bits evenly divides
36// BigDigit::BITS
37pub(super) fn from_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint {
38    debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits == 0);
39    debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits)));
40
41    let digits_per_big_digit = big_digit::BITS / bits;
42
43    let data = v
44        .chunks(digits_per_big_digit.into())
45        .map(|chunk| {
46            chunk
47                .iter()
48                .rev()
49                .fold(0, |acc, &c| (acc << bits) | BigDigit::from(c))
50        })
51        .collect();
52
53    biguint_from_vec(data)
54}
55
56// Convert from a power of two radix (bits == ilog2(radix)) where bits doesn't evenly divide
57// BigDigit::BITS
58fn from_inexact_bitwise_digits_le(v: &[u8], bits: u8) -> BigUint {
59    debug_assert!(!v.is_empty() && bits <= 8 && big_digit::BITS % bits != 0);
60    debug_assert!(v.iter().all(|&c| BigDigit::from(c) < (1 << bits)));
61
62    let total_bits = (v.len() as u64).saturating_mul(bits.into());
63    let big_digits = Integer::div_ceil(&total_bits, &big_digit::BITS.into())
64        .to_usize()
65        .unwrap_or(core::usize::MAX);
66    let mut data = Vec::with_capacity(big_digits);
67
68    let mut d = 0;
69    let mut dbits = 0; // number of bits we currently have in d
70
71    // walk v accumululating bits in d; whenever we accumulate big_digit::BITS in d, spit out a
72    // big_digit:
73    for &c in v {
74        d |= BigDigit::from(c) << dbits;
75        dbits += bits;
76
77        if dbits >= big_digit::BITS {
78            data.push(d);
79            dbits -= big_digit::BITS;
80            // if dbits was > big_digit::BITS, we dropped some of the bits in c (they couldn't fit
81            // in d) - grab the bits we lost here:
82            d = BigDigit::from(c) >> (bits - dbits);
83        }
84    }
85
86    if dbits > 0 {
87        debug_assert!(dbits < big_digit::BITS);
88        data.push(d as BigDigit);
89    }
90
91    biguint_from_vec(data)
92}
93
94pub(super) fn from_radix_be(buf: &[u8], radix: u32) -> Option<BigUint> {
95    assert!(2 <= radix && radix <= 256, "The radix must be within 2...256");
96    assert!(radix.is_power_of_two(), "The radix must be a power of 2");
97
98    if buf.is_empty() {
99        return Some(Zero::zero());
100    }
101
102    if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
103        return None;
104    }
105
106    let res = {
107        // Powers of two can use bitwise masks and shifting instead of multiplication
108        let bits = ilog2(radix);
109        let mut v = Vec::from(buf);
110        v.reverse();
111        if big_digit::BITS % bits == 0 {
112            from_bitwise_digits_le(&v, bits)
113        } else {
114            from_inexact_bitwise_digits_le(&v, bits)
115        }
116    };
117
118    Some(res)
119}
120
121pub(super) fn from_radix_le(buf: &[u8], radix: u32) -> Option<BigUint> {
122    assert!(2 <= radix && radix <= 256, "The radix must be within 2...256");
123    assert!(radix.is_power_of_two(), "The radix must be a power of 2");
124
125    if buf.is_empty() {
126        return Some(Zero::zero());
127    }
128
129    if radix != 256 && buf.iter().any(|&b| b >= radix as u8) {
130        return None;
131    }
132
133    let res = {
134        // Powers of two can use bitwise masks and shifting instead of multiplication
135        let bits = ilog2(radix);
136        if big_digit::BITS % bits == 0 {
137            from_bitwise_digits_le(buf, bits)
138        } else {
139            from_inexact_bitwise_digits_le(buf, bits)
140        }
141    };
142
143    Some(res)
144}
145
146impl Num for BigUint {
147    type FromStrRadixErr = ParseBigIntError;
148
149    /// Creates and initializes a `BigUint`.
150    fn from_str_radix(s: &str, radix: u32) -> Result<BigUint, ParseBigIntError> {
151        assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
152        assert!(radix.is_power_of_two(), "The radix must be a power of 2");
153
154        let mut s = s;
155        if s.starts_with('+') {
156            let tail = &s[1..];
157            if !tail.starts_with('+') {
158                s = tail
159            }
160        }
161
162        if s.is_empty() {
163            return Err(ParseBigIntError::empty());
164        }
165
166        if s.starts_with('_') {
167            // Must lead with a real digit!
168            return Err(ParseBigIntError::invalid());
169        }
170
171        // First normalize all characters to plain digit values
172        let mut v = Vec::with_capacity(s.len());
173        for b in s.bytes() {
174            let d = match b {
175                b'0'..=b'9' => b - b'0',
176                b'a'..=b'z' => b - b'a' + 10,
177                b'A'..=b'Z' => b - b'A' + 10,
178                b'_' => continue,
179                _ => core::u8::MAX,
180            };
181            if d < radix as u8 {
182                v.push(d);
183            } else {
184                return Err(ParseBigIntError::invalid());
185            }
186        }
187
188        let res = {
189            // Powers of two can use bitwise masks and shifting instead of multiplication
190            let bits = ilog2(radix);
191            v.reverse();
192            if big_digit::BITS % bits == 0 {
193                from_bitwise_digits_le(&v, bits)
194            } else {
195                from_inexact_bitwise_digits_le(&v, bits)
196            }
197        };
198        Ok(res)
199    }
200}
201
202impl ToPrimitive for BigUint {
203    #[inline]
204    fn to_i64(&self) -> Option<i64> {
205        self.to_u64().as_ref().and_then(u64::to_i64)
206    }
207
208    #[inline]
209    fn to_i128(&self) -> Option<i128> {
210        self.to_u128().as_ref().and_then(u128::to_i128)
211    }
212
213    #[allow(clippy::useless_conversion)]
214    #[inline]
215    fn to_u64(&self) -> Option<u64> {
216        let mut ret: u64 = 0;
217        let mut bits = 0;
218
219        for i in self.data.iter() {
220            if bits >= 64 {
221                return None;
222            }
223
224            // XXX Conversion is useless if already 64-bit.
225            ret += u64::from(*i) << bits;
226            bits += big_digit::BITS;
227        }
228
229        Some(ret)
230    }
231
232    #[inline]
233    fn to_u128(&self) -> Option<u128> {
234        let mut ret: u128 = 0;
235        let mut bits = 0;
236
237        for i in self.data.iter() {
238            if bits >= 128 {
239                return None;
240            }
241
242            ret |= u128::from(*i) << bits;
243            bits += big_digit::BITS;
244        }
245
246        Some(ret)
247    }
248}
249
250macro_rules! impl_try_from_biguint {
251    ($T:ty, $to_ty:path) => {
252        #[cfg(has_try_from)]
253        impl TryFrom<&BigUint> for $T {
254            type Error = TryFromBigIntError<()>;
255
256            #[inline]
257            fn try_from(value: &BigUint) -> Result<$T, TryFromBigIntError<()>> {
258                $to_ty(value).ok_or(TryFromBigIntError::new(()))
259            }
260        }
261
262        #[cfg(has_try_from)]
263        impl TryFrom<BigUint> for $T {
264            type Error = TryFromBigIntError<BigUint>;
265
266            #[inline]
267            fn try_from(value: BigUint) -> Result<$T, TryFromBigIntError<BigUint>> {
268                <$T>::try_from(&value).map_err(|_| TryFromBigIntError::new(value))
269            }
270        }
271    };
272}
273
274impl_try_from_biguint!(u8, ToPrimitive::to_u8);
275impl_try_from_biguint!(u16, ToPrimitive::to_u16);
276impl_try_from_biguint!(u32, ToPrimitive::to_u32);
277impl_try_from_biguint!(u64, ToPrimitive::to_u64);
278impl_try_from_biguint!(usize, ToPrimitive::to_usize);
279impl_try_from_biguint!(u128, ToPrimitive::to_u128);
280
281impl_try_from_biguint!(i8, ToPrimitive::to_i8);
282impl_try_from_biguint!(i16, ToPrimitive::to_i16);
283impl_try_from_biguint!(i32, ToPrimitive::to_i32);
284impl_try_from_biguint!(i64, ToPrimitive::to_i64);
285impl_try_from_biguint!(isize, ToPrimitive::to_isize);
286impl_try_from_biguint!(i128, ToPrimitive::to_i128);
287
288impl FromPrimitive for BigUint {
289    #[inline]
290    fn from_i64(n: i64) -> Option<BigUint> {
291        if n >= 0 {
292            Some(BigUint::from(n as u64))
293        } else {
294            None
295        }
296    }
297
298    #[inline]
299    fn from_i128(n: i128) -> Option<BigUint> {
300        if n >= 0 {
301            Some(BigUint::from(n as u128))
302        } else {
303            None
304        }
305    }
306
307    #[inline]
308    fn from_u64(n: u64) -> Option<BigUint> {
309        Some(BigUint::from(n))
310    }
311
312    #[inline]
313    fn from_u128(n: u128) -> Option<BigUint> {
314        Some(BigUint::from(n))
315    }
316}
317
318impl From<u64> for BigUint {
319    #[inline]
320    fn from(mut n: u64) -> Self {
321        let mut ret: BigUint = Zero::zero();
322
323        while n != 0 {
324            ret.data.push(n as BigDigit);
325            // don't overflow if BITS is 64:
326            n = (n >> 1) >> (big_digit::BITS - 1);
327        }
328
329        ret
330    }
331}
332
333impl From<u128> for BigUint {
334    #[inline]
335    fn from(mut n: u128) -> Self {
336        let mut ret: BigUint = Zero::zero();
337
338        while n != 0 {
339            ret.data.push(n as BigDigit);
340            n >>= big_digit::BITS;
341        }
342
343        ret
344    }
345}
346
347macro_rules! impl_biguint_from_uint {
348    ($T:ty) => {
349        impl From<$T> for BigUint {
350            #[inline]
351            fn from(n: $T) -> Self {
352                BigUint::from(n as u64)
353            }
354        }
355    };
356}
357
358impl_biguint_from_uint!(u8);
359impl_biguint_from_uint!(u16);
360impl_biguint_from_uint!(u32);
361impl_biguint_from_uint!(usize);
362
363macro_rules! impl_biguint_try_from_int {
364    ($T:ty, $from_ty:path) => {
365        #[cfg(has_try_from)]
366        impl TryFrom<$T> for BigUint {
367            type Error = TryFromBigIntError<()>;
368
369            #[inline]
370            fn try_from(value: $T) -> Result<BigUint, TryFromBigIntError<()>> {
371                $from_ty(value).ok_or(TryFromBigIntError::new(()))
372            }
373        }
374    };
375}
376
377impl_biguint_try_from_int!(i8, FromPrimitive::from_i8);
378impl_biguint_try_from_int!(i16, FromPrimitive::from_i16);
379impl_biguint_try_from_int!(i32, FromPrimitive::from_i32);
380impl_biguint_try_from_int!(i64, FromPrimitive::from_i64);
381impl_biguint_try_from_int!(isize, FromPrimitive::from_isize);
382impl_biguint_try_from_int!(i128, FromPrimitive::from_i128);
383
384impl ToBigUint for BigUint {
385    #[inline]
386    fn to_biguint(&self) -> Option<BigUint> {
387        Some(self.clone())
388    }
389}
390
391macro_rules! impl_to_biguint {
392    ($T:ty, $from_ty:path) => {
393        impl ToBigUint for $T {
394            #[inline]
395            fn to_biguint(&self) -> Option<BigUint> {
396                $from_ty(*self)
397            }
398        }
399    };
400}
401
402impl_to_biguint!(isize, FromPrimitive::from_isize);
403impl_to_biguint!(i8, FromPrimitive::from_i8);
404impl_to_biguint!(i16, FromPrimitive::from_i16);
405impl_to_biguint!(i32, FromPrimitive::from_i32);
406impl_to_biguint!(i64, FromPrimitive::from_i64);
407impl_to_biguint!(i128, FromPrimitive::from_i128);
408
409impl_to_biguint!(usize, FromPrimitive::from_usize);
410impl_to_biguint!(u8, FromPrimitive::from_u8);
411impl_to_biguint!(u16, FromPrimitive::from_u16);
412impl_to_biguint!(u32, FromPrimitive::from_u32);
413impl_to_biguint!(u64, FromPrimitive::from_u64);
414impl_to_biguint!(u128, FromPrimitive::from_u128);
415
416// Extract bitwise digits that evenly divide BigDigit
417pub(super) fn to_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec<u8> {
418    debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits == 0);
419
420    let last_i = u.data.len() - 1;
421    let mask: BigDigit = (1 << bits) - 1;
422    let digits_per_big_digit = big_digit::BITS / bits;
423    let digits = Integer::div_ceil(&u.bits(), &u64::from(bits))
424        .to_usize()
425        .unwrap_or(core::usize::MAX);
426    let mut res = Vec::with_capacity(digits);
427
428    for mut r in u.data[..last_i].iter().cloned() {
429        for _ in 0..digits_per_big_digit {
430            res.push((r & mask) as u8);
431            r >>= bits;
432        }
433    }
434
435    let mut r = u.data[last_i];
436    while r != 0 {
437        res.push((r & mask) as u8);
438        r >>= bits;
439    }
440
441    res
442}
443
444// Extract bitwise digits that don't evenly divide BigDigit
445fn to_inexact_bitwise_digits_le(u: &BigUint, bits: u8) -> Vec<u8> {
446    debug_assert!(!u.is_zero() && bits <= 8 && big_digit::BITS % bits != 0);
447
448    let mask: BigDigit = (1 << bits) - 1;
449    let digits = Integer::div_ceil(&u.bits(), &u64::from(bits))
450        .to_usize()
451        .unwrap_or(core::usize::MAX);
452    let mut res = Vec::with_capacity(digits);
453
454    let mut r = 0;
455    let mut rbits = 0;
456
457    for c in &u.data {
458        r |= *c << rbits;
459        rbits += big_digit::BITS;
460
461        while rbits >= bits {
462            res.push((r & mask) as u8);
463            r >>= bits;
464
465            // r had more bits than it could fit - grab the bits we lost
466            if rbits > big_digit::BITS {
467                r = *c >> (big_digit::BITS - (rbits - bits));
468            }
469
470            rbits -= bits;
471        }
472    }
473
474    if rbits != 0 {
475        res.push(r as u8);
476    }
477
478    while let Some(&0) = res.last() {
479        res.pop();
480    }
481
482    res
483}
484
485pub(super) fn to_radix_le(u: &BigUint, radix: u32) -> Vec<u8> {
486    assert!(radix.is_power_of_two(), "The radix must be a power of 2");
487    if u.is_zero() {
488        vec![0]
489    } else {
490        // Powers of two can use bitwise masks and shifting instead of division
491        let bits = ilog2(radix);
492        if big_digit::BITS % bits == 0 {
493            to_bitwise_digits_le(u, bits)
494        } else {
495            to_inexact_bitwise_digits_le(u, bits)
496        }
497    }
498}
499
500pub(crate) fn to_str_radix_reversed(u: &BigUint, radix: u32) -> Vec<u8> {
501    assert!(2 <= radix && radix <= 36, "The radix must be within 2...36");
502
503    if u.is_zero() {
504        return vec![b'0'];
505    }
506
507    let mut res = to_radix_le(u, radix);
508
509    // Now convert everything to ASCII digits.
510    for r in &mut res {
511        debug_assert!(u32::from(*r) < radix);
512        if *r < 10 {
513            *r += b'0';
514        } else {
515            *r += b'a' - 10;
516        }
517    }
518    res
519}