libjpeg-turbo-rs 0.3.0

Pure Rust reimplementation of libjpeg-turbo with NEON/AVX2 SIMD acceleration
Documentation
/// Arithmetic coding probability estimation table (ITU-T T.81 Table D.2).
///
/// Each entry is packed as: (Qe_Value << 16) | (Next_Index_MPS << 8) | (Switch_MPS << 7) | Next_Index_LPS
///
/// - Qe_Value (bits 16-31): probability estimate
/// - Next_Index_MPS (bits 8-15): next state for More Probable Symbol
/// - Switch_MPS (bit 7): whether to toggle MPS/LPS on LPS path
/// - Next_Index_LPS (bits 0-6): next state for Less Probable Symbol
pub const ARITAB: [u32; 114] = [
    // Index 0-13
    (0x5a1d << 16) | (1 << 8) | (1 << 7) | 1, // 0
    ((0x2586 << 16) | (2 << 8)) | 14,         // 1
    ((0x1114 << 16) | (3 << 8)) | 16,         // 2
    ((0x080b << 16) | (4 << 8)) | 18,         // 3
    ((0x03d8 << 16) | (5 << 8)) | 20,         // 4
    ((0x01da << 16) | (6 << 8)) | 23,         // 5
    ((0x00e5 << 16) | (7 << 8)) | 25,         // 6
    ((0x006f << 16) | (8 << 8)) | 28,         // 7
    ((0x0036 << 16) | (9 << 8)) | 30,         // 8
    ((0x001a << 16) | (10 << 8)) | 33,        // 9
    ((0x000d << 16) | (11 << 8)) | 35,        // 10
    ((0x0006 << 16) | (12 << 8)) | 9,         // 11
    ((0x0003 << 16) | (13 << 8)) | 10,        // 12
    ((0x0001 << 16) | (13 << 8)) | 12,        // 13
    // Index 14-35
    (0x5a7f << 16) | (15 << 8) | (1 << 7) | 15, // 14
    ((0x3f25 << 16) | (16 << 8)) | 36,          // 15
    ((0x2cf2 << 16) | (17 << 8)) | 38,          // 16
    ((0x207c << 16) | (18 << 8)) | 39,          // 17
    ((0x17b9 << 16) | (19 << 8)) | 40,          // 18
    ((0x1182 << 16) | (20 << 8)) | 42,          // 19
    ((0x0cef << 16) | (21 << 8)) | 43,          // 20
    ((0x09a1 << 16) | (22 << 8)) | 45,          // 21
    ((0x072f << 16) | (23 << 8)) | 46,          // 22
    ((0x055c << 16) | (24 << 8)) | 48,          // 23
    ((0x0406 << 16) | (25 << 8)) | 49,          // 24
    ((0x0303 << 16) | (26 << 8)) | 51,          // 25
    ((0x0240 << 16) | (27 << 8)) | 52,          // 26
    ((0x01b1 << 16) | (28 << 8)) | 54,          // 27
    ((0x0144 << 16) | (29 << 8)) | 56,          // 28
    ((0x00f5 << 16) | (30 << 8)) | 57,          // 29
    ((0x00b7 << 16) | (31 << 8)) | 59,          // 30
    ((0x008a << 16) | (32 << 8)) | 60,          // 31
    ((0x0068 << 16) | (33 << 8)) | 62,          // 32
    ((0x004e << 16) | (34 << 8)) | 63,          // 33
    ((0x003b << 16) | (35 << 8)) | 32,          // 34
    ((0x002c << 16) | (9 << 8)) | 33,           // 35
    // Index 36-63
    (0x5ae1 << 16) | (37 << 8) | (1 << 7) | 37, // 36
    ((0x484c << 16) | (38 << 8)) | 64,          // 37
    ((0x3a0d << 16) | (39 << 8)) | 65,          // 38
    ((0x2ef1 << 16) | (40 << 8)) | 67,          // 39
    ((0x261f << 16) | (41 << 8)) | 68,          // 40
    ((0x1f33 << 16) | (42 << 8)) | 69,          // 41
    ((0x19a8 << 16) | (43 << 8)) | 70,          // 42
    ((0x1518 << 16) | (44 << 8)) | 72,          // 43
    ((0x1177 << 16) | (45 << 8)) | 73,          // 44
    ((0x0e74 << 16) | (46 << 8)) | 74,          // 45
    ((0x0bfb << 16) | (47 << 8)) | 75,          // 46
    ((0x09f8 << 16) | (48 << 8)) | 77,          // 47
    ((0x0861 << 16) | (49 << 8)) | 78,          // 48
    ((0x0706 << 16) | (50 << 8)) | 79,          // 49
    ((0x05cd << 16) | (51 << 8)) | 48,          // 50
    ((0x04de << 16) | (52 << 8)) | 50,          // 51
    ((0x040f << 16) | (53 << 8)) | 50,          // 52
    ((0x0363 << 16) | (54 << 8)) | 51,          // 53
    ((0x02d4 << 16) | (55 << 8)) | 52,          // 54
    ((0x025c << 16) | (56 << 8)) | 53,          // 55
    ((0x01f8 << 16) | (57 << 8)) | 54,          // 56
    ((0x01a4 << 16) | (58 << 8)) | 55,          // 57
    ((0x0160 << 16) | (59 << 8)) | 56,          // 58
    ((0x0125 << 16) | (60 << 8)) | 57,          // 59
    ((0x00f6 << 16) | (61 << 8)) | 58,          // 60
    ((0x00cb << 16) | (62 << 8)) | 59,          // 61
    ((0x00ab << 16) | (63 << 8)) | 61,          // 62
    ((0x008f << 16) | (32 << 8)) | 61,          // 63
    // Index 64-79
    (0x5b12 << 16) | (65 << 8) | (1 << 7) | 65, // 64
    ((0x4d04 << 16) | (66 << 8)) | 80,          // 65
    ((0x412c << 16) | (67 << 8)) | 81,          // 66
    ((0x37d8 << 16) | (68 << 8)) | 82,          // 67
    ((0x2fe8 << 16) | (69 << 8)) | 83,          // 68
    ((0x293c << 16) | (70 << 8)) | 84,          // 69
    ((0x2379 << 16) | (71 << 8)) | 86,          // 70
    ((0x1edf << 16) | (72 << 8)) | 87,          // 71
    ((0x1aa9 << 16) | (73 << 8)) | 87,          // 72
    ((0x174e << 16) | (74 << 8)) | 72,          // 73
    ((0x1424 << 16) | (75 << 8)) | 72,          // 74
    ((0x119c << 16) | (76 << 8)) | 74,          // 75
    ((0x0f6b << 16) | (77 << 8)) | 74,          // 76
    ((0x0d51 << 16) | (78 << 8)) | 75,          // 77
    ((0x0bb6 << 16) | (79 << 8)) | 77,          // 78
    ((0x0a40 << 16) | (48 << 8)) | 77,          // 79
    // Index 80-87
    (0x5832 << 16) | (81 << 8) | (1 << 7) | 80, // 80
    ((0x4d1c << 16) | (82 << 8)) | 88,          // 81
    ((0x438e << 16) | (83 << 8)) | 89,          // 82
    ((0x3bdd << 16) | (84 << 8)) | 90,          // 83
    ((0x34ee << 16) | (85 << 8)) | 91,          // 84
    ((0x2eae << 16) | (86 << 8)) | 92,          // 85
    ((0x299a << 16) | (87 << 8)) | 93,          // 86
    ((0x2516 << 16) | (71 << 8)) | 86,          // 87
    // Index 88-100
    (0x5570 << 16) | (89 << 8) | (1 << 7) | 88, // 88
    ((0x4ca9 << 16) | (90 << 8)) | 95,          // 89
    ((0x44d9 << 16) | (91 << 8)) | 96,          // 90
    ((0x3e22 << 16) | (92 << 8)) | 97,          // 91
    ((0x3824 << 16) | (93 << 8)) | 99,          // 92
    ((0x32b4 << 16) | (94 << 8)) | 99,          // 93
    ((0x2e17 << 16) | (86 << 8)) | 93,          // 94
    (0x56a8 << 16) | (96 << 8) | (1 << 7) | 95, // 95
    ((0x4f46 << 16) | (97 << 8)) | 101,         // 96
    ((0x47e5 << 16) | (98 << 8)) | 102,         // 97
    ((0x41cf << 16) | (99 << 8)) | 103,         // 98
    ((0x3c3d << 16) | (100 << 8)) | 104,        // 99
    ((0x375e << 16) | (93 << 8)) | 99,          // 100
    // Index 101-112
    ((0x5231 << 16) | (102 << 8)) | 105,          // 101
    ((0x4c0f << 16) | (103 << 8)) | 106,          // 102
    ((0x4639 << 16) | (104 << 8)) | 107,          // 103
    ((0x415e << 16) | (99 << 8)) | 103,           // 104
    (0x5627 << 16) | (106 << 8) | (1 << 7) | 105, // 105
    ((0x50e7 << 16) | (107 << 8)) | 108,          // 106
    ((0x4b85 << 16) | (103 << 8)) | 109,          // 107
    ((0x5597 << 16) | (109 << 8)) | 110,          // 108
    ((0x504f << 16) | (107 << 8)) | 111,          // 109
    (0x5a10 << 16) | (111 << 8) | (1 << 7) | 110, // 110
    ((0x5522 << 16) | (109 << 8)) | 112,          // 111
    (0x59eb << 16) | (111 << 8) | (1 << 7) | 112, // 112
    // Index 113 — fixed probability 0.5
    ((0x5a1d << 16) | (113 << 8)) | 113, // 113
];

/// DC statistics bins per table.
pub const DC_STAT_BINS: usize = 64;
/// AC statistics bins per table.
pub const AC_STAT_BINS: usize = 256;

/// Extract Qe value from ARITAB entry.
#[inline]
pub fn qe_value(entry: u32) -> u32 {
    entry >> 16
}

/// Extract Next_Index_MPS from ARITAB entry.
#[inline]
pub fn next_mps(entry: u32) -> u8 {
    ((entry >> 8) & 0xFF) as u8
}

/// Extract Next_Index_LPS (including Switch bit) from ARITAB entry.
#[inline]
pub fn next_lps_with_switch(entry: u32) -> u8 {
    (entry & 0xFF) as u8
}

/// Extract Switch_MPS flag from LPS byte.
#[inline]
pub fn switch_mps(nl: u8) -> bool {
    (nl & 0x80) != 0
}

/// Extract Next_Index_LPS (without Switch bit).
#[inline]
pub fn next_lps_index(nl: u8) -> u8 {
    nl & 0x7F
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn aritab_has_114_entries() {
        assert_eq!(ARITAB.len(), 114);
    }

    #[test]
    fn aritab_entry_0_qe() {
        // Entry 0: Qe = 0x5a1d
        assert_eq!(qe_value(ARITAB[0]), 0x5a1d);
    }

    #[test]
    fn aritab_entry_113_fixed_probability() {
        // Entry 113: fixed probability 0.5, Qe = 0x5a1d
        assert_eq!(qe_value(ARITAB[113]), 0x5a1d);
        // Next state for both MPS and LPS is 113 (self-loop)
        assert_eq!(next_mps(ARITAB[113]), 113);
        assert_eq!(next_lps_index(next_lps_with_switch(ARITAB[113])), 113);
        assert!(!switch_mps(next_lps_with_switch(ARITAB[113])));
    }

    #[test]
    fn aritab_entry_0_transition() {
        // Entry 0: MPS -> state 1, LPS -> state 1 with switch
        assert_eq!(next_mps(ARITAB[0]), 1);
        let nl = next_lps_with_switch(ARITAB[0]);
        assert_eq!(next_lps_index(nl), 1);
        assert!(switch_mps(nl));
    }
}