115 lines
3.3 KiB
Rust
115 lines
3.3 KiB
Rust
use std::ptr;
|
|
use std::slice;
|
|
|
|
use super::{ESCAPED, ESCAPED_LEN, ESCAPE_LUT};
|
|
use crate::utils::memcpy_16;
|
|
use crate::Buffer;
|
|
|
|
#[inline]
|
|
pub(super) unsafe fn escape(
|
|
buffer: &mut Buffer,
|
|
mut start_ptr: *const u8,
|
|
ptr: *const u8,
|
|
end_ptr: *const u8,
|
|
) {
|
|
start_ptr = proceed(buffer, start_ptr, ptr, end_ptr);
|
|
|
|
if likely!(end_ptr > start_ptr) {
|
|
let slc = slice::from_raw_parts(start_ptr, end_ptr as usize - start_ptr as usize);
|
|
buffer.push_str(std::str::from_utf8_unchecked(slc));
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub(super) unsafe fn proceed(
|
|
buffer: &mut Buffer,
|
|
mut start_ptr: *const u8,
|
|
mut ptr: *const u8,
|
|
end_ptr: *const u8,
|
|
) -> *const u8 {
|
|
while ptr < end_ptr {
|
|
debug_assert!(start_ptr <= ptr);
|
|
let idx = ESCAPE_LUT[*ptr as usize] as usize;
|
|
debug_assert!(idx <= 9);
|
|
if likely!(idx >= ESCAPED_LEN) {
|
|
ptr = ptr.add(1);
|
|
} else {
|
|
if ptr > start_ptr {
|
|
let slc =
|
|
slice::from_raw_parts(start_ptr, ptr as usize - start_ptr as usize);
|
|
buffer.push_str(std::str::from_utf8_unchecked(slc));
|
|
}
|
|
push_escaped_str(*ESCAPED.get_unchecked(idx), buffer);
|
|
start_ptr = ptr.add(1);
|
|
ptr = ptr.add(1);
|
|
}
|
|
}
|
|
|
|
debug_assert_eq!(ptr, end_ptr);
|
|
debug_assert!(start_ptr <= ptr);
|
|
start_ptr
|
|
}
|
|
|
|
pub(super) unsafe fn escape_small(feed: &str, mut buf: *mut u8) -> usize {
|
|
let mut start_ptr = feed.as_ptr();
|
|
let mut ptr = start_ptr;
|
|
let end_ptr = start_ptr.add(feed.len());
|
|
let buf_begin = buf;
|
|
|
|
while ptr < end_ptr {
|
|
debug_assert!(start_ptr <= ptr);
|
|
let idx = *ESCAPE_LUT.get_unchecked(*ptr as usize) as usize;
|
|
debug_assert!(idx <= 9);
|
|
if likely!(idx >= ESCAPED_LEN) {
|
|
ptr = ptr.add(1);
|
|
} else {
|
|
let escaped = ESCAPED.get_unchecked(idx);
|
|
if ptr > start_ptr {
|
|
let len = ptr as usize - start_ptr as usize;
|
|
|
|
memcpy_16(start_ptr, buf, len);
|
|
buf = buf.add(len);
|
|
}
|
|
memcpy_16(escaped.as_ptr(), buf, escaped.len());
|
|
buf = buf.add(escaped.len());
|
|
start_ptr = ptr.add(1);
|
|
ptr = ptr.add(1);
|
|
}
|
|
}
|
|
|
|
debug_assert_eq!(ptr, end_ptr);
|
|
debug_assert!(start_ptr <= ptr);
|
|
|
|
if likely!(end_ptr > start_ptr) {
|
|
let len = end_ptr as usize - start_ptr as usize;
|
|
memcpy_16(start_ptr, buf, len);
|
|
buf = buf.add(len);
|
|
}
|
|
|
|
buf as usize - buf_begin as usize
|
|
}
|
|
|
|
#[cfg(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))]
|
|
#[inline]
|
|
pub(super) unsafe fn push_escaped_str(value: &str, buffer: &mut Buffer) {
|
|
buffer.reserve_small(value.len());
|
|
|
|
let src = value.as_ptr();
|
|
let dst = buffer.as_mut_ptr().add(buffer.len());
|
|
|
|
// memcpy
|
|
let offset = value.len() - 4;
|
|
let t2 = ptr::read_unaligned(src.add(offset) as *const u32);
|
|
let t1 = ptr::read_unaligned(src as *const u32);
|
|
ptr::write_unaligned(dst.add(offset) as *mut u32, t2);
|
|
ptr::write_unaligned(dst as *mut u32, t1);
|
|
|
|
buffer._set_len(buffer.len() + value.len());
|
|
}
|
|
|
|
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64")))]
|
|
#[inline]
|
|
pub(super) unsafe fn push_escaped_str(value: &str, buffer: &mut Buffer) {
|
|
buffer.push_str(value);
|
|
}
|