perf: replace all str.find(..)
s with memchr(..)
which is much faster, theoretically.
This commit is contained in:
parent
19f7bacf55
commit
da04d3d25d
|
@ -12,7 +12,9 @@ impl Keyword {
|
||||||
let key = until_while!(src, 2, b':', |c: u8| c.is_ascii_alphabetic() || c == b'_')?;
|
let key = until_while!(src, 2, b':', |c: u8| c.is_ascii_alphabetic() || c == b'_')?;
|
||||||
|
|
||||||
// includes the eol character
|
// includes the eol character
|
||||||
let end = src.find('\n').map(|i| i + 1).unwrap_or_else(|| src.len());
|
let end = memchr::memchr(b'\n', src.as_bytes())
|
||||||
|
.map(|i| i + 1)
|
||||||
|
.unwrap_or_else(|| src.len());
|
||||||
|
|
||||||
Some((&src[2..key], &src[key + 1..end].trim(), end))
|
Some((&src[2..key], &src[key + 1..end].trim(), end))
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,9 @@ impl List {
|
||||||
|
|
||||||
// returns (contents_begin, contents_end)
|
// returns (contents_begin, contents_end)
|
||||||
pub fn parse_item(src: &str, ident: usize) -> (usize, usize) {
|
pub fn parse_item(src: &str, ident: usize) -> (usize, usize) {
|
||||||
let beg = src[ident..].find(' ').map(|i| ident + i + 1).unwrap();
|
let beg = memchr::memchr(b' ', &src.as_bytes()[ident..])
|
||||||
|
.map(|i| i + ident + 1)
|
||||||
|
.unwrap();
|
||||||
let mut lines = lines!(src);
|
let mut lines = lines!(src);
|
||||||
// skip first line
|
// skip first line
|
||||||
let mut pos = lines.next().unwrap();
|
let mut pos = lines.next().unwrap();
|
||||||
|
|
|
@ -179,12 +179,12 @@ impl<'a> Element<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: multiple lines fixed width area
|
||||||
if bytes[pos] == b':' && bytes.get(pos + 1).map(|&b| b == b' ').unwrap_or(false) {
|
if bytes[pos] == b':' && bytes.get(pos + 1).map(|&b| b == b' ').unwrap_or(false) {
|
||||||
let eol = src[pos..]
|
let eol = memchr::memchr(b'\n', &src.as_bytes()[pos..])
|
||||||
.find('\n')
|
.map(|i| i + 1)
|
||||||
.map(|i| i + pos + 1)
|
.unwrap_or_else(|| src.len() - pos);
|
||||||
.unwrap_or_else(|| src.len());
|
ret!(Element::FixedWidth(&src[pos + 1..pos + eol]), eol);
|
||||||
ret!(Element::FixedWidth(&src[pos + 1..eol]), eol);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if bytes[pos] == b'#' && bytes.get(pos + 1).filter(|&&b| b == b'+').is_some() {
|
if bytes[pos] == b'#' && bytes.get(pos + 1).filter(|&&b| b == b'+').is_some() {
|
||||||
|
@ -246,12 +246,12 @@ impl<'a> Element<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comment
|
// Comment
|
||||||
|
// TODO: multiple lines comment
|
||||||
if bytes[pos] == b'#' && bytes.get(pos + 1).map(|&b| b == b' ').unwrap_or(false) {
|
if bytes[pos] == b'#' && bytes.get(pos + 1).map(|&b| b == b' ').unwrap_or(false) {
|
||||||
let eol = src[pos..]
|
let eol = memchr::memchr(b'\n', &src.as_bytes()[pos..])
|
||||||
.find('\n')
|
.map(|i| i + 1)
|
||||||
.map(|i| i + pos + 1)
|
.unwrap_or_else(|| src.len() - pos);
|
||||||
.unwrap_or_else(|| src.len());
|
ret!(Element::Comment(&src[pos + 1..pos + eol]), eol);
|
||||||
ret!(Element::Comment(&src[pos + 1..eol]), eol);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
use memchr::memchr;
|
|
||||||
|
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Rule;
|
pub struct Rule;
|
||||||
|
|
||||||
impl Rule {
|
impl Rule {
|
||||||
pub fn parse(src: &str) -> usize {
|
pub fn parse(src: &str) -> usize {
|
||||||
let end = memchr(b'\n', src.as_bytes())
|
let end = memchr::memchr(b'\n', src.as_bytes())
|
||||||
.map(|i| i + 1)
|
.map(|i| i + 1)
|
||||||
.unwrap_or_else(|| src.len());
|
.unwrap_or_else(|| src.len());
|
||||||
let rules = &src[0..end].trim();
|
let rules = &src[0..end].trim();
|
||||||
|
|
|
@ -48,13 +48,14 @@ impl<'a> Headline<'a> {
|
||||||
fn parse_tags(src: &'a str) -> (Option<&'a str>, usize) {
|
fn parse_tags(src: &'a str) -> (Option<&'a str>, usize) {
|
||||||
if let Some(last) = src.split_whitespace().last() {
|
if let Some(last) = src.split_whitespace().last() {
|
||||||
if last.len() > 2 && last.starts_with(':') && last.ends_with(':') {
|
if last.len() > 2 && last.starts_with(':') && last.ends_with(':') {
|
||||||
(Some(last), src.rfind(':').unwrap() - last.len())
|
return (
|
||||||
} else {
|
Some(last),
|
||||||
(None, src.len())
|
memchr::memrchr(b':', src.as_bytes()).unwrap() - last.len(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
(None, src.len())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(None, src.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(src: &'a str) -> (Headline<'a>, usize, usize) {
|
pub fn parse(src: &'a str) -> (Headline<'a>, usize, usize) {
|
||||||
|
@ -72,23 +73,17 @@ impl<'a> Headline<'a> {
|
||||||
|
|
||||||
let mut title_start = skip_space!(src, level);
|
let mut title_start = skip_space!(src, level);
|
||||||
|
|
||||||
let keyword = match Headline::parse_keyword(&src[title_start..eol]) {
|
let keyword = Headline::parse_keyword(&src[title_start..eol]).map(|(k, l)| {
|
||||||
Some((k, l)) => {
|
|
||||||
title_start += l;
|
title_start += l;
|
||||||
Some(k)
|
k
|
||||||
}
|
});
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
title_start = skip_space!(src, title_start);
|
title_start = skip_space!(src, title_start);
|
||||||
|
|
||||||
let priority = match Headline::parse_priority(&src[title_start..eol]) {
|
let priority = Headline::parse_priority(&src[title_start..eol]).map(|p| {
|
||||||
Some(p) => {
|
|
||||||
title_start += 4;
|
title_start += 4;
|
||||||
Some(p)
|
p
|
||||||
}
|
});
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
title_start = skip_space!(src, title_start);
|
title_start = skip_space!(src, title_start);
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ pub enum Container {
|
||||||
Section {
|
Section {
|
||||||
end: usize,
|
end: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
Paragraph {
|
Paragraph {
|
||||||
cont_end: usize,
|
cont_end: usize,
|
||||||
end: usize,
|
end: usize,
|
||||||
|
@ -33,7 +32,6 @@ pub enum Container {
|
||||||
cont_end: usize,
|
cont_end: usize,
|
||||||
end: usize,
|
end: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
List {
|
List {
|
||||||
ident: usize,
|
ident: usize,
|
||||||
ordered: bool,
|
ordered: bool,
|
||||||
|
@ -43,7 +41,6 @@ pub enum Container {
|
||||||
ListItem {
|
ListItem {
|
||||||
end: usize,
|
end: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
Italic {
|
Italic {
|
||||||
end: usize,
|
end: usize,
|
||||||
},
|
},
|
||||||
|
@ -182,20 +179,20 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_sec_or_hdl(&mut self, tail: &'a str) -> Event<'a> {
|
fn next_sec_or_hdl(&mut self) -> Event<'a> {
|
||||||
let end = Headline::find_level(tail, std::usize::MAX);
|
let end = Headline::find_level(&self.text[self.off..], std::usize::MAX);
|
||||||
if end != 0 {
|
if end != 0 {
|
||||||
self.stack.push(Container::Section {
|
self.stack.push(Container::Section {
|
||||||
end: self.off + end,
|
end: self.off + end,
|
||||||
});
|
});
|
||||||
Event::SectionBeg
|
Event::SectionBeg
|
||||||
} else {
|
} else {
|
||||||
self.start_hdl(tail)
|
self.next_hdl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_hdl(&mut self, tail: &'a str) -> Event<'a> {
|
fn next_hdl(&mut self) -> Event<'a> {
|
||||||
let (hdl, off, end) = Headline::parse(tail);
|
let (hdl, off, end) = Headline::parse(&self.text[self.off..]);
|
||||||
self.stack.push(Container::Headline {
|
self.stack.push(Container::Headline {
|
||||||
beg: self.off + off,
|
beg: self.off + off,
|
||||||
end: self.off + end,
|
end: self.off + end,
|
||||||
|
@ -215,6 +212,8 @@ impl<'a> Parser<'a> {
|
||||||
(ele, off)
|
(ele, off)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
debug_assert!(self.off + off <= end);
|
||||||
|
|
||||||
if let Some(ele) = ele {
|
if let Some(ele) = ele {
|
||||||
match ele {
|
match ele {
|
||||||
Element::Paragraph { cont_end, end } => self.stack.push(Container::Paragraph {
|
Element::Paragraph { cont_end, end } => self.stack.push(Container::Paragraph {
|
||||||
|
@ -284,6 +283,8 @@ impl<'a> Parser<'a> {
|
||||||
(obj, off)
|
(obj, off)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
debug_assert!(self.off + off <= end);
|
||||||
|
|
||||||
match obj {
|
match obj {
|
||||||
Object::Underline { end } => self.stack.push(Container::Underline {
|
Object::Underline { end } => self.stack.push(Container::Underline {
|
||||||
end: self.off + end,
|
end: self.off + end,
|
||||||
|
@ -390,21 +391,19 @@ impl<'a> Iterator for Parser<'a> {
|
||||||
if self.off >= self.text.len() {
|
if self.off >= self.text.len() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let tail = &self.text[self.off..];
|
Some(self.next_sec_or_hdl())
|
||||||
Some(self.start_sec_or_hdl(tail))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let last = *self.stack.last_mut().unwrap();
|
let last = *self.stack.last_mut().unwrap();
|
||||||
|
|
||||||
Some(match last {
|
Some(match last {
|
||||||
Container::Headline { beg, end } => {
|
Container::Headline { beg, end } => {
|
||||||
let tail = &self.text[self.off..];
|
|
||||||
if self.off >= end {
|
if self.off >= end {
|
||||||
self.end()
|
self.end()
|
||||||
} else if self.off == beg {
|
} else if self.off == beg {
|
||||||
self.start_sec_or_hdl(tail)
|
self.next_sec_or_hdl()
|
||||||
} else {
|
} else {
|
||||||
self.start_hdl(tail)
|
self.next_hdl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Container::DynBlock { cont_end, end, .. }
|
Container::DynBlock { cont_end, end, .. }
|
||||||
|
|
|
@ -13,11 +13,10 @@ macro_rules! expect {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! eol {
|
macro_rules! eol {
|
||||||
($src:expr) => {
|
($src:expr) => {
|
||||||
$src.find('\n').unwrap_or_else(|| $src.len())
|
memchr::memchr(b'\n', $src.as_bytes()).unwrap_or_else(|| $src.len())
|
||||||
};
|
};
|
||||||
($src:expr, $from:expr) => {
|
($src:expr, $from:expr) => {
|
||||||
$src[$from..]
|
memchr::memchr(b'\n', $src.as_bytes()[$from..])
|
||||||
.find('\n')
|
|
||||||
.map(|i| i + $from)
|
.map(|i| i + $from)
|
||||||
.unwrap_or_else(|| $src.len())
|
.unwrap_or_else(|| $src.len())
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue