153 lines
4.3 KiB
Rust
153 lines
4.3 KiB
Rust
fn fault() -> Fault {
|
|
&FaultInfo {
|
|
message: "integer arithmetic fault",
|
|
source: "reference.dever",
|
|
line: 1,
|
|
column: 1,
|
|
}
|
|
}
|
|
|
|
fn map_reference(values: &[i64]) -> Result<Vec<i64>, Fault> {
|
|
let mut output = Vec::with_capacity(values.len());
|
|
for value in values {
|
|
output.push(value.checked_add(1).ok_or_else(fault)?);
|
|
}
|
|
Ok(output)
|
|
}
|
|
|
|
fn total_reference(values: &[i64]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
let adjusted = value.checked_add(1).ok_or_else(fault)?;
|
|
total = total.checked_add(adjusted).ok_or_else(fault)?;
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
// 与跨包调用一致,投影失败和累计失败必须能定位到不同来源。
|
|
fn total_reference_distinct_faults(values: &[i64]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
let adjusted = value.checked_add(1).ok_or(&FaultInfo {
|
|
message: "integer arithmetic fault",
|
|
source: "reference/value.rs",
|
|
line: 1,
|
|
column: 1,
|
|
})?;
|
|
total = total.checked_add(adjusted).ok_or(&FaultInfo {
|
|
message: "integer arithmetic fault",
|
|
source: "reference/batch.rs",
|
|
line: 2,
|
|
column: 1,
|
|
})?;
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
fn dispatch_generated(values: &[i64]) -> Result<i64, Fault> {
|
|
GENERATED_DISPATCH(values.first().copied().unwrap_or(0))
|
|
}
|
|
|
|
fn dispatch_reference(values: &[i64]) -> Result<i64, Fault> {
|
|
values
|
|
.first()
|
|
.copied()
|
|
.unwrap_or(0)
|
|
.checked_mul(2)
|
|
.ok_or_else(fault)
|
|
}
|
|
|
|
fn dispatch_total_reference(values: &[i64]) -> Result<i64, Fault> {
|
|
let mut total = 0i64;
|
|
for value in values {
|
|
let doubled = value.checked_mul(2).ok_or_else(fault)?;
|
|
total = total.checked_add(doubled).ok_or(&FaultInfo {
|
|
message: "integer overflow",
|
|
source: "reference/dispatch.rs",
|
|
line: 2,
|
|
column: 1,
|
|
})?;
|
|
}
|
|
Ok(total)
|
|
}
|
|
|
|
fn main() {
|
|
let values: Vec<i64> = (0..1024).map(|value| value % 17).collect();
|
|
for values in [&[i64::MAX][..], &[i64::MAX - 1, 1][..], &[i64::MIN][..]] {
|
|
assert_eq!(
|
|
GENERATED_MAP(values).map_err(|_| ()),
|
|
map_reference(values).map_err(|_| ())
|
|
);
|
|
assert_eq!(
|
|
GENERATED_TOTAL(values).map_err(|_| ()),
|
|
total_reference(values).map_err(|_| ())
|
|
);
|
|
assert_eq!(
|
|
GENERATED_TOTAL(values).map_err(|fault| fault.message),
|
|
total_reference_distinct_faults(values).map_err(|fault| fault.message)
|
|
);
|
|
assert_eq!(
|
|
dispatch_generated(values).map_err(|_| ()),
|
|
dispatch_reference(values).map_err(|_| ())
|
|
);
|
|
}
|
|
let projection = GENERATED_TOTAL(&[i64::MAX]).unwrap_err();
|
|
let sum = GENERATED_TOTAL(&[i64::MAX - 1, 1]).unwrap_err();
|
|
assert_ne!(projection.source, sum.source);
|
|
assert_ne!(
|
|
total_reference_distinct_faults(&[i64::MAX])
|
|
.unwrap_err()
|
|
.source,
|
|
total_reference_distinct_faults(&[i64::MAX - 1, 1])
|
|
.unwrap_err()
|
|
.source
|
|
);
|
|
for values in [&[i64::MAX][..], &[i64::MAX / 2, 1][..], &[i64::MIN][..]] {
|
|
assert_eq!(
|
|
GENERATED_DISPATCH_TOTAL(values).map_err(|fault| fault.message),
|
|
dispatch_total_reference(values).map_err(|fault| fault.message)
|
|
);
|
|
}
|
|
println!("case,sample,implementation,elapsed_ns,checksum");
|
|
compare(
|
|
"package_map",
|
|
&values,
|
|
20000,
|
|
GENERATED_MAP,
|
|
map_reference,
|
|
|value| value.iter().map(|value| *value as u64).sum(),
|
|
);
|
|
compare(
|
|
"package_total",
|
|
&values,
|
|
20000,
|
|
GENERATED_TOTAL,
|
|
total_reference,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"package_total_distinct_faults",
|
|
&values,
|
|
20000,
|
|
GENERATED_TOTAL,
|
|
total_reference_distinct_faults,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"package_dispatch",
|
|
&[21],
|
|
3000000,
|
|
dispatch_generated,
|
|
dispatch_reference,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"package_dispatch_batch",
|
|
&values,
|
|
20000,
|
|
GENERATED_DISPATCH_TOTAL,
|
|
dispatch_total_reference,
|
|
|value| *value as u64,
|
|
);
|
|
}
|