#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
use smallvec::SmallVec;
#[inline]
fn is_escaped_quote(data: &[u8], quote_pos: usize) -> bool {
let mut backslash_count = 0;
let mut pos = quote_pos;
while pos > 0 && data[pos - 1] == b'\\' {
backslash_count += 1;
pos -= 1;
}
backslash_count % 2 == 1
}
pub struct Stage1Output {
pub structural_indices: Vec<u32>,
pub bracket_pairs: Vec<(u32, u32)>,
}
impl Stage1Output {
pub fn new() -> Self {
Self {
structural_indices: Vec::new(),
bracket_pairs: Vec::new(),
}
}
fn clear(&mut self) {
self.structural_indices.clear();
self.bracket_pairs.clear();
}
}
impl Default for Stage1Output {
fn default() -> Self {
Self::new()
}
}
#[inline]
pub fn find_structural_indices(data: &[u8], output: &mut Stage1Output) {
output.clear();
const SMALL_INPUT_THRESHOLD: usize = 64;
if data.len() < SMALL_INPUT_THRESHOLD {
find_structural_indices_scalar(data, output);
return;
}
#[cfg(target_arch = "x86_64")]
{
if is_x86_feature_detected!("avx2") {
unsafe { find_structural_indices_avx2(data, output) }
} else if is_x86_feature_detected!("sse4.2") {
unsafe { find_structural_indices_sse42(data, output) }
} else {
find_structural_indices_scalar(data, output)
}
}
#[cfg(not(target_arch = "x86_64"))]
{
find_structural_indices_scalar(data, output)
}
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
unsafe fn find_structural_indices_avx2(data: &[u8], output: &mut Stage1Output) {
const CHUNK_SIZE: usize = 64;
let mut pos = 0;
while pos + CHUNK_SIZE <= data.len() {
unsafe {
let ptr = data.as_ptr().add(pos);
if pos + CHUNK_SIZE * 2 <= data.len() {
_mm_prefetch(
data.as_ptr().add(pos + CHUNK_SIZE * 2) as *const i8,
_MM_HINT_T0,
);
}
let v0 = _mm256_loadu_si256(ptr as *const __m256i);
let v1 = _mm256_loadu_si256(ptr.add(32) as *const __m256i);
let structural_mask0 = classify_structural_avx2(v0);
let structural_mask1 = classify_structural_avx2(v1);
let bits0 = _mm256_movemask_epi8(structural_mask0) as u32;
let bits1 = _mm256_movemask_epi8(structural_mask1) as u32;
let combined_bits = (bits1 as u64) << 32 | bits0 as u64;
extract_indices(combined_bits, pos as u32, &mut output.structural_indices);
pos += CHUNK_SIZE;
}
}
if pos + 32 <= data.len() {
unsafe {
let ptr = data.as_ptr().add(pos);
let v0 = _mm_loadu_si128(ptr as *const __m128i);
let v1 = _mm_loadu_si128(ptr.add(16) as *const __m128i);
let mask0 = classify_structural_sse42(v0);
let mask1 = classify_structural_sse42(v1);
let bits =
((_mm_movemask_epi8(mask1) as u32) << 16) | (_mm_movemask_epi8(mask0) as u32);
extract_indices(bits as u64, pos as u32, &mut output.structural_indices);
pos += 32;
}
}
while pos < data.len() {
if crate::charclass::is_structural(data[pos]) {
output.structural_indices.push(pos as u32);
}
pos += 1;
}
pair_brackets(data, &output.structural_indices, &mut output.bracket_pairs);
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "avx2")]
unsafe fn classify_structural_avx2(chunk: __m256i) -> __m256i {
let low_nibble_mask = _mm256_setr_epi8(
0, 0, -96, 0, 0, 0, 0, 0, 0, 0, 64, 24, 32, 24, 0, 0, 0, 0, -96, 0, 0, 0, 0, 0, 0, 0, 64, 24, 32, 24, 0, 0, );
let high_nibble_mask = _mm256_setr_epi8(
0, 0, -96, 64, 0, 16, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -96, 64, 0, 16, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, );
let low_mask = _mm256_set1_epi8(0x0F);
let low_nibbles = _mm256_and_si256(chunk, low_mask);
let high_nibbles = _mm256_and_si256(_mm256_srli_epi32(chunk, 4), low_mask);
let low_result = _mm256_shuffle_epi8(low_nibble_mask, low_nibbles);
let high_result = _mm256_shuffle_epi8(high_nibble_mask, high_nibbles);
let result = _mm256_and_si256(low_result, high_result);
let zeros = _mm256_setzero_si256();
let eq_zero = _mm256_cmpeq_epi8(result, zeros); _mm256_xor_si256(eq_zero, _mm256_set1_epi8(-1)) }
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse4.2")]
unsafe fn find_structural_indices_sse42(data: &[u8], output: &mut Stage1Output) {
const CHUNK_SIZE: usize = 32;
let mut pos = 0;
while pos + CHUNK_SIZE <= data.len() {
unsafe {
let ptr = data.as_ptr().add(pos);
if pos + CHUNK_SIZE * 2 <= data.len() {
_mm_prefetch(
data.as_ptr().add(pos + CHUNK_SIZE * 2) as *const i8,
_MM_HINT_T0,
);
}
let v0 = _mm_loadu_si128(ptr as *const __m128i);
let v1 = _mm_loadu_si128(ptr.add(16) as *const __m128i);
let structural_mask0 = classify_structural_sse42(v0);
let structural_mask1 = classify_structural_sse42(v1);
let bits0 = _mm_movemask_epi8(structural_mask0) as u16;
let bits1 = _mm_movemask_epi8(structural_mask1) as u16;
let combined_bits = (bits1 as u32) << 16 | bits0 as u32;
extract_indices(
combined_bits as u64,
pos as u32,
&mut output.structural_indices,
);
pos += CHUNK_SIZE;
}
}
if pos + 16 <= data.len() {
unsafe {
let ptr = data.as_ptr().add(pos);
let v0 = _mm_loadu_si128(ptr as *const __m128i);
let mask0 = classify_structural_sse42(v0);
let bits = _mm_movemask_epi8(mask0) as u16;
extract_indices(bits as u64, pos as u32, &mut output.structural_indices);
pos += 16;
}
}
while pos < data.len() {
if crate::charclass::is_structural(data[pos]) {
output.structural_indices.push(pos as u32);
}
pos += 1;
}
pair_brackets(data, &output.structural_indices, &mut output.bracket_pairs);
}
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse4.2")]
unsafe fn classify_structural_sse42(chunk: __m128i) -> __m128i {
let low_nibble_mask = _mm_setr_epi8(0, 0, -96, 0, 0, 0, 0, 0, 0, 0, 64, 24, 32, 24, 0, 0);
let high_nibble_mask = _mm_setr_epi8(0, 0, -96, 64, 0, 16, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0);
let low_mask = _mm_set1_epi8(0x0F);
let low_nibbles = _mm_and_si128(chunk, low_mask);
let high_nibbles = _mm_and_si128(_mm_srli_epi32(chunk, 4), low_mask);
let low_result = _mm_shuffle_epi8(low_nibble_mask, low_nibbles);
let high_result = _mm_shuffle_epi8(high_nibble_mask, high_nibbles);
let result = _mm_and_si128(low_result, high_result);
let zeros = _mm_setzero_si128();
let eq_zero = _mm_cmpeq_epi8(result, zeros);
_mm_xor_si128(eq_zero, _mm_set1_epi8(-1))
}
#[inline]
fn extract_indices(mut bitmask: u64, base_pos: u32, indices: &mut Vec<u32>) {
while bitmask != 0 {
let offset = bitmask.trailing_zeros();
indices.push(base_pos + offset);
bitmask &= bitmask - 1; }
}
fn find_structural_indices_scalar(data: &[u8], output: &mut Stage1Output) {
for (pos, byte) in data.iter().enumerate() {
if crate::charclass::is_structural(*byte) {
output.structural_indices.push(pos as u32);
}
}
pair_brackets(data, &output.structural_indices, &mut output.bracket_pairs);
}
fn pair_brackets(data: &[u8], indices: &[u32], output: &mut Vec<(u32, u32)>) {
let mut brace_stack: SmallVec<[u32; 16]> = SmallVec::new(); let mut bracket_stack: SmallVec<[u32; 16]> = SmallVec::new();
let mut in_string = false;
for &idx in indices {
let byte = data[idx as usize];
if byte == b'"' {
if !is_escaped_quote(data, idx as usize) {
in_string = !in_string; }
}
if in_string && (byte == b'{' || byte == b'}' || byte == b'[' || byte == b']') {
continue;
}
match byte {
b'{' => brace_stack.push(idx),
b'}' => {
if let Some(open_pos) = brace_stack.pop() {
output.push((open_pos, idx));
}
}
b'[' => bracket_stack.push(idx),
b']' => {
if let Some(open_pos) = bracket_stack.pop() {
output.push((open_pos, idx));
}
}
_ => {} }
}
output.sort_unstable_by_key(|(open, _close)| *open);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_find_structural_simple_object() {
let json = br#"{"key":"value"}"#;
let mut output = Stage1Output::new();
find_structural_indices(json, &mut output);
assert_eq!(output.structural_indices.len(), 7);
assert_eq!(output.structural_indices[0], 0); assert_eq!(output.structural_indices[1], 1); assert_eq!(output.structural_indices[2], 5); assert_eq!(output.structural_indices[3], 6); assert_eq!(output.structural_indices[4], 7); assert_eq!(output.structural_indices[5], 13); assert_eq!(output.structural_indices[6], 14); }
#[test]
fn test_find_structural_array() {
let json = br#"[1,2,3]"#;
let mut output = Stage1Output::new();
find_structural_indices(json, &mut output);
assert_eq!(output.structural_indices.len(), 4);
assert_eq!(output.structural_indices[0], 0); assert_eq!(output.structural_indices[1], 2); assert_eq!(output.structural_indices[2], 4); assert_eq!(output.structural_indices[3], 6); }
#[test]
fn test_find_structural_nested() {
let json = br#"{"a":[1,2]}"#;
let mut output = Stage1Output::new();
find_structural_indices(json, &mut output);
assert_eq!(output.structural_indices.len(), 8);
}
#[test]
fn test_scalar_matches_simd() {
let json = br#"{"test":[1,2,3],"nested":{"key":"value"}}"#;
let mut scalar_output = Stage1Output::new();
find_structural_indices_scalar(json, &mut scalar_output);
let mut simd_output = Stage1Output::new();
find_structural_indices(json, &mut simd_output);
assert_eq!(
scalar_output.structural_indices,
simd_output.structural_indices
);
}
#[test]
fn test_large_document() {
let mut json = String::from("[");
for i in 0..1000 {
if i > 0 {
json.push(',');
}
json.push_str(&format!(r#"{{"id":{}}}"#, i));
}
json.push(']');
let mut output = Stage1Output::new();
find_structural_indices(json.as_bytes(), &mut output);
assert!(output.structural_indices.len() > 1000);
}
#[test]
fn test_shufti_each_structural_char() {
let test_cases = vec![
(b'{', "left brace"),
(b'}', "right brace"),
(b'[', "left bracket"),
(b']', "right bracket"),
(b':', "colon"),
(b',', "comma"),
(b'"', "quote"),
];
for (ch, name) in test_cases {
let data = vec![ch];
let mut output = Stage1Output::new();
find_structural_indices(&data, &mut output);
assert_eq!(
output.structural_indices.len(),
1,
"{} (0x{:02X}) should be detected as structural",
name,
ch
);
assert_eq!(
output.structural_indices[0], 0,
"{} should be at position 0",
name
);
}
}
#[test]
fn test_extract_indices_known_bitmasks() {
let mut indices = Vec::new();
extract_indices(0b1, 0, &mut indices);
assert_eq!(indices, vec![0]);
indices.clear();
extract_indices(0b100000, 10, &mut indices);
assert_eq!(indices, vec![15]);
indices.clear();
extract_indices(0b10001001, 0, &mut indices);
assert_eq!(indices, vec![0, 3, 7]);
indices.clear();
extract_indices(0b1_00000000_00000000_00000000_00000000, 0, &mut indices);
assert_eq!(indices, vec![32]);
}
#[test]
fn test_single_chunk_exactly_64_bytes() {
let json = br#"{"k0":0}{"k1":1}{"k2":2}{"k3":3}{"k4":4}{"k5":5}{"k6":6}{"k7":7}"#;
assert_eq!(json.len(), 64, "Test JSON must be exactly 64 bytes");
let mut output = Stage1Output::new();
find_structural_indices(json, &mut output);
let expected_count = json
.iter()
.filter(|&&b| {
b == b'{'
|| b == b'}'
|| b == b'"'
|| b == b':'
|| b == b','
|| b == b'['
|| b == b']'
})
.count();
println!(
"Single chunk (64 bytes): Found {} structural chars, expected {}",
output.structural_indices.len(),
expected_count
);
assert_eq!(
output.structural_indices.len(),
expected_count,
"Single 64-byte chunk should find all structural characters"
);
}
#[test]
fn test_two_chunks_exactly_128_bytes() {
let json = br#"{"k0":0}{"k1":1}{"k2":2}{"k3":3}{"k4":4}{"k5":5}{"k6":6}{"k7":7}{"k100":100}{"k101":101}{"k102":102}{"k103":103}{"k104":104} "#;
assert_eq!(json.len(), 128, "Test JSON must be exactly 128 bytes");
let mut output = Stage1Output::new();
find_structural_indices(json, &mut output);
let expected_count = json
.iter()
.filter(|&&b| {
b == b'{'
|| b == b'}'
|| b == b'"'
|| b == b':'
|| b == b','
|| b == b'['
|| b == b']'
})
.count();
println!(
"Two chunks (128 bytes): Found {} structural chars, expected {}",
output.structural_indices.len(),
expected_count
);
assert_eq!(
output.structural_indices.len(),
expected_count,
"Two 64-byte chunks should find all structural characters"
);
}
#[test]
fn test_progressive_sizes() {
let sizes = vec![7, 32, 64, 96, 128, 160, 192, 256];
for size in sizes {
let mut json = String::from("[");
let mut current_len = 1;
let mut item_num = 0;
while current_len < size - 10 {
if item_num > 0 {
json.push(',');
current_len += 1;
}
json.push_str(r#"{"x":1}"#);
current_len += 7;
item_num += 1;
}
json.push(']');
let json_bytes = json.as_bytes();
let mut output = Stage1Output::new();
find_structural_indices(json_bytes, &mut output);
let expected_count = json_bytes
.iter()
.filter(|&&b| {
b == b'{'
|| b == b'}'
|| b == b'['
|| b == b']'
|| b == b'"'
|| b == b':'
|| b == b','
})
.count();
println!(
"Size {}: Found {} structural chars, expected {}",
json_bytes.len(),
output.structural_indices.len(),
expected_count
);
assert_eq!(
output.structural_indices.len(),
expected_count,
"Size {} should find all {} structural characters",
json_bytes.len(),
expected_count
);
}
}
#[test]
fn test_chunk_boundary_structural_chars() {
let mut json = vec![b' '; 192];
json[0] = b'{'; json[32] = b'"'; json[63] = b':'; json[64] = b'['; json[96] = b','; json[127] = b']'; json[128] = b'{'; json[160] = b'"'; json[191] = b'}';
let mut output = Stage1Output::new();
find_structural_indices(&json, &mut output);
let expected_positions = vec![0, 32, 63, 64, 96, 127, 128, 160, 191];
println!(
"Chunk boundary test: Found {} indices",
output.structural_indices.len()
);
println!("Expected positions: {:?}", expected_positions);
println!("Found positions: {:?}", output.structural_indices);
assert_eq!(
output.structural_indices.len(),
expected_positions.len(),
"Should find exactly {} structural characters at known positions",
expected_positions.len()
);
for (i, &expected_pos) in expected_positions.iter().enumerate() {
assert_eq!(
output.structural_indices[i], expected_pos,
"Structural char {} should be at position {}",
i, expected_pos
);
}
}
}