sonic_number/
common.rs

1//! Common utilities, for internal use only.
2
3// The code is cloned from [rust-lang](https://github.com/rust-lang/rust) and modified necessary parts.
4
5/// Helper methods to process immutable bytes.
6pub(crate) trait ByteSlice {
7    /// Read 8 bytes as a 64-bit integer in little-endian order.
8    fn read_u64(&self) -> u64;
9
10    /// Write a 64-bit integer as 8 bytes in little-endian order.
11    fn write_u64(&mut self, value: u64);
12
13    /// Iteratively parse and consume digits from bytes.
14    /// Returns the same bytes with consumed digits being
15    /// elided.
16    fn parse_digits(&self, func: impl FnMut(u8)) -> &Self;
17}
18
19impl ByteSlice for [u8] {
20    #[inline(always)] // inlining this is crucial to remove bound checks
21    fn read_u64(&self) -> u64 {
22        let mut tmp = [0; 8];
23        tmp.copy_from_slice(&self[..8]);
24        u64::from_le_bytes(tmp)
25    }
26
27    #[inline(always)] // inlining this is crucial to remove bound checks
28    fn write_u64(&mut self, value: u64) {
29        self[..8].copy_from_slice(&value.to_le_bytes())
30    }
31
32    #[inline]
33    fn parse_digits(&self, mut func: impl FnMut(u8)) -> &Self {
34        let mut s = self;
35
36        // FIXME: Can't use s.split_first() here yet,
37        // see https://github.com/rust-lang/rust/issues/109328
38        while let [c, s_next @ ..] = s {
39            let c = c.wrapping_sub(b'0');
40            if c < 10 {
41                func(c);
42                s = s_next;
43            } else {
44                break;
45            }
46        }
47
48        s
49    }
50}
51
52/// Determine if 8 bytes are all decimal digits.
53/// This does not care about the order in which the bytes were loaded.
54pub(crate) fn is_8digits(v: u64) -> bool {
55    let a = v.wrapping_add(0x4646_4646_4646_4646);
56    let b = v.wrapping_sub(0x3030_3030_3030_3030);
57    (a | b) & 0x8080_8080_8080_8080 == 0
58}
59
60/// A custom 64-bit floating point type, representing `f * 2^e`.
61/// e is biased, so it be directly shifted into the exponent bits.
62#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
63pub struct BiasedFp {
64    /// The significant digits.
65    pub f: u64,
66    /// The biased, binary exponent.
67    pub e: i32,
68}
69
70impl BiasedFp {
71    #[inline]
72    pub const fn zero_pow2(e: i32) -> Self {
73        Self { f: 0, e }
74    }
75}