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