use crate::topology::types::EfficiencyClass;
const MAX_CLASSES: usize = 256;
pub(super) fn dense_ranks(raw: &[u32]) -> Option<Box<[EfficiencyClass]>> {
if raw.is_empty() {
return None;
}
let mut distinct: Vec<u32> = raw.to_vec();
distinct.sort_unstable();
distinct.dedup();
if distinct.len() > MAX_CLASSES {
return None;
}
let classes = raw
.iter()
.map(|value| {
let rank = match distinct.binary_search(value) {
Ok(rank) | Err(rank) => rank,
};
u8::try_from(rank).ok().map(EfficiencyClass::new)
})
.collect::<Option<Vec<_>>>()?;
Some(classes.into_boxed_slice())
}
#[cfg(test)]
mod tests {
use super::dense_ranks;
use crate::topology::types::EfficiencyClass;
fn ranks(raw: &[u32]) -> Vec<u8> {
dense_ranks(raw)
.expect("fixture reports at least one processor")
.iter()
.map(|class| class.rank())
.collect()
}
#[test]
fn homogeneous_values_collapse_to_the_lowest_rank() {
assert_eq!(ranks(&[1, 1, 1, 1]), vec![0, 0, 0, 0]);
assert_eq!(
dense_ranks(&[7; 4]).expect("fixture reports processors")[0],
EfficiencyClass::LOWEST
);
}
#[test]
fn sparse_platform_values_compress_while_preserving_order() {
assert_eq!(ranks(&[462, 462, 1024, 1024]), vec![0, 0, 1, 1]);
assert_eq!(ranks(&[100, 9000, 250, 100]), vec![0, 2, 1, 0]);
}
#[test]
fn higher_raw_value_always_ranks_higher() {
let table = dense_ranks(&[0, 1, 2]).expect("fixture reports processors");
assert!(table[0] < table[1]);
assert!(table[1] < table[2]);
}
#[test]
fn empty_and_oversized_tables_are_absent() {
assert_eq!(dense_ranks(&[]), None);
let too_many: Vec<u32> = (0..257).collect();
assert_eq!(dense_ranks(&too_many), None);
let at_limit: Vec<u32> = (0..256).collect();
assert!(dense_ranks(&at_limit).is_some());
}
}