• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #[global_allocator]
2 static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
3 
4 use criterion::*;
5 
6 use nom::{
7   bytes::complete::{is_a, tag, take_till, take_while},
8   character::complete::{alphanumeric1 as alphanumeric, char, not_line_ending, space0 as space},
9   combinator::opt,
10   multi::many0,
11   sequence::{delimited, pair, terminated, tuple},
12   IResult,
13 };
14 
15 use std::collections::HashMap;
16 
is_line_ending_or_comment(chr: char) -> bool17 fn is_line_ending_or_comment(chr: char) -> bool {
18   chr == ';' || chr == '\n'
19 }
20 
space_or_line_ending(i: &str) -> IResult<&str, &str>21 fn space_or_line_ending(i: &str) -> IResult<&str, &str> {
22   is_a(" \r\n")(i)
23 }
24 
category(i: &str) -> IResult<&str, &str>25 fn category(i: &str) -> IResult<&str, &str> {
26   terminated(
27     delimited(char('['), take_while(|c| c != ']'), char(']')),
28     opt(is_a(" \r\n")),
29   )(i)
30 }
31 
key_value(i: &str) -> IResult<&str, (&str, &str)>32 fn key_value(i: &str) -> IResult<&str, (&str, &str)> {
33   let (i, key) = alphanumeric(i)?;
34   let (i, _) = tuple((opt(space), tag("="), opt(space)))(i)?;
35   let (i, val) = take_till(is_line_ending_or_comment)(i)?;
36   let (i, _) = opt(space)(i)?;
37   let (i, _) = opt(pair(tag(";"), not_line_ending))(i)?;
38   let (i, _) = opt(space_or_line_ending)(i)?;
39   Ok((i, (key, val)))
40 }
41 
keys_and_values_aggregator(i: &str) -> IResult<&str, Vec<(&str, &str)>>42 fn keys_and_values_aggregator(i: &str) -> IResult<&str, Vec<(&str, &str)>> {
43   many0(key_value)(i)
44 }
45 
keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>>46 fn keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>> {
47   match keys_and_values_aggregator(input) {
48     Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())),
49     Err(e) => Err(e),
50   }
51 }
52 
category_and_keys(i: &str) -> IResult<&str, (&str, HashMap<&str, &str>)>53 fn category_and_keys(i: &str) -> IResult<&str, (&str, HashMap<&str, &str>)> {
54   pair(category, keys_and_values)(i)
55 }
56 
categories_aggregator(i: &str) -> IResult<&str, Vec<(&str, HashMap<&str, &str>)>>57 fn categories_aggregator(i: &str) -> IResult<&str, Vec<(&str, HashMap<&str, &str>)>> {
58   many0(category_and_keys)(i)
59 }
60 
categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str>>>61 fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str>>> {
62   match categories_aggregator(input) {
63     Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())),
64     Err(e) => Err(e),
65   }
66 }
67 
bench_ini_str(c: &mut Criterion)68 fn bench_ini_str(c: &mut Criterion) {
69   let s = "[owner]
70 name=John Doe
71 organization=Acme Widgets Inc.
72 
73 [database]
74 server=192.0.2.62
75 port=143
76 file=payroll.dat
77 ";
78 
79   let mut group = c.benchmark_group("ini str");
80   group.throughput(Throughput::Bytes(s.len() as u64));
81   group.bench_function(BenchmarkId::new("parse", s.len()), |b| {
82     b.iter(|| categories(s).unwrap())
83   });
84 }
85 
86 criterion_group!(benches, bench_ini_str);
87 criterion_main!(benches);
88