245 lines
6.5 KiB
Rust
245 lines
6.5 KiB
Rust
fn fault() -> Fault {
|
|
&FaultInfo {
|
|
message: "integer arithmetic fault",
|
|
source: "reference.dever",
|
|
line: 1,
|
|
column: 1,
|
|
}
|
|
}
|
|
|
|
fn integer_reference(values: &[i64]) -> Result<i64, Fault> {
|
|
values
|
|
.first()
|
|
.copied()
|
|
.unwrap_or(0)
|
|
.checked_add(1)
|
|
.ok_or_else(fault)
|
|
}
|
|
|
|
fn integer_generated(values: &[i64]) -> Result<i64, Fault> {
|
|
GENERATED_INTEGER(values.first().copied().unwrap_or(0))
|
|
}
|
|
|
|
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 fold_reference(values: &[i64]) -> Result<i64, Fault> {
|
|
let mut state = 0i64;
|
|
for value in values {
|
|
state = state.checked_add(*value).ok_or_else(fault)?;
|
|
}
|
|
Ok(state)
|
|
}
|
|
|
|
fn text_reference(values: &[String]) -> Result<String, Fault> {
|
|
let value = values.first().map(String::as_str).unwrap_or("");
|
|
let mut result = String::with_capacity(value.len() + "新".len());
|
|
result.push_str(value);
|
|
result.push_str("新");
|
|
Ok(result)
|
|
}
|
|
|
|
fn text_generated(values: &[String]) -> Result<String, Fault> {
|
|
GENERATED_TEXT(values.first().map(String::as_str).unwrap_or(""))
|
|
}
|
|
|
|
fn text_direct_generated(values: &[String]) -> Result<String, Fault> {
|
|
GENERATED_APPEND(values.first().map(String::as_str).unwrap_or(""))
|
|
}
|
|
|
|
fn append_reference(value: &str) -> Result<String, Fault> {
|
|
let mut result = String::with_capacity(value.len() + "新".len());
|
|
result.push_str(value);
|
|
result.push_str("新");
|
|
Ok(result)
|
|
}
|
|
|
|
fn text_helper_reference(values: &[String]) -> Result<String, Fault> {
|
|
append_reference(values.first().map(String::as_str).unwrap_or(""))
|
|
}
|
|
|
|
fn rows_reference(values: &[ROW_TYPE]) -> Result<Vec<ROW_TYPE>, Fault> {
|
|
let mut result = Vec::with_capacity(values.len());
|
|
for value in values {
|
|
let mut name = String::with_capacity(value.field0.len() + "新".len());
|
|
name.push_str(&value.field0);
|
|
name.push_str("新");
|
|
result.push(ROW_TYPE {
|
|
field0: name,
|
|
field1: value.field1.checked_add(1).ok_or_else(fault)?,
|
|
});
|
|
}
|
|
Ok(result)
|
|
}
|
|
|
|
fn capture_reference(values: &[i64]) -> Result<Vec<RESULT_TYPE>, Fault> {
|
|
let mut result = Vec::with_capacity(values.len());
|
|
for value in values {
|
|
result.push(if *value < 0 {
|
|
RESULT_TYPE::Variant1(PROBLEM_TYPE::Variant0(*value))
|
|
} else {
|
|
RESULT_TYPE::Variant0(*value)
|
|
});
|
|
}
|
|
Ok(result)
|
|
}
|
|
|
|
fn capture_generated(values: &[i64]) -> Result<Vec<RESULT_TYPE>, Fault> {
|
|
let mut result = Vec::with_capacity(values.len());
|
|
for value in values {
|
|
result.push(GENERATED_CAPTURE(*value)?);
|
|
}
|
|
Ok(result)
|
|
}
|
|
|
|
// 观察部分构造后失败的清理,成功返回的 bool 保持共享计时/内存入口不变。
|
|
fn map_failed_generated(values: &[i64]) -> Result<bool, Fault> {
|
|
Ok(GENERATED_MAP(values).is_err())
|
|
}
|
|
|
|
fn map_failed_reference(values: &[i64]) -> Result<bool, Fault> {
|
|
Ok(map_reference(values).is_err())
|
|
}
|
|
|
|
fn rows_failed_generated(values: &[ROW_TYPE]) -> Result<bool, Fault> {
|
|
Ok(GENERATED_ROWS(values).is_err())
|
|
}
|
|
|
|
fn rows_failed_reference(values: &[ROW_TYPE]) -> Result<bool, Fault> {
|
|
Ok(rows_reference(values).is_err())
|
|
}
|
|
|
|
fn main() {
|
|
let values: Vec<i64> = (0..1024).map(|value| (value * 17) % 1000 - 1).collect();
|
|
let failures: Vec<i64> = (0..128).map(|value| (value % 8) - 1).collect();
|
|
let rows: Vec<_> = (0..64)
|
|
.map(|index| ROW_TYPE {
|
|
field0: "雪山树林".repeat(4),
|
|
field1: index,
|
|
})
|
|
.collect();
|
|
let texts = ["雪山树林".repeat(16)];
|
|
eprintln!(
|
|
"text_forward_equals_direct_address={}",
|
|
std::ptr::fn_addr_eq(
|
|
text_generated as fn(&[String]) -> Result<String, Fault>,
|
|
text_direct_generated as fn(&[String]) -> Result<String, Fault>
|
|
)
|
|
);
|
|
for values in [&[i64::MAX][..], &[i64::MAX, 1][..], &[i64::MIN, -1][..]] {
|
|
assert_eq!(
|
|
integer_generated(values).map_err(|_| ()),
|
|
integer_reference(values).map_err(|_| ())
|
|
);
|
|
assert_eq!(
|
|
GENERATED_MAP(values).map_err(|_| ()),
|
|
map_reference(values).map_err(|_| ())
|
|
);
|
|
assert_eq!(
|
|
GENERATED_FOLD(values).map_err(|_| ()),
|
|
fold_reference(values).map_err(|_| ())
|
|
);
|
|
assert_eq!(
|
|
capture_generated(values).unwrap(),
|
|
capture_reference(values).unwrap()
|
|
);
|
|
}
|
|
println!("case,sample,implementation,elapsed_ns,checksum");
|
|
compare(
|
|
"handler_integer",
|
|
&[41],
|
|
3000000,
|
|
integer_generated,
|
|
integer_reference,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"handler_map",
|
|
&values,
|
|
20000,
|
|
GENERATED_MAP,
|
|
map_reference,
|
|
|value| value.len() as u64,
|
|
);
|
|
compare(
|
|
"handler_fold",
|
|
&values,
|
|
30000,
|
|
GENERATED_FOLD,
|
|
fold_reference,
|
|
|value| *value as u64,
|
|
);
|
|
compare(
|
|
"handler_text",
|
|
&texts,
|
|
300000,
|
|
text_generated,
|
|
text_reference,
|
|
|value| value.len() as u64,
|
|
);
|
|
compare_borrowed(
|
|
"handler_text",
|
|
&texts,
|
|
300000,
|
|
text_generated,
|
|
text_reference,
|
|
|value| value.len() as u64,
|
|
);
|
|
compare(
|
|
"handler_text_helper",
|
|
&texts,
|
|
300000,
|
|
text_generated,
|
|
text_helper_reference,
|
|
|value| value.len() as u64,
|
|
);
|
|
compare_named(
|
|
"handler_text_direct",
|
|
&texts,
|
|
300000,
|
|
text_generated,
|
|
text_direct_generated,
|
|
|value| value.len() as u64,
|
|
"direct",
|
|
);
|
|
compare(
|
|
"handler_record",
|
|
&rows,
|
|
5000,
|
|
GENERATED_ROWS,
|
|
rows_reference,
|
|
|value| value.len() as u64,
|
|
);
|
|
compare(
|
|
"handler_capture",
|
|
&failures,
|
|
30000,
|
|
capture_generated,
|
|
capture_reference,
|
|
|value| value.len() as u64,
|
|
);
|
|
compare(
|
|
"handler_map_failure",
|
|
&[1, 2, i64::MAX],
|
|
100000,
|
|
map_failed_generated,
|
|
map_failed_reference,
|
|
|value| u64::from(*value),
|
|
);
|
|
let mut failed_rows = rows;
|
|
failed_rows.last_mut().unwrap().field1 = i64::MAX;
|
|
compare(
|
|
"handler_record_failure",
|
|
&failed_rows,
|
|
5000,
|
|
rows_failed_generated,
|
|
rows_failed_reference,
|
|
|value| u64::from(*value),
|
|
);
|
|
}
|