#![cfg(not(feature = "compact"))]
#![doc(hidden)]
use lexical_util::{
assert::debug_assert_radix,
div128::u128_divrem,
num::{AsPrimitive, UnsignedInteger},
step::u64_step,
};
use crate::decimal::DecimalCount;
#[inline(always)]
pub fn fast_log2<T: UnsignedInteger>(x: T) -> usize {
T::BITS - 1 - (x | T::ONE).leading_zeros() as usize
}
macro_rules! digit_count {
(@2 $x:expr) => {{
digit_log2($x)
}};
(@4 $x:expr) => {{
digit_log4($x)
}};
(@8 $x:expr) => {{
digit_log8($x)
}};
(@16 $x:expr) => {{
digit_log16($x)
}};
(@32 $x:expr) => {{
digit_log32($x)
}};
(@naive $t:ty, $radix:expr, $x:expr) => {{
let radix = $radix as u32;
let radix2 = radix * radix;
let radix4 = radix2 * radix2;
let mut digits = 1;
let mut value = $x;
if <$t>::BITS >= 32 || radix4 < <$t>::MAX.as_u32() {
let radix4 = <$t as AsPrimitive>::from_u32(radix4);
while value >= radix4 {
digits += 4;
value /= radix4;
}
}
if <$t>::BITS >= 16 || radix2 < <$t>::MAX.as_u32() {
let radix2 = <$t as AsPrimitive>::from_u32(radix2);
while value >= radix2 {
digits += 2;
value /= radix2;
}
}
let radix = <$t as AsPrimitive>::from_u32(radix);
while value >= radix {
digits += 1;
value /= radix;
}
digits
}};
}
#[inline(always)]
fn digit_log2<T: UnsignedInteger>(x: T) -> usize {
fast_log2(x) + 1
}
#[inline(always)]
fn digit_log4<T: UnsignedInteger>(x: T) -> usize {
(fast_log2(x) / 2) + 1
}
#[inline(always)]
fn digit_log8<T: UnsignedInteger>(x: T) -> usize {
(fast_log2(x) / 3) + 1
}
#[inline(always)]
fn digit_log16<T: UnsignedInteger>(x: T) -> usize {
(fast_log2(x) / 4) + 1
}
#[inline(always)]
fn digit_log32<T: UnsignedInteger>(x: T) -> usize {
(fast_log2(x) / 5) + 1
}
pub unsafe trait DigitCount: UnsignedInteger + DecimalCount {
#[inline(always)]
fn digit_count(self, radix: u32) -> usize {
assert!((2..=36).contains(&radix), "radix must be >= 2 and <= 36");
match radix {
10 => self.decimal_count(),
2 => digit_count!(@2 self),
4 => digit_count!(@4 self),
8 => digit_count!(@8 self),
16 => digit_count!(@16 self),
32 => digit_count!(@32 self),
_ => digit_count!(@naive Self, radix, self),
}
}
#[inline(always)]
fn slow_digit_count(self, radix: u32) -> usize {
digit_count!(@naive Self, radix, self)
}
}
macro_rules! digit_impl {
($($t:ty)*) => ($(
unsafe impl DigitCount for $t {
}
)*);
}
digit_impl! { u8 u16 usize u32 u64 }
unsafe impl DigitCount for u128 {
#[inline(always)]
fn digit_count(self, radix: u32) -> usize {
debug_assert_radix(radix);
match radix {
10 => self.decimal_count(),
2 => digit_count!(@2 self),
4 => digit_count!(@4 self),
8 => digit_count!(@8 self),
16 => digit_count!(@16 self),
32 => digit_count!(@32 self),
_ => {
if self <= u64::MAX as u128 {
return digit_count!(@naive u64, radix, self as u64);
}
let step = u64_step(radix);
let (value, _) = u128_divrem(self, radix);
let mut count = step;
if value <= u64::MAX as u128 {
count += digit_count!(@naive u64, radix, value as u64);
} else {
let (value, _) = u128_divrem(value, radix);
count += step;
if value != 0 {
count += digit_count!(@naive u64, radix, value as u64);
}
}
count
},
}
}
}