#![warn(clippy::pedantic)]
#![allow(clippy::unreadable_literal)]
#![no_std]
mod tests;
pub trait IntLog {
fn log10(self) -> usize;
fn log2(self) -> usize;
fn checked_log10(self) -> Option<usize>;
fn checked_log2(self) -> Option<usize>;
}
macro_rules! forward_ref_intlog {
($imp:ident, $t:ty) => {
impl $imp for &$t {
#[inline]
fn log10(self) -> usize {
$imp::log10(*self)
}
#[inline]
fn log2(self) -> usize {
$imp::log2(*self)
}
#[inline]
fn checked_log10(self) -> Option<usize> {
$imp::checked_log10(*self)
}
#[inline]
fn checked_log2(self) -> Option<usize> {
$imp::checked_log2(*self)
}
}
}
}
macro_rules! impl_unsigned_log {
($SelfT: ty, $Msb: expr, $ApproxMul: expr, $ApproxShr: expr, $Table: ident) => {
impl IntLog for $SelfT {
#[inline]
fn log10(self) -> usize {
let y = ($ApproxMul * ($Msb - self.leading_zeros() as usize)) >> $ApproxShr;
y + (($Table[y + 1] as $SelfT).wrapping_sub(self) >> $Msb) as usize
}
#[inline]
fn log2(self) -> usize {
$Msb - self.leading_zeros() as usize
}
#[inline]
fn checked_log10(self) -> Option<usize> {
if self > 0 { Some(self.log10()) } else { None }
}
#[inline]
fn checked_log2(self) -> Option<usize> {
if self > 0 { Some(self.log2()) } else { None }
}
}
forward_ref_intlog!(IntLog, $SelfT);
}
}
macro_rules! impl_signed_log {
($SelfT: ty, $UnsignedT: ty) => {
impl IntLog for $SelfT {
#[inline]
fn log10(self) -> usize {
<$UnsignedT>::log10(self as $UnsignedT)
}
#[inline]
fn log2(self) -> usize {
<$UnsignedT>::log2(self as $UnsignedT)
}
#[inline]
fn checked_log10(self) -> Option<usize> {
if self > 0 { Some(<$UnsignedT>::log10(self as $UnsignedT)) } else { None }
}
#[inline]
fn checked_log2(self) -> Option<usize> {
if self > 0 { Some(<$UnsignedT>::log2(self as $UnsignedT)) } else { None }
}
}
forward_ref_intlog!(IntLog, $SelfT);
}
}
const LOG10_U8_TABLE: [u8; 4] = [0, 9, 99, u8::MAX];
impl_unsigned_log! { u8, 7, 19, 6, LOG10_U8_TABLE }
impl_signed_log! { i8, u8 }
const LOG10_U16_TABLE: [u16; 6] = [0, 9, 99, 999, 9999, u16::MAX];
impl_unsigned_log! { u16, 15, 18, 6, LOG10_U16_TABLE }
impl_signed_log! { i16, u16 }
#[cfg(target_pointer_width = "16")]
impl_unsigned_log! { usize, 15, 18, 6, LOG10_U16_TABLE }
#[cfg(target_pointer_width = "16")]
impl_signed_log! { isize, u16 }
const LOG10_U32_TABLE: [u32; 11] = [0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, u32::MAX];
impl_unsigned_log! { u32, 31, 19, 6, LOG10_U32_TABLE }
impl_signed_log! { i32, u32 }
#[cfg(target_pointer_width = "32")]
impl_unsigned_log! { usize, 31, 19, 6, LOG10_U32_TABLE }
#[cfg(target_pointer_width = "32")]
impl_signed_log! { isize, u32 }
const LOG10_U64_TABLE: [u64; 20] = [0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999,
9999999999999999, 99999999999999999, 999999999999999999, 9999999999999999999];
impl_unsigned_log! { u64, 63, 19, 6, LOG10_U64_TABLE }
impl_signed_log! { i64, u64 }
#[cfg(target_pointer_width = "64")]
impl_unsigned_log! { usize, 63, 19, 6, LOG10_U64_TABLE }
#[cfg(target_pointer_width = "64")]
impl_signed_log! { isize, u64 }
const LOG10_U128_TABLE: [u128; 40] = [0, 9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999,
9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999,
9999999999999999, 99999999999999999, 999999999999999999, 9999999999999999999, 99999999999999999999,
999999999999999999999, 9999999999999999999999, 99999999999999999999999, 999999999999999999999999,
9999999999999999999999999, 99999999999999999999999999, 999999999999999999999999999, 9999999999999999999999999999,
99999999999999999999999999999, 999999999999999999999999999999, 9999999999999999999999999999999,
99999999999999999999999999999999, 999999999999999999999999999999999, 9999999999999999999999999999999999,
99999999999999999999999999999999999, 999999999999999999999999999999999999, 9999999999999999999999999999999999999,
99999999999999999999999999999999999999, u128::MAX];
impl_unsigned_log! { u128, 127, 77, 8, LOG10_U128_TABLE }
impl_signed_log! { i128, u128 }