#![warn(missing_docs)]
#![warn(rustdoc::missing_doc_code_examples)]
#![deny(clippy::all)]
#![deny(clippy::pedantic)]
use core::cmp::{max, min, Ord};
use core::convert::TryInto;
use core::fmt;
use core::fmt::Display;
use std::error::Error;
#[derive(Debug)]
pub enum CountingSortError {
IntoIndexFailed(&'static str),
IteratorEmpty(&'static str),
SortingUnnecessary(&'static str),
MinValueLargerMaxValue(&'static str),
IndexOutOfBounds(&'static str),
}
impl Display for CountingSortError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
match self {
CountingSortError::IntoIndexFailed(description)
| CountingSortError::IteratorEmpty(description)
| CountingSortError::SortingUnnecessary(description)
| CountingSortError::MinValueLargerMaxValue(description)
| CountingSortError::IndexOutOfBounds(description) => description.fmt(f),
}
}
}
impl Error for CountingSortError {}
impl CountingSortError {
fn from_try_into_index_failed() -> CountingSortError {
CountingSortError::IntoIndexFailed("Conversion into index failed")
}
fn from_empty_iterator() -> CountingSortError {
CountingSortError::IteratorEmpty("There are no element available in the iterator")
}
fn from_sorting_unnecessary() -> CountingSortError {
CountingSortError::SortingUnnecessary(
"Minimum value is identical to maximum value, therefore no sorting is necessary",
)
}
fn from_min_value_larger_max_value() -> CountingSortError {
CountingSortError::MinValueLargerMaxValue("Minimum value is larger than maximum value")
}
fn from_index_out_of_bounds() -> CountingSortError {
CountingSortError::IndexOutOfBounds(
"Index is out of bounds, most likely the given maximum value is too small",
)
}
}
pub trait CountingSort<'a, T>
where
T: Ord + Copy + TryIntoIndex + 'a,
Self: Clone + Sized + Iterator<Item = &'a T>,
{
fn cnt_sort(self) -> Result<Vec<T>, CountingSortError> {
counting_sort(self)
}
fn cnt_sort_min_max(self, min_value: &T, max_value: &T) -> Result<Vec<T>, CountingSortError> {
counting_sort_min_max(self, min_value, max_value)
}
}
impl<'a, T, ITER> CountingSort<'a, T> for ITER
where
T: Ord + Copy + TryIntoIndex + 'a,
ITER: Sized + Iterator<Item = &'a T> + Clone,
{
}
pub trait TryIntoIndex {
type Error;
fn try_into_index(value: &Self, min_value: &Self) -> Result<usize, Self::Error>;
}
macro_rules! try_into_index_impl_for_signed {
($smaller_int:ty,$larger_int:ty) => {
impl TryIntoIndex for $smaller_int {
type Error = <$larger_int as TryInto<usize>>::Error;
fn try_into_index(value: &Self, min_value: &Self) -> Result<usize, Self::Error> {
<$larger_int>::try_into(
<$larger_int>::from(*value) - <$larger_int>::from(*min_value),
)
}
}
};
}
macro_rules! try_into_index_impl_for_unsigned {
($unsigned:ty) => {
impl TryIntoIndex for $unsigned {
type Error = <$unsigned as TryInto<usize>>::Error;
#[inline]
fn try_into_index(value: &Self, min_value: &Self) -> Result<usize, Self::Error> {
<$unsigned>::try_into(*value - *min_value)
}
}
};
}
macro_rules! try_into_index_impl_for_small_unsigned {
($unsigned:ty) => {
impl TryIntoIndex for $unsigned {
type Error = CountingSortError;
#[inline]
fn try_into_index(value: &Self, min_value: &Self) -> Result<usize, Self::Error> {
Ok(usize::from(*value - *min_value))
}
}
};
}
try_into_index_impl_for_signed!(i8, i16);
try_into_index_impl_for_signed!(i16, i32);
try_into_index_impl_for_signed!(i32, i64);
try_into_index_impl_for_small_unsigned!(u8);
try_into_index_impl_for_small_unsigned!(u16);
try_into_index_impl_for_unsigned!(u32);
try_into_index_impl_for_unsigned!(usize);
#[inline]
fn counting_sort<'a, ITER, T>(iterator: ITER) -> Result<Vec<T>, CountingSortError>
where
ITER: Iterator<Item = &'a T> + Clone,
T: Ord + Copy + TryIntoIndex + 'a,
{
let optional_tuple = get_min_max(&mut iterator.clone());
if let Some((min_value, max_value)) = optional_tuple {
counting_sort_min_max(iterator, min_value, max_value)
} else {
Err(CountingSortError::from_empty_iterator())
}
}
#[inline]
fn counting_sort_min_max<'a, ITER, T>(
iterator: ITER,
min_value: &T,
max_value: &T,
) -> Result<Vec<T>, CountingSortError>
where
ITER: Iterator<Item = &'a T> + Clone,
T: Ord + Copy + TryIntoIndex + 'a,
{
if min_value == max_value {
return Err(CountingSortError::from_sorting_unnecessary());
}
if min_value > max_value {
return Err(CountingSortError::from_min_value_larger_max_value());
}
let mut count_vector = count_values(&mut iterator.clone(), min_value, max_value)?;
calculate_prefix_sum(&mut count_vector);
let length = *count_vector.last().unwrap(); re_order(iterator, &mut count_vector, length, &min_value)
}
#[inline]
fn re_order<'a, T, ITER>(
iterator: ITER,
count_vector: &mut Vec<usize>,
length: usize,
min_value: &T,
) -> Result<Vec<T>, CountingSortError>
where
T: Ord + Copy + TryIntoIndex + 'a,
ITER: Iterator<Item = &'a T>,
{
let mut sorted_vector: Vec<T> = vec![*min_value; length];
for value in iterator {
let index_count_vector_result = T::try_into_index(value, min_value);
if index_count_vector_result.is_err() {
return Err(CountingSortError::from_try_into_index_failed());
} else {
let index_count_vector = index_count_vector_result.unwrap_or(0);
if index_count_vector >= count_vector.len() {
return Err(CountingSortError::from_index_out_of_bounds());
}
let mut index = count_vector[index_count_vector];
sorted_vector[index] = *value;
index += 1;
count_vector[index_count_vector] = index;
}
}
Ok(sorted_vector)
}
#[inline]
fn count_values<'a, ITER, T>(
iterator: &mut ITER,
min_value: &T,
max_value: &T,
) -> Result<Vec<usize>, CountingSortError>
where
ITER: Iterator<Item = &'a T>,
T: Ord + Copy + TryIntoIndex + 'a,
{
let distance_result = T::try_into_index(max_value, min_value);
if distance_result.is_ok() {
let length = distance_result.unwrap_or(0) + 2; let mut count_vector: Vec<usize> = vec![0; length];
for value in iterator {
let index_result = T::try_into_index(value, min_value);
if index_result.is_err() {
return Err(CountingSortError::from_try_into_index_failed());
} else {
let index = index_result.unwrap_or(0) + 1; if index >= count_vector.len() {
return Err(CountingSortError::from_index_out_of_bounds());
}
let new_count_value = count_vector[index] + 1;
count_vector[index] = new_count_value;
}
}
return Ok(count_vector);
}
Err(CountingSortError::from_try_into_index_failed())
}
#[inline]
fn calculate_prefix_sum(count_vector: &mut Vec<usize>) {
let mut iterator = count_vector.iter_mut();
let optional_first_element = iterator.next();
if let Some(first_element) = optional_first_element {
let mut total = *first_element;
for value in iterator {
total += *value;
*value = total;
}
}
}
#[inline]
fn get_min_max<T, ITER>(iterator: &mut ITER) -> Option<(T, T)>
where
T: Ord + Copy,
ITER: Iterator<Item = T>,
{
let min_value_optional = iterator.next();
if let Some(min_value) = min_value_optional {
let tuple = iterator.fold((min_value, min_value), |(min_val, max_val), value| {
(min(min_val, value), max(max_val, value))
});
return Some(tuple);
}
None
}
#[cfg(test)]
#[cfg(not(tarpaulin_include))]
mod unit_tests {
use super::*;
const TEST_ARRAY_MIN_VALUE: u8 = 1;
const TEST_ARRAY_MAX_VALUE: u8 = 30;
const TEST_ARRAY_UNSORTED: [u8; 30] = [
13, 24, 27, 3, 10, 1, 9, 17, 6, 7, 3, 30, 14, 15, 2, 3, 7, 11, 21, 16, 7, 11, 21, 5, 23,
25, 26, 28, 28, 4,
];
const TEST_ARRAY_SORTED: [u8; 30] = [
1, 2, 3, 3, 3, 4, 5, 6, 7, 7, 7, 9, 10, 11, 11, 13, 14, 15, 16, 17, 21, 21, 23, 24, 25, 26,
27, 28, 28, 30,
];
const TEST_COUNT_VALUES_ARRAY: [usize; 31] = [
0, 1, 1, 3, 1, 1, 1, 3, 0, 1, 1, 2, 0, 1, 1, 1, 1, 1, 0, 0, 0, 2, 0, 1, 1, 1, 1, 1, 2, 0, 1,
];
const TEST_PREFIX_SUM_ARRAY: [usize; 31] = [
0, 1, 2, 5, 6, 7, 8, 11, 11, 12, 13, 15, 15, 16, 17, 18, 19, 20, 20, 20, 20, 22, 22, 23,
24, 25, 26, 27, 29, 29, 30,
];
#[test]
fn test_cnt_sort_i8_vector() {
let test_vector: Vec<i8> = vec![2, -2, 1, -6];
let sorted_vector = counting_sort(test_vector.iter()).unwrap();
assert_eq!(vec![-6, -2, 1, 2], sorted_vector);
}
#[test]
fn test_cnt_sort_i8_vector_with_overflow() {
let test_vector: Vec<i8> = vec![2, -100, 50, -6];
let sorted_vector = counting_sort(test_vector.iter()).unwrap();
assert_eq!(vec![-100, -6, 2, 50], sorted_vector);
}
#[test]
fn test_cnt_sort_u8_vector() {
let mut test_vector = TEST_ARRAY_UNSORTED.to_vec();
test_vector = test_vector.iter().cnt_sort().unwrap();
let sorted_vector = TEST_ARRAY_SORTED.to_vec();
assert_eq!(sorted_vector, test_vector);
}
#[test]
fn test_cnt_sort_min_max_u8_vector() {
let mut test_vector = TEST_ARRAY_UNSORTED.to_vec();
test_vector = test_vector
.iter()
.cnt_sort_min_max(&TEST_ARRAY_MIN_VALUE, &TEST_ARRAY_MAX_VALUE)
.unwrap();
let sorted_vector = TEST_ARRAY_SORTED.to_vec();
assert_eq!(sorted_vector, test_vector);
}
#[test]
fn test_into_index_i8() {
assert_eq!(255, i8::try_into_index(&127, &-128).unwrap());
assert_eq!(0, i8::try_into_index(&-128, &-128).unwrap());
assert_eq!(150, i8::try_into_index(&50, &-100).unwrap());
assert_eq!(50, i8::try_into_index(&-50, &-100).unwrap());
assert_eq!(27, i8::try_into_index(&127, &100).unwrap());
}
#[test]
fn test_into_index_i16() {
assert_eq!(0xFFFF, i16::try_into_index(&32767, &-32768).unwrap());
assert_eq!(0, i16::try_into_index(&-32768, &-32768).unwrap());
assert_eq!(0, i16::try_into_index(&32767, &32767).unwrap());
}
#[test]
fn test_into_index_i32() {
assert_eq!(
0xFFFFFFFF,
i32::try_into_index(&2147483647, &-2147483648).unwrap()
);
assert_eq!(0, i32::try_into_index(&-2147483648, &-2147483648).unwrap());
assert_eq!(1, i32::try_into_index(&-2147483647, &-2147483648).unwrap());
assert_eq!(0, i32::try_into_index(&2147483647, &2147483647).unwrap());
}
#[test]
fn test_into_index_u8() {
assert_eq!(255, u8::try_into_index(&255, &0).unwrap());
assert_eq!(0, u8::try_into_index(&0, &0).unwrap());
assert_eq!(0, u8::try_into_index(&255, &255).unwrap());
assert_eq!(50, u8::try_into_index(&150, &100).unwrap());
assert_eq!(50, u8::try_into_index(&100, &50).unwrap());
assert_eq!(27, i8::try_into_index(&127, &100).unwrap());
}
#[test]
fn test_into_index_u16() {
assert_eq!(0xFFFF, u16::try_into_index(&0xFFFF, &0).unwrap());
assert_eq!(0, u16::try_into_index(&0, &0).unwrap());
assert_eq!(0, u16::try_into_index(&0xFFFF, &0xFFFF).unwrap());
assert_eq!(1, u16::try_into_index(&0xFFFF, &0xFFFE).unwrap());
}
#[test]
fn test_into_index_u32() {
assert_eq!(0xFFFFFFFF, u32::try_into_index(&0xFFFFFFFF, &0).unwrap());
assert_eq!(0, u32::try_into_index(&0, &0).unwrap());
assert_eq!(50, u32::try_into_index(&1000000, &999950).unwrap());
assert_eq!(50, u8::try_into_index(&100, &50).unwrap());
assert_eq!(27, i8::try_into_index(&127, &100).unwrap());
}
#[test]
fn test_counting_sort() {
let test_vector: Vec<u8> = TEST_ARRAY_UNSORTED.to_vec();
let sorted_vector = counting_sort(test_vector.iter()).unwrap();
let expected_vector = TEST_ARRAY_SORTED.to_vec();
assert_eq!(expected_vector, sorted_vector);
}
#[test]
fn test_counting_sort_min_max() {
let test_vector: Vec<u8> = TEST_ARRAY_UNSORTED.to_vec();
let sorted_vector = counting_sort_min_max(
test_vector.iter(),
&TEST_ARRAY_MIN_VALUE,
&TEST_ARRAY_MAX_VALUE,
)
.unwrap();
let expected_vector = TEST_ARRAY_SORTED.to_vec();
assert_eq!(expected_vector, sorted_vector);
}
#[test]
fn test_count_values() {
let test_vector = TEST_ARRAY_UNSORTED.to_vec();
let result_count_value_vector = count_values(
&mut test_vector.iter(),
&TEST_ARRAY_MIN_VALUE,
&TEST_ARRAY_MAX_VALUE,
);
assert!(result_count_value_vector.is_ok());
let count_values_vector = result_count_value_vector.unwrap();
let expected_vector = TEST_COUNT_VALUES_ARRAY.to_vec();
assert_eq!(expected_vector, count_values_vector);
}
#[test]
fn test_get_min_max_unsigned() {
let test_vector: Vec<u8> = vec![1, 2, 3, 4];
let tuple = get_min_max(&mut test_vector.iter());
assert!(tuple.is_some());
let (min_value, max_value) = tuple.unwrap();
assert_eq!(1, *min_value);
assert_eq!(4, *max_value);
}
#[test]
fn test_get_min_max_without_min() {
let test_vector: Vec<u8> = Vec::new();
let tuple = get_min_max(&mut test_vector.iter());
assert!(tuple.is_none());
}
#[test]
fn test_get_min_max_signed() {
let test_vector: Vec<i8> = vec![-128, 2, 3, 127];
let tuple = get_min_max(&mut test_vector.iter());
assert!(tuple.is_some());
let (min_value, max_value) = tuple.unwrap();
assert_eq!(-128, *min_value);
assert_eq!(127, *max_value);
}
#[test]
fn test_calculate_prefix_sum_1() {
let mut test_vector: Vec<usize> = vec![1; 4];
calculate_prefix_sum(&mut test_vector);
assert_eq!(vec![1, 2, 3, 4], test_vector);
}
#[test]
fn test_calculate_prefix_sum_2() {
let mut test_vector: Vec<usize> = vec![1, 2, 3, 4, 5];
calculate_prefix_sum(&mut test_vector);
assert_eq!(vec![1, 3, 6, 10, 15], test_vector);
}
#[test]
fn test_calculate_prefix_sum_3() {
let mut test_vector = TEST_COUNT_VALUES_ARRAY.to_vec();
calculate_prefix_sum(&mut test_vector);
assert_eq!(TEST_PREFIX_SUM_ARRAY.to_vec(), test_vector);
}
#[test]
fn test_re_order() {
let test_vector = TEST_ARRAY_UNSORTED.to_vec();
let mut test_count_vector = TEST_PREFIX_SUM_ARRAY.to_vec();
let result_sorted_vector = re_order(
test_vector.iter(),
&mut test_count_vector,
test_vector.len(),
&TEST_ARRAY_MIN_VALUE,
);
assert!(result_sorted_vector.is_ok());
let sorted_vector = result_sorted_vector.unwrap();
assert_eq!(TEST_ARRAY_SORTED.to_vec(), sorted_vector);
}
#[test]
fn test_min_value_larger_max_value_error() {
let test_vector = vec![1];
let result = counting_sort_min_max(test_vector.iter(), &1, &0);
assert!(result.is_err());
assert_eq!(
"Minimum value is larger than maximum value",
format!("{}", result.unwrap_err())
);
}
#[test]
fn test_sorting_unnecessary_error() {
let test_vector = vec![1];
let result = counting_sort_min_max(test_vector.iter(), &1, &1);
assert!(result.is_err());
assert_eq!(
"Minimum value is identical to maximum value, therefore no sorting is necessary",
format!("{}", result.unwrap_err())
);
}
#[test]
fn test_empty_iterator_error() {
let test_vector: Vec<u8> = vec![];
let result = counting_sort(test_vector.iter());
assert!(result.is_err());
assert_eq!(
"There are no element available in the iterator",
format!("{}", result.unwrap_err())
);
let test_vector: Vec<u8> = vec![];
let result = counting_sort_min_max(test_vector.iter(), &0, &1);
assert!(result.is_ok());
assert_eq!(test_vector, result.unwrap());
}
#[test]
fn test_incorrect_given_min_max_values() {
let vec = vec![4, 3, 2, 1];
let error = vec.iter().cnt_sort_min_max(&2, &4);
assert!(error.is_err());
assert_eq!(
"Conversion into index failed",
format!("{}", error.unwrap_err())
);
let error = vec.iter().cnt_sort_min_max(&1, &3);
assert!(error.is_err());
assert_eq!(
"Index is out of bounds, most likely the given maximum value is too small",
format!("{}", error.unwrap_err())
);
}
#[test]
fn test_try_into_error() {
#[derive(Ord, PartialOrd, PartialEq, Eq, Copy, Clone, Debug)]
struct ValueWithTryIntoError {
value: u8,
}
let min_value = ValueWithTryIntoError { value: 0 };
let max_value = ValueWithTryIntoError {
value: u8::max_value(),
};
impl TryIntoIndex for ValueWithTryIntoError {
type Error = String;
fn try_into_index(_value: &Self, _min_value: &Self) -> Result<usize, Self::Error> {
Err(String::from("TryInto always fails"))
}
}
let test_vector: Vec<ValueWithTryIntoError> = Vec::new();
let result = counting_sort_min_max(test_vector.iter(), &min_value, &max_value);
assert!(result.is_err());
assert_eq!(
CountingSortError::from_try_into_index_failed().to_string(),
result.unwrap_err().to_string()
);
let mut count_vector = vec![0, 0];
let test_vector = vec![max_value, min_value];
let result = re_order(test_vector.iter(), &mut count_vector, 2, &min_value);
assert!(result.is_err());
assert_eq!(
CountingSortError::from_try_into_index_failed().to_string(),
result.unwrap_err().to_string()
);
}
#[test]
fn test_empty_count_values_vector_is_impossible() {
#[derive(Ord, PartialOrd, PartialEq, Eq, Copy, Clone, Debug)]
struct ValueWithWrongSubstraction {
value: usize,
}
let min_value = ValueWithWrongSubstraction { value: 0 };
let max_value = ValueWithWrongSubstraction {
value: usize::max_value(),
};
impl TryIntoIndex for ValueWithWrongSubstraction {
type Error = String;
fn try_into_index(_value: &Self, _min_value: &Self) -> Result<usize, Self::Error> {
Ok(0)
}
}
let test_vector: Vec<ValueWithWrongSubstraction> = Vec::new();
let result = counting_sort_min_max(test_vector.iter(), &min_value, &max_value);
assert!(result.is_ok());
assert_eq!(test_vector, result.unwrap());
}
#[test]
fn test_re_order_index_out_of_bounds_error() {
let vec = vec![1, 2];
let mut count_vector = vec![1];
let result = re_order(vec.iter(), &mut count_vector, 2, &1);
assert!(result.is_err());
assert_eq!(
CountingSortError::from_index_out_of_bounds().to_string(),
result.unwrap_err().to_string()
);
}
}
#[cfg_attr(tarpaulin, skip)]
#[cfg(doctest)]
macro_rules! doc_check {
($x:expr) => {
#[doc = $x]
extern "C" {}
};
}
#[cfg_attr(tarpaulin, skip)]
#[cfg(doctest)]
doc_check!(include_str!("../README.md"));