pub trait IntegerKey: sealed::Key {}
pub trait BucketKey: sealed::Bucket {}
pub(super) mod sealed {
pub trait Key: Copy + Ord {
type Bits: Bits + super::IntegerKey;
fn bits(self) -> Self::Bits;
fn distance(self, min: Self) -> u128;
fn offset(self, min: Self) -> usize;
fn nth(min: Self, offset: usize) -> Self;
}
pub trait Bits: Copy + Ord {
const ZERO: Self;
const BITS: u32;
fn or(self, other: Self) -> Self;
fn xor(self, other: Self) -> Self;
fn leading_zeros(self) -> u32;
fn trailing_zeros(self) -> u32;
fn digit(self, shift: u32, mask: usize) -> usize;
fn of(n: usize) -> Self;
fn wrapping_sub(self, other: Self) -> Self;
fn shr(self, shift: u32) -> Self;
fn low64(self) -> u64;
}
pub trait Bucket: Copy {
type Bits: Bits + super::IntegerKey;
const IDENTITY: bool;
const FLOAT: bool;
fn ordered(self) -> Self::Bits;
fn from_ordered(bits: Self::Bits) -> Self;
fn value(bits: Self::Bits) -> f64;
fn value32(bits: Self::Bits) -> f32;
}
}
macro_rules! bits {
($($u:ty),*) => {$(
impl sealed::Bits for $u {
const ZERO: Self = 0;
const BITS: u32 = <$u>::BITS;
#[inline(always)]
fn or(self, other: Self) -> Self {
self | other
}
#[inline(always)]
fn xor(self, other: Self) -> Self {
self ^ other
}
#[inline(always)]
fn leading_zeros(self) -> u32 {
<$u>::leading_zeros(self)
}
#[inline(always)]
fn trailing_zeros(self) -> u32 {
<$u>::trailing_zeros(self)
}
#[inline(always)]
fn digit(self, shift: u32, mask: usize) -> usize {
(self >> shift) as usize & mask
}
#[inline(always)]
fn of(n: usize) -> Self {
n as $u
}
#[inline(always)]
fn wrapping_sub(self, other: Self) -> Self {
<$u>::wrapping_sub(self, other)
}
#[inline(always)]
fn shr(self, shift: u32) -> Self {
self >> shift
}
#[inline(always)]
fn low64(self) -> u64 {
self as u64
}
}
)*};
}
bits!(u8, u16, u32, u64, u128, usize);
macro_rules! integer_key {
($($t:ty => $u:ty, $sign:expr);* $(;)?) => {$(
impl sealed::Key for $t {
type Bits = $u;
#[inline(always)]
fn bits(self) -> $u {
(self as $u) ^ $sign
}
#[inline(always)]
fn distance(self, min: Self) -> u128 {
(self as $u).wrapping_sub(min as $u) as u128
}
#[inline(always)]
fn offset(self, min: Self) -> usize {
(self as $u).wrapping_sub(min as $u) as usize
}
#[inline(always)]
fn nth(min: Self, offset: usize) -> Self {
(min as $u).wrapping_add(offset as $u) as $t
}
}
impl IntegerKey for $t {}
impl sealed::Bucket for $t {
type Bits = $u;
const IDENTITY: bool = {
let sign: $u = $sign;
sign == 0
};
const FLOAT: bool = false;
#[inline(always)]
fn ordered(self) -> $u {
sealed::Key::bits(self)
}
#[inline(always)]
fn from_ordered(bits: $u) -> Self {
(bits ^ $sign) as $t
}
#[inline(always)]
fn value(_: $u) -> f64 {
0.0
}
#[inline(always)]
fn value32(_: $u) -> f32 {
0.0
}
}
impl BucketKey for $t {}
)*};
}
integer_key! {
u8 => u8, 0; u16 => u16, 0; u32 => u32, 0; u64 => u64, 0; u128 => u128, 0;
usize => usize, 0;
i8 => u8, 1 << 7; i16 => u16, 1 << 15; i32 => u32, 1 << 31; i64 => u64, 1 << 63;
i128 => u128, 1 << 127; isize => usize, 1 << (usize::BITS - 1);
}
impl sealed::Key for char {
type Bits = u32;
#[inline(always)]
fn bits(self) -> u32 {
self as u32
}
#[inline(always)]
fn distance(self, min: Self) -> u128 {
u128::from(self as u32 - min as u32)
}
#[inline(always)]
fn offset(self, min: Self) -> usize {
(self as u32).wrapping_sub(min as u32) as usize
}
#[inline(always)]
fn nth(min: Self, offset: usize) -> Self {
char::from_u32((min as u32).wrapping_add(offset as u32)).unwrap_or(min)
}
}
impl IntegerKey for char {}
impl sealed::Bucket for char {
type Bits = u32;
const IDENTITY: bool = true;
const FLOAT: bool = false;
#[inline(always)]
fn ordered(self) -> u32 {
self as u32
}
#[inline(always)]
fn from_ordered(bits: u32) -> Self {
char::from_u32(bits).unwrap_or_default()
}
#[inline(always)]
fn value(_: u32) -> f64 {
0.0
}
#[inline(always)]
fn value32(_: u32) -> f32 {
0.0
}
}
impl BucketKey for char {}
impl sealed::Key for bool {
type Bits = u8;
#[inline(always)]
fn bits(self) -> u8 {
self as u8
}
#[inline(always)]
fn distance(self, min: Self) -> u128 {
u128::from(self as u8 - min as u8)
}
#[inline(always)]
fn offset(self, min: Self) -> usize {
usize::from(self).wrapping_sub(usize::from(min))
}
#[inline(always)]
fn nth(min: Self, offset: usize) -> Self {
usize::from(min) + offset != 0
}
}
impl IntegerKey for bool {}
impl sealed::Bucket for bool {
type Bits = u8;
const IDENTITY: bool = true;
const FLOAT: bool = false;
#[inline(always)]
fn ordered(self) -> u8 {
self as u8
}
#[inline(always)]
fn from_ordered(bits: u8) -> Self {
bits != 0
}
#[inline(always)]
fn value(_: u8) -> f64 {
0.0
}
#[inline(always)]
fn value32(_: u8) -> f32 {
0.0
}
}
impl BucketKey for bool {}
macro_rules! float_key {
($($f:ty => $u:ty, $i:ty);* $(;)?) => {$(
impl sealed::Bucket for $f {
type Bits = $u;
const IDENTITY: bool = false;
const FLOAT: bool = true;
#[inline(always)]
fn ordered(self) -> $u {
let u = self.to_bits();
u ^ ((((u as $i) >> (<$u>::BITS - 1)) as $u) | (1 << (<$u>::BITS - 1)))
}
#[inline(always)]
fn from_ordered(bits: $u) -> Self {
let flip = ((((!bits) as $i) >> (<$u>::BITS - 1)) as $u) | (1 << (<$u>::BITS - 1));
<$f>::from_bits(bits ^ flip)
}
#[inline(always)]
fn value(bits: $u) -> f64 {
f64::from(<Self as sealed::Bucket>::from_ordered(bits))
}
#[inline(always)]
fn value32(bits: $u) -> f32 {
<Self as sealed::Bucket>::from_ordered(bits) as f32
}
}
impl BucketKey for $f {}
)*};
}
float_key! { f32 => u32, i32; f64 => u64, i64 }