use util::*;
#[cfg(feature = "table")]
#[inline]
fn optimized<T>(mut value: T, radix: T, table: &[u8], buffer: &mut [u8])
-> usize
where T: UnsignedInteger
{
let radix2 = radix * radix;
let radix4 = radix2 * radix2;
let mut iter = buffer.iter_mut().rev();
while value >= radix4 {
let rem = value % radix4;
value /= radix4;
let r1 = (T::TWO * (rem / radix2)).as_usize();
let r2 = (T::TWO * (rem % radix2)).as_usize();
*iter.next().unwrap() = index!(table[r2+1]);
*iter.next().unwrap() = index!(table[r2]);
*iter.next().unwrap() = index!(table[r1+1]);
*iter.next().unwrap() = index!(table[r1]);
}
while value >= radix2 {
let rem = (T::TWO * (value % radix2)).as_usize();
value /= radix2;
*iter.next().unwrap() = index!(table[rem+1]);
*iter.next().unwrap() = index!(table[rem]);
}
if value < radix {
*iter.next().unwrap() = digit_to_char(value);
} else {
let rem = (T::TWO * value).as_usize();
*iter.next().unwrap() = index!(table[rem+1]);
*iter.next().unwrap() = index!(table[rem]);
}
iter.count()
}
#[cfg(not(feature = "table"))]
#[inline]
fn naive<T>(mut value: T, radix: T, buffer: &mut [u8])
-> usize
where T: UnsignedInteger
{
let mut iter = buffer.iter_mut().rev();
while value >= radix {
let rem = (value % radix).as_usize();
value /= radix;
*iter.next().unwrap() = digit_to_char(rem);
}
let rem = (value % radix).as_usize();
*iter.next().unwrap() = digit_to_char(rem);
iter.count()
}
#[inline]
pub(crate) fn forward<T>(value: T, radix: u32, bytes: &mut [u8])
-> usize
where T: UnsignedInteger
{
if value == T::ZERO {
index_mut!(bytes[0] = b'0');
return 1;
}
debug_assert_radix!(radix);
let mut buffer: [u8; BUFFER_SIZE] = explicit_uninitialized();
let count = {
#[cfg(not(feature = "table"))] {
naive(value, as_cast(radix), &mut buffer)
}
#[cfg(all(not(feature = "radix"), feature = "table"))] {
optimized(value, as_cast(radix), &DIGIT_TO_BASE10_SQUARED, &mut buffer)
}
#[cfg(all(feature = "radix", feature = "table"))]{
let table: &[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!(),
};
optimized(value, as_cast(radix), table, &mut buffer)
}
};
debug_assert!(count <= buffer.len());
copy_to_dst(bytes, &index!(buffer[count..]))
}
#[inline]
pub(crate) fn unsigned<Value, UWide>(value: Value, radix: u32, bytes: &mut [u8])
-> usize
where Value: UnsignedInteger,
UWide: UnsignedInteger
{
let v: UWide = as_cast(value);
forward(v, radix, bytes)
}
#[inline]
pub(crate) fn signed<Value, UWide, IWide>(value: Value, radix: u32, bytes: &mut [u8])
-> usize
where Value: SignedInteger,
UWide: UnsignedInteger,
IWide: SignedInteger
{
let v: UWide;
if value < Value::ZERO {
let wide: IWide = as_cast(value);
v = as_cast(wide.wrapping_neg());
index_mut!(bytes[0] = b'-');
forward(v, radix, &mut index_mut!(bytes[1..])) + 1
} else {
v = as_cast(value);
forward(v, radix, bytes)
}
}
macro_rules! wrap_unsigned {
($name:ident, $t:ty, $uwide:ty) => (
#[inline]
fn $name<'a>(value: $t, radix: u8, bytes: &'a mut [u8])
-> usize
{
unsigned::<$t, $uwide>(value, radix.into(), bytes)
}
)
}
wrap_unsigned!(u8toa_impl, u8, u32);
wrap_unsigned!(u16toa_impl, u16, u32);
wrap_unsigned!(u32toa_impl, u32, u32);
wrap_unsigned!(u64toa_impl, u64, u64);
wrap_unsigned!(usizetoa_impl, usize, usize);
#[cfg(has_i128)]
wrap_unsigned!(u128toa_impl, u128, u128);
macro_rules! wrap_signed {
($name:ident, $t:ty, $uwide:ty, $iwide:ty) => (
#[inline]
fn $name<'a>(value: $t, radix: u8, bytes: &'a mut [u8])
-> usize
{
signed::<$t, $uwide, $iwide>(value, radix.into(), bytes)
}
)
}
wrap_signed!(i8toa_impl, i8, u32, i32);
wrap_signed!(i16toa_impl, i16, u32, i32);
wrap_signed!(i32toa_impl, i32, u32, i32);
wrap_signed!(i64toa_impl, i64, u64, i64);
wrap_signed!(isizetoa_impl, isize, usize, isize);
#[cfg(has_i128)]
wrap_signed!(i128toa_impl, i128, u128, i128);
generate_to_range_api!(u8toa_range, u8toa_radix_range, u8, u8toa_impl, MAX_U8_SIZE);
generate_to_range_api!(u16toa_range, u16toa_radix_range, u16, u16toa_impl, MAX_U16_SIZE);
generate_to_range_api!(u32toa_range, u32toa_radix_range, u32, u32toa_impl, MAX_U32_SIZE);
generate_to_range_api!(u64toa_range, u64toa_radix_range, u64, u64toa_impl, MAX_U64_SIZE);
generate_to_range_api!(usizetoa_range, usizetoa_radix_range, usize, usizetoa_impl, MAX_USIZE_SIZE);
generate_to_range_api!(i8toa_range, i8toa_radix_range, i8, i8toa_impl, MAX_I8_SIZE);
generate_to_range_api!(i16toa_range, i16toa_radix_range, i16, i16toa_impl, MAX_I16_SIZE);
generate_to_range_api!(i32toa_range, i32toa_radix_range, i32, i32toa_impl, MAX_I32_SIZE);
generate_to_range_api!(i64toa_range, i64toa_radix_range, i64, i64toa_impl, MAX_I64_SIZE);
generate_to_range_api!(isizetoa_range, isizetoa_radix_range, isize, isizetoa_impl, MAX_ISIZE_SIZE);
#[cfg(has_i128)] generate_to_range_api!(u128toa_range, u128toa_radix_range, u128, u128toa_impl, MAX_U128_SIZE);
#[cfg(has_i128)] generate_to_range_api!(i128toa_range, i128toa_radix_range, i128, i128toa_impl, MAX_I128_SIZE);
generate_to_slice_api!(u8toa_slice, u8toa_radix_slice, u8, u8toa_impl, MAX_U8_SIZE);
generate_to_slice_api!(u16toa_slice, u16toa_radix_slice, u16, u16toa_impl, MAX_U16_SIZE);
generate_to_slice_api!(u32toa_slice, u32toa_radix_slice, u32, u32toa_impl, MAX_U32_SIZE);
generate_to_slice_api!(u64toa_slice, u64toa_radix_slice, u64, u64toa_impl, MAX_U64_SIZE);
generate_to_slice_api!(usizetoa_slice, usizetoa_radix_slice, usize, usizetoa_impl, MAX_USIZE_SIZE);
generate_to_slice_api!(i8toa_slice, i8toa_radix_slice, i8, i8toa_impl, MAX_I8_SIZE);
generate_to_slice_api!(i16toa_slice, i16toa_radix_slice, i16, i16toa_impl, MAX_I16_SIZE);
generate_to_slice_api!(i32toa_slice, i32toa_radix_slice, i32, i32toa_impl, MAX_I32_SIZE);
generate_to_slice_api!(i64toa_slice, i64toa_radix_slice, i64, i64toa_impl, MAX_I64_SIZE);
generate_to_slice_api!(isizetoa_slice, isizetoa_radix_slice, isize, isizetoa_impl, MAX_ISIZE_SIZE);
#[cfg(has_i128)] generate_to_slice_api!(u128toa_slice, u128toa_radix_slice, u128, u128toa_impl, MAX_U128_SIZE);
#[cfg(has_i128)] generate_to_slice_api!(i128toa_slice, i128toa_radix_slice, i128, i128toa_impl, MAX_I128_SIZE);
#[cfg(test)]
mod tests {
use atoi::*;
use util::test::*;
use super::*;
#[test]
fn u8toa_test() {
let mut buffer = new_buffer();
assert_eq!(b"0", u8toa_slice(0, &mut buffer));
assert_eq!(b"1", u8toa_slice(1, &mut buffer));
assert_eq!(b"127", u8toa_slice(127, &mut buffer));
assert_eq!(b"128", u8toa_slice(128, &mut buffer));
assert_eq!(b"255", u8toa_slice(255, &mut buffer));
assert_eq!(b"255", u8toa_slice(-1i8 as u8, &mut buffer));
}
#[test]
fn i8toa_test() {
let mut buffer = new_buffer();
assert_eq!(b"0", i8toa_slice(0, &mut buffer));
assert_eq!(b"1", i8toa_slice(1, &mut buffer));
assert_eq!(b"127", i8toa_slice(127, &mut buffer));
assert_eq!(b"-128", i8toa_slice(128u8 as i8, &mut buffer));
assert_eq!(b"-1", i8toa_slice(255u8 as i8, &mut buffer));
assert_eq!(b"-1", i8toa_slice(-1, &mut buffer));
}
#[test]
fn u16toa_test() {
let mut buffer = new_buffer();
assert_eq!(b"0", u16toa_slice(0, &mut buffer));
assert_eq!(b"1", u16toa_slice(1, &mut buffer));
assert_eq!(b"32767", u16toa_slice(32767, &mut buffer));
assert_eq!(b"32768", u16toa_slice(32768, &mut buffer));
assert_eq!(b"65535", u16toa_slice(65535, &mut buffer));
assert_eq!(b"65535", u16toa_slice(-1i16 as u16, &mut buffer));
}
#[test]
fn i16toa_test() {
let mut buffer = new_buffer();
assert_eq!(b"0", i16toa_slice(0, &mut buffer));
assert_eq!(b"1", i16toa_slice(1, &mut buffer));
assert_eq!(b"32767", i16toa_slice(32767, &mut buffer));
assert_eq!(b"-32768", i16toa_slice(32768u16 as i16, &mut buffer));
assert_eq!(b"-1", i16toa_slice(65535u16 as i16, &mut buffer));
assert_eq!(b"-1", i16toa_slice(-1, &mut buffer));
}
#[test]
fn u32toa_test() {
let mut buffer = new_buffer();
assert_eq!(b"0", u32toa_slice(0, &mut buffer));
assert_eq!(b"1", u32toa_slice(1, &mut buffer));
assert_eq!(b"2147483647", u32toa_slice(2147483647, &mut buffer));
assert_eq!(b"2147483648", u32toa_slice(2147483648, &mut buffer));
assert_eq!(b"4294967295", u32toa_slice(4294967295, &mut buffer));
assert_eq!(b"4294967295", u32toa_slice(-1i32 as u32, &mut buffer));
}
#[test]
fn i32toa_test() {
let mut buffer = new_buffer();
assert_eq!(b"0", i32toa_slice(0, &mut buffer));
assert_eq!(b"1", i32toa_slice(1, &mut buffer));
assert_eq!(b"2147483647", i32toa_slice(2147483647, &mut buffer));
assert_eq!(b"-2147483648", i32toa_slice(2147483648u32 as i32, &mut buffer));
assert_eq!(b"-1", i32toa_slice(4294967295u32 as i32, &mut buffer));
assert_eq!(b"-1", i32toa_slice(-1, &mut buffer));
}
#[test]
fn u64toa_test() {
let mut buffer = new_buffer();
assert_eq!(b"0", u64toa_slice(0, &mut buffer));
assert_eq!(b"1", u64toa_slice(1, &mut buffer));
assert_eq!(b"9223372036854775807", u64toa_slice(9223372036854775807, &mut buffer));
assert_eq!(b"9223372036854775808", u64toa_slice(9223372036854775808, &mut buffer));
assert_eq!(b"18446744073709551615", u64toa_slice(18446744073709551615, &mut buffer));
assert_eq!(b"18446744073709551615", u64toa_slice(-1i64 as u64, &mut buffer));
}
#[test]
fn i64toa_test() {
let mut buffer = new_buffer();
assert_eq!(b"0", i64toa_slice(0, &mut buffer));
assert_eq!(b"1", i64toa_slice(1, &mut buffer));
assert_eq!(b"9223372036854775807", i64toa_slice(9223372036854775807, &mut buffer));
assert_eq!(b"-9223372036854775808", i64toa_slice(9223372036854775808u64 as i64, &mut buffer));
assert_eq!(b"-1", i64toa_slice(18446744073709551615u64 as i64, &mut buffer));
assert_eq!(b"-1", i64toa_slice(-1, &mut buffer));
}
#[cfg(feature = "radix")]
#[test]
fn basen_test() {
let data = [
(2, "100101"),
(3, "1101"),
(4, "211"),
(5, "122"),
(6, "101"),
(7, "52"),
(8, "45"),
(9, "41"),
(10, "37"),
(11, "34"),
(12, "31"),
(13, "2B"),
(14, "29"),
(15, "27"),
(16, "25"),
(17, "23"),
(18, "21"),
(19, "1I"),
(20, "1H"),
(21, "1G"),
(22, "1F"),
(23, "1E"),
(24, "1D"),
(25, "1C"),
(26, "1B"),
(27, "1A"),
(28, "19"),
(29, "18"),
(30, "17"),
(31, "16"),
(32, "15"),
(33, "14"),
(34, "13"),
(35, "12"),
(36, "11"),
];
let mut buffer = new_buffer();
for (base, expected) in data.iter() {
assert_eq!(expected.as_bytes(), i8toa_radix_slice(37, *base, &mut buffer));
}
}
quickcheck! {
fn u8_quickcheck(i: u8) -> bool {
let mut buffer = new_buffer();
i == atou8_slice(u8toa_slice(i, &mut buffer))
}
fn u16_quickcheck(i: u16) -> bool {
let mut buffer = new_buffer();
i == atou16_slice(u16toa_slice(i, &mut buffer))
}
fn u32_quickcheck(i: u32) -> bool {
let mut buffer = new_buffer();
i == atou32_slice(u32toa_slice(i, &mut buffer))
}
fn u64_quickcheck(i: u64) -> bool {
let mut buffer = new_buffer();
i == atou64_slice(u64toa_slice(i, &mut buffer))
}
fn usize_quickcheck(i: usize) -> bool {
let mut buffer = new_buffer();
i == atousize_slice(usizetoa_slice(i, &mut buffer))
}
fn i8_quickcheck(i: i8) -> bool {
let mut buffer = new_buffer();
i == atoi8_slice(i8toa_slice(i, &mut buffer))
}
fn i16_quickcheck(i: i16) -> bool {
let mut buffer = new_buffer();
i == atoi16_slice(i16toa_slice(i, &mut buffer))
}
fn i32_quickcheck(i: i32) -> bool {
let mut buffer = new_buffer();
i == atoi32_slice(i32toa_slice(i, &mut buffer))
}
fn i64_quickcheck(i: i64) -> bool {
let mut buffer = new_buffer();
i == atoi64_slice(i64toa_slice(i, &mut buffer))
}
fn isize_quickcheck(i: isize) -> bool {
let mut buffer = new_buffer();
i == atoisize_slice(isizetoa_slice(i, &mut buffer))
}
}
proptest! {
#[test]
fn u8_proptest(i in u8::min_value()..u8::max_value()) {
let mut buffer = new_buffer();
i == atou8_slice(u8toa_slice(i, &mut buffer))
}
#[test]
fn i8_proptest(i in i8::min_value()..i8::max_value()) {
let mut buffer = new_buffer();
i == atoi8_slice(i8toa_slice(i, &mut buffer))
}
#[test]
fn u16_proptest(i in u16::min_value()..u16::max_value()) {
let mut buffer = new_buffer();
i == atou16_slice(u16toa_slice(i, &mut buffer))
}
#[test]
fn i16_proptest(i in i16::min_value()..i16::max_value()) {
let mut buffer = new_buffer();
i == atoi16_slice(i16toa_slice(i, &mut buffer))
}
#[test]
fn u32_proptest(i in u32::min_value()..u32::max_value()) {
let mut buffer = new_buffer();
i == atou32_slice(u32toa_slice(i, &mut buffer))
}
#[test]
fn i32_proptest(i in i32::min_value()..i32::max_value()) {
let mut buffer = new_buffer();
i == atoi32_slice(i32toa_slice(i, &mut buffer))
}
#[test]
fn u64_proptest(i in u64::min_value()..u64::max_value()) {
let mut buffer = new_buffer();
i == atou64_slice(u64toa_slice(i, &mut buffer))
}
#[test]
fn i64_proptest(i in i64::min_value()..i64::max_value()) {
let mut buffer = new_buffer();
i == atoi64_slice(i64toa_slice(i, &mut buffer))
}
#[test]
fn u128_proptest(i in u128::min_value()..u128::max_value()) {
let mut buffer = new_buffer();
i == atou128_slice(u128toa_slice(i, &mut buffer))
}
#[test]
fn i128_proptest(i in i128::min_value()..i128::max_value()) {
let mut buffer = new_buffer();
i == atoi128_slice(i128toa_slice(i, &mut buffer))
}
#[test]
fn usize_proptest(i in usize::min_value()..usize::max_value()) {
let mut buffer = new_buffer();
i == atousize_slice(usizetoa_slice(i, &mut buffer))
}
#[test]
fn isize_proptest(i in isize::min_value()..isize::max_value()) {
let mut buffer = new_buffer();
i == atoisize_slice(isizetoa_slice(i, &mut buffer))
}
}
#[test]
#[should_panic]
fn i8toa_buffer_test() {
let mut buffer = [b'0'; MAX_I8_SIZE-1];
i8toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn i16toa_buffer_test() {
let mut buffer = [b'0'; MAX_I16_SIZE-1];
i16toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn i32toa_buffer_test() {
let mut buffer = [b'0'; MAX_I32_SIZE-1];
i32toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn i64toa_buffer_test() {
let mut buffer = [b'0'; MAX_I64_SIZE-1];
i64toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn i128toa_buffer_test() {
let mut buffer = [b'0'; MAX_I128_SIZE-1];
i128toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn isizetoa_buffer_test() {
let mut buffer = [b'0'; MAX_ISIZE_SIZE-1];
isizetoa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn u8toa_buffer_test() {
let mut buffer = [b'0'; MAX_U8_SIZE-1];
i8toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn u16toa_buffer_test() {
let mut buffer = [b'0'; MAX_U16_SIZE-1];
i16toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn u32toa_buffer_test() {
let mut buffer = [b'0'; MAX_U32_SIZE-1];
i32toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn u64toa_buffer_test() {
let mut buffer = [b'0'; MAX_U64_SIZE-1];
i64toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn u128toa_buffer_test() {
let mut buffer = [b'0'; MAX_U128_SIZE-1];
i128toa_slice(12, &mut buffer);
}
#[test]
#[should_panic]
fn usizetoa_buffer_test() {
let mut buffer = [b'0'; MAX_USIZE_SIZE-1];
usizetoa_slice(12, &mut buffer);
}
}