1#[macro_use]
2extern crate criterion;
3
4#[global_allocator]
5static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
6
7use criterion::Criterion;
8use nom::{
9  branch::alt,
10  character::complete::{char, digit1, one_of, space0},
11  combinator::map_res,
12  multi::fold_many0,
13  sequence::{delimited, pair},
14  IResult,
15};
16
17// Parser definition
18
19// We transform an integer string into a i64, ignoring surrounding whitespaces
20// We look for a digit suite, and try to convert it.
21// If there are no digits, we look for a parenthesized expression.
22fn factor(input: &[u8]) -> IResult<&[u8], i64> {
23  delimited(
24    space0,
25    alt((
26      map_res(digit1, |digits| {
27        unsafe { std::str::from_utf8_unchecked(digits) }.parse()
28      }),
29      delimited(char('('), expr, char(')')),
30    )),
31    space0,
32  )(input)
33}
34
35// We read an initial factor and for each time we find
36// a * or / operator followed by another factor, we do
37// the math by folding everything
38fn term(input: &[u8]) -> IResult<&[u8], i64> {
39  let (input, init) = factor(input)?;
40  fold_many0(
41    pair(one_of("*/"), factor),
42    move || init,
43    |acc, (op, val)| {
44      if op == '*' {
45        acc * val
46      } else {
47        acc / val
48      }
49    },
50  )(input)
51}
52
53fn expr(input: &[u8]) -> IResult<&[u8], i64> {
54  let (input, init) = term(input)?;
55  fold_many0(
56    pair(one_of("+-"), term),
57    move || init,
58    |acc, (op, val)| {
59      if op == '+' {
60        acc + val
61      } else {
62        acc - val
63      }
64    },
65  )(input)
66}
67
68#[allow(clippy::eq_op, clippy::erasing_op)]
69fn arithmetic(c: &mut Criterion) {
70  let data = b"  2*2 / ( 5 - 1) + 3 / 4 * (2 - 7 + 567 *12 /2) + 3*(1+2*( 45 /2));";
71
72  assert_eq!(
73    expr(data),
74    Ok((
75      &b";"[..],
76      2 * 2 / (5 - 1) + 3 / 4 * (2 - 7 + 567 * 12 / 2) + 3 * (1 + 2 * (45 / 2)),
77    ))
78  );
79  c.bench_function("arithmetic", |b| {
80    b.iter(|| expr(data).unwrap());
81  });
82}
83
84criterion_group!(benches, arithmetic);
85criterion_main!(benches);
86