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