232 lines
7.1 KiB
Rust
232 lines
7.1 KiB
Rust
use std::hint::black_box;
|
|
use std::time::Instant;
|
|
|
|
#[derive(Debug)]
|
|
enum ReferenceFailure {
|
|
Fault(Fault),
|
|
Failed(String, Fault),
|
|
}
|
|
|
|
fn state_reference(value: &STATE_TYPE) -> Result<i64, Fault> {
|
|
Ok(match value {
|
|
STATE_TYPE::Variant0 => 0,
|
|
STATE_TYPE::Variant1(number) => *number,
|
|
STATE_TYPE::Variant2(text) => text.chars().count() as i64,
|
|
})
|
|
}
|
|
|
|
fn nullable_reference(value: &Option<String>) -> Result<i64, Fault> {
|
|
Ok(match value {
|
|
None => -1,
|
|
Some(text) if text == "zero" => 0,
|
|
Some(text) => text.chars().count() as i64,
|
|
})
|
|
}
|
|
|
|
fn operation_reference(value: i64) -> Result<i64, ReferenceFailure> {
|
|
if value >= 0 {
|
|
Ok(value)
|
|
} else {
|
|
Err(ReferenceFailure::Failed(
|
|
"negative".into(),
|
|
&FaultInfo {
|
|
message: "Result.Failed",
|
|
source: "reference.dever",
|
|
line: 1,
|
|
column: 1,
|
|
},
|
|
))
|
|
}
|
|
}
|
|
|
|
fn propagate_reference(value: i64) -> Result<i64, ReferenceFailure> {
|
|
Ok(operation_reference(value)?)
|
|
}
|
|
|
|
fn capture_reference(value: i64) -> Result<RESULT_TYPE, Fault> {
|
|
match propagate_reference(value) {
|
|
Ok(number) => Ok(RESULT_TYPE::Variant0(number)),
|
|
Err(ReferenceFailure::Failed(message, _origin)) => Ok(RESULT_TYPE::Variant1(message)),
|
|
Err(ReferenceFailure::Fault(fault)) => Err(fault),
|
|
}
|
|
}
|
|
|
|
fn change_reference(value: &STATE_TYPE) -> Result<STATE_TYPE, Fault> {
|
|
Ok(match value {
|
|
STATE_TYPE::Variant2(text) => {
|
|
let mut result = String::with_capacity(text.len() + "新".len());
|
|
result.push_str(text);
|
|
result.push_str("新");
|
|
STATE_TYPE::Variant2(result)
|
|
}
|
|
_ => value.clone(),
|
|
})
|
|
}
|
|
|
|
fn score(value: RESULT_TYPE) -> usize {
|
|
match value {
|
|
RESULT_TYPE::Variant0(number) => number as usize,
|
|
RESULT_TYPE::Variant1(message) => message.len(),
|
|
}
|
|
}
|
|
|
|
fn sample(
|
|
name: &str,
|
|
sample: usize,
|
|
implementation: &str,
|
|
count: usize,
|
|
mut operation: impl FnMut(usize) -> usize,
|
|
) {
|
|
let start = Instant::now();
|
|
let mut checksum = 0usize;
|
|
for position in 0..count {
|
|
checksum = checksum.wrapping_add(black_box(operation(black_box(position))));
|
|
}
|
|
println!(
|
|
"{name},{sample},{implementation},{},{checksum}",
|
|
start.elapsed().as_nanos()
|
|
);
|
|
}
|
|
|
|
fn main() {
|
|
let states = [
|
|
STATE_TYPE::Variant0,
|
|
STATE_TYPE::Variant1(42),
|
|
STATE_TYPE::Variant2("雪山树林".repeat(16)),
|
|
];
|
|
let texts = [None, Some("zero".into()), Some("雪山树林".repeat(16))];
|
|
for state in &states {
|
|
assert_eq!(
|
|
GENERATED_STATE(state).unwrap(),
|
|
state_reference(state).unwrap()
|
|
);
|
|
assert_eq!(
|
|
GENERATED_CHANGE(state).unwrap(),
|
|
change_reference(state).unwrap()
|
|
);
|
|
}
|
|
for text in &texts {
|
|
assert_eq!(
|
|
GENERATED_NULLABLE(text).unwrap(),
|
|
nullable_reference(text).unwrap()
|
|
);
|
|
}
|
|
for value in [i64::MIN, -1, 0, 1, i64::MAX] {
|
|
assert_eq!(
|
|
GENERATED_PROPAGATE(value).map_err(|_| ()),
|
|
propagate_reference(value).map_err(|_| ())
|
|
);
|
|
assert_eq!(
|
|
GENERATED_CAPTURE(value).unwrap(),
|
|
capture_reference(value).unwrap()
|
|
);
|
|
}
|
|
println!("case,sample,implementation,elapsed_ns,checksum");
|
|
for iteration in 0..9 {
|
|
for generated in if iteration % 2 == 0 {
|
|
[true, false]
|
|
} else {
|
|
[false, true]
|
|
} {
|
|
let implementation = if generated { "dever" } else { "rust" };
|
|
if generated {
|
|
sample(
|
|
"choice_payload",
|
|
iteration,
|
|
implementation,
|
|
1_000_000,
|
|
|position| GENERATED_STATE(black_box(&states[position % 3])).unwrap() as usize,
|
|
);
|
|
sample(
|
|
"nullable_text",
|
|
iteration,
|
|
implementation,
|
|
1_000_000,
|
|
|position| {
|
|
GENERATED_NULLABLE(black_box(&texts[position % 3])).unwrap() as usize
|
|
},
|
|
);
|
|
sample(
|
|
"default_failure",
|
|
iteration,
|
|
implementation,
|
|
500_000,
|
|
|position| {
|
|
black_box(GENERATED_PROPAGATE((position % 8) as i64 - 1)).unwrap_or(7)
|
|
as usize
|
|
},
|
|
);
|
|
sample(
|
|
"capture_failure",
|
|
iteration,
|
|
implementation,
|
|
500_000,
|
|
|position| {
|
|
score(black_box(
|
|
GENERATED_CAPTURE((position % 8) as i64 - 1).unwrap(),
|
|
))
|
|
},
|
|
);
|
|
sample(
|
|
"choice_copy",
|
|
iteration,
|
|
implementation,
|
|
300_000,
|
|
|_| match black_box(GENERATED_CHANGE(black_box(&states[2])).unwrap()) {
|
|
STATE_TYPE::Variant2(text) => text.len(),
|
|
_ => unreachable!(),
|
|
},
|
|
);
|
|
} else {
|
|
sample(
|
|
"choice_payload",
|
|
iteration,
|
|
implementation,
|
|
1_000_000,
|
|
|position| state_reference(black_box(&states[position % 3])).unwrap() as usize,
|
|
);
|
|
sample(
|
|
"nullable_text",
|
|
iteration,
|
|
implementation,
|
|
1_000_000,
|
|
|position| {
|
|
nullable_reference(black_box(&texts[position % 3])).unwrap() as usize
|
|
},
|
|
);
|
|
sample(
|
|
"default_failure",
|
|
iteration,
|
|
implementation,
|
|
500_000,
|
|
|position| {
|
|
black_box(propagate_reference((position % 8) as i64 - 1)).unwrap_or(7)
|
|
as usize
|
|
},
|
|
);
|
|
sample(
|
|
"capture_failure",
|
|
iteration,
|
|
implementation,
|
|
500_000,
|
|
|position| {
|
|
score(black_box(
|
|
capture_reference((position % 8) as i64 - 1).unwrap(),
|
|
))
|
|
},
|
|
);
|
|
sample(
|
|
"choice_copy",
|
|
iteration,
|
|
implementation,
|
|
300_000,
|
|
|_| match black_box(change_reference(black_box(&states[2])).unwrap()) {
|
|
STATE_TYPE::Variant2(text) => text.len(),
|
|
_ => unreachable!(),
|
|
},
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|