blob: 95fff512511239eb8f8aedf2f2c422162a419b3d [file]
// Copyright 2022 The Blaze Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#[inline]
pub fn radix_sort_u16_by<T>(array: &mut [T], key: impl Fn(&T) -> u16) -> Vec<usize> {
radix_sort_u16_ranged_by(array, 65536, key)
}
#[inline]
pub fn radix_sort_u16_ranged_by<T>(
array: &mut [T],
num_keys: usize,
key: impl Fn(&T) -> u16,
) -> Vec<usize> {
// performance critical
unsafe {
// count
let mut counts = vec![0; num_keys];
for item in array.iter() {
*counts.get_unchecked_mut(key(item) as usize) += 1;
}
// construct parts
#[derive(Default, Clone, Copy)]
struct Part {
cur: usize,
end: usize,
}
let mut parts = vec![Part::default(); num_keys];
let mut beg = 0;
for (idx, count) in counts.iter().enumerate() {
if *count > 0 {
*parts.get_unchecked_mut(idx) = Part {
cur: beg,
end: beg + count,
};
beg += count;
}
}
// reorganize each partition
let mut inexhausted_part_indices = vec![0; num_keys];
for i in 0..num_keys {
inexhausted_part_indices[i] = i;
}
while {
inexhausted_part_indices.retain(|&i| {
let part = parts.get_unchecked(i);
part.cur < part.end
});
inexhausted_part_indices.len() > 1
} {
for &part_idx in &inexhausted_part_indices {
let cur_part = parts.get_unchecked(part_idx);
let cur = cur_part.cur;
let end = cur_part.end;
for item_idx in cur..end {
let target_part_idx = key(array.get_unchecked(item_idx)) as usize;
let target_part = parts.get_unchecked_mut(target_part_idx);
array.swap_unchecked(item_idx, target_part.cur);
target_part.cur += 1;
}
}
}
// returns counts of each bucket
counts
}
}
#[cfg(test)]
mod test {
use rand::Rng;
use crate::rdxsort::radix_sort_u16_by;
#[test]
fn fuzzytest_u16_small() {
for n in 0..1000 {
let mut array = vec![];
for _ in 0..n {
array.push(rand::thread_rng().gen::<u16>());
}
let mut array1 = array.clone();
radix_sort_u16_by(&mut array1, |key| *key);
let mut array2 = array.clone();
array2.sort_unstable();
assert_eq!(array1, array2);
}
}
#[test]
fn fuzzytest_u16_1m() {
let mut array = vec![];
for _ in 0..1000000 {
array.push(rand::thread_rng().gen::<u16>());
}
let mut array1 = array.clone();
radix_sort_u16_by(&mut array1, |key| *key);
let mut array2 = array.clone();
array2.sort_unstable();
assert_eq!(array1, array2);
}
}