mesh_loader/utils/float/
common.rs

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_u64le(&self) -> u64;
7
8    /// Write a 64-bit integer as 8 bytes in little-endian order.
9    fn write_u64le(&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    #[allow(clippy::impl_trait_in_params)] // clippy bug: should not warn method of private trait
18    fn parse_digits(&self, func: impl FnMut(u8)) -> &Self;
19}
20
21impl ByteSlice for [u8] {
22    #[inline(always)] // inlining this is crucial to remove bound checks
23    fn read_u64le(&self) -> u64 {
24        u64::from_le_bytes(self[..8].try_into().unwrap())
25    }
26
27    #[inline(always)] // inlining this is crucial to remove bound checks
28    fn write_u64le(&mut self, value: u64) {
29        self[..8].copy_from_slice(&value.to_le_bytes());
30    }
31
32    #[inline]
33    fn offset_from(&self, other: &Self) -> isize {
34        other.len() as isize - self.len() as isize
35    }
36
37    #[inline]
38    fn parse_digits(&self, mut func: impl FnMut(u8)) -> &Self {
39        let mut s = self;
40
41        // FIXME: Can't use s.split_first() here yet,
42        // see https://github.com/rust-lang/rust/issues/109328
43        // (fixed in LLVM 17)
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) const fn is_8digits(v: u64) -> bool {
61    let a = v.wrapping_add(0x4646_4646_4646_4646);
62    let b = 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(Copy, Clone, PartialEq, Eq, Default)]
69pub(crate) struct BiasedFp {
70    /// The significant digits.
71    pub(crate) f: u64,
72    /// The biased, binary exponent.
73    pub(crate) e: i32,
74}
75
76impl BiasedFp {
77    #[inline]
78    pub(crate) const fn zero_pow2(e: i32) -> Self {
79        Self { f: 0, e }
80    }
81}