use crate::{RadixDataType, RadixResult};
pub trait RadixSortable: Sized + Clone {
type RadixKey: Copy + Eq + Ord;
fn data_type() -> RadixDataType;
fn to_radix_key(value: Self) -> Self::RadixKey;
fn from_radix_key(key: Self::RadixKey) -> Self;
fn extract_byte(key: Self::RadixKey, byte_index: usize) -> u8;
fn key_size() -> usize;
#[inline]
fn validate(_value: &Self) -> RadixResult<()> {
Ok(())
}
#[inline]
fn string_length(_value: &Self) -> usize {
0
}
#[inline]
fn string_byte_at(_value: &Self, _char_index: usize) -> u8 {
0
}
}
macro_rules! impl_radix_sortable_unsigned {
($($t:ty),*) => {
$(
impl RadixSortable for $t {
type RadixKey = $t;
#[inline]
fn data_type() -> RadixDataType {
RadixDataType::UnsignedInteger
}
#[inline]
fn to_radix_key(value: Self) -> Self::RadixKey {
value
}
#[inline]
fn from_radix_key(key: Self::RadixKey) -> Self {
key
}
#[inline]
fn extract_byte(key: Self::RadixKey, byte_index: usize) -> u8 {
((key as u128) >> (byte_index * 8)) as u8
}
#[inline]
fn key_size() -> usize {
std::mem::size_of::<Self>()
}
}
)*
};
}
impl_radix_sortable_unsigned!(u8, u16, u32, u64, u128, usize);
macro_rules! impl_radix_sortable_signed {
($($t:ty => $u:ty),*) => {
$(
impl RadixSortable for $t {
type RadixKey = $u;
#[inline]
fn data_type() -> RadixDataType {
RadixDataType::SignedInteger
}
#[inline]
fn to_radix_key(value: Self) -> Self::RadixKey {
const SIGN_BIT: $u = 1 << (std::mem::size_of::<$t>() * 8 - 1);
(value as $u) ^ SIGN_BIT
}
#[inline]
fn from_radix_key(key: Self::RadixKey) -> Self {
const SIGN_BIT: $u = 1 << (std::mem::size_of::<$t>() * 8 - 1);
(key ^ SIGN_BIT) as $t
}
#[inline]
fn extract_byte(key: Self::RadixKey, byte_index: usize) -> u8 {
((key as u128) >> (byte_index * 8)) as u8
}
#[inline]
fn key_size() -> usize {
std::mem::size_of::<$u>()
}
}
)*
};
}
impl_radix_sortable_signed!(i8 => u8, i16 => u16, i32 => u32, i64 => u64, i128 => u128, isize => usize);
impl RadixSortable for f32 {
type RadixKey = u32;
#[inline]
fn data_type() -> RadixDataType {
RadixDataType::Float
}
#[inline]
fn to_radix_key(value: Self) -> Self::RadixKey {
let bits = value.to_bits();
if value.is_nan() {
u32::MAX
} else if bits & 0x8000_0000 != 0 {
!bits
} else {
bits ^ 0x8000_0000
}
}
#[inline]
fn from_radix_key(key: Self::RadixKey) -> Self {
if key == u32::MAX {
return f32::NAN;
}
let bits = if key & 0x8000_0000 != 0 {
key ^ 0x8000_0000
} else {
!key
};
f32::from_bits(bits)
}
#[inline]
fn extract_byte(key: Self::RadixKey, byte_index: usize) -> u8 {
((key as u128) >> (byte_index * 8)) as u8
}
#[inline]
fn key_size() -> usize {
std::mem::size_of::<u32>()
}
#[inline]
fn validate(_value: &Self) -> RadixResult<()> {
Ok(())
}
}
impl RadixSortable for f64 {
type RadixKey = u64;
#[inline]
fn data_type() -> RadixDataType {
RadixDataType::Float
}
#[inline]
fn to_radix_key(value: Self) -> Self::RadixKey {
let bits = value.to_bits();
if value.is_nan() {
u64::MAX
} else if bits & 0x8000_0000_0000_0000 != 0 {
!bits
} else {
bits ^ 0x8000_0000_0000_0000
}
}
#[inline]
fn from_radix_key(key: Self::RadixKey) -> Self {
if key == u64::MAX {
return f64::NAN;
}
let bits = if key & 0x8000_0000_0000_0000 != 0 {
key ^ 0x8000_0000_0000_0000
} else {
!key
};
f64::from_bits(bits)
}
#[inline]
fn extract_byte(key: Self::RadixKey, byte_index: usize) -> u8 {
((key as u128) >> (byte_index * 8)) as u8
}
#[inline]
fn key_size() -> usize {
std::mem::size_of::<u64>()
}
#[inline]
fn validate(_value: &Self) -> RadixResult<()> {
Ok(())
}
}
impl RadixSortable for String {
type RadixKey = u8;
#[inline]
fn data_type() -> RadixDataType {
RadixDataType::String
}
#[inline]
fn to_radix_key(value: Self) -> Self::RadixKey {
value.as_bytes().first().copied().unwrap_or(0)
}
#[inline]
fn from_radix_key(_key: Self::RadixKey) -> Self {
String::new()
}
#[inline]
fn extract_byte(_key: Self::RadixKey, _byte_index: usize) -> u8 {
0
}
#[inline]
fn key_size() -> usize {
1
}
#[inline]
fn string_length(value: &Self) -> usize {
value.len()
}
#[inline]
fn string_byte_at(value: &Self, char_index: usize) -> u8 {
value.as_bytes().get(char_index).copied().unwrap_or(0)
}
}
impl RadixSortable for &str {
type RadixKey = u8;
#[inline]
fn data_type() -> RadixDataType {
RadixDataType::String
}
#[inline]
fn to_radix_key(value: Self) -> Self::RadixKey {
value.as_bytes().first().copied().unwrap_or(0)
}
#[inline]
fn from_radix_key(_key: Self::RadixKey) -> Self {
""
}
#[inline]
fn extract_byte(_key: Self::RadixKey, _byte_index: usize) -> u8 {
0
}
#[inline]
fn key_size() -> usize {
1
}
#[inline]
fn string_length(value: &Self) -> usize {
value.len()
}
#[inline]
fn string_byte_at(value: &Self, char_index: usize) -> u8 {
value.as_bytes().get(char_index).copied().unwrap_or(0)
}
}