struct Breakpoint {
input: f64,
score: f64,
}
fn piecewise(value: f64, curve: &[Breakpoint]) -> f64 {
debug_assert!(
curve.windows(2).all(|w| w[0].input <= w[1].input),
"Breakpoints must be sorted by input in ascending order"
);
if curve.is_empty() {
return 0.0;
}
if value <= curve[0].input {
return curve[0].score;
}
for w in curve.windows(2) {
if value <= w[1].input {
let frac = (value - w[0].input) / (w[1].input - w[0].input);
return w[0].score + frac * (w[1].score - w[0].score);
}
}
curve.last().unwrap().score
}
const MI_CURVE: &[Breakpoint] = &[
Breakpoint {
input: -100.0,
score: 0.0,
},
Breakpoint {
input: 0.0,
score: 30.0,
},
Breakpoint {
input: 40.0,
score: 50.0,
},
Breakpoint {
input: 65.0,
score: 70.0,
},
Breakpoint {
input: 85.0,
score: 90.0,
},
Breakpoint {
input: 171.0,
score: 100.0,
},
];
const COMPLEXITY_CURVE: &[Breakpoint] = &[
Breakpoint {
input: 5.0,
score: 100.0,
},
Breakpoint {
input: 6.0,
score: 90.0,
},
Breakpoint {
input: 10.0,
score: 80.0,
},
Breakpoint {
input: 20.0,
score: 50.0,
},
Breakpoint {
input: 50.0,
score: 5.0,
},
Breakpoint {
input: 100.0,
score: 0.0,
},
];
const DUPLICATION_CURVE: &[Breakpoint] = &[
Breakpoint {
input: 5.0,
score: 100.0,
},
Breakpoint {
input: 10.0,
score: 80.0,
},
Breakpoint {
input: 20.0,
score: 40.0,
},
Breakpoint {
input: 40.0,
score: 10.0,
},
Breakpoint {
input: 100.0,
score: 0.0,
},
];
const INDENT_CURVE: &[Breakpoint] = &[
Breakpoint {
input: 1.0,
score: 100.0,
},
Breakpoint {
input: 1.5,
score: 80.0,
},
Breakpoint {
input: 2.0,
score: 50.0,
},
Breakpoint {
input: 3.0,
score: 20.0,
},
Breakpoint {
input: 5.0,
score: 0.0,
},
];
const HALSTEAD_EPL_CURVE: &[Breakpoint] = &[
Breakpoint {
input: 1000.0,
score: 100.0,
},
Breakpoint {
input: 5000.0,
score: 70.0,
},
Breakpoint {
input: 10000.0,
score: 40.0,
},
Breakpoint {
input: 20000.0,
score: 0.0,
},
];
const FILE_SIZE_CURVE: &[Breakpoint] = &[
Breakpoint {
input: 500.0,
score: 100.0,
},
Breakpoint {
input: 1000.0,
score: 60.0,
},
Breakpoint {
input: 2000.0,
score: 20.0,
},
Breakpoint {
input: 4000.0,
score: 0.0,
},
];
pub fn normalize_mi(mi_score: f64) -> f64 {
piecewise(mi_score, MI_CURVE)
}
pub fn normalize_complexity(max_complexity: usize) -> f64 {
piecewise(max_complexity as f64, COMPLEXITY_CURVE)
}
pub fn normalize_duplication(dup_percent: f64) -> f64 {
piecewise(dup_percent, DUPLICATION_CURVE)
}
pub fn normalize_indent(stddev: f64) -> f64 {
piecewise(stddev, INDENT_CURVE)
}
pub fn normalize_halstead(effort: f64, code_lines: usize) -> f64 {
if effort <= 0.0 || code_lines == 0 {
return 50.0; }
piecewise(effort / code_lines as f64, HALSTEAD_EPL_CURVE)
}
pub fn normalize_file_size(code_lines: usize) -> f64 {
piecewise(code_lines as f64, FILE_SIZE_CURVE)
}
#[cfg(test)]
#[path = "normalize_test.rs"]
mod tests;