Coverage Report

Created: 2026-04-12 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/httparse/src/simd/sse42.rs
Line
Count
Source
1
use crate::iter::Bytes;
2
3
#[target_feature(enable = "sse4.2")]
4
0
pub unsafe fn match_uri_vectored(bytes: &mut Bytes) {
5
0
    while bytes.as_ref().len() >= 16 {
6
0
        let advance = match_url_char_16_sse(bytes.as_ref());
7
8
0
        bytes.advance(advance);
9
10
0
        if advance != 16 {
11
0
            return;
12
0
        }
13
    }
14
0
    super::swar::match_uri_vectored(bytes);
15
0
}
16
17
#[inline(always)]
18
#[allow(non_snake_case)]
19
0
unsafe fn match_url_char_16_sse(buf: &[u8]) -> usize {
20
0
    debug_assert!(buf.len() >= 16);
21
22
    #[cfg(target_arch = "x86")]
23
    use core::arch::x86::*;
24
    #[cfg(target_arch = "x86_64")]
25
    use core::arch::x86_64::*;
26
27
0
    let ptr = buf.as_ptr();
28
29
    // %x21-%x7e %x80-%xff
30
0
    let DEL: __m128i = _mm_set1_epi8(0x7f);
31
0
    let LOW: __m128i = _mm_set1_epi8(0x21);
32
33
0
    let dat = _mm_lddqu_si128(ptr as *const _);
34
    // unsigned comparison dat >= LOW
35
0
    let low = _mm_cmpeq_epi8(_mm_max_epu8(dat, LOW), dat);
36
0
    let del = _mm_cmpeq_epi8(dat, DEL);
37
0
    let bit = _mm_andnot_si128(del, low);
38
0
    let res = _mm_movemask_epi8(bit) as u16;
39
40
0
    res.trailing_ones() as usize
41
0
}
42
43
#[target_feature(enable = "sse4.2")]
44
0
pub unsafe fn match_header_value_vectored(bytes: &mut Bytes) {
45
0
    while bytes.as_ref().len() >= 16 {
46
0
        let advance = match_header_value_char_16_sse(bytes.as_ref());
47
0
        bytes.advance(advance);
48
49
0
       if advance != 16 {
50
0
            return;
51
0
       }
52
    }
53
0
    super::swar::match_header_value_vectored(bytes);
54
0
}
55
56
#[inline(always)]
57
#[allow(non_snake_case)]
58
0
unsafe fn match_header_value_char_16_sse(buf: &[u8]) -> usize {
59
0
    debug_assert!(buf.len() >= 16);
60
61
    #[cfg(target_arch = "x86")]
62
    use core::arch::x86::*;
63
    #[cfg(target_arch = "x86_64")]
64
    use core::arch::x86_64::*;
65
66
0
    let ptr = buf.as_ptr();
67
68
    // %x09 %x20-%x7e %x80-%xff
69
0
    let TAB: __m128i = _mm_set1_epi8(0x09);
70
0
    let DEL: __m128i = _mm_set1_epi8(0x7f);
71
0
    let LOW: __m128i = _mm_set1_epi8(0x20);
72
73
0
    let dat = _mm_lddqu_si128(ptr as *const _);
74
    // unsigned comparison dat >= LOW
75
0
    let low = _mm_cmpeq_epi8(_mm_max_epu8(dat, LOW), dat);
76
0
    let tab = _mm_cmpeq_epi8(dat, TAB);
77
0
    let del = _mm_cmpeq_epi8(dat, DEL);
78
0
    let bit = _mm_andnot_si128(del, _mm_or_si128(low, tab));
79
0
    let res = _mm_movemask_epi8(bit) as u16;
80
81
0
    res.trailing_ones() as usize
82
0
}
83
84
#[test]
85
fn sse_code_matches_uri_chars_table() {
86
    if !is_x86_feature_detected!("sse4.2") {
87
        return;
88
    }
89
90
    #[allow(clippy::undocumented_unsafe_blocks)]
91
    unsafe {
92
        assert!(byte_is_allowed(b'_', match_uri_vectored));
93
94
        for (b, allowed) in crate::URI_MAP.iter().cloned().enumerate() {
95
            assert_eq!(
96
                byte_is_allowed(b as u8, match_uri_vectored), allowed,
97
                "byte_is_allowed({:?}) should be {:?}", b, allowed,
98
            );
99
        }
100
    }
101
}
102
103
#[test]
104
fn sse_code_matches_header_value_chars_table() {
105
    if !is_x86_feature_detected!("sse4.2") {
106
        return;
107
    }
108
109
    #[allow(clippy::undocumented_unsafe_blocks)]
110
    unsafe {
111
        assert!(byte_is_allowed(b'_', match_header_value_vectored));
112
113
        for (b, allowed) in crate::HEADER_VALUE_MAP.iter().cloned().enumerate() {
114
            assert_eq!(
115
                byte_is_allowed(b as u8, match_header_value_vectored), allowed,
116
                "byte_is_allowed({:?}) should be {:?}", b, allowed,
117
            );
118
        }
119
    }
120
}
121
122
#[allow(clippy::missing_safety_doc)]
123
#[cfg(test)]
124
unsafe fn byte_is_allowed(byte: u8, f: unsafe fn(bytes: &mut Bytes<'_>)) -> bool {
125
    let slice = [
126
        b'_', b'_', b'_', b'_',
127
        b'_', b'_', b'_', b'_',
128
        b'_', b'_', byte, b'_',
129
        b'_', b'_', b'_', b'_',
130
    ];
131
    let mut bytes = Bytes::new(&slice);
132
133
    f(&mut bytes);
134
135
    match bytes.pos() {
136
        16 => true,
137
        10 => false,
138
        _ => unreachable!(),
139
    }
140
}