use crate::Match;
use alloc::{vec, vec::Vec};
#[inline]
pub fn radix_sort_matches(matches: &mut Vec<Match>) {
let (matches_b, high_radices) = radix_sort_first_pass(matches);
if high_radices == 0 {
*matches = matches_b;
return;
}
radix_sort_second_pass(matches_b, matches);
}
#[inline(always)]
fn radix_sort_first_pass(matches: &[Match]) -> (Vec<Match>, u8) {
let mut histogram = [0u32; 256];
let mut high_radices = 0u8;
for m in matches.iter() {
let radix = m.score & 0xFF;
histogram[radix as usize] += 1;
high_radices |= (m.score >> 8) as u8;
}
let mut offsets = [0u32; 256];
for idx in (1..256).rev() {
offsets[idx - 1] = offsets[idx] + histogram[idx];
}
let mut matches_b = vec![Match::default(); matches.len()];
for m in matches.iter() {
let radix = m.score & 0xFF;
let output_idx = offsets[radix as usize] as usize;
matches_b[output_idx] = *m;
offsets[radix as usize] += 1;
}
(matches_b, high_radices)
}
#[inline(always)]
fn radix_sort_second_pass(matches_b: Vec<Match>, matches: &mut [Match]) {
let mut histogram = [0u32; 256];
for m in matches_b.iter() {
let radix = (m.score >> 8) & 0xFF;
histogram[radix as usize] += 1;
}
let mut offsets = [0u32; 256];
for idx in (1..256).rev() {
offsets[idx - 1] = offsets[idx] + histogram[idx];
}
for m in matches_b {
let radix = (m.score >> 8) & 0xFF;
matches[offsets[radix as usize] as usize] = m;
offsets[radix as usize] += 1;
}
}
#[cfg(test)]
mod test {
use super::*;
use rand::{RngExt, SeedableRng};
#[test]
fn test_sorted() {
let mut rng = rand::rngs::SmallRng::seed_from_u64(42);
let count = if cfg!(miri) { 1 << 12 } else { 1 << 24 };
let mut matches = (0u32..count)
.map(|index| Match {
score: rng.random::<u16>(),
index,
exact: rng.random_bool(0.5),
#[cfg(feature = "match_end_col")]
end_col: 0,
})
.collect::<Vec<_>>();
radix_sort_matches(&mut matches);
assert!(matches.is_sorted());
}
}