use super::add::{read, read_small, write};
use super::div::{divide_2by1, reciprocal};
use super::mul::{Operand, Product, to_limbs};
use super::{ByteOrder, Divisor, Number};
use core::fmt;
use core::mem::MaybeUninit;
const DIGITS: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";
const WRITE_SPLIT: usize = 80;
const READ_SPLIT: usize = 220;
const PASSES: usize = 8;
const TEN_19: u64 = 10_000_000_000_000_000_000;
const TEN_19_INVERSE: u64 = (u128::MAX / TEN_19 as u128 - (1 << 64)) as u64;
const STACK_TEXT: usize = 160;
const STACK_BLOCKS: usize = 64;
const READ_PASSES: usize = 6;
const READ_WAVES: usize = 2;
fn block(radix: u32) -> (u64, usize) {
let (mut b, mut k) = (u64::from(radix), 1);
while let Some(next) = b.checked_mul(u64::from(radix)) {
b = next;
k += 1;
}
(b, k)
}
#[track_caller]
fn check_radix(radix: u32) {
assert!(
(2..=36).contains(&radix),
"from_str_radix_int: must lie in the range `[2, 36]` - found {radix}"
);
}
impl Number {
#[track_caller]
pub fn to_str_radix(&self, radix: u32) -> String {
check_radix(radix);
let x = Operand::of(self);
let sign = usize::from(self.negative && x.significant != 0);
let mut out =
Vec::<u8>::with_capacity(digits_bound(x.significant, radix).saturating_add(sign));
unsafe {
let p = out.as_mut_ptr();
*p = b'-';
let n = write_magnitude(x, radix, p.add(sign));
out.set_len(sign + n);
String::from_utf8_unchecked(out)
}
}
#[track_caller]
pub fn from_str_radix(
src: &str,
radix: u32,
byte_order: ByteOrder,
) -> Result<Number, ParseNumberError> {
check_radix(radix);
let bytes = src.as_bytes();
let (negative, digits) = match bytes.first() {
None => return Err(error(NumberErrorKind::Empty)),
Some(b'-') => (true, &bytes[1..]),
Some(b'+') => (false, &bytes[1..]),
Some(_) => (false, bytes),
};
if digits.is_empty() {
return Err(error(NumberErrorKind::InvalidDigit));
}
if radix == 10 {
read_decimal(digits, negative, byte_order)
} else if radix.is_power_of_two() {
read_bits(digits, radix.trailing_zeros(), negative, byte_order)
} else {
read_long(digits, radix, negative, byte_order)
}
.ok_or(error(NumberErrorKind::InvalidDigit))
}
}
#[cold]
fn error(kind: NumberErrorKind) -> ParseNumberError {
ParseNumberError { kind }
}
fn digits_bound(bytes: usize, radix: u32) -> usize {
let bits = 8 * bytes as u64;
let digits = if radix == 10 {
((bits * 1234) >> 12) + 1
} else {
bits / u64::from(31 - radix.leading_zeros()) + 1
};
usize::try_from(digits).unwrap_or(usize::MAX)
}
unsafe fn write_magnitude(x: Operand, radix: u32, dst: *mut u8) -> usize {
unsafe {
if x.significant == 0 {
*dst = b'0';
return 1;
}
if radix.is_power_of_two() {
return write_bits(x, radix.trailing_zeros(), dst);
}
let n = x.significant.div_ceil(8);
if radix == 10 && n <= 2 {
let order = if x.big_endian {
ByteOrder::BigEndian
} else {
ByteOrder::LittleEndian
};
return write_u128(read_small(significant(x), order), dst);
}
if n < WRITE_SPLIT {
let mut u = [MaybeUninit::<u64>::uninit(); WRITE_SPLIT + PASSES];
let u = u.as_mut_ptr().cast::<u64>();
to_limbs(x, u);
return write_limbs(u, n, radix, None, dst);
}
let mut powers = Vec::new();
write_split(le_number(x), radix, None, dst, &mut powers, true)
}
}
unsafe fn significant<'a>(x: Operand) -> &'a [u8] {
let start = if x.big_endian {
x.len - x.significant
} else {
0
};
unsafe { core::slice::from_raw_parts(x.ptr.add(start), x.significant) }
}
unsafe fn le_number(x: Operand) -> Number {
let bytes = unsafe { significant(x) };
let le = if x.big_endian {
bytes.iter().rev().copied().collect()
} else {
bytes.to_vec()
};
Number {
value: le,
negative: false,
byte_order: ByteOrder::LittleEndian,
}
}
#[inline]
unsafe fn write_u64(x: u64, dst: *mut u8) -> usize {
unsafe {
if x >= TEN_19 {
*dst = b'1';
write_block(x - TEN_19, dst.add(1));
20
} else {
write_top(x, dst)
}
}
}
#[inline]
unsafe fn write_u128(x: u128, dst: *mut u8) -> usize {
let (hi, lo) = ((x >> 64) as u64, x as u64);
unsafe {
if hi == 0 {
return write_u64(lo, dst);
}
let (top, hi) = if hi >= TEN_19 {
(1, hi - TEN_19)
} else {
(0, hi)
};
let (q, r) = divide_2by1(hi, lo, TEN_19, TEN_19_INVERSE);
let n = if top == 0 {
write_u64(q, dst)
} else {
let y = (1 << 64) + u128::from(q);
let t = 1 + u64::from(y >= 2 * TEN_19 as u128) + u64::from(y >= 3 * TEN_19 as u128);
*dst = b'0' + t as u8;
write_block((y - u128::from(t) * u128::from(TEN_19)) as u64, dst.add(1));
20
};
write_block(r, dst.add(n));
n + 19
}
}
unsafe fn write_limbs(
u: *mut u64,
n: usize,
radix: u32,
width: Option<usize>,
dst: *mut u8,
) -> usize {
let mut blocks = [MaybeUninit::<u64>::uninit(); 2 * WRITE_SPLIT + PASSES];
let blocks = blocks.as_mut_ptr().cast::<u64>();
unsafe {
let count = if radix == 10 {
decimal_blocks(u, n, blocks)
} else {
let (b, _) = block(radix);
let s = b.leading_zeros();
let base = Base {
s,
d: b << s,
v: reciprocal(b << s),
};
if SELECTS.contains(&radix) {
select_blocks(u, n, base, blocks)
} else {
other_blocks(u, n, base, blocks)
}
};
put_blocks(
core::slice::from_raw_parts(blocks, count),
radix,
width,
dst,
)
}
}
#[derive(Clone, Copy)]
struct Base {
s: u32,
d: u64,
v: u64,
}
unsafe fn decimal_blocks(u: *mut u64, n: usize, blocks: *mut u64) -> usize {
let base = Base {
s: 0,
d: TEN_19,
v: TEN_19_INVERSE,
};
unsafe { divide_blocks::<false>(u, n, base, blocks) }
}
unsafe fn other_blocks(u: *mut u64, n: usize, base: Base, blocks: *mut u64) -> usize {
unsafe { divide_blocks::<false>(u, n, base, blocks) }
}
unsafe fn select_blocks(u: *mut u64, n: usize, base: Base, blocks: *mut u64) -> usize {
unsafe { divide_blocks::<true>(u, n, base, blocks) }
}
const SELECTS: [u32; 5] = [6, 26, 29, 34, 36];
#[inline(always)]
unsafe fn divide_blocks<const SELECT: bool>(
u: *mut u64,
mut n: usize,
base: Base,
blocks: *mut u64,
) -> usize {
let mut count = 0;
unsafe {
while n > 1 {
let out = blocks.add(count);
let (taken, left) = match n - 1 {
1 => (1, group::<1, SELECT>(u, n, base, out)),
2 | 3 => (2, group::<2, SELECT>(u, n, base, out)),
4..=7 => (4, group::<4, SELECT>(u, n, base, out)),
_ => (PASSES, group::<PASSES, SELECT>(u, n, base, out)),
};
count += taken;
n = left;
}
if n == 1 {
let (x, b) = (*u, base.d >> base.s);
*blocks.add(count) = x % b;
*blocks.add(count + 1) = x / b;
count += 2;
}
if count == 0 {
*blocks = 0;
count = 1;
}
while count > 1 && *blocks.add(count - 1) == 0 {
count -= 1;
}
}
count
}
#[inline(always)]
fn step<const SELECT: bool>(r: u64, x: u64, base: Base) -> (u64, u64) {
let (u1, u0) = (r | ((x >> 1) >> (63 - base.s)), x << base.s);
if !SELECT {
return divide_2by1(u1, u0, base.d, base.v);
}
let (d, v) = (base.d, base.v);
let p = (u128::from(v) * u128::from(u1))
.wrapping_add((u128::from(u1.wrapping_add(1)) << 64) | u128::from(u0));
let (q, q0) = ((p >> 64) as u64, p as u64);
let r = u0.wrapping_sub(q.wrapping_mul(d));
let mask = u64::from(r > q0).wrapping_neg();
let (q, r) = (q.wrapping_add(mask), r.wrapping_add(mask & d));
let more = r >= d;
(
q + u64::from(more),
r - (d & u64::from(more).wrapping_neg()),
)
}
#[inline(always)]
unsafe fn group<const K: usize, const SELECT: bool>(
u: *mut u64,
n: usize,
base: Base,
out: *mut u64,
) -> usize {
let mut r = [0u64; K];
let mut c = [0u64; K];
unsafe {
for t in 0..n {
let mut p = K;
while p > 1 {
p -= 1;
let (q, rest) = step::<SELECT>(r[p], c[p - 1], base);
r[p] = rest;
if p == K - 1 {
*u.add(n + K - 2 - t) = q;
} else {
c[p] = q;
}
}
let (q, rest) = step::<SELECT>(r[0], *u.add(n - 1 - t), base);
r[0] = rest;
if K == 1 {
*u.add(n - 1 - t) = q;
} else {
c[0] = q;
}
}
*out = r[0] >> base.s;
for i in 0..K - 1 {
let mut p = K;
while p > i + 1 {
p -= 1;
let (q, rest) = step::<SELECT>(r[p], c[p - 1], base);
r[p] = rest;
if p == K - 1 {
*u.add(K - 2 - i) = q;
} else {
c[p] = q;
}
}
*out.add(i + 1) = r[i + 1] >> base.s;
}
}
let mut len = n;
while len > 0 && unsafe { *u.add(len - 1) } == 0 {
len -= 1;
}
len
}
unsafe fn put_blocks(blocks: &[u64], radix: u32, width: Option<usize>, dst: *mut u8) -> usize {
let (_, k) = block(radix);
let count = blocks.len();
unsafe {
let (total, whole) = match width {
None => {
let top = blocks[count - 1];
let head = if radix == 10 {
write_top(top, dst)
} else {
write_short_top(top, Radix::new(radix), dst)
};
(head + k * (count - 1), count - 1)
}
Some(w) => {
let whole = (w / k).min(count);
let head = w - k * whole;
if head > 0 {
let next = if whole < count { blocks[whole] } else { 0 };
write_partial(next, radix, k, head, dst);
}
(w, whole)
}
};
let mut at = dst.add(total);
if radix == 10 {
for &b in &blocks[..whole] {
at = at.sub(k);
write_block(b, at);
}
} else {
let radix = Radix::new(radix);
let (fours, rest) = blocks[..whole].as_chunks::<4>();
for four in fours {
at = at.sub(4 * k);
write_four(*four, radix, at, k);
}
for &b in rest {
at = at.sub(k);
write_digits(b, radix, at, k);
}
}
total
}
}
unsafe fn write_partial(x: u64, radix: u32, k: usize, n: usize, dst: *mut u8) {
unsafe {
if n <= k {
let mut buffer = [0u8; 64];
if radix == 10 {
write_block(x, buffer.as_mut_ptr());
} else {
write_digits(x, Radix::new(radix), buffer.as_mut_ptr(), k);
}
core::ptr::copy_nonoverlapping(buffer.as_ptr().add(k - n), dst, n);
} else {
core::ptr::write_bytes(dst, b'0', n - k);
write_partial(x, radix, k, k, dst.add(n - k));
}
}
}
unsafe fn write_digits(mut x: u64, radix: Radix, dst: *mut u8, n: usize) {
unsafe {
for i in (0..n).rev() {
let (q, digit) = radix.div_rem(x);
*dst.add(i) = DIGITS[digit as usize];
x = q;
}
}
}
unsafe fn write_four(mut x: [u64; 4], radix: Radix, dst: *mut u8, n: usize) {
unsafe {
for i in (0..n).rev() {
for (j, x) in x.iter_mut().enumerate() {
let (q, digit) = radix.div_rem(*x);
*dst.add((3 - j) * n + i) = DIGITS[digit as usize];
*x = q;
}
}
}
}
unsafe fn write_short_top(mut x: u64, radix: Radix, dst: *mut u8) -> usize {
let mut buffer = [0u8; 64];
let mut i = 64;
loop {
i -= 1;
let (q, digit) = radix.div_rem(x);
buffer[i] = DIGITS[digit as usize];
x = q;
if x == 0 {
break;
}
}
unsafe { core::ptr::copy_nonoverlapping(buffer.as_ptr().add(i), dst, 64 - i) };
64 - i
}
#[derive(Clone, Copy)]
struct Radix {
d: u64,
m: u64,
l: u32,
}
impl Radix {
fn new(d: u32) -> Radix {
let d = u64::from(d);
let l = 64 - (d - 1).leading_zeros();
let m = (((1u128 << l) - u128::from(d)) << 64) / u128::from(d) + 1;
Radix { d, m: m as u64, l }
}
#[inline(always)]
fn div_rem(self, n: u64) -> (u64, u64) {
let t = ((u128::from(self.m) * u128::from(n)) >> 64) as u64;
let q = (t + ((n - t) >> 1)) >> (self.l - 1);
(q, n - q * self.d)
}
}
#[inline(always)]
fn eight_digits(x: u64) -> u64 {
let hi = (x * 109_951_163) >> 40;
let x = hi | ((x - hi * 10_000) << 32);
let q = ((x * 10_486) >> 20) & 0x0000_007F_0000_007F;
let x = q | ((x - q * 100) << 16);
let t = ((x * 103) >> 10) & 0x000F_000F_000F_000F;
t | ((x - t * 10) << 8)
}
#[inline(always)]
unsafe fn write_block(x: u64, dst: *mut u8) {
let (a, b, c) = split_block(x);
let zeros = 0x3030_3030_3030_3030;
unsafe {
write(dst, (three_digits(a) as u32 | 0x0030_3030).to_le_bytes());
write(dst.add(3), (eight_digits(b) | zeros).to_le_bytes());
write(dst.add(11), (eight_digits(c) | zeros).to_le_bytes());
}
}
#[inline(always)]
fn split_block(x: u64) -> (u64, u64, u64) {
let a = x / 10_000_000_000_000_000;
let rest = x - a * 10_000_000_000_000_000;
let b = rest / 100_000_000;
(a, b, rest - b * 100_000_000)
}
#[inline(always)]
fn three_digits(x: u64) -> u64 {
let h = (x * 41) >> 12;
let rest = x - h * 100;
let t = (rest * 103) >> 10;
h | (t << 8) | ((rest - t * 10) << 16)
}
#[inline(always)]
unsafe fn write_top(x: u64, dst: *mut u8) -> usize {
let (a, b, c) = split_block(x);
let (a, b, c) = (three_digits(a), eight_digits(b), eight_digits(c));
let zeros = if a != 0 {
a.trailing_zeros() / 8
} else if b != 0 {
3 + b.trailing_zeros() / 8
} else {
11 + (c | 1 << 56).trailing_zeros() / 8
} as usize;
let mut buffer = [0u8; 24];
let ascii = 0x3030_3030_3030_3030;
let p = buffer.as_mut_ptr();
unsafe {
write(p.add(4), ((a << 8) as u32 | 0x3030_3030).to_le_bytes());
write(p.add(8), (b | ascii).to_le_bytes());
write(p.add(16), (c | ascii).to_le_bytes());
copy_short(dst, p.add(5 + zeros), 19 - zeros);
}
19 - zeros
}
#[inline(always)]
unsafe fn copy_short(dst: *mut u8, src: *const u8, n: usize) {
unsafe {
if n >= 8 {
write::<8>(dst, read(src));
if n > 16 {
write::<8>(dst.add(8), read(src.add(8)));
}
write::<8>(dst.add(n - 8), read(src.add(n - 8)));
} else if n >= 4 {
write::<4>(dst, read(src));
write::<4>(dst.add(n - 4), read(src.add(n - 4)));
} else {
*dst = *src;
*dst.add(n / 2) = *src.add(n / 2);
*dst.add(n - 1) = *src.add(n - 1);
}
}
}
struct Power {
odd: Number,
zeros: usize,
places: usize,
divisor: Option<Divisor>,
}
impl Power {
fn bytes(&self) -> usize {
self.odd.value.len() + self.zeros
}
fn first(b: u64, k: usize) -> Power {
let zeros = (b.trailing_zeros() / 8) as usize;
Power {
odd: Number::new(
(b >> (8 * zeros)).to_le_bytes().to_vec(),
ByteOrder::LittleEndian,
),
zeros,
places: k,
divisor: None,
}
}
fn square(&self) -> Power {
let mut odd = &self.odd * &self.odd;
let more = odd.value.iter().take_while(|&&byte| byte == 0).count();
odd.value.drain(..more);
Power {
odd,
zeros: 2 * self.zeros + more,
places: 2 * self.places,
divisor: None,
}
}
}
fn largest(
powers: &mut Vec<Power>,
b: u64,
k: usize,
fits: impl Fn(usize, usize) -> bool,
) -> usize {
if powers.is_empty() {
powers.push(Power::first(b, k));
}
let mut i = 0;
loop {
if i + 1 == powers.len() {
let p = &powers[i];
if !fits(2 * p.bytes() - 1, 2 * p.places) {
return i;
}
let next = p.square();
powers.push(next);
}
let p = &powers[i + 1];
if !fits(p.bytes(), p.places) {
return i;
}
i += 1;
}
}
unsafe fn write_split(
x: Number,
radix: u32,
width: Option<usize>,
dst: *mut u8,
powers: &mut Vec<Power>,
top: bool,
) -> usize {
let limbs = x.value.len().div_ceil(8);
unsafe {
if limbs < WRITE_SPLIT {
if limbs == 0 || x.value == [0] {
return write_limbs([0; PASSES + 1].as_mut_ptr(), 0, radix, width, dst);
}
let mut u = [MaybeUninit::<u64>::uninit(); WRITE_SPLIT + PASSES];
let u = u.as_mut_ptr().cast::<u64>();
to_limbs(Operand::of(&x), u);
return write_limbs(u, limbs, radix, width, dst);
}
let (b, k) = block(radix);
let half = 8 * (limbs.div_ceil(2) + 1);
let i = largest(powers, b, k, |bytes, _| bytes <= half);
let power = &mut powers[i];
let (zeros, places) = (power.zeros, power.places);
let (q, r) = if x.value.len() > zeros {
let high = Number {
value: x.value[zeros..].to_vec(),
negative: false,
byte_order: ByteOrder::LittleEndian,
};
let (q, r) = if top {
high.div_rem(&power.odd)
} else {
power
.divisor
.get_or_insert_with(|| Divisor::new(&power.odd))
.div_rem(&high)
};
let mut low = x.value;
low.truncate(zeros);
if r.value != [0] {
low.extend_from_slice(&r.value);
}
(q, trimmed(low))
} else {
(Number::new(vec![0], ByteOrder::LittleEndian), x)
};
let n = match width {
None if q.value == [0] => return write_split(r, radix, None, dst, powers, top),
None => write_split(q, radix, None, dst, powers, false),
Some(w) => write_split(q, radix, Some(w - places), dst, powers, false),
};
n + write_split(r, radix, Some(places), dst.add(n), powers, false)
}
}
fn trimmed(mut value: Vec<u8>) -> Number {
while value.len() > 1 && value.last() == Some(&0) {
value.pop();
}
if value.is_empty() {
value.push(0);
}
Number {
value,
negative: false,
byte_order: ByteOrder::LittleEndian,
}
}
unsafe fn write_bits(x: Operand, bits: u32, dst: *mut u8) -> usize {
let bytes = unsafe { significant(x) };
let l = bytes.len();
let from_top =
|i: usize| unsafe { *bytes.get_unchecked(if x.big_endian { i } else { l - 1 - i }) };
let top = from_top(0);
let total = 8 * (l as u64 - 1) + u64::from(8 - top.leading_zeros());
let n = total.div_ceil(u64::from(bits)) as usize;
unsafe {
match bits {
4 => {
let mut at = dst;
if top < 16 {
*at = DIGITS[usize::from(top)];
at = at.add(1);
} else {
write(at, HEX[usize::from(top)]);
at = at.add(2);
}
for i in 1..l {
write(at, HEX[usize::from(from_top(i))]);
at = at.add(2);
}
}
1 => {
let k = 8 - top.leading_zeros() as usize;
for j in 0..k {
*dst.add(j) = b'0' + ((top >> (k - 1 - j)) & 1);
}
for i in 1..l {
write(dst.add(k + 8 * (i - 1)), binary_digits(from_top(i)));
}
}
_ => {
let (mut next, mut j) = match bits {
2 => groups::<2, 1, 4>(from_top, l, n, dst),
3 => groups::<3, 3, 8>(from_top, l, n, dst),
_ => groups::<5, 5, 8>(from_top, l, n, dst),
};
let mask = (1u32 << bits) - 1;
let (mut acc, mut have) = (0u32, 0u32);
while j > 0 {
j -= 1;
if have < bits && next > 0 {
next -= 1;
acc |= u32::from(from_top(next)) << have;
have += 8;
}
*dst.add(j) = DIGITS[(acc & mask) as usize];
acc >>= bits;
have = have.saturating_sub(bits);
}
}
}
}
n
}
#[inline(always)]
unsafe fn groups<const B: u32, const G: usize, const D: usize>(
from_top: impl Fn(usize) -> u8,
l: usize,
n: usize,
dst: *mut u8,
) -> (usize, usize) {
let (mut bytes, mut digits) = (l, n);
while bytes >= G && digits >= D {
let mut v = 0u64;
for t in 0..G {
v |= u64::from(from_top(bytes - 1 - t)) << (8 * t);
}
for t in 0..D {
unsafe {
*dst.add(digits - 1 - t) =
DIGITS[((v >> (B as usize * t)) & ((1 << B) - 1)) as usize]
};
}
bytes -= G;
digits -= D;
}
(bytes, digits)
}
#[inline(always)]
fn binary_digits(byte: u8) -> [u8; 8] {
let spread = (u64::from(byte).wrapping_mul(0x8040_2010_0804_0201) >> 7) & 0x0101_0101_0101_0101;
(spread | 0x3030_3030_3030_3030).to_le_bytes()
}
const HEX: [[u8; 2]; 256] = {
let mut t = [[0; 2]; 256];
let mut i = 0;
while i < 256 {
t[i] = [DIGITS[i >> 4], DIGITS[i & 15]];
i += 1;
}
t
};
const VALUES: [u8; 256] = {
let mut t = [255; 256];
let mut i = 0;
while i < 36 {
t[DIGITS[i] as usize] = i as u8;
t[DIGITS[i].to_ascii_uppercase() as usize] = i as u8;
i += 1;
}
t
};
fn read_bits(text: &[u8], bits: u32, negative: bool, order: ByteOrder) -> Option<Number> {
let start = text.iter().position(|&c| c != b'0').unwrap_or(text.len());
let digits = &text[start..];
let Some(&first) = digits.first() else {
return Some(zero(order));
};
let top = VALUES[usize::from(first)];
if top >> bits != 0 {
return None;
}
let n = digits.len();
let len = (u64::from(bits) * (n as u64 - 1) + u64::from(8 - top.leading_zeros())).div_ceil(8)
as usize;
let mut value = Vec::<u8>::with_capacity(len);
let be = order == ByteOrder::BigEndian;
let out = value.as_mut_ptr();
let mut seen = 0u8;
unsafe {
let put = |j: usize, byte: u8| *out.add(if be { len - 1 - j } else { j }) = byte;
let digit = |i: usize| VALUES[usize::from(*digits.get_unchecked(i))];
if bits == 4 {
let mut j = 0;
let mut i = n;
while i >= 2 {
let (high, low) = (digit(i - 2), digit(i - 1));
seen |= high | low;
put(j, high << 4 | low);
j += 1;
i -= 2;
}
if i == 1 {
put(j, top);
}
} else {
let (mut acc, mut have, mut j) = (0u32, 0u32, 0);
for i in (0..n).rev() {
let v = digit(i);
seen |= v;
acc |= u32::from(v) << have;
have += bits;
if have >= 8 {
put(j, acc as u8);
j += 1;
acc >>= 8;
have -= 8;
}
}
if j < len {
put(j, acc as u8);
}
}
if seen >> bits != 0 {
return None;
}
value.set_len(len);
}
Some(Number {
value,
negative,
byte_order: order,
})
}
fn zero(order: ByteOrder) -> Number {
Number {
value: vec![0],
negative: false,
byte_order: order,
}
}
const ASCII_ZEROS: u64 = 0x3030_3030_3030_3030;
#[inline(always)]
fn not_digits(w: u64) -> u64 {
let high = 0xF0F0_F0F0_F0F0_F0F0;
((w & high) | ((w.wrapping_add(0x0606_0606_0606_0606) & high) >> 4)) ^ 0x3333_3333_3333_3333
}
#[inline(always)]
fn eight_value(w: u64) -> u64 {
let x = w.wrapping_sub(ASCII_ZEROS);
let x = x.wrapping_mul(10).wrapping_add(x >> 8);
let pairs = 0x0000_00FF_0000_00FF;
(x & pairs)
.wrapping_mul(100 + (1_000_000 << 32))
.wrapping_add(((x >> 16) & pairs).wrapping_mul(1 + (10_000 << 32)))
>> 32
}
#[inline(always)]
unsafe fn block_value(p: *const u8) -> (u64, u64) {
let (a, b, c) = unsafe {
(
u64::from_le_bytes(read(p)),
u64::from_le_bytes(read(p.add(8))),
u64::from_le_bytes(read(p.add(11))),
)
};
let low = (c & 0xFFFF_FF00_0000_0000) | 0x0000_0030_3030_3030;
let value = eight_value(a)
.wrapping_mul(100_000_000_000)
.wrapping_add(eight_value(b).wrapping_mul(1000))
.wrapping_add(eight_value(low));
(value, not_digits(a) | not_digits(b) | not_digits(c))
}
#[inline(always)]
unsafe fn head_value(p: *const u8, n: usize) -> (u64, u64) {
let mut buffer = [b'0'; 24];
unsafe {
copy_short(buffer.as_mut_ptr().add(24 - n), p, n);
block_value(buffer.as_ptr().add(5))
}
}
fn read_decimal(text: &[u8], negative: bool, order: ByteOrder) -> Option<Number> {
let n = text.len();
if n <= 38 {
let p = text.as_ptr();
let head = n - 19 * ((n - 1) / 19);
let (x, bad) = unsafe {
let (first, bad) = head_value(p, head);
if n <= 19 {
(u128::from(first), bad)
} else {
let (low, more) = block_value(p.add(head));
(
u128::from(first) * u128::from(TEN_19) + u128::from(low),
bad | more,
)
}
};
return (bad == 0).then(|| small_number(x, negative, order));
}
read_long(text, 10, negative, order)
}
fn read_long(text: &[u8], radix: u32, negative: bool, order: ByteOrder) -> Option<Number> {
let (b, k) = block(radix);
let blocks = text.len().div_ceil(k);
if blocks <= READ_SPLIT {
let mut stack = [MaybeUninit::<u64>::uninit(); STACK_BLOCKS + 1];
let mut heap = Vec::new();
let x = if blocks <= STACK_BLOCKS {
stack.as_mut_ptr().cast::<u64>()
} else {
heap.reserve_exact(blocks + 1);
heap.as_mut_ptr()
};
let len = unsafe { read_blocks(text, radix, b, k, x)? };
return Some(limbs_number(x, len, negative, order));
}
let mut powers = Vec::new();
let x = read_split(text, radix, &mut powers)?;
Some(in_order(x, negative, order))
}
#[inline(always)]
unsafe fn mul_add(x: *mut u64, len: usize, b: u64, v: u64) -> u64 {
let mut carry = v;
unsafe {
for i in 0..len {
let t = u128::from(*x.add(i)) * u128::from(b) + u128::from(carry);
*x.add(i) = t as u64;
carry = (t >> 64) as u64;
}
}
carry
}
fn small_number(x: u128, negative: bool, order: ByteOrder) -> Number {
let limbs = [x as u64, (x >> 64) as u64];
let len = usize::from(x != 0) + usize::from(x >> 64 != 0);
limbs_number(limbs.as_ptr().cast_mut(), len, negative, order)
}
fn limbs_number(x: *mut u64, len: usize, negative: bool, order: ByteOrder) -> Number {
let bytes = if len == 0 {
1
} else {
8 * len - unsafe { *x.add(len - 1) }.leading_zeros() as usize / 8
};
let p = Product {
r: if len == 0 { core::ptr::null() } else { x },
len: bytes,
negative: negative && len != 0,
};
let mut value = Vec::with_capacity(bytes);
unsafe {
p.write(value.as_mut_ptr(), order);
value.set_len(bytes);
}
Number {
value,
negative: p.negative,
byte_order: order,
}
}
fn in_order(mut x: Number, negative: bool, order: ByteOrder) -> Number {
if order == ByteOrder::BigEndian {
x.value.reverse();
}
x.negative = negative && x.value != [0];
x.byte_order = order;
x
}
unsafe fn read_blocks(text: &[u8], radix: u32, b: u64, k: usize, x: *mut u64) -> Option<usize> {
let n = text.len();
let head = n - k * ((n - 1) / k);
let count = (n - head) / k;
let p = text.as_ptr();
let mut bad = 0u64;
let mut value = |at: usize, len: usize| -> u64 {
if radix == 10 {
let (v, more) = unsafe {
if len == 19 {
block_value(p.add(at))
} else {
head_value(p.add(at), len)
}
};
bad |= more;
v
} else {
text[at..at + len].iter().fold(0u64, |acc, &c| {
let v = VALUES[usize::from(c)];
bad |= u64::from(u32::from(v) >= radix);
acc.wrapping_mul(u64::from(radix))
.wrapping_add(u64::from(v))
})
}
};
let first = value(0, head);
let mut len = usize::from(first != 0);
let mut j = 0;
let at = |j: usize| head + k * j;
unsafe {
*x = first;
while j < count {
if len >= READ_WAVES && count - j >= READ_PASSES {
let v: [u64; READ_PASSES] = core::array::from_fn(|i| value(at(j + i), k));
len = mul_add_group(x, len, b, v);
j += READ_PASSES;
} else {
let carry = mul_add(x, len, b, value(at(j), k));
*x.add(len) = carry;
len += usize::from(carry != 0);
j += 1;
}
}
}
(bad == 0).then_some(len)
}
#[inline(always)]
unsafe fn mul_add_group<const K: usize>(x: *mut u64, len: usize, b: u64, v: [u64; K]) -> usize {
let n = len + K - 1;
let mut carry = v;
let mut c = [0u64; K];
unsafe {
let mut wave = |t: usize, from: usize, to: usize| {
let mut p = to;
while p > from {
p -= 1;
let input = if p > 0 {
c[p - 1]
} else if t < len {
*x.add(t)
} else {
0
};
let s = u128::from(input) * u128::from(b) + u128::from(carry[p]);
carry[p] = (s >> 64) as u64;
if p == K - 1 {
*x.add(t - p) = s as u64;
} else {
c[p] = s as u64;
}
}
};
for t in 0..K - 1 {
wave(t, 0, t + 1);
}
for t in K - 1..n {
wave(t, 0, K);
}
for i in 0..K - 1 {
wave(n + i, i + 1, K);
}
*x.add(n) = carry[K - 1];
let mut top = n + 1;
while top > 0 && *x.add(top - 1) == 0 {
top -= 1;
}
top
}
}
fn read_split(text: &[u8], radix: u32, powers: &mut Vec<Power>) -> Option<Number> {
let (b, k) = block(radix);
let blocks = text.len().div_ceil(k);
if blocks <= READ_SPLIT {
let mut x = Vec::<u64>::with_capacity(blocks + 1);
let len = unsafe { read_blocks(text, radix, b, k, x.as_mut_ptr())? };
return Some(limbs_number(
x.as_mut_ptr(),
len,
false,
ByteOrder::LittleEndian,
));
}
let half = text.len() / 2;
let i = largest(powers, b, k, |_, places| places <= half);
let (places, zeros) = (powers[i].places, powers[i].zeros);
let (high, low) = text.split_at(text.len() - places);
let high = read_split(high, radix, powers)?;
let low = read_split(low, radix, powers)?;
let product = &high * &powers[i].odd;
let mut value = low.value;
let sum = if value.len() > zeros {
let above = Number {
value: value[zeros..].to_vec(),
negative: false,
byte_order: ByteOrder::LittleEndian,
};
&product + &above
} else {
product
};
value.resize(zeros, 0);
value.extend_from_slice(&sum.value);
Some(trimmed(value))
}
impl core::str::FromStr for Number {
type Err = ParseNumberError;
#[inline]
fn from_str(src: &str) -> Result<Number, ParseNumberError> {
Number::from_str_radix(src, 10, ByteOrder::LittleEndian)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseNumberError {
kind: NumberErrorKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum NumberErrorKind {
Empty,
InvalidDigit,
}
impl ParseNumberError {
pub fn kind(&self) -> &NumberErrorKind {
&self.kind
}
}
impl fmt::Display for ParseNumberError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.kind {
NumberErrorKind::Empty => "cannot parse integer from empty string",
NumberErrorKind::InvalidDigit => "invalid digit found in string",
}
.fmt(f)
}
}
impl std::error::Error for ParseNumberError {}
fn format(
n: &Number,
radix: u32,
prefix: &str,
upper: bool,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
let x = Operand::of(n);
let bound = digits_bound(x.significant, radix);
let non_negative = !n.negative || x.significant == 0;
let mut stack = [MaybeUninit::<u8>::uninit(); STACK_TEXT];
let mut heap = Vec::new();
let dst = if bound <= STACK_TEXT {
stack.as_mut_ptr().cast::<u8>()
} else {
heap.reserve_exact(bound);
heap.as_mut_ptr()
};
let digits = unsafe {
let len = write_magnitude(x, radix, dst);
let digits = core::slice::from_raw_parts_mut(dst, len);
if upper {
digits.make_ascii_uppercase();
}
core::str::from_utf8_unchecked(digits)
};
f.pad_integral(non_negative, prefix, digits)
}
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format(self, 10, "", false, f)
}
}
impl fmt::LowerHex for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format(self, 16, "0x", false, f)
}
}
impl fmt::UpperHex for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format(self, 16, "0x", true, f)
}
}
impl fmt::Octal for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format(self, 8, "0o", false, f)
}
}
impl fmt::Binary for Number {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format(self, 2, "0b", false, f)
}
}