16855e09eSopenharmony_ci#[macro_use]
26855e09eSopenharmony_ciextern crate criterion;
36855e09eSopenharmony_ci
46855e09eSopenharmony_ci#[global_allocator]
56855e09eSopenharmony_cistatic ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
66855e09eSopenharmony_ci
76855e09eSopenharmony_ciuse criterion::Criterion;
86855e09eSopenharmony_ciuse nom::{
96855e09eSopenharmony_ci  branch::alt,
106855e09eSopenharmony_ci  character::complete::{char, digit1, one_of, space0},
116855e09eSopenharmony_ci  combinator::map_res,
126855e09eSopenharmony_ci  multi::fold_many0,
136855e09eSopenharmony_ci  sequence::{delimited, pair},
146855e09eSopenharmony_ci  IResult,
156855e09eSopenharmony_ci};
166855e09eSopenharmony_ci
176855e09eSopenharmony_ci// Parser definition
186855e09eSopenharmony_ci
196855e09eSopenharmony_ci// We transform an integer string into a i64, ignoring surrounding whitespaces
206855e09eSopenharmony_ci// We look for a digit suite, and try to convert it.
216855e09eSopenharmony_ci// If there are no digits, we look for a parenthesized expression.
226855e09eSopenharmony_cifn factor(input: &[u8]) -> IResult<&[u8], i64> {
236855e09eSopenharmony_ci  delimited(
246855e09eSopenharmony_ci    space0,
256855e09eSopenharmony_ci    alt((
266855e09eSopenharmony_ci      map_res(digit1, |digits| {
276855e09eSopenharmony_ci        unsafe { std::str::from_utf8_unchecked(digits) }.parse()
286855e09eSopenharmony_ci      }),
296855e09eSopenharmony_ci      delimited(char('('), expr, char(')')),
306855e09eSopenharmony_ci    )),
316855e09eSopenharmony_ci    space0,
326855e09eSopenharmony_ci  )(input)
336855e09eSopenharmony_ci}
346855e09eSopenharmony_ci
356855e09eSopenharmony_ci// We read an initial factor and for each time we find
366855e09eSopenharmony_ci// a * or / operator followed by another factor, we do
376855e09eSopenharmony_ci// the math by folding everything
386855e09eSopenharmony_cifn term(input: &[u8]) -> IResult<&[u8], i64> {
396855e09eSopenharmony_ci  let (input, init) = factor(input)?;
406855e09eSopenharmony_ci  fold_many0(
416855e09eSopenharmony_ci    pair(one_of("*/"), factor),
426855e09eSopenharmony_ci    move || init,
436855e09eSopenharmony_ci    |acc, (op, val)| {
446855e09eSopenharmony_ci      if op == '*' {
456855e09eSopenharmony_ci        acc * val
466855e09eSopenharmony_ci      } else {
476855e09eSopenharmony_ci        acc / val
486855e09eSopenharmony_ci      }
496855e09eSopenharmony_ci    },
506855e09eSopenharmony_ci  )(input)
516855e09eSopenharmony_ci}
526855e09eSopenharmony_ci
536855e09eSopenharmony_cifn expr(input: &[u8]) -> IResult<&[u8], i64> {
546855e09eSopenharmony_ci  let (input, init) = term(input)?;
556855e09eSopenharmony_ci  fold_many0(
566855e09eSopenharmony_ci    pair(one_of("+-"), term),
576855e09eSopenharmony_ci    move || init,
586855e09eSopenharmony_ci    |acc, (op, val)| {
596855e09eSopenharmony_ci      if op == '+' {
606855e09eSopenharmony_ci        acc + val
616855e09eSopenharmony_ci      } else {
626855e09eSopenharmony_ci        acc - val
636855e09eSopenharmony_ci      }
646855e09eSopenharmony_ci    },
656855e09eSopenharmony_ci  )(input)
666855e09eSopenharmony_ci}
676855e09eSopenharmony_ci
686855e09eSopenharmony_ci#[allow(clippy::eq_op, clippy::erasing_op)]
696855e09eSopenharmony_cifn arithmetic(c: &mut Criterion) {
706855e09eSopenharmony_ci  let data = b"  2*2 / ( 5 - 1) + 3 / 4 * (2 - 7 + 567 *12 /2) + 3*(1+2*( 45 /2));";
716855e09eSopenharmony_ci
726855e09eSopenharmony_ci  assert_eq!(
736855e09eSopenharmony_ci    expr(data),
746855e09eSopenharmony_ci    Ok((
756855e09eSopenharmony_ci      &b";"[..],
766855e09eSopenharmony_ci      2 * 2 / (5 - 1) + 3 / 4 * (2 - 7 + 567 * 12 / 2) + 3 * (1 + 2 * (45 / 2)),
776855e09eSopenharmony_ci    ))
786855e09eSopenharmony_ci  );
796855e09eSopenharmony_ci  c.bench_function("arithmetic", |b| {
806855e09eSopenharmony_ci    b.iter(|| expr(data).unwrap());
816855e09eSopenharmony_ci  });
826855e09eSopenharmony_ci}
836855e09eSopenharmony_ci
846855e09eSopenharmony_cicriterion_group!(benches, arithmetic);
856855e09eSopenharmony_cicriterion_main!(benches);
86