use indexmap::IndexMap; struct Lookup { generated: Map, reference: IndexMap, keys: Vec, } struct TextLookup { generated: Map, reference: IndexMap, keys: Vec, } fn text_lookup_generated(values: &[TextLookup]) -> Result { values.first().map_or(Ok(0), |value| { GENERATED_TEXT_LOOKUP(&value.generated, &value.keys) }) } fn text_lookup_reference(values: &[TextLookup]) -> Result { let Some(value) = values.first() else { return Ok(0); }; let mut total = 0i64; for key in &value.keys { total = total .checked_add(value.reference.get(key.as_str()).copied().unwrap_or(0)) .ok_or_else(overflow)?; } Ok(total) } fn text_lookup_same_table(values: &[TextLookup]) -> Result { let Some(value) = values.first() else { return Ok(0); }; let mut total = 0i64; for key in &value.keys { total = total .checked_add(value.generated.get(key.as_str()).copied().unwrap_or(0)) .ok_or_else(overflow)?; } Ok(total) } fn text_lookup_comparisons() { let reference_first = match std::env::var("DEVER_BENCH_MAP_ORDER") .as_deref() .unwrap_or("dever-first") { "dever-first" => false, "rust-first" => true, order => panic!("unknown table construction order: {order}"), }; for count in [512, 1024, 2048, 4096] { let keys: Vec<_> = (0..count) .map(|index| format!("lookup-key-{index}")) .collect(); let (mut generated, mut reference) = if reference_first { let reference = IndexMap::with_capacity(count); (Map::with_capacity(count), reference) } else { (Map::with_capacity(count), IndexMap::with_capacity(count)) }; for key in &keys { if reference_first { reference.insert(key.clone(), 120); generated.insert(key.clone(), 120); } else { generated.insert(key.clone(), 120); reference.insert(key.clone(), 120); } } assert_eq!( GENERATED_TEXT_LOOKUP(&generated, &["missing".to_owned()]).unwrap(), 0 ); let values = [TextLookup { generated, reference, keys, }]; compare( &format!("map_text_lookup_{count}"), &values, 200, text_lookup_generated, text_lookup_reference, |value| *value as u64, ); // 同表只隔离生成层;独立 IndexMap 参照不能被这个控制组替代。 compare_named( &format!("map_text_lookup_{count}_same_table"), &values, 200, text_lookup_generated, text_lookup_same_table, |value| *value as u64, "rust_runtime", ); } } fn overflow() -> Fault { &FaultInfo { message: "integer overflow", source: "reference.dever", line: 1, column: 1, } } fn lookup_generated(values: &[Lookup]) -> Result { match values.first() { Some(value) => GENERATED_LOOKUP(&value.generated, &value.keys), None => Ok(0), } } fn lookup_reference(values: &[Lookup]) -> Result { let Some(value) = values.first() else { return Ok(0); }; let mut answer = 0i64; for key in &value.keys { answer = answer .checked_add(value.reference.get(key).copied().unwrap_or(0)) .ok_or_else(overflow)?; } Ok(answer) } fn lookup_same_table(values: &[Lookup]) -> Result { let Some(value) = values.first() else { return Ok(0); }; let mut answer = 0i64; for key in &value.keys { answer = answer .checked_add(value.generated.get(key).copied().unwrap_or(0)) .ok_or_else(overflow)?; } Ok(answer) } fn scan_generated(values: &[Lookup]) -> Result { match values.first() { Some(value) => GENERATED_SCAN(&value.generated), None => Ok(0), } } fn scan_reference(values: &[Lookup]) -> Result { let Some(value) = values.first() else { return Ok(0); }; value.reference.values().try_fold(0i64, |total, item| { total.checked_add(*item).ok_or_else(overflow) }) } fn map_generated(values: &[i64]) -> Result, Fault> { GENERATED_ENTRIES(values) } fn map_reference(values: &[i64]) -> Result, Fault> { let mut result = IndexMap::new(); for value in values { result.insert(*value, *value); } Ok(result.into_iter().collect()) } fn list_reference(values: &[i64]) -> Result, Fault> { let mut result = Vec::new(); for value in values { result.push(*value); } Ok(result) } fn buffer_reference(values: &dever_runtime::Bytes) -> Result { let mut items = Vec::new(); let mut count = 0i64; for value in values.iter() { items.push(i64::from(*value)); count = count.checked_add(1).ok_or_else(overflow)?; } Ok(BUFFER_STATE { field0: items, field1: count, }) } fn buffer_inspect_reference(values: &dever_runtime::Bytes) -> Result { let mut items = Vec::new(); let mut count = 0i64; for value in values.iter() { count = (items.len() as i64).checked_add(1).ok_or_else(overflow)?; items.push(i64::from(*value)); } Ok(BUFFER_STATE { field0: items, field1: count, }) } fn read_records_reference(values: &[SCALAR_ROW]) -> Result { let mut total = 0i64; for row in values { let projected = row .field0 .checked_add(row.field1) .ok_or_else(overflow)? .checked_add(row.field2) .ok_or_else(overflow)?; total = total.checked_add(projected).ok_or_else(overflow)?; } Ok(total) } fn main() { let values: Vec = (0..1024).collect(); let lookup = Lookup { generated: GENERATED_BUILD_MAP(&values).unwrap(), reference: values.iter().map(|value| (*value, *value)).collect(), keys: (0..1024).map(|index| (index * 17) % 1152).collect(), }; let lookups = [lookup]; let overflow_case = [Lookup { generated: GENERATED_BUILD_MAP(&[i64::MAX, 1]).unwrap(), reference: [(i64::MAX, i64::MAX), (1, 1)].into_iter().collect(), keys: vec![i64::MAX, 1], }]; assert!(scan_generated(&overflow_case).is_err()); assert!(scan_reference(&overflow_case).is_err()); assert!(lookup_generated(&overflow_case).is_err()); assert!(lookup_reference(&overflow_case).is_err()); assert_eq!( map_generated(&[3, 1, 3, 2]).unwrap(), map_reference(&[3, 1, 3, 2]).unwrap() ); println!("case,sample,implementation,elapsed_ns,checksum"); text_lookup_comparisons(); for count in [512, 1024, 2048, 4096] { let bytes = dever_runtime::Bytes::from(vec![120u8; count]); let rows: Vec<_> = bytes .iter() .map(|value| SCALAR_ROW { field0: i64::from(*value), field1: 0, field2: 0, }) .collect(); compare( &format!("list_record_read_{count}"), &rows, 1000, GENERATED_RECORD_READ, read_records_reference, |value| *value as u64, ); compare_bytes( &format!("record_update_{count}"), &bytes, 1000, GENERATED_BUFFER_BUILD, buffer_reference, |value| value.field1 as u64, ); compare_bytes( &format!("record_inspect_{count}"), &bytes, 1000, GENERATED_BUFFER_INSPECT, buffer_inspect_reference, |value| value.field1 as u64, ); } compare( "map_lookup", &lookups, 2000, lookup_generated, lookup_reference, |value| *value as u64, ); // 同一张表隔离随机哈希布局;独立 IndexMap 参照仍保留。 compare_named( "map_lookup_same_table", &lookups, 2000, lookup_generated, lookup_same_table, |value| *value as u64, "rust_runtime", ); compare( "map_scan", &lookups, 20000, scan_generated, scan_reference, |value| *value as u64, ); compare( "map_build", &values[..512], 400, map_generated, map_reference, |value| value.len() as u64, ); compare( "list_build", &values, 1000, GENERATED_BUILD_LIST, list_reference, |value| value.len() as u64, ); }