#![cfg(not(feature = "compact"))]
#![doc(hidden)]
use crate::algorithm::{algorithm, algorithm_u128};
use crate::table::DIGIT_TO_BASE10_SQUARED;
use lexical_util::format::{RADIX, RADIX_SHIFT, STANDARD};
use lexical_util::num::UnsignedInteger;
#[inline]
pub fn fast_log2<T: UnsignedInteger>(x: T) -> usize {
T::BITS - 1 - (x | T::ONE).leading_zeros() as usize
}
#[inline]
pub fn fast_log10<T: UnsignedInteger>(x: T) -> usize {
let log2 = fast_log2(x);
(log2 * 1233) >> 12
}
#[inline]
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 = unsafe { index_unchecked!(TABLE[fast_log2(x)]) };
let count = (x as u64 + shift) >> 32;
count as usize
}
#[inline]
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 trait DigitCount: UnsignedInteger {
fn digit_count(self) -> usize;
}
macro_rules! digit_count_unimpl {
($($t:ty)*) => ($(
impl DigitCount for $t {
#[inline]
fn digit_count(self) -> usize {
unimplemented!()
}
}
)*)
}
digit_count_unimpl! { u8 u16 usize }
impl DigitCount for u32 {
#[inline]
fn digit_count(self) -> usize {
fast_digit_count(self)
}
}
impl DigitCount for u64 {
#[inline]
fn digit_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)
}
}
impl DigitCount for u128 {
#[inline]
fn digit_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)
}
}
pub trait Decimal: DigitCount {
unsafe fn decimal(self, buffer: &mut [u8]) -> usize;
}
macro_rules! decimal_unimpl {
($($t:ty)*) => ($(
impl Decimal for $t {
#[inline(always)]
unsafe fn decimal(self, _: &mut [u8]) -> usize {
unimplemented!()
}
}
)*);
}
decimal_unimpl! { u8 u16 usize }
macro_rules! decimal_impl {
($($t:ty)*) => ($(
impl Decimal for $t {
#[inline(always)]
unsafe fn decimal(self, buffer: &mut [u8]) -> usize {
let count = self.digit_count();
debug_assert!(count <= buffer.len());
unsafe {
algorithm(self, 10, &DIGIT_TO_BASE10_SQUARED, &mut buffer[..count]);
count
}
}
}
)*);
}
decimal_impl! { u32 u64 }
impl Decimal for u128 {
#[inline(always)]
unsafe fn decimal(self, buffer: &mut [u8]) -> usize {
let count = self.digit_count();
debug_assert!(count <= buffer.len());
unsafe {
algorithm_u128::<{ STANDARD }, { RADIX }, { RADIX_SHIFT }>(
self,
&DIGIT_TO_BASE10_SQUARED,
&mut buffer[..count],
);
count
}
}
}