pub trait SplitBytes {
fn split_bytes<'a>(&'a self, delimiter: &[u8]) -> Vec<&'a [u8]>;
fn split_header_body(&self) -> (Vec<u8>, Vec<u8>);
}
pub fn find_header_end(data: &[u8]) -> Option<usize> {
#[cfg(feature = "simd")]
{
return simd::find_header_end_simd(data);
}
#[cfg(not(feature = "simd"))]
{
data.windows(4).position(|w| w == b"\r\n\r\n")
}
}
#[cfg(feature = "simd")]
mod simd {
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse2")]
pub unsafe fn find_header_end_sse2(data: &[u8]) -> Option<usize> {
if data.len() < 16 {
return find_header_end_scalar(data);
}
let pattern = [b'\r', b'\n', b'\r', b'\n'];
let _pattern_vec = _mm_set_epi8(
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
pattern[3] as i8,
pattern[2] as i8,
pattern[1] as i8,
pattern[0] as i8,
);
let mut i = 0;
let end = data.len() - 15;
while i < end {
let chunk = _mm_loadu_si128(data.as_ptr().add(i) as *const __m128i);
let cr_cmp = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\r' as i8));
let cr_mask = _mm_movemask_epi8(cr_cmp) as u16;
if cr_mask != 0 {
for bit_pos in 0..16 {
if (cr_mask & (1 << bit_pos)) != 0 {
let pos = i + bit_pos;
if pos + 4 <= data.len() && data[pos..pos + 4] == pattern {
return Some(pos);
}
}
}
}
i += 16;
}
find_header_end_scalar(&data[i..]).map(|pos| pos + i)
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
pub unsafe fn find_header_end_avx2(data: &[u8]) -> Option<usize> {
if data.len() < 32 {
return find_header_end_sse2(data);
}
let pattern = [b'\r', b'\n', b'\r', b'\n'];
let mut i = 0;
let end = data.len() - 31;
while i < end {
let chunk = _mm256_loadu_si256(data.as_ptr().add(i) as *const __m256i);
let cr_cmp = _mm256_cmpeq_epi8(chunk, _mm256_set1_epi8(b'\r' as i8));
let cr_mask = _mm256_movemask_epi8(cr_cmp) as u32;
if cr_mask != 0 {
for bit_pos in 0..32 {
if (cr_mask & (1 << bit_pos)) != 0 {
let pos = i + bit_pos;
if pos + 4 <= data.len() && data[pos..pos + 4] == pattern {
return Some(pos);
}
}
}
}
i += 32;
}
find_header_end_sse2(&data[i..]).map(|pos| pos + i)
}
fn find_header_end_scalar(data: &[u8]) -> Option<usize> {
if data.len() < 4 {
return None;
}
data.windows(4).position(|w| w == b"\r\n\r\n")
}
pub fn find_header_end_simd(data: &[u8]) -> Option<usize> {
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx2") {
return unsafe { find_header_end_avx2(data) };
} else if is_x86_feature_detected!("sse2") {
return unsafe { find_header_end_sse2(data) };
}
}
find_header_end_scalar(data)
}
}
impl SplitBytes for [u8] {
fn split_bytes<'a>(&'a self, delimiter: &[u8]) -> Vec<&'a [u8]> {
let mut result = Vec::new();
if delimiter.is_empty() || self.len() < delimiter.len() {
return result;
}
let mut start = 0;
let mut i = 0;
let end = self.len() - delimiter.len();
while i <= end {
if &self[i..i + delimiter.len()] == delimiter {
let part = &self[start..i];
if !part.is_empty() {
result.push(part);
}
i += delimiter.len();
start = i;
} else {
i += 1;
}
}
let last = &self[start..];
if !last.is_empty() && last != b"--\r\n" {
result.push(last);
}
result
}
fn split_header_body(&self) -> (Vec<u8>, Vec<u8>) {
if let Some(pos) = find_header_end(self) {
(self[..pos].to_vec(), self[pos + 4..].to_vec())
} else {
(self.to_vec(), Vec::new())
}
}
}
#[cfg(feature = "arena")]
pub trait SplitBytesArena {
fn split_bytes_arena(&self, delimiter: &[u8]) -> Vec<&[u8]>;
fn split_header_body_arena(&self) -> (&[u8], &[u8]);
}
#[cfg(feature = "arena")]
impl SplitBytesArena for &[u8] {
fn split_bytes_arena(&self, delimiter: &[u8]) -> Vec<&[u8]> {
let mut result = Vec::new();
let mut start = 0;
for i in 0..self.len() {
if i + delimiter.len() <= self.len() && &self[i..i + delimiter.len()] == delimiter {
if start < i {
let slice = &self[start..i];
if !slice.is_empty() {
result.push(slice);
}
}
start = i + delimiter.len();
}
}
if start < self.len() {
let last_slice = &self[start..];
if last_slice != [45, 45, 13, 10] && !last_slice.is_empty() {
result.push(last_slice);
}
}
result
}
fn split_header_body_arena(&self) -> (&[u8], &[u8]) {
#[cfg(feature = "simd")]
{
if let Some(pos) = simd::find_header_end_simd(self) {
let header = &self[..pos];
let body = &self[pos + 4..];
return (header, body);
}
}
#[cfg(not(feature = "simd"))]
{
let delimiter = b"\r\n\r\n";
for i in 0..self.len() {
if i + delimiter.len() <= self.len() && &self[i..i + delimiter.len()] == delimiter {
let header = &self[..i];
let body = &self[i + delimiter.len()..];
return (header, body);
}
}
}
(self, &[])
}
}