1//! Common utilities, for internal use only.
2
3/// Helper methods to process immutable bytes.
4pub(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
20impl 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.
60pub(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)]
69pub struct BiasedFp {
70 /// The significant digits.
71 pub f: u64,
72 /// The biased, binary exponent.
73 pub e: i32,
74}
75
76impl BiasedFp {
77 #[inline]
78 pub const fn zero_pow2(e: i32) -> Self {
79 Self { f: 0, e }
80 }
81}
82