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}