use core::ptr;
pub(crate) const MAX_OUTPUT_STRING_LENGTH: usize = 25;
#[rustfmt::skip]
static RADIX_100_TABLE: [u8; 200] = [
b'0', b'0', b'0', b'1', b'0', b'2', b'0', b'3', b'0', b'4',
b'0', b'5', b'0', b'6', b'0', b'7', b'0', b'8', b'0', b'9',
b'1', b'0', b'1', b'1', b'1', b'2', b'1', b'3', b'1', b'4',
b'1', b'5', b'1', b'6', b'1', b'7', b'1', b'8', b'1', b'9',
b'2', b'0', b'2', b'1', b'2', b'2', b'2', b'3', b'2', b'4',
b'2', b'5', b'2', b'6', b'2', b'7', b'2', b'8', b'2', b'9',
b'3', b'0', b'3', b'1', b'3', b'2', b'3', b'3', b'3', b'4',
b'3', b'5', b'3', b'6', b'3', b'7', b'3', b'8', b'3', b'9',
b'4', b'0', b'4', b'1', b'4', b'2', b'4', b'3', b'4', b'4',
b'4', b'5', b'4', b'6', b'4', b'7', b'4', b'8', b'4', b'9',
b'5', b'0', b'5', b'1', b'5', b'2', b'5', b'3', b'5', b'4',
b'5', b'5', b'5', b'6', b'5', b'7', b'5', b'8', b'5', b'9',
b'6', b'0', b'6', b'1', b'6', b'2', b'6', b'3', b'6', b'4',
b'6', b'5', b'6', b'6', b'6', b'7', b'6', b'8', b'6', b'9',
b'7', b'0', b'7', b'1', b'7', b'2', b'7', b'3', b'7', b'4',
b'7', b'5', b'7', b'6', b'7', b'7', b'7', b'8', b'7', b'9',
b'8', b'0', b'8', b'1', b'8', b'2', b'8', b'3', b'8', b'4',
b'8', b'5', b'8', b'6', b'8', b'7', b'8', b'8', b'8', b'9',
b'9', b'0', b'9', b'1', b'9', b'2', b'9', b'3', b'9', b'4',
b'9', b'5', b'9', b'6', b'9', b'7', b'9', b'8', b'9', b'9',
];
#[rustfmt::skip]
static RADIX_100_HEAD_TABLE: [u8; 200] = [
0x00, 0x00, b'1', 0x00, b'2', 0x00, b'3', 0x00, b'4', 0x00,
b'5', 0x00, b'6', 0x00, b'7', 0x00, b'8', 0x00, b'9', 0x00,
b'1', b'0', b'1', b'1', b'1', b'2', b'1', b'3', b'1', b'4',
b'1', b'5', b'1', b'6', b'1', b'7', b'1', b'8', b'1', b'9',
b'2', b'0', b'2', b'1', b'2', b'2', b'2', b'3', b'2', b'4',
b'2', b'5', b'2', b'6', b'2', b'7', b'2', b'8', b'2', b'9',
b'3', b'0', b'3', b'1', b'3', b'2', b'3', b'3', b'3', b'4',
b'3', b'5', b'3', b'6', b'3', b'7', b'3', b'8', b'3', b'9',
b'4', b'0', b'4', b'1', b'4', b'2', b'4', b'3', b'4', b'4',
b'4', b'5', b'4', b'6', b'4', b'7', b'4', b'8', b'4', b'9',
b'5', b'0', b'5', b'1', b'5', b'2', b'5', b'3', b'5', b'4',
b'5', b'5', b'5', b'6', b'5', b'7', b'5', b'8', b'5', b'9',
b'6', b'0', b'6', b'1', b'6', b'2', b'6', b'3', b'6', b'4',
b'6', b'5', b'6', b'6', b'6', b'7', b'6', b'8', b'6', b'9',
b'7', b'0', b'7', b'1', b'7', b'2', b'7', b'3', b'7', b'4',
b'7', b'5', b'7', b'6', b'7', b'7', b'7', b'8', b'7', b'9',
b'8', b'0', b'8', b'1', b'8', b'2', b'8', b'3', b'8', b'4',
b'8', b'5', b'8', b'6', b'8', b'7', b'8', b'8', b'8', b'9',
b'9', b'0', b'9', b'1', b'9', b'2', b'9', b'3', b'9', b'4',
b'9', b'5', b'9', b'6', b'9', b'7', b'9', b'8', b'9', b'9',
];
pub(crate) unsafe fn to_chars(x: f64, mut buffer: *mut u8) -> *mut u8 {
let br = x.to_bits();
let exponent_bits = crate::extract_exponent_bits(br);
let s = crate::remove_exponent_bits(br, exponent_bits);
if crate::is_nonzero(br) {
if crate::is_negative(s) {
*buffer = b'-';
buffer = buffer.add(1);
}
let result = crate::to_decimal(x);
to_chars_detail(result.significand, result.exponent, buffer)
} else {
*buffer = b'0';
buffer.add(1)
}
}
unsafe fn convert_2_digits(n: u8, buffer: *mut u8) {
debug_assert!(n < 100);
let index = (n as usize) * 2;
ptr::copy_nonoverlapping(RADIX_100_TABLE.as_ptr().add(index), buffer, 2);
}
unsafe fn convert_head_digits(n: u8, buffer: *mut u8) -> u8 {
debug_assert!(n < 100);
let digit_count = 1 + (n >= 10) as u8;
let index = (n as usize) * 2;
ptr::copy_nonoverlapping(
RADIX_100_HEAD_TABLE.as_ptr().add(index),
buffer,
digit_count as usize,
);
digit_count
}
unsafe fn convert_8_digits(n: u32, buffer: *mut u8) {
const K_UINT32_MASK: u64 = u32::MAX as u64;
let mut prod = (n as u64) * 281474978;
prod >>= 16;
prod += 1;
convert_2_digits((prod >> 32) as u8, buffer);
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(2));
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(4));
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(6));
}
unsafe fn convert_up_to_9_digits(n: u32, mut buffer: *mut u8) -> u8 {
const K_UINT32_MASK: u64 = u32::MAX as u64;
if n >= 100_000_000 {
let mut prod = (n as u64) * 1441151882;
prod >>= 25;
let head_digit = (prod >> 32) as u8;
debug_assert!(head_digit < 10);
*buffer = b'0' + head_digit;
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(1));
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(3));
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(5));
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(7));
return 9;
}
if n >= 1_000_000 {
let mut prod = (n as u64) * 281474978;
prod >>= 16;
let head_digits = (prod >> 32) as u8;
let head_digit_count = convert_head_digits(head_digits, buffer);
buffer = buffer.add(head_digit_count as usize);
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer);
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(2));
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(4));
return 6 + head_digit_count;
}
if n >= 10_000 {
let mut prod = (n as u64) * 429497;
let head_digits = (prod >> 32) as u8;
let head_digit_count = convert_head_digits(head_digits, buffer);
buffer = buffer.add(head_digit_count as usize);
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer);
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer.add(2));
return 4 + head_digit_count;
}
if n >= 100 {
let mut prod = (n as u64) * 42949673;
let head_digits = (prod >> 32) as u8;
let head_digit_count = convert_head_digits(head_digits, buffer);
buffer = buffer.add(head_digit_count as usize);
prod = (prod & K_UINT32_MASK) * 100;
convert_2_digits((prod >> 32) as u8, buffer);
return 2 + head_digit_count;
}
convert_head_digits(n as u8, buffer)
}
unsafe fn significand_to_chars(n: u64, buffer: *mut u8) -> u8 {
debug_assert!(n < 99999999999999999);
if n >= 100_000_000 {
let first_block = (n / 100_000_000) as u32;
let second_block = (n % 100_000_000) as u32;
let first_block_digits = convert_up_to_9_digits(first_block, buffer);
convert_8_digits(second_block, buffer.add(first_block_digits as usize));
first_block_digits + 8
} else {
convert_up_to_9_digits(n as u32, buffer)
}
}
unsafe fn add_exponent(exp: i32, mut buffer: *mut u8) -> *mut u8 {
debug_assert!(exp >= 0);
debug_assert!(exp <= 999);
if exp >= 100 {
let d1 = ((exp as u32) * 6554) >> 16;
let d2 = (exp as u32) - 10 * d1;
convert_2_digits(d1 as u8, buffer);
buffer = buffer.add(2);
*buffer = b'0' + d2 as u8;
buffer = buffer.add(1);
} else if exp >= 10 {
convert_2_digits(exp as u8, buffer);
buffer = buffer.add(2);
} else {
*buffer = b'0' + exp as u8;
buffer = buffer.add(1);
}
buffer
}
unsafe fn to_chars_detail(significand: u64, exponent: i32, mut buffer: *mut u8) -> *mut u8 {
let mut decimal_rep = [0u8; 17];
let length = significand_to_chars(significand, decimal_rep.as_mut_ptr()) as i32;
let decimal_point = length as i32 + exponent;
if length <= decimal_point && decimal_point <= 21 {
ptr::copy_nonoverlapping(decimal_rep.as_ptr(), buffer, length as usize);
buffer = buffer.add(length as usize);
for _ in 0..(decimal_point - length) {
*buffer = b'0';
buffer = buffer.add(1);
}
} else if 0 < decimal_point && decimal_point <= 21 {
ptr::copy_nonoverlapping(decimal_rep.as_ptr(), buffer, decimal_point as usize);
buffer = buffer.add(decimal_point as usize);
*buffer = b'.';
buffer = buffer.add(1);
let remaining = length - decimal_point;
ptr::copy_nonoverlapping(
decimal_rep.as_ptr().add(decimal_point as usize),
buffer,
remaining as usize,
);
buffer = buffer.add(remaining as usize);
} else if decimal_point <= 0 && decimal_point > -6 {
ptr::copy_nonoverlapping(b"0.".as_ptr(), buffer, 2);
buffer = buffer.add(2);
for _ in 0..(-decimal_point) {
*buffer = b'0';
buffer = buffer.add(1);
}
ptr::copy_nonoverlapping(decimal_rep.as_ptr(), buffer, length as usize);
buffer = buffer.add(length as usize);
} else {
*buffer = decimal_rep[0];
buffer = buffer.add(1);
if length != 1 {
*buffer = b'.';
buffer = buffer.add(1);
ptr::copy_nonoverlapping(decimal_rep.as_ptr().add(1), buffer, (length - 1) as usize);
buffer = buffer.add((length - 1) as usize);
}
*buffer = b'e';
buffer = buffer.add(1);
let exp = decimal_point - 1;
if exp >= 0 {
*buffer = b'+';
} else {
*buffer = b'-';
}
buffer = buffer.add(1);
buffer = add_exponent(exp.abs(), buffer);
}
buffer
}