Coverage Report

Created: 2026-10-13 07:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rust-brotli/src/enc/util.rs
Line
Count
Source
1
#![allow(clippy::excessive_precision)]
2
3
use crate::enc::log_table_16::logs_16;
4
use crate::enc::log_table_8::logs_8;
5
6
#[cfg(feature = "float64")]
7
pub type floatX = f64;
8
9
#[cfg(not(feature = "float64"))]
10
pub type floatX = f32;
11
12
#[inline(always)]
13
0
pub fn FastLog2u16(v: u16) -> floatX {
14
0
    logs_16[v as usize]
15
0
}
16
17
// The `portable-float` feature routes `std` builds onto the table-driven
18
// implementations below, which are the same ones `no_std` builds already use.
19
// They contain no calls into the platform's libm, so the encoder's cost
20
// estimates -- and therefore the bytes it emits -- are identical on every
21
// target. The feature is a no-op for `no_std` builds: those are already
22
// portable, because the libm path is unavailable to them in the first place.
23
24
#[cfg(all(feature = "std", not(feature = "portable-float")))]
25
#[inline(always)]
26
0
pub fn FastLog2(v: u64) -> floatX {
27
0
    if v < 256 {
28
0
        logs_8[v as usize]
29
    } else {
30
0
        (v as f32).log2() as floatX
31
    }
32
0
}
33
34
#[cfg(any(not(feature = "std"), feature = "portable-float"))]
35
#[inline(always)]
36
pub fn FastLog2(v: u64) -> floatX {
37
    if v < 256 {
38
        logs_8[v as usize]
39
    } else {
40
        FastLog2u64(v)
41
    }
42
}
43
44
#[cfg(all(feature = "std", not(feature = "portable-float")))]
45
#[inline(always)]
46
0
pub fn FastLog2f64(v: u64) -> floatX {
47
0
    if v < 256 {
48
0
        logs_8[v as usize]
49
    } else {
50
0
        (v as floatX).log2()
51
    }
52
0
}
53
54
#[cfg(any(not(feature = "std"), feature = "portable-float"))]
55
#[inline(always)]
56
pub fn FastLog2f64(v: u64) -> floatX {
57
    FastLog2(v) as floatX
58
}
59
60
#[inline]
61
0
pub fn FastLog2u64(v: u64) -> floatX {
62
0
    let bsr_8 = 56i8 - v.leading_zeros() as i8;
63
0
    let offset = bsr_8 & -((bsr_8 >= 0) as i8);
64
0
    (offset as floatX) + logs_8[(v >> offset) as usize]
65
0
}
66
67
#[inline(always)]
68
0
pub fn FastLog2u32(v: i32) -> floatX {
69
0
    let bsr_8 = 24i8 - v.leading_zeros() as i8;
70
0
    let offset = bsr_8 & -((bsr_8 >= 0) as i8);
71
0
    (offset as floatX) + logs_8[(v >> offset) as usize]
72
0
}
73
74
#[inline(always)]
75
0
pub fn xFastLog2u16(v: u16) -> floatX {
76
0
    let bsr_8 = 8i8 - v.leading_zeros() as i8;
77
0
    let offset = (bsr_8 & -((bsr_8 >= 0) as i8));
78
0
    (offset as floatX) + logs_8[(v >> offset) as usize]
79
0
}
80
81
#[cfg(all(feature = "std", not(feature = "portable-float")))]
82
#[inline(always)]
83
0
pub fn FastPow2(v: floatX) -> floatX {
84
0
    (2 as floatX).powf(v)
85
0
}
86
87
#[cfg(any(not(feature = "std"), feature = "portable-float"))]
88
#[inline(always)]
89
pub fn FastPow2(v: floatX) -> floatX {
90
    assert!(v >= 0 as floatX);
91
    let round_down = v as i32;
92
    let remainder = v - round_down as floatX;
93
    let mut x = 1 as floatX;
94
    // (1 + (x/n) * ln2) ^ n
95
    // let n = 8
96
    x += remainder * (0.693147180559945309417232121458 / 256.0) as floatX;
97
    x *= x;
98
    x *= x;
99
    x *= x;
100
    x *= x;
101
    x *= x;
102
    x *= x;
103
    x *= x;
104
    x *= x;
105
106
    (1 << round_down) as floatX * x
107
}
108
109
#[inline(always)]
110
0
pub fn Log2FloorNonZero(v: u64) -> u32 {
111
0
    63u32 ^ v.leading_zeros()
112
0
}
113
114
#[cfg(test)]
115
mod test {
116
    fn baseline_log2_floor_non_zero(mut n: u64) -> u32 {
117
        let mut result: u32 = 0;
118
        while {
119
            n >>= 1i32;
120
            n
121
        } != 0
122
        {
123
            result = result.wrapping_add(1);
124
        }
125
        result
126
    }
127
128
    #[test]
129
    fn log2floor_non_zero_works() {
130
        let examples = [
131
            4u64,
132
            254,
133
            256,
134
            1428,
135
            25412509,
136
            21350891256,
137
            65536,
138
            1258912591,
139
            60968101,
140
            1,
141
            12589125190825,
142
            105912059215091,
143
            0,
144
        ];
145
        for example in examples.iter() {
146
            let fast_version = super::Log2FloorNonZero(*example);
147
            let baseline_version = baseline_log2_floor_non_zero(*example);
148
            if *example != 0 {
149
                // make sure we don't panic when computing...but don't care about result
150
                assert_eq!(fast_version, baseline_version);
151
            }
152
        }
153
    }
154
    pub fn approx_eq(a: f64, b: f64, tol: f64) {
155
        let mut t0 = a - b;
156
        let mut t1 = b - a;
157
        if t0 < 0.0 {
158
            t0 = -t0;
159
        }
160
        if t1 < 0.0 {
161
            t1 = -t1;
162
        }
163
        if (!(t1 < tol)) {
164
            assert_eq!(a, b);
165
        }
166
        if (!(t0 < tol)) {
167
            assert_eq!(a, b);
168
        }
169
    }
170
    #[test]
171
    fn fast_log2_works() {
172
        let examples = [
173
            4u64,
174
            254,
175
            256,
176
            1428,
177
            25412509,
178
            21350891256,
179
            65536,
180
            1258912591,
181
            60968101,
182
            1,
183
            12589125190825,
184
            105912059215091,
185
            0,
186
        ];
187
        let tol = [
188
            0.00001, 0.0001, 0.0001, 0.005, 0.007, 0.008, 0.01, 0.01, 0.01, 0.000001, 0.01, 0.01,
189
            0.0001,
190
        ];
191
        for (index, example) in examples.iter().enumerate() {
192
            let fast_version = super::FastLog2(*example);
193
            if *example != 0 {
194
                // make sure we don't panic when computing...but don't care about result
195
                let baseline_version = (*example as f64).log2();
196
                approx_eq(fast_version as f64, baseline_version, tol[index]);
197
            } else {
198
                //assert_eq!(fast_version as f64, 0.0 as f64);
199
            }
200
        }
201
    }
202
}