#![cfg(not(feature = "compact"))]
#![doc(hidden)]
use lexical_util::num::UnsignedInteger;
use crate::digit_count::fast_log2;
use crate::jeaiii;
#[inline(always)]
pub fn fast_log10<T: UnsignedInteger>(x: T) -> usize {
let log2 = fast_log2(x);
(log2 * 1233) >> 12
}
#[inline(always)]
pub fn fast_digit_count(x: u32) -> usize {
const TABLE: [u64; 32] = [
4294967296,
8589934582,
8589934582,
8589934582,
12884901788,
12884901788,
12884901788,
17179868184,
17179868184,
17179868184,
21474826480,
21474826480,
21474826480,
21474826480,
25769703776,
25769703776,
25769703776,
30063771072,
30063771072,
30063771072,
34349738368,
34349738368,
34349738368,
34349738368,
38554705664,
38554705664,
38554705664,
41949672960,
41949672960,
41949672960,
42949672960,
42949672960,
];
let shift = TABLE[fast_log2(x)];
let count = (x as u64 + shift) >> 32;
count as usize
}
#[inline(always)]
pub fn fallback_digit_count<T: UnsignedInteger>(x: T, table: &[T]) -> usize {
let log10 = fast_log10(x);
let shift_up = table.get(log10).map_or(false, |&y| x >= y);
log10 + shift_up as usize + 1
}
pub unsafe trait DecimalCount: UnsignedInteger {
fn decimal_count(self) -> usize;
}
unsafe impl DecimalCount for u8 {
#[inline(always)]
fn decimal_count(self) -> usize {
fast_digit_count(self as u32)
}
}
unsafe impl DecimalCount for u16 {
#[inline(always)]
fn decimal_count(self) -> usize {
fast_digit_count(self as u32)
}
}
unsafe impl DecimalCount for u32 {
#[inline(always)]
fn decimal_count(self) -> usize {
fast_digit_count(self)
}
}
unsafe impl DecimalCount for u64 {
#[inline(always)]
fn decimal_count(self) -> usize {
const TABLE: [u64; 19] = [
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
1000000000000000000,
10000000000000000000,
];
fallback_digit_count(self, &TABLE)
}
}
unsafe impl DecimalCount for u128 {
#[inline(always)]
fn decimal_count(self) -> usize {
const TABLE: [u128; 38] = [
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
1000000000000000000,
10000000000000000000,
100000000000000000000,
1000000000000000000000,
10000000000000000000000,
100000000000000000000000,
1000000000000000000000000,
10000000000000000000000000,
100000000000000000000000000,
1000000000000000000000000000,
10000000000000000000000000000,
100000000000000000000000000000,
1000000000000000000000000000000,
10000000000000000000000000000000,
100000000000000000000000000000000,
1000000000000000000000000000000000,
10000000000000000000000000000000000,
100000000000000000000000000000000000,
1000000000000000000000000000000000000,
10000000000000000000000000000000000000,
100000000000000000000000000000000000000,
];
fallback_digit_count(self, &TABLE)
}
}
unsafe impl DecimalCount for usize {
#[inline(always)]
fn decimal_count(self) -> usize {
match Self::BITS {
8 | 16 | 32 => (self as u32).decimal_count(),
64 => (self as u64).decimal_count(),
128 => (self as u128).decimal_count(),
_ => unimplemented!(),
}
}
}
pub trait Decimal: DecimalCount {
fn decimal(self, buffer: &mut [u8]) -> usize;
#[inline(always)]
fn decimal_signed(self, buffer: &mut [u8]) -> usize {
self.decimal(buffer)
}
}
macro_rules! decimal_impl {
($($t:ty; $f:ident)*) => ($(
impl Decimal for $t {
#[inline(always)]
fn decimal(self, buffer: &mut [u8]) -> usize {
jeaiii::$f(self, buffer)
}
}
)*);
}
decimal_impl! {
u8; from_u8
u16; from_u16
u32; from_u32
u128; from_u128
}
impl Decimal for u64 {
#[inline(always)]
fn decimal(self, buffer: &mut [u8]) -> usize {
jeaiii::from_u64(self, buffer)
}
#[inline(always)]
fn decimal_signed(self, buffer: &mut [u8]) -> usize {
jeaiii::from_i64(self, buffer)
}
}
impl Decimal for usize {
#[inline(always)]
fn decimal(self, buffer: &mut [u8]) -> usize {
match usize::BITS {
8 => (self as u8).decimal(buffer),
16 => (self as u16).decimal(buffer),
32 => (self as u32).decimal(buffer),
64 => (self as u64).decimal(buffer),
128 => (self as u128).decimal(buffer),
_ => unimplemented!(),
}
}
#[inline(always)]
fn decimal_signed(self, buffer: &mut [u8]) -> usize {
match usize::BITS {
8 => (self as u8).decimal_signed(buffer),
16 => (self as u16).decimal_signed(buffer),
32 => (self as u32).decimal_signed(buffer),
64 => (self as u64).decimal_signed(buffer),
128 => (self as u128).decimal_signed(buffer),
_ => unimplemented!(),
}
}
}