1#[global_allocator]
2static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
3
4use criterion::*;
5
6use nom::{
7  bytes::complete::take_while,
8  character::complete::{
9    alphanumeric1 as alphanumeric, char, multispace1 as multispace, space1 as space,
10  },
11  combinator::{map, map_res, opt},
12  multi::many0,
13  sequence::{delimited, pair, separated_pair, terminated, tuple},
14  IResult,
15};
16use std::collections::HashMap;
17use std::str;
18
19fn category(i: &[u8]) -> IResult<&[u8], &str> {
20  map_res(
21    delimited(char('['), take_while(|c| c != b']'), char(']')),
22    str::from_utf8,
23  )(i)
24}
25
26fn key_value(i: &[u8]) -> IResult<&[u8], (&str, &str)> {
27  let (i, key) = map_res(alphanumeric, str::from_utf8)(i)?;
28  let (i, _) = tuple((opt(space), char('='), opt(space)))(i)?;
29  let (i, val) = map_res(take_while(|c| c != b'\n' && c != b';'), str::from_utf8)(i)?;
30  let (i, _) = opt(pair(char(';'), take_while(|c| c != b'\n')))(i)?;
31  Ok((i, (key, val)))
32}
33
34fn categories(i: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str>>> {
35  map(
36    many0(separated_pair(
37      category,
38      opt(multispace),
39      map(
40        many0(terminated(key_value, opt(multispace))),
41        |vec: Vec<_>| vec.into_iter().collect(),
42      ),
43    )),
44    |vec: Vec<_>| vec.into_iter().collect(),
45  )(i)
46}
47
48fn bench_ini(c: &mut Criterion) {
49  let str = "[owner]
50name=John Doe
51organization=Acme Widgets Inc.
52
53[database]
54server=192.0.2.62
55port=143
56file=payroll.dat
57\0";
58
59  let mut group = c.benchmark_group("ini");
60  group.throughput(Throughput::Bytes(str.len() as u64));
61  group.bench_function(BenchmarkId::new("parse", str.len()), |b| {
62    b.iter(|| categories(str.as_bytes()).unwrap())
63  });
64}
65
66fn bench_ini_keys_and_values(c: &mut Criterion) {
67  let str = "server=192.0.2.62
68port=143
69file=payroll.dat
70\0";
71
72  fn acc(i: &[u8]) -> IResult<&[u8], Vec<(&str, &str)>> {
73    many0(key_value)(i)
74  }
75
76  let mut group = c.benchmark_group("ini keys and values");
77  group.throughput(Throughput::Bytes(str.len() as u64));
78  group.bench_function(BenchmarkId::new("parse", str.len()), |b| {
79    b.iter(|| acc(str.as_bytes()).unwrap())
80  });
81}
82
83fn bench_ini_key_value(c: &mut Criterion) {
84  let str = "server=192.0.2.62\n";
85
86  let mut group = c.benchmark_group("ini key value");
87  group.throughput(Throughput::Bytes(str.len() as u64));
88  group.bench_function(BenchmarkId::new("parse", str.len()), |b| {
89    b.iter(|| key_value(str.as_bytes()).unwrap())
90  });
91}
92
93criterion_group!(
94  benches,
95  bench_ini,
96  bench_ini_keys_and_values,
97  bench_ini_key_value
98);
99criterion_main!(benches);
100