#[allow(unused_imports)] use sonic_rs::{JsonContainerTrait, JsonNumberTrait, JsonValueTrait, Value as SonicValue};
pub struct SimdClassifier;
impl SimdClassifier {
#[inline(always)]
pub fn classify_value_type(value: &SonicValue) -> ValueClass {
if value.is_number() {
if let Some(num) = value.as_number() {
if num.is_i64() {
ValueClass::Integer
} else if num.is_u64() {
ValueClass::UnsignedInteger
} else {
ValueClass::Float
}
} else {
ValueClass::Float
}
} else if value.is_str() {
ValueClass::String
} else if value.is_array() {
ValueClass::Array
} else if value.is_object() {
ValueClass::Object
} else if value.as_bool().is_some() {
ValueClass::Boolean
} else {
ValueClass::Null
}
}
#[inline(always)]
pub fn is_numeric_array(arr: &sonic_rs::Array) -> bool {
if arr.len() < 3 {
return false;
}
arr.iter().all(|v| v.is_number())
}
#[inline(always)]
pub fn calculate_total_string_length(arr: &sonic_rs::Array) -> usize {
let size_hint = arr.len();
if size_hint > 32 {
Self::vectorized_string_length_sum(arr)
} else {
arr.iter().filter_map(|v| v.as_str()).map(|s| s.len()).sum()
}
}
#[inline(always)]
fn vectorized_string_length_sum(arr: &sonic_rs::Array) -> usize {
const CHUNK_SIZE: usize = 16; let mut total_length = 0;
for chunk_start in (0..arr.len()).step_by(CHUNK_SIZE) {
let chunk_end = (chunk_start + CHUNK_SIZE).min(arr.len());
let mut chunk_length = 0;
for i in chunk_start..chunk_end {
if let Some(string_val) = arr.get(i).and_then(|v| v.as_str()) {
chunk_length += string_val.len();
}
}
total_length += chunk_length;
}
total_length
}
#[inline(always)]
pub fn scan_object_keys(obj: &sonic_rs::Object) -> KeyScanResult {
let mut result = KeyScanResult {
has_timestamp: false,
has_coordinates: false,
has_type_field: false,
key_count: obj.len(),
};
if obj.len() > 16 {
return Self::vectorized_key_scan(obj, result);
}
for (key, _) in obj.iter() {
match key.as_bytes() {
b"timestamp" | b"time" => result.has_timestamp = true,
b"coordinates" | b"coord" => result.has_coordinates = true,
b"type" => result.has_type_field = true,
_ => {}
}
}
result
}
#[inline(always)]
fn vectorized_key_scan(obj: &sonic_rs::Object, mut result: KeyScanResult) -> KeyScanResult {
const TARGET_KEYS: &[&[u8]] = &[b"timestamp", b"time", b"coordinates", b"coord", b"type"];
for (key, _) in obj.iter() {
let key_bytes = key.as_bytes();
for &target in TARGET_KEYS {
if key_bytes.len() == target.len() && key_bytes == target {
match target {
b"timestamp" | b"time" => result.has_timestamp = true,
b"coordinates" | b"coord" => result.has_coordinates = true,
b"type" => result.has_type_field = true,
_ => {}
}
}
}
}
result
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ValueClass {
Object,
Array,
String,
Integer,
UnsignedInteger,
Float,
Boolean,
Null,
}
#[derive(Debug, Default)]
pub struct KeyScanResult {
pub has_timestamp: bool,
pub has_coordinates: bool,
pub has_type_field: bool,
pub key_count: usize,
}
pub struct SimdNumericOps;
impl SimdNumericOps {
#[inline(always)]
pub fn fast_array_sum(arr: &sonic_rs::Array) -> Option<f64> {
let mut sum = 0.0;
let mut count = 0;
let iter = arr.iter();
let size_hint = iter.size_hint().0;
if size_hint > 64 {
return Self::vectorized_sum(arr);
}
for value in iter {
let num = value.as_number()?;
if let Some(f) = num.as_f64() {
sum += f;
count += 1;
}
}
if count > 0 { Some(sum) } else { None }
}
#[inline(always)]
fn vectorized_sum(arr: &sonic_rs::Array) -> Option<f64> {
let mut sum = 0.0;
let mut count = 0;
let chunk_size = 32; let mut chunks = arr.iter().peekable();
while chunks.peek().is_some() {
let mut chunk_sum = 0.0;
let mut chunk_count = 0;
for _ in 0..chunk_size {
if let Some(value) = chunks.next() {
let num = value.as_number()?;
if let Some(f) = num.as_f64() {
chunk_sum += f;
chunk_count += 1;
}
} else {
break;
}
}
sum += chunk_sum;
count += chunk_count;
}
if count > 0 { Some(sum) } else { None }
}
#[inline(always)]
pub fn array_stats(arr: &sonic_rs::Array) -> Option<ArrayStats> {
let mut stats = ArrayStats {
min: f64::INFINITY,
max: f64::NEG_INFINITY,
sum: 0.0,
count: 0,
};
for value in arr.iter() {
let num = value.as_number()?;
if let Some(f) = num.as_f64() {
stats.min = stats.min.min(f);
stats.max = stats.max.max(f);
stats.sum += f;
stats.count += 1;
}
}
if stats.count > 0 { Some(stats) } else { None }
}
}
#[derive(Debug, Clone)]
pub struct ArrayStats {
pub min: f64,
pub max: f64,
pub sum: f64,
pub count: usize,
}
impl ArrayStats {
pub fn mean(&self) -> f64 {
if self.count > 0 {
self.sum / self.count as f64
} else {
0.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use sonic_rs;
#[test]
fn test_simd_classifier() {
let json =
r#"{"number": 42, "text": "hello", "array": [1,2,3], "flag": true, "empty": null}"#;
let value: SonicValue = sonic_rs::from_str(json).unwrap();
if let Some(obj) = value.as_object() {
let scan_result = SimdClassifier::scan_object_keys(obj);
assert_eq!(scan_result.key_count, 5);
}
}
#[test]
fn test_numeric_array_detection() {
let json = "[1, 2, 3, 4, 5]";
let value: SonicValue = sonic_rs::from_str(json).unwrap();
if let Some(arr) = value.as_array() {
assert!(SimdClassifier::is_numeric_array(arr));
}
}
#[test]
fn test_array_stats() {
let json = "[1.5, 2.0, 3.5, 4.0]";
let value: SonicValue = sonic_rs::from_str(json).unwrap();
if let Some(arr) = value.as_array() {
let stats = SimdNumericOps::array_stats(arr).unwrap();
assert_eq!(stats.count, 4);
assert_eq!(stats.sum, 11.0);
assert_eq!(stats.mean(), 2.75);
}
}
}