use crate::util::*;
use super::shared::*;
perftools_inline!{
#[cfg(feature = "format")]
fn validate_no_leading_zeros<'a>(digits: &[u8], digit_separator: u8, ptr: *const u8)
-> ParseResult<()>
{
let index = distance(digits.as_ptr(), ptr);
let digits = &index!(digits[..index]);
let mut iter = iterate_digits_ignore_separator(digits, digit_separator);
let is_zero = match iter.next() {
Some(&b'+') | Some(&b'-') => false,
Some(&b'0') => true,
_ => return Ok(())
};
match iter.next() {
Some(_) if is_zero => return Err((ErrorCode::InvalidLeadingZeros, digits.as_ptr())),
Some(&b'0') => (),
_ => return Ok(())
}
match iter.next() {
Some(_) => Err((ErrorCode::InvalidLeadingZeros, digits.as_ptr())),
_ => Ok(())
}
}}
macro_rules! parse_digits {
($value:ident, $iter:ident, $radix:ident, $op:ident, $code:ident) => (
while let Some(c) = $iter.next() {
let digit = match to_digit!(*c, $radix) {
Some(v) => v,
None => return Ok(($value, c)),
};
$value = match $value.checked_mul(as_cast($radix)) {
Some(v) => v,
None => return Err((ErrorCode::$code, c)),
};
$value = match $value.$op(as_cast(digit)) {
Some(v) => v,
None => return Err((ErrorCode::$code, c)),
};
}
);
}
perftools_inline_always!{
fn parse_digits<'a, T, Iter>(digits: &[u8], mut iter: Iter, radix: u32, sign: Sign)
-> ParseResult<(T, *const u8)>
where T: Integer,
Iter: AsPtrIterator<'a, u8>
{
let mut value = T::ZERO;
if sign == Sign::Positive {
parse_digits!(value, iter, radix, checked_add, Overflow);
} else {
parse_digits!(value, iter, radix, checked_sub, Underflow);
}
Ok((value, last_ptr(digits)))
}}
perftools_inline_always!{
fn standalone<T>(bytes: &[u8], radix: u32)
-> ParseResult<(T, *const u8)>
where T: Integer
{
let (sign, digits) = parse_sign!(bytes, T::IS_SIGNED, Empty);
let iter = iterate_digits_no_separator(digits, b'\x00');
parse_digits(digits, iter, radix, sign)
}}
perftools_inline_always!{
#[cfg(feature = "format")]
fn standalone_iltc<T>(bytes: &[u8], radix: u32, digit_separator: u8)
-> ParseResult<(T, *const u8)>
where T: Integer
{
let (sign, digits) = parse_sign_lc_separator::<T>(bytes, digit_separator);
if digits.is_empty() {
return Err((ErrorCode::Empty, digits.as_ptr()));
}
let iter = iterate_digits_ignore_separator(digits, digit_separator);
parse_digits(digits, iter, radix, sign)
}}
macro_rules! standalone_atoi_separator {
(
fn $name:ident,
sign => $sign:ident,
consume => $consume:ident
) => (
perftools_inline_always!{
#[cfg(feature = "format")]
fn $name<T>(
bytes: &[u8],
radix: u32,
digit_separator: u8
)
-> ParseResult<(T, *const u8)>
where T: Integer
{
let (sign, digits) = $sign::<T>(bytes, digit_separator);
if digits.is_empty() {
return Err((ErrorCode::Empty, digits.as_ptr()));
}
let leading = $consume(digits, radix, digit_separator).0;
let iter = iterate_digits_ignore_separator(leading, digit_separator);
parse_digits(leading, iter, radix, sign)
}}
);
}
standalone_atoi_separator!(
fn standalone_i,
sign => parse_sign_no_separator,
consume => consume_digits_i
);
standalone_atoi_separator!(
fn standalone_ic,
sign => parse_sign_no_separator,
consume => consume_digits_ic
);
standalone_atoi_separator!(
fn standalone_l,
sign => parse_sign_l_separator,
consume => consume_digits_l
);
standalone_atoi_separator!(
fn standalone_lc,
sign => parse_sign_lc_separator,
consume => consume_digits_lc
);
standalone_atoi_separator!(
fn standalone_t,
sign => parse_sign_no_separator,
consume => consume_digits_t
);
standalone_atoi_separator!(
fn standalone_tc,
sign => parse_sign_no_separator,
consume => consume_digits_tc
);
standalone_atoi_separator!(
fn standalone_il,
sign => parse_sign_l_separator,
consume => consume_digits_il
);
standalone_atoi_separator!(
fn standalone_ilc,
sign => parse_sign_lc_separator,
consume => consume_digits_ilc
);
standalone_atoi_separator!(
fn standalone_it,
sign => parse_sign_no_separator,
consume => consume_digits_it
);
standalone_atoi_separator!(
fn standalone_itc,
sign => parse_sign_no_separator,
consume => consume_digits_itc
);
standalone_atoi_separator!(
fn standalone_lt,
sign => parse_sign_l_separator,
consume => consume_digits_lt
);
standalone_atoi_separator!(
fn standalone_ltc,
sign => parse_sign_lc_separator,
consume => consume_digits_ltc
);
standalone_atoi_separator!(
fn standalone_ilt,
sign => parse_sign_l_separator,
consume => consume_digits_ilt
);
perftools_inline_always!{
pub(crate) fn standalone_no_separator<T>(bytes: &[u8], radix: u32)
-> ParseResult<(T, *const u8)>
where T: Integer
{
standalone(bytes, radix)
}}
perftools_inline_always!{
#[cfg(feature = "format")]
pub(crate) fn standalone_separator<V>(bytes: &[u8], radix: u32, format: NumberFormat)
-> ParseResult<(V, *const u8)>
where V: Integer
{
const I: NumberFormat = NumberFormat::INTEGER_INTERNAL_DIGIT_SEPARATOR;
const L: NumberFormat = NumberFormat::INTEGER_LEADING_DIGIT_SEPARATOR;
const T: NumberFormat = NumberFormat::INTEGER_TRAILING_DIGIT_SEPARATOR;
const C: NumberFormat = NumberFormat::INTEGER_CONSECUTIVE_DIGIT_SEPARATOR;
const IL: NumberFormat = NumberFormat::from_bits_truncate(I.bits() | L.bits());
const IT: NumberFormat = NumberFormat::from_bits_truncate(I.bits() | T.bits());
const LT: NumberFormat = NumberFormat::from_bits_truncate(L.bits() | T.bits());
const ILT: NumberFormat = NumberFormat::from_bits_truncate(IL.bits() | T.bits());
const IC: NumberFormat = NumberFormat::from_bits_truncate(I.bits() | C.bits());
const LC: NumberFormat = NumberFormat::from_bits_truncate(L.bits() | C.bits());
const TC: NumberFormat = NumberFormat::from_bits_truncate(T.bits() | C.bits());
const ILC: NumberFormat = NumberFormat::from_bits_truncate(IL.bits() | C.bits());
const ITC: NumberFormat = NumberFormat::from_bits_truncate(IT.bits() | C.bits());
const LTC: NumberFormat = NumberFormat::from_bits_truncate(LT.bits() | C.bits());
const ILTC: NumberFormat = NumberFormat::from_bits_truncate(ILT.bits() | C.bits());
let digit_separator = format.digit_separator();
let (value, ptr) = match format & NumberFormat::INTEGER_DIGIT_SEPARATOR_FLAG_MASK {
I => standalone_i(bytes, radix, digit_separator),
IC => standalone_ic(bytes, radix, digit_separator),
L => standalone_l(bytes, radix, digit_separator),
LC => standalone_lc(bytes, radix, digit_separator),
T => standalone_t(bytes, radix, digit_separator),
TC => standalone_tc(bytes, radix, digit_separator),
IL => standalone_il(bytes, radix, digit_separator),
ILC => standalone_ilc(bytes, radix, digit_separator),
IT => standalone_it(bytes, radix, digit_separator),
ITC => standalone_itc(bytes, radix, digit_separator),
LT => standalone_lt(bytes, radix, digit_separator),
LTC => standalone_ltc(bytes, radix, digit_separator),
ILT => standalone_ilt(bytes, radix, digit_separator),
ILTC => standalone_iltc(bytes, radix, digit_separator),
_ => standalone(bytes, radix)
}?;
if format.no_integer_leading_zeros() {
validate_no_leading_zeros(bytes, digit_separator, ptr)?;
}
Ok((value, ptr))
}}
perftools_inline_always!{
fn step_u64(radix: u32) -> usize {
u128_divisor(radix).1
}}
macro_rules! add_temporary_128 {
($value:ident, $tmp:ident, $step_power:ident, $ptr:expr, $op:ident, $code:ident) => (
if !$value.is_zero() {
$value = match $value.checked_mul(as_cast($step_power)) {
Some(v) => v,
None => return Err((ErrorCode::$code, $ptr)),
};
}
$value = match $value.$op(as_cast($tmp)) {
Some(v) => v,
None => return Err((ErrorCode::$code, $ptr)),
};
);
}
macro_rules! parse_digits_u128 {
($value:ident, $iter:ident, $radix:ident, $step:ident, $op:ident, $code:ident) => ({
while !$iter.consumed() {
let mut value: u64 = 0;
let mut index = 0;
while index < $step {
if let Some(c) = $iter.next() {
index += 1;
let digit = match to_digit!(*c, $radix) {
Some(v) => v,
None => {
let radix_pow = $radix.as_u64().pow(index.as_u32());
add_temporary_128!($value, value, radix_pow, c, $op, $code);
return Ok(($value, c));
},
};
value *= $radix.as_u64();
value += digit.as_u64();
} else {
break;
}
}
let radix_pow = $radix.as_u64().pow(index.as_u32());
add_temporary_128!($value, value, radix_pow, $iter.as_ptr(), $op, $code);
}
});
}
perftools_inline_always!{
fn parse_digits_128_fast<'a, W, N, Iter>(digits: &[u8], iter: Iter, radix: u32, sign: Sign)
-> ParseResult<(W, *const u8)>
where W: Integer,
N: Integer,
Iter: ConsumedIterator<Item=&'a u8> + AsPtrIterator<'a, u8>
{
let (value, ptr) = parse_digits::<N, _>(digits, iter, radix, sign)?;
Ok((as_cast(value), ptr))
}}
perftools_inline_always!{
fn parse_digits_128_slow<'a, T, Iter>(digits: &[u8], mut iter: Iter, radix: u32, step: usize, sign: Sign)
-> ParseResult<(T, *const u8)>
where T: Integer,
Iter: ConsumedIterator<Item=&'a u8> + AsPtrIterator<'a, u8>
{
let mut value = T::ZERO;
if sign == Sign::Positive {
parse_digits_u128!(value, iter, radix, step, checked_add, Overflow)
} else {
parse_digits_u128!(value, iter, radix, step, checked_sub, Underflow)
}
Ok((value, last_ptr(digits)))
}}
perftools_inline_always!{
fn parse_digits_128<'a, W, N, Iter>(digits: &[u8], iter: Iter, radix: u32, sign: Sign)
-> ParseResult<(W, *const u8)>
where W: Integer,
N: Integer,
Iter: ConsumedIterator<Item=&'a u8> + AsPtrIterator<'a, u8>
{
let step = step_u64(radix);
if digits.len() < step {
parse_digits_128_fast::<W, N, _>(digits, iter, radix, sign)
} else {
parse_digits_128_slow(digits, iter, radix, step, sign)
}
}}
perftools_inline_always!{
fn standalone_128<W, N>(bytes: &[u8], radix: u32)
-> ParseResult<(W, *const u8)>
where W: Integer,
N: Integer
{
let (sign, digits) = parse_sign!(bytes, W::IS_SIGNED, Empty);
let iter = iterate_digits_no_separator(digits, b'\x00');
parse_digits_128::<W, N, _>(digits, iter, radix, sign)
}}
perftools_inline_always!{
#[cfg(feature = "format")]
fn standalone_128_iltc<W, N>(bytes: &[u8], radix: u32, digit_separator: u8)
-> ParseResult<(W, *const u8)>
where W: Integer,
N: Integer
{
let (sign, digits) = parse_sign_lc_separator::<W>(bytes, digit_separator);
if digits.is_empty() {
return Err((ErrorCode::Empty, digits.as_ptr()));
}
let iter = iterate_digits_ignore_separator(digits, digit_separator);
parse_digits_128::<W, N, _>(digits, iter, radix, sign)
}}
macro_rules! standalone_atoi_128_separator {
(
fn $name:ident,
sign => $sign:ident,
consume => $consume:ident
) => (
perftools_inline!{
#[cfg(feature = "format")]
fn $name<W, N>(
bytes: &[u8],
radix: u32,
digit_separator: u8
)
-> ParseResult<(W, *const u8)>
where W: Integer,
N: Integer
{
let (sign, digits) = $sign::<W>(bytes, digit_separator);
if digits.is_empty() {
return Err((ErrorCode::Empty, digits.as_ptr()));
}
let leading = $consume(digits, radix, digit_separator).0;
let iter = iterate_digits_ignore_separator(leading, digit_separator);
parse_digits_128::<W, N, _>(leading, iter, radix, sign)
}}
);
}
standalone_atoi_128_separator!(
fn standalone_128_i,
sign => parse_sign_no_separator,
consume => consume_digits_i
);
standalone_atoi_128_separator!(
fn standalone_128_ic,
sign => parse_sign_no_separator,
consume => consume_digits_ic
);
standalone_atoi_128_separator!(
fn standalone_128_l,
sign => parse_sign_l_separator,
consume => consume_digits_l
);
standalone_atoi_128_separator!(
fn standalone_128_lc,
sign => parse_sign_lc_separator,
consume => consume_digits_lc
);
standalone_atoi_128_separator!(
fn standalone_128_t,
sign => parse_sign_no_separator,
consume => consume_digits_t
);
standalone_atoi_128_separator!(
fn standalone_128_tc,
sign => parse_sign_no_separator,
consume => consume_digits_tc
);
standalone_atoi_128_separator!(
fn standalone_128_il,
sign => parse_sign_l_separator,
consume => consume_digits_il
);
standalone_atoi_128_separator!(
fn standalone_128_ilc,
sign => parse_sign_lc_separator,
consume => consume_digits_ilc
);
standalone_atoi_128_separator!(
fn standalone_128_it,
sign => parse_sign_no_separator,
consume => consume_digits_it
);
standalone_atoi_128_separator!(
fn standalone_128_itc,
sign => parse_sign_no_separator,
consume => consume_digits_itc
);
standalone_atoi_128_separator!(
fn standalone_128_lt,
sign => parse_sign_l_separator,
consume => consume_digits_lt
);
standalone_atoi_128_separator!(
fn standalone_128_ltc,
sign => parse_sign_lc_separator,
consume => consume_digits_ltc
);
standalone_atoi_128_separator!(
fn standalone_128_ilt,
sign => parse_sign_l_separator,
consume => consume_digits_ilt
);
perftools_inline_always!{
pub(crate) fn standalone_128_no_separator<W, N>(bytes: &[u8], radix: u32)
-> ParseResult<(W, *const u8)>
where W: Integer,
N: Integer
{
standalone_128::<W, N>(bytes, radix)
}}
perftools_inline_always!{
#[cfg(feature = "format")]
pub(crate) fn standalone_128_separator<W, N>(bytes: &[u8], radix: u32, format: NumberFormat)
-> ParseResult<(W, *const u8)>
where W: Integer,
N: Integer
{
const I: NumberFormat = NumberFormat::INTEGER_INTERNAL_DIGIT_SEPARATOR;
const L: NumberFormat = NumberFormat::INTEGER_LEADING_DIGIT_SEPARATOR;
const T: NumberFormat = NumberFormat::INTEGER_TRAILING_DIGIT_SEPARATOR;
const C: NumberFormat = NumberFormat::INTEGER_CONSECUTIVE_DIGIT_SEPARATOR;
const IL: NumberFormat = NumberFormat::from_bits_truncate(I.bits() | L.bits());
const IT: NumberFormat = NumberFormat::from_bits_truncate(I.bits() | T.bits());
const LT: NumberFormat = NumberFormat::from_bits_truncate(L.bits() | T.bits());
const ILT: NumberFormat = NumberFormat::from_bits_truncate(IL.bits() | T.bits());
const IC: NumberFormat = NumberFormat::from_bits_truncate(I.bits() | C.bits());
const LC: NumberFormat = NumberFormat::from_bits_truncate(L.bits() | C.bits());
const TC: NumberFormat = NumberFormat::from_bits_truncate(T.bits() | C.bits());
const ILC: NumberFormat = NumberFormat::from_bits_truncate(IL.bits() | C.bits());
const ITC: NumberFormat = NumberFormat::from_bits_truncate(IT.bits() | C.bits());
const LTC: NumberFormat = NumberFormat::from_bits_truncate(LT.bits() | C.bits());
const ILTC: NumberFormat = NumberFormat::from_bits_truncate(ILT.bits() | C.bits());
let digit_separator = format.digit_separator();
let (value, ptr) = match format & NumberFormat::INTEGER_DIGIT_SEPARATOR_FLAG_MASK {
I => standalone_128_i::<W, N>(bytes, radix, digit_separator),
IC => standalone_128_ic::<W, N>(bytes, radix, digit_separator),
L => standalone_128_l::<W, N>(bytes, radix, digit_separator),
LC => standalone_128_lc::<W, N>(bytes, radix, digit_separator),
T => standalone_128_t::<W, N>(bytes, radix, digit_separator),
TC => standalone_128_tc::<W, N>(bytes, radix, digit_separator),
IL => standalone_128_il::<W, N>(bytes, radix, digit_separator),
ILC => standalone_128_ilc::<W, N>(bytes, radix, digit_separator),
IT => standalone_128_it::<W, N>(bytes, radix, digit_separator),
ITC => standalone_128_itc::<W, N>(bytes, radix, digit_separator),
LT => standalone_128_lt::<W, N>(bytes, radix, digit_separator),
LTC => standalone_128_ltc::<W, N>(bytes, radix, digit_separator),
ILT => standalone_128_ilt::<W, N>(bytes, radix, digit_separator),
ILTC => standalone_128_iltc::<W, N>(bytes, radix, digit_separator),
_ => standalone_128::<W, N>(bytes, radix)
}?;
if format.no_integer_leading_zeros() {
validate_no_leading_zeros(bytes, digit_separator, ptr)?;
}
Ok((value, ptr))
}}