use sealed::ptr;
use table::BASEN;
use util::distance;
macro_rules! is_valid_num {
($c:expr, $upper:expr) => ($c >= b'0' && $c <= $upper)
}
macro_rules! is_valid_alnum {
($c:expr, $upper:expr) => ({
let c = $c.to_ascii_uppercase();
is_valid_num!(c, b'9') || (c >= b'A' && c <= $upper)
})
}
macro_rules! atoi_num_impl {
($value:ident, $first:expr, $last:expr, $base:expr, $t:ty, $mul:ident, $add:ident)
=>
({
let base = $base as $t;
let upper = *BASEN.get_unchecked($base as usize - 1);
let mut p = $first;
while p < $last && is_valid_num!(*p, upper) {
$value = $value.$mul(base);
$value = $value.$add((*p - b'0') as $t);
p = p.add(1)
}
p
})
}
macro_rules! atoi_alnum_impl {
($value:ident, $first:expr, $last:expr, $base:expr, $t:ty, $mul:ident, $add:ident)
=>
({
let base = $base as $t;
let upper = *BASEN.get_unchecked($base as usize - 1);
let mut p = $first;
while p < $last && is_valid_alnum!(*p, upper) {
$value = $value.$mul(base);
let c = *p;
p = p.add(1);
if c <= b'9' {
$value = $value.$add((c - b'0') as $t);
} else if c >= b'A' && c <= b'Z' {
$value = $value.$add((c - b'A' + 10) as $t);
} else {
debug_assert!(c >= b'a' && c <= b'z');
$value = $value.$add((c - b'a' + 10) as $t);
}
}
p
})
}
macro_rules! atoi_pointer {
($value:ident, $first:expr, $last:expr, $base:ident, $t:ty, $mul:ident, $add:ident)
=>
({
debug_assert!($base >= 2 && $base <= 36, "Numerical base must be from 2-36");
if $base <= 10 {
atoi_num_impl!($value, $first, $last, $base, $t, $mul, $add)
} else {
atoi_alnum_impl!($value, $first, $last, $base, $t, $mul, $add)
}
});
($value:ident, $first:expr, $last:expr, $base:ident, $t:ty) => (
atoi_pointer!($value, $first, $last, $base, $t, wrapping_mul, wrapping_add)
);
}
macro_rules! atoi_value {
($first:expr, $last:expr, $base:expr, $t:ty, $mul:ident, $add:ident)
=>
({
debug_assert!($base >= 2 && $base <= 36, "Numerical base must be from 2-36");
let mut value: $t = 0;
let base = $base as $t;
let p = atoi_pointer!(value, $first, $last, base, $t, $mul, $add);
(value, p)
});
($first:expr, $last:expr, $base:expr, $t:ty) => (
atoi_value!($first, $last, $base, $t, wrapping_mul, wrapping_add)
);
}
macro_rules! atoi_unsigned {
($first:expr, $last:expr, $base:expr, $t:ty) => ({
if $first == $last {
(0, ptr::null())
} else if *$first == b'+' {
atoi_value!($first.add(1), $last, $base, $t)
} else if *$first == b'-' {
let (value, p) = atoi_value!($first.add(1), $last, $base, $t);
(value.wrapping_neg(), p)
} else {
atoi_value!($first, $last, $base, $t)
}
})
}
macro_rules! atoi_signed {
($first:expr, $last:expr, $base:expr, $t:ty) => ({
if $first == $last {
(0, ptr::null())
} else if *$first == b'+' {
atoi_value!($first.add(1), $last, $base, $t)
} else if *$first == b'-' {
let (value, p) = atoi_value!($first.add(1), $last, $base, $t);
(-value, p)
} else {
atoi_value!($first, $last, $base, $t)
}
})
}
macro_rules! unsigned_unsafe_impl {
($func:ident, $t:ty) => (
#[inline]
pub unsafe extern "C" fn $func(
first: *const u8,
last: *const u8,
base: u8
)
-> ($t, *const u8)
{
atoi_unsigned!(first, last, base, $t)
}
)
}
unsigned_unsafe_impl!(atou8_unsafe, u8);
unsigned_unsafe_impl!(atou16_unsafe, u16);
unsigned_unsafe_impl!(atou32_unsafe, u32);
unsigned_unsafe_impl!(atou64_unsafe, u64);
unsigned_unsafe_impl!(atousize_unsafe, usize);
macro_rules! signed_unsafe_impl {
($func:ident, $t:ty) => (
#[inline]
pub unsafe extern "C" fn $func(
first: *const u8,
last: *const u8,
base: u8
)
-> ($t, *const u8)
{
atoi_signed!(first, last, base, $t)
}
)
}
signed_unsafe_impl!(atoi8_unsafe, i8);
signed_unsafe_impl!(atoi16_unsafe, i16);
signed_unsafe_impl!(atoi32_unsafe, i32);
signed_unsafe_impl!(atoi64_unsafe, i64);
signed_unsafe_impl!(atoisize_unsafe, isize);
bytes_impl!(atou8_bytes, u8, atou8_unsafe);
bytes_impl!(atou16_bytes, u16, atou16_unsafe);
bytes_impl!(atou32_bytes, u32, atou32_unsafe);
bytes_impl!(atou64_bytes, u64, atou64_unsafe);
bytes_impl!(atousize_bytes, usize, atousize_unsafe);
bytes_impl!(atoi8_bytes, i8, atoi8_unsafe);
bytes_impl!(atoi16_bytes, i16, atoi16_unsafe);
bytes_impl!(atoi32_bytes, i32, atoi32_unsafe);
bytes_impl!(atoi64_bytes, i64, atoi64_unsafe);
bytes_impl!(atoisize_bytes, isize, atoisize_unsafe);
try_bytes_impl!(try_atou8_bytes, u8, atou8_unsafe);
try_bytes_impl!(try_atou16_bytes, u16, atou16_unsafe);
try_bytes_impl!(try_atou32_bytes, u32, atou32_unsafe);
try_bytes_impl!(try_atou64_bytes, u64, atou64_unsafe);
try_bytes_impl!(try_atousize_bytes, usize, atousize_unsafe);
try_bytes_impl!(try_atoi8_bytes, i8, atoi8_unsafe);
try_bytes_impl!(try_atoi16_bytes, i16, atoi16_unsafe);
try_bytes_impl!(try_atoi32_bytes, i32, atoi32_unsafe);
try_bytes_impl!(try_atoi64_bytes, i64, atoi64_unsafe);
try_bytes_impl!(try_atoisize_bytes, isize, atoisize_unsafe);
#[cfg(test)]
mod tests {
use super::*;
const DATA: [(u8, &'static str); 35] = [
(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"),
];
#[test]
fn atou8_base10_test() {
assert_eq!(0, atou8_bytes(b"0", 10));
assert_eq!(127, atou8_bytes(b"127", 10));
assert_eq!(128, atou8_bytes(b"128", 10));
assert_eq!(255, atou8_bytes(b"255", 10));
assert_eq!(255, atou8_bytes(b"-1", 10));
assert_eq!(1, atou8_bytes(b"1a", 10));
}
#[test]
fn atou8_basen_test() {
for (b, s) in DATA.iter() {
assert_eq!(atou8_bytes(s.as_bytes(), *b), 37);
}
}
#[test]
fn atoi8_base10_test() {
assert_eq!(0, atoi8_bytes(b"0", 10));
assert_eq!(127, atoi8_bytes(b"127", 10));
assert_eq!(-128, atoi8_bytes(b"128", 10));
assert_eq!(-1, atoi8_bytes(b"255", 10));
assert_eq!(-1, atoi8_bytes(b"-1", 10));
assert_eq!(1, atoi8_bytes(b"1a", 10));
}
#[test]
fn atou16_base10_test() {
assert_eq!(0, atou16_bytes(b"0", 10));
assert_eq!(32767, atou16_bytes(b"32767", 10));
assert_eq!(32768, atou16_bytes(b"32768", 10));
assert_eq!(65535, atou16_bytes(b"65535", 10));
assert_eq!(65535, atou16_bytes(b"-1", 10));
assert_eq!(1, atou16_bytes(b"1a", 10));
}
#[test]
fn atoi16_base10_test() {
assert_eq!(0, atoi16_bytes(b"0", 10));
assert_eq!(32767, atoi16_bytes(b"32767", 10));
assert_eq!(-32768, atoi16_bytes(b"32768", 10));
assert_eq!(-1, atoi16_bytes(b"65535", 10));
assert_eq!(-1, atoi16_bytes(b"-1", 10));
assert_eq!(1, atoi16_bytes(b"1a", 10));
}
#[test]
fn atoi16_basen_test() {
assert_eq!(atoi16_bytes(b"YA", 36), 1234);
}
#[test]
fn atou32_base10_test() {
assert_eq!(0, atou32_bytes(b"0", 10));
assert_eq!(2147483647, atou32_bytes(b"2147483647", 10));
assert_eq!(2147483648, atou32_bytes(b"2147483648", 10));
assert_eq!(4294967295, atou32_bytes(b"4294967295", 10));
assert_eq!(4294967295, atou32_bytes(b"-1", 10));
assert_eq!(1, atou32_bytes(b"1a", 10));
}
#[test]
fn atoi32_base10_test() {
assert_eq!(0, atoi32_bytes(b"0", 10));
assert_eq!(2147483647, atoi32_bytes(b"2147483647", 10));
assert_eq!(-2147483648, atoi32_bytes(b"2147483648", 10));
assert_eq!(-1, atoi32_bytes(b"4294967295", 10));
assert_eq!(-1, atoi32_bytes(b"-1", 10));
assert_eq!(1, atoi32_bytes(b"1a", 10));
}
#[test]
fn atou64_base10_test() {
assert_eq!(0, atou64_bytes(b"0", 10));
assert_eq!(9223372036854775807, atou64_bytes(b"9223372036854775807", 10));
assert_eq!(9223372036854775808, atou64_bytes(b"9223372036854775808", 10));
assert_eq!(18446744073709551615, atou64_bytes(b"18446744073709551615", 10));
assert_eq!(18446744073709551615, atou64_bytes(b"-1", 10));
assert_eq!(1, atou64_bytes(b"1a", 10));
}
#[test]
fn atoi64_base10_test() {
assert_eq!(0, atoi64_bytes(b"0", 10));
assert_eq!(9223372036854775807, atoi64_bytes(b"9223372036854775807", 10));
assert_eq!(-9223372036854775808, atoi64_bytes(b"9223372036854775808", 10));
assert_eq!(-1, atoi64_bytes(b"18446744073709551615", 10));
assert_eq!(-1, atoi64_bytes(b"-1", 10));
assert_eq!(1, atoi64_bytes(b"1a", 10));
}
#[test]
fn try_atou8_base10_test() {
assert_eq!(Err(0), try_atou8_bytes(b"", 10));
assert_eq!(Ok(0), try_atou8_bytes(b"0", 10));
assert_eq!(Err(1), try_atou8_bytes(b"1a", 10));
}
#[test]
fn try_atoi8_base10_test() {
assert_eq!(Err(0), try_atoi8_bytes(b"", 10));
assert_eq!(Ok(0), try_atoi8_bytes(b"0", 10));
assert_eq!(Err(1), try_atoi8_bytes(b"1a", 10));
}
#[test]
fn try_atou16_base10_test() {
assert_eq!(Err(0), try_atou16_bytes(b"", 10));
assert_eq!(Ok(0), try_atou16_bytes(b"0", 10));
assert_eq!(Err(1), try_atou16_bytes(b"1a", 10));
}
#[test]
fn try_atoi16_base10_test() {
assert_eq!(Err(0), try_atoi16_bytes(b"", 10));
assert_eq!(Ok(0), try_atoi16_bytes(b"0", 10));
assert_eq!(Err(1), try_atoi16_bytes(b"1a", 10));
}
#[test]
fn try_atou32_base10_test() {
assert_eq!(Err(0), try_atou32_bytes(b"", 10));
assert_eq!(Ok(0), try_atou32_bytes(b"0", 10));
assert_eq!(Err(1), try_atou32_bytes(b"1a", 10));
}
#[test]
fn try_atoi32_base10_test() {
assert_eq!(Err(0), try_atoi32_bytes(b"", 10));
assert_eq!(Ok(0), try_atoi32_bytes(b"0", 10));
assert_eq!(Err(1), try_atoi32_bytes(b"1a", 10));
}
#[test]
fn try_atou64_base10_test() {
assert_eq!(Err(0), try_atou64_bytes(b"", 10));
assert_eq!(Ok(0), try_atou64_bytes(b"0", 10));
assert_eq!(Err(1), try_atou64_bytes(b"1a", 10));
}
#[test]
fn try_atoi64_base10_test() {
assert_eq!(Err(0), try_atoi64_bytes(b"", 10));
assert_eq!(Ok(0), try_atoi64_bytes(b"0", 10));
assert_eq!(Err(1), try_atoi64_bytes(b"1a", 10));
}
}