use util::*;
macro_rules! generic_algorithm {
($value:ident, $radix:ident, $buffer:ident, $t:tt, $table:ident, $index:ident, $radix2:ident, $radix4:ident) => ({
while $value >= $radix4 {
let r = $value % $radix4;
$value /= $radix4;
let r1 = ($t::TWO * (r / $radix2)).as_usize();
let r2 = ($t::TWO * (r % $radix2)).as_usize();
$index -= 1;
unchecked_index_mut!($buffer[$index] = unchecked_index!($table[r2+1]));
$index -= 1;
unchecked_index_mut!($buffer[$index] = unchecked_index!($table[r2]));
$index -= 1;
unchecked_index_mut!($buffer[$index] = unchecked_index!($table[r1+1]));
$index -= 1;
unchecked_index_mut!($buffer[$index] = unchecked_index!($table[r1]));
}
while $value >= $radix2 {
let r = ($t::TWO * ($value % $radix2)).as_usize();
$value /= $radix2;
$index -= 1;
unchecked_index_mut!($buffer[$index] = unchecked_index!($table[r+1]));
$index -= 1;
unchecked_index_mut!($buffer[$index] = unchecked_index!($table[r]));
}
if $value < $radix {
$index -= 1;
unchecked_index_mut!($buffer[$index] = digit_to_char($value));
} else {
let r = ($t::TWO * $value).as_usize();
$index -= 1;
unchecked_index_mut!($buffer[$index] = unchecked_index!($table[r+1]));
$index -= 1;
unchecked_index_mut!($buffer[$index] = unchecked_index!($table[r]));
}
});
}
perftools_inline!{
#[cfg(feature = "radix")]
fn get_table(radix: u32) -> &'static [u8] {
match radix {
2 => &DIGIT_TO_BASE2_SQUARED,
3 => &DIGIT_TO_BASE3_SQUARED,
4 => &DIGIT_TO_BASE4_SQUARED,
5 => &DIGIT_TO_BASE5_SQUARED,
6 => &DIGIT_TO_BASE6_SQUARED,
7 => &DIGIT_TO_BASE7_SQUARED,
8 => &DIGIT_TO_BASE8_SQUARED,
9 => &DIGIT_TO_BASE9_SQUARED,
10 => &DIGIT_TO_BASE10_SQUARED,
11 => &DIGIT_TO_BASE11_SQUARED,
12 => &DIGIT_TO_BASE12_SQUARED,
13 => &DIGIT_TO_BASE13_SQUARED,
14 => &DIGIT_TO_BASE14_SQUARED,
15 => &DIGIT_TO_BASE15_SQUARED,
16 => &DIGIT_TO_BASE16_SQUARED,
17 => &DIGIT_TO_BASE17_SQUARED,
18 => &DIGIT_TO_BASE18_SQUARED,
19 => &DIGIT_TO_BASE19_SQUARED,
20 => &DIGIT_TO_BASE20_SQUARED,
21 => &DIGIT_TO_BASE21_SQUARED,
22 => &DIGIT_TO_BASE22_SQUARED,
23 => &DIGIT_TO_BASE23_SQUARED,
24 => &DIGIT_TO_BASE24_SQUARED,
25 => &DIGIT_TO_BASE25_SQUARED,
26 => &DIGIT_TO_BASE26_SQUARED,
27 => &DIGIT_TO_BASE27_SQUARED,
28 => &DIGIT_TO_BASE28_SQUARED,
29 => &DIGIT_TO_BASE29_SQUARED,
30 => &DIGIT_TO_BASE30_SQUARED,
31 => &DIGIT_TO_BASE31_SQUARED,
32 => &DIGIT_TO_BASE32_SQUARED,
33 => &DIGIT_TO_BASE33_SQUARED,
34 => &DIGIT_TO_BASE34_SQUARED,
35 => &DIGIT_TO_BASE35_SQUARED,
36 => &DIGIT_TO_BASE36_SQUARED,
_ => unreachable!(),
}
}}
perftools_inline!{
#[cfg(not(feature = "radix"))]
fn get_table(_: u32) -> &'static [u8] {
&DIGIT_TO_BASE10_SQUARED
}}
perftools_inline!{
#[allow(unused_unsafe)]
fn generic<T>(mut value: T, radix: u32, table: &[u8], buffer: &mut [u8])
-> usize
where T: UnsignedInteger
{
let radix: T = as_cast(radix);
let radix2 = radix * radix;
let radix4 = radix2 * radix2;
let mut index = buffer.len();
generic_algorithm!(value, radix, buffer, T, table, index, radix2, radix4);
index
}}
perftools_inline!{
#[cfg(has_i128)]
#[allow(unused_unsafe)]
fn generic_u128(value: u128, radix: u32, table: &[u8], buffer: &mut [u8])
-> usize
{
let (divisor, digits_per_iter, d_cltz) = u128_divisor(radix);
let radix: u64 = as_cast(radix);
let radix2 = radix * radix;
let radix4 = radix2 * radix2;
let mut index = buffer.len();
let mut start_index = index;
let (value, mut low) = u128_divrem(value, divisor, d_cltz);
generic_algorithm!(low, radix, buffer, u64, table, index, radix2, radix4);
if value != 0 {
start_index -= digits_per_iter;
index = index.min(start_index);
let (value, mut mid) = u128_divrem(value, divisor, d_cltz);
generic_algorithm!(mid, radix, buffer, u64, table, index, radix2, radix4);
if value != 0 {
start_index -= digits_per_iter;
index = index.min(start_index);
let mut high = value as u64;
generic_algorithm!(high, radix, buffer, u64, table, index, radix2, radix4);
}
}
index
}}
pub(crate) trait Generic {
fn generic(self, radix: u32, buffer: &mut [u8]) -> usize;
}
macro_rules! generic_impl {
($($t:ty)*) => ($(
impl Generic for $t {
perftools_inline_always!{
fn generic(self, radix: u32, buffer: &mut [u8]) -> usize {
let table = get_table(radix);
generic(self, radix, table, buffer)
}}
}
)*);
}
generic_impl! { u8 u16 u32 u64 usize }
#[cfg(has_i128)]
impl Generic for u128 {
perftools_inline_always!{
fn generic(self, radix: u32, buffer: &mut [u8]) -> usize {
let table = get_table(radix);
generic_u128(self, radix, table, buffer)
}}
}