use core::mem;
use crate::sort::RadixKey;
pub trait Scalar: Copy + private::Sealed {
type ToRadixKey: RadixKey;
fn to_radix_key(self) -> Self::ToRadixKey;
}
macro_rules! key_impl_unsigned {
($($t:ty)*) => ($( key_impl_unsigned!($t => $t); )*);
($t:ty => $radix_key:ty) => (
impl Scalar for $t {
type ToRadixKey = $radix_key;
#[inline(always)]
fn to_radix_key(self) -> Self::ToRadixKey {
self as $radix_key
}
}
)
}
key_impl_unsigned! { u8 u16 u32 u64 u128 }
#[cfg(target_pointer_width = "16")]
key_impl_unsigned!(usize => u16);
#[cfg(target_pointer_width = "32")]
key_impl_unsigned!(usize => u32);
#[cfg(target_pointer_width = "64")]
key_impl_unsigned!(usize => u64);
#[cfg(target_pointer_width = "128")]
key_impl_unsigned!(usize => u128);
key_impl_unsigned!(bool => u8);
key_impl_unsigned!(char => u32);
macro_rules! key_impl_signed {
($($t:ty => $radix_key:ty),*) => ($(
impl Scalar for $t {
type ToRadixKey = $radix_key;
#[inline(always)]
fn to_radix_key(self) -> Self::ToRadixKey {
const BIT_COUNT: usize = 8 * mem::size_of::<$t>();
const SIGN_BIT: $radix_key = 1 << (BIT_COUNT-1);
(self as $radix_key) ^ SIGN_BIT
}
}
)*)
}
key_impl_signed! {
i8 => u8,
i16 => u16,
i32 => u32,
i64 => u64,
i128 => u128
}
#[cfg(target_pointer_width = "16")]
key_impl_signed!(isize => u16);
#[cfg(target_pointer_width = "32")]
key_impl_signed!(isize => u32);
#[cfg(target_pointer_width = "64")]
key_impl_signed!(isize => u64);
#[cfg(target_pointer_width = "128")]
key_impl_signed!(isize => u128);
macro_rules! key_impl_float {
($($t:ty => $radix_key:ty : $signed_key:ty),*) => ($(
impl Scalar for $t {
type ToRadixKey = $radix_key;
#[inline(always)]
fn to_radix_key(self) -> Self::ToRadixKey {
const BIT_COUNT: usize = 8 * mem::size_of::<$t>();
const FLIP_SIGN_MASK: $radix_key = 1 << (BIT_COUNT-1);
let bits = self.to_bits();
let flip_negative_mask = ((bits as $signed_key) >> (BIT_COUNT-1)) as $radix_key;
bits ^ (flip_negative_mask | FLIP_SIGN_MASK)
}
}
)*)
}
key_impl_float! {
f32 => u32 : i32,
f64 => u64 : i64
}
mod private {
pub trait Sealed {}
macro_rules! sealed_impl { ($($t:ty)*) => ($(
impl Sealed for $t {}
)*) }
sealed_impl! {
bool char
u8 u16 u32 u64 u128 usize
i8 i16 i32 i64 i128 isize
f32 f64
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_bool() {
assert!(false.to_radix_key() < true.to_radix_key());
}
#[test]
fn test_key_char() {
let mut actual = [
'\u{0}', '\u{1}', '\u{F}', '\u{7F}', '\u{80}', '\u{81}', '\u{FF}', '\u{7FF}', '\u{800}', '\u{801}', '\u{FFF}', '\u{FFFF}', '\u{10000}', '\u{10001}', '\u{FFFFF}', '\u{10FFFF}' ];
let expected = actual.clone();
actual.reverse();
actual.sort_by_key(|v| v.to_radix_key());
assert_eq!(actual, expected);
}
#[test]
fn test_key_numeric() {
macro_rules! implement {
($($t:ident)*) => ($(
let mut actual = [
core::$t::MIN, core::$t::MIN+1, core::$t::MIN / 2,
core::$t::MIN >> (mem::size_of::<$t>() * 8 / 2),
core::$t::MAX, core::$t::MAX-1, core::$t::MAX / 2,
core::$t::MAX >> (mem::size_of::<$t>() * 8 / 2),
(-1i8) as $t, 0, 1,
];
let mut expected = actual.clone();
expected.sort();
actual.sort_by_key(|v| v.to_radix_key());
assert_eq!(actual, expected);
)*)
}
implement! {
u8 u16 u32 u64 u128 usize
i8 i16 i32 i64 i128 isize
}
}
#[test]
#[allow(clippy::inconsistent_digit_grouping)]
fn test_key_float() {
{ let mut actual = [
f32::from_bits(0b1_11111111_11111111111111111111111), f32::from_bits(0b1_11111111_00000000000000000000001), f32::from_bits(0b1_11111111_00000000000000000000000), f32::from_bits(0b1_11111110_11111111111111111111111), f32::from_bits(0b1_01111111_00000000000000000000000), f32::from_bits(0b1_01111110_11111111111111111111111), f32::from_bits(0b1_00000001_00000000000000000000000), f32::from_bits(0b1_00000000_11111111111111111111111), f32::from_bits(0b1_00000000_00000000000000000000001), f32::from_bits(0b1_00000000_00000000000000000000000), f32::from_bits(0b0_00000000_00000000000000000000000), f32::from_bits(0b0_00000000_00000000000000000000001), f32::from_bits(0b0_00000000_11111111111111111111111), f32::from_bits(0b0_00000001_00000000000000000000000), f32::from_bits(0b0_01111110_11111111111111111111111), f32::from_bits(0b0_01111111_00000000000000000000000), f32::from_bits(0b0_11111110_11111111111111111111111), f32::from_bits(0b0_11111111_00000000000000000000000), f32::from_bits(0b0_11111111_00000000000000000000001), f32::from_bits(0b0_11111111_11111111111111111111111), ];
let expected = actual;
actual.reverse();
actual.sort_by_key(|v| v.to_radix_key());
for (a, e) in actual.iter().zip(expected.iter()) {
assert_eq!(a.to_bits(), e.to_bits());
}
}
{ let mut actual = [
f64::from_bits(0b1_11111111111_1111111111111111111111111111111111111111111111111111), f64::from_bits(0b1_11111111111_0000000000000000000000000000000000000000000000000001), f64::from_bits(0b1_11111111111_0000000000000000000000000000000000000000000000000000), f64::from_bits(0b1_11111111110_1111111111111111111111111111111111111111111111111111), f64::from_bits(0b1_01111111111_0000000000000000000000000000000000000000000000000000), f64::from_bits(0b1_01111111110_1111111111111111111111111111111111111111111111111111), f64::from_bits(0b1_00000000001_0000000000000000000000000000000000000000000000000000), f64::from_bits(0b1_00000000000_1111111111111111111111111111111111111111111111111111), f64::from_bits(0b1_00000000000_0000000000000000000000000000000000000000000000000001), f64::from_bits(0b1_00000000000_0000000000000000000000000000000000000000000000000000), f64::from_bits(0b0_00000000000_0000000000000000000000000000000000000000000000000000), f64::from_bits(0b0_00000000000_0000000000000000000000000000000000000000000000000001), f64::from_bits(0b0_00000000000_1111111111111111111111111111111111111111111111111111), f64::from_bits(0b0_00000000001_0000000000000000000000000000000000000000000000000000), f64::from_bits(0b0_01111111110_1111111111111111111111111111111111111111111111111111), f64::from_bits(0b0_01111111111_0000000000000000000000000000000000000000000000000000), f64::from_bits(0b0_11111111110_1111111111111111111111111111111111111111111111111111), f64::from_bits(0b0_11111111111_0000000000000000000000000000000000000000000000000000), f64::from_bits(0b0_11111111111_0000000000000000000000000000000000000000000000000001), f64::from_bits(0b0_11111111111_1111111111111111111111111111111111111111111111111111), ];
let expected = actual;
actual.reverse();
actual.sort_by_key(|v| v.to_radix_key());
for (a, e) in actual.iter().zip(expected.iter()) {
assert_eq!(a.to_bits(), e.to_bits());
}
}
}
}