#![cfg(not(feature = "compact"))]
#![doc(hidden)]
use lexical_util::digit::digit_to_char_const;
use lexical_util::div128::fast_u128_divrem;
use crate::table::DIGIT_TO_BASE10_SQUARED;
const LO32: u64 = u32::MAX as u64;
#[inline(always)]
fn next2(prod: &mut u64) -> u32 {
*prod = (*prod & LO32) * 100;
(*prod >> 32) as u32
}
#[inline(always)]
fn u128_divrem_10_10pow10(n: u128) -> (u128, u64) {
fast_u128_divrem(
n,
10000000000,
18889465931478580854784,
10,
73075081866545145910184241635814150983,
31,
)
}
#[inline(always)]
fn div128_rem_1e10(n: u128) -> (u128, u64) {
u128_divrem_10_10pow10(n)
}
macro_rules! i {
($array:ident[$index:expr]) => {
unsafe { *$array.get_unchecked($index) }
};
}
macro_rules! write_n {
(@1 $buffer:ident, $index:expr, $n:expr) => {{
let index = $index;
let digit = digit_to_char_const($n as u32, 10);
$buffer[index] = digit;
index + 1
}};
(@2 $buffer:ident, $index:expr, $r:expr) => {{
let index = $index;
let r = $r as usize;
debug_assert!(r < DIGIT_TO_BASE10_SQUARED.len());
$buffer[index] = i!(DIGIT_TO_BASE10_SQUARED[r]);
$buffer[index + 1] = i!(DIGIT_TO_BASE10_SQUARED[r + 1]);
index + 2
}};
(@2sub $buffer:ident, $index:ident, $r:expr) => {{
$index -= 2;
_ = write_n!(@2 $buffer, $index, $r);
}};
(@4sub $buffer:ident, $index:ident, $value:ident) => {{
let r = $value % 10000;
$value /= 10000;
let r1 = 2 * (r / 100);
let r2 = 2 * (r % 100);
write_n!(@2sub $buffer, $index, r2);
write_n!(@2sub $buffer, $index, r1);
}};
}
macro_rules! print_n {
(@2 $buffer:ident, $index:ident, $prod:ident) => {
$index = write_n!(@2 $buffer, $index, next2(&mut $prod) * 2);
};
(@n $buffer:ident, $index:ident, $n:ident, $magic:expr, $shift:expr, $remaining:expr) => {{
let mut prod = ($n as u64) * $magic;
prod >>= $shift;
let two = (prod >> 32) as u32;
if two < 10 {
$index = write_n!(@1 $buffer, $index, two);
for _ in 0..$remaining {
print_n!(@2 $buffer, $index, prod);
}
} else {
$index = write_n!(@2 $buffer, $index, two * 2);
for _ in 0..$remaining {
print_n!(@2 $buffer, $index, prod);
}
}
$index
}};
}
macro_rules! write_digits {
(@1 $buffer:ident, $n:ident) => {
write_n!(@1 $buffer, 0, $n)
};
(@2 $buffer:ident, $n:ident) => {
write_n!(@2 $buffer, 0, $n * 2)
};
(@3 $buffer:ident, $n:ident) => {{
let mut y = $n as u64 * 42949673u64;
_ = write_n!(@1 $buffer, 0, y >> 32);
write_n!(@2 $buffer, 1, next2(&mut y) * 2)
}};
(@3-4 $buffer:ident, $n:ident) => {{
let mut index = 0;
print_n!(@n $buffer, index, $n, 42949673u64, 0, 1)
}};
(@5 $buffer:ident, $n:ident) => {{
let mut y = $n as u64 * 429497u64;
_ = write_n!(@1 $buffer, 0, y >> 32);
_ = write_n!(@2 $buffer, 1, next2(&mut y) * 2);
write_n!(@2 $buffer, 3, next2(&mut y) * 2)
}};
(@5-6 $buffer:ident, $n:ident) => {{
let mut index = 0;
print_n!(@n $buffer, index, $n, 429497u64, 0, 2)
}};
(@7-8 $buffer:ident, $n:ident) => {{
let mut index = 0;
print_n!(@n $buffer, index, $n, 281474978u64, 16, 3)
}};
(@9 $buffer:ident, $n:ident) => {{
let mut y = ($n as u64) * 1441151882u64;
y >>= 25;
_ = write_n!(@1 $buffer, 0, y >> 32);
_ = write_n!(@2 $buffer, 1, next2(&mut y) * 2);
_ = write_n!(@2 $buffer, 3, next2(&mut y) * 2);
_ = write_n!(@2 $buffer, 5, next2(&mut y) * 2);
write_n!(@2 $buffer, 7, next2(&mut y) * 2)
}};
(@10 $buffer:ident, $n:ident) => {{
let mut y = ($n as u64) * 1441151881u64;
y >>= 25;
_ = write_n!(@2 $buffer, 0, (y >> 32) * 2);
_ = write_n!(@2 $buffer, 2, next2(&mut y) * 2);
_ = write_n!(@2 $buffer, 4, next2(&mut y) * 2);
_ = write_n!(@2 $buffer, 6, next2(&mut y) * 2);
write_n!(@2 $buffer, 8, next2(&mut y) * 2)
}};
(@10u64 $buffer:ident, $n:ident) => {{
let prod = ($n as u128) * 11529215047u128;
let mut y = (prod >> 28) as u64;
_ = write_n!(@2 $buffer, 0, (y >> 32) * 2);
_ = write_n!(@2 $buffer, 2, next2(&mut y) * 2);
_ = write_n!(@2 $buffer, 4, next2(&mut y) * 2);
_ = write_n!(@2 $buffer, 6, next2(&mut y) * 2);
write_n!(@2 $buffer, 8, next2(&mut y) * 2)
}};
(@10alex $buffer:ident, $n:ident, $offset:ident) => {{
let mut value = $n;
let mut index = 10 + $offset;
write_n!(@4sub $buffer, index, value);
write_n!(@4sub $buffer, index, value);
write_n!(@2sub $buffer, index, value * 2);
10 + $offset
}};
}
#[inline(always)]
pub fn from_u8(n: u8, buffer: &mut [u8]) -> usize {
let buffer = &mut buffer[..3];
if n >= 100 {
write_digits!(@3 buffer, n)
} else if n >= 10 {
write_digits!(@2 buffer, n)
} else {
write_digits!(@1 buffer, n)
}
}
#[inline(always)]
pub fn from_u16(n: u16, buffer: &mut [u8]) -> usize {
let buffer = &mut buffer[..5];
if n >= 1_0000 {
write_digits!(@5 buffer, n)
} else if n >= 100 {
write_digits!(@3-4 buffer, n)
} else if n >= 10 {
write_digits!(@2 buffer, n)
} else {
write_digits!(@1 buffer, n)
}
}
#[inline(always)]
#[allow(clippy::collapsible_else_if)] pub fn from_u32(n: u32, buffer: &mut [u8]) -> usize {
let buffer = &mut buffer[..10];
if n < 1_0000 {
if n >= 100 {
write_digits!(@3-4 buffer, n)
} else if n >= 10 {
write_digits!(@2 buffer, n)
} else {
write_digits!(@1 buffer, n)
}
} else if n < 1_0000_0000 {
if n >= 100_0000 {
write_digits!(@7-8 buffer, n)
} else {
write_digits!(@5-6 buffer, n)
}
} else {
if n >= 10_0000_0000 {
write_digits!(@10 buffer, n)
} else {
write_digits!(@9 buffer, n)
}
}
}
#[inline(always)]
#[allow(clippy::collapsible_else_if)] fn from_u64_impl(n: u64, buffer: &mut [u8], is_signed: bool) -> usize {
const FACTOR: u64 = 100_0000_0000;
let buffer = if is_signed {
&mut buffer[..19]
} else {
&mut buffer[..20]
};
if n < 1_0000 {
if n >= 100 {
write_digits!(@3-4 buffer, n)
} else if n >= 10 {
write_digits!(@2 buffer, n)
} else {
write_digits!(@1 buffer, n)
}
} else if n < FACTOR {
if n >= 10_0000_0000 {
write_digits!(@10u64 buffer, n)
} else if n >= 1_0000_0000 {
write_digits!(@9 buffer, n)
} else if n >= 100_0000 {
write_digits!(@7-8 buffer, n)
} else {
write_digits!(@5-6 buffer, n)
}
} else {
let hi = (n / FACTOR) as u32;
let lo = n % FACTOR;
let offset = from_u32(hi, buffer);
write_digits!(@10alex buffer, lo, offset)
}
}
#[inline(always)]
pub fn from_u64(n: u64, buffer: &mut [u8]) -> usize {
from_u64_impl(n, buffer, false)
}
#[inline(always)]
pub fn from_i64(n: u64, buffer: &mut [u8]) -> usize {
debug_assert!(n <= 1000_0000_0000_0000_0000u64);
from_u64_impl(n, buffer, true)
}
#[inline(always)]
#[allow(clippy::collapsible_else_if)] pub fn from_u128(n: u128, buffer: &mut [u8]) -> usize {
let buffer = &mut buffer[..39];
if n < 1_0000 {
if n >= 100 {
write_digits!(@3-4 buffer, n)
} else if n >= 10 {
write_digits!(@2 buffer, n)
} else {
write_digits!(@1 buffer, n)
}
} else if n < 100_0000_0000 {
if n >= 10_0000_0000 {
write_digits!(@10u64 buffer, n)
} else if n >= 1_0000_0000 {
write_digits!(@9 buffer, n)
} else if n >= 100_0000 {
write_digits!(@7-8 buffer, n)
} else {
write_digits!(@5-6 buffer, n)
}
} else {
if n >= 100_0000_0000_0000_0000_0000_0000_0000 {
let (mid, d) = div128_rem_1e10(n);
let (mid, c) = div128_rem_1e10(mid);
let (hi, b) = div128_rem_1e10(mid);
let a = hi as u32;
let mut offset = from_u32(a, buffer);
offset = write_digits!(@10alex buffer, b, offset);
offset = write_digits!(@10alex buffer, c, offset);
write_digits!(@10alex buffer, d, offset)
} else if n >= 1_0000_0000_0000_0000_0000 {
let (mid, lo) = div128_rem_1e10(n);
let (hi, mid) = div128_rem_1e10(mid);
let hi = hi as u64;
let mut offset = from_u64(hi, buffer);
offset = write_digits!(@10alex buffer, mid, offset);
write_digits!(@10alex buffer, lo, offset)
} else {
let (hi, lo) = div128_rem_1e10(n);
let hi = hi as u64;
let offset = from_u64(hi, buffer);
write_digits!(@10alex buffer, lo, offset)
}
}
}