inline: reuse event buffer between blocks

make sure not to allocate a new buffer on each block
This commit is contained in:
Noah Hellman 2023-02-09 21:59:53 +01:00
parent 1e5e56c463
commit 9429f90307
3 changed files with 45 additions and 24 deletions

View file

@ -94,6 +94,13 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
} }
} }
pub fn reset(&mut self, chars: I) {
self.lexer = lex::Lexer::new(chars);
self.span = Span::new(0, 0);
self.openers.clear();
debug_assert!(self.events.is_empty());
}
fn eat(&mut self) -> Option<lex::Token> { fn eat(&mut self) -> Option<lex::Token> {
let tok = self.lexer.next(); let tok = self.lexer.next();
if let Some(t) = &tok { if let Some(t) = &tok {

View file

@ -604,8 +604,8 @@ pub struct Parser<'s> {
/// Spans to the inlines in the leaf block currently being parsed. /// Spans to the inlines in the leaf block currently being parsed.
inlines: span::InlineSpans<'s>, inlines: span::InlineSpans<'s>,
/// Inline parser, recreated for each new inline. /// Inline parser.
inline_parser: Option<inline::Parser<span::InlineCharsIter<'s>>>, inline_parser: inline::Parser<span::InlineCharsIter<'s>>,
} }
struct Heading { struct Heading {
@ -629,7 +629,11 @@ struct PrePass<'s> {
impl<'s> PrePass<'s> { impl<'s> PrePass<'s> {
#[must_use] #[must_use]
fn new(src: &'s str, mut tree: block::Tree) -> Self { fn new(
src: &'s str,
mut tree: block::Tree,
inline_parser: &mut inline::Parser<span::InlineCharsIter<'s>>,
) -> Self {
let mut link_definitions = Map::new(); let mut link_definitions = Map::new();
let mut headings: Vec<Heading> = Vec::new(); let mut headings: Vec<Heading> = Vec::new();
let mut used_ids: Set<&str> = Set::new(); let mut used_ids: Set<&str> = Set::new();
@ -667,7 +671,8 @@ impl<'s> PrePass<'s> {
inlines.set_spans(tree.take_inlines()); inlines.set_spans(tree.take_inlines());
let mut id_auto = String::new(); let mut id_auto = String::new();
let mut last_whitespace = true; let mut last_whitespace = true;
inline::Parser::new(inlines.chars()).for_each(|ev| match ev.kind { inline_parser.reset(inlines.chars());
inline_parser.for_each(|ev| match ev.kind {
inline::EventKind::Str => { inline::EventKind::Str => {
let mut chars = inlines.slice(ev.span).chars().peekable(); let mut chars = inlines.slice(ev.span).chars().peekable();
while let Some(c) = chars.next() { while let Some(c) = chars.next() {
@ -767,7 +772,8 @@ impl<'s> Parser<'s> {
#[must_use] #[must_use]
pub fn new(src: &'s str) -> Self { pub fn new(src: &'s str) -> Self {
let tree = block::parse(src); let tree = block::parse(src);
let pre_pass = PrePass::new(src, tree.clone()); let mut inline_parser = inline::Parser::new(span::InlineChars::empty(src));
let pre_pass = PrePass::new(src, tree.clone(), &mut inline_parser);
Self { Self {
src, src,
@ -780,13 +786,14 @@ impl<'s> Parser<'s> {
footnote_index: 0, footnote_index: 0,
footnote_active: false, footnote_active: false,
inlines: span::InlineSpans::new(src), inlines: span::InlineSpans::new(src),
inline_parser: None, inline_parser,
} }
} }
fn inline(&mut self) -> Option<Event<'s>> { fn inline(&mut self) -> Option<Event<'s>> {
self.inline_parser.as_mut().and_then(|parser| { let mut inline = self.inline_parser.next();
let mut inline = parser.next();
inline.as_ref()?;
let mut first_is_attr = false; let mut first_is_attr = false;
let mut attributes = inline.as_ref().map_or_else(Attributes::new, |inl| { let mut attributes = inline.as_ref().map_or_else(Attributes::new, |inl| {
@ -799,10 +806,12 @@ impl<'s> Parser<'s> {
}); });
if first_is_attr { if first_is_attr {
inline = parser.next(); inline = self.inline_parser.next();
} }
inline.map(|inline| match inline.kind { inline.map(|inline| {
let enter = matches!(inline.kind, inline::EventKind::Enter(_));
match inline.kind {
inline::EventKind::Enter(c) | inline::EventKind::Exit(c) => { inline::EventKind::Enter(c) | inline::EventKind::Exit(c) => {
let t = match c { let t = match c {
inline::Container::Span => Container::Span, inline::Container::Span => Container::Span,
@ -870,7 +879,7 @@ impl<'s> Parser<'s> {
Container::Link(url, ty) Container::Link(url, ty)
} }
}; };
if matches!(inline.kind, inline::EventKind::Enter(_)) { if enter {
Event::Start(t, attributes) Event::Start(t, attributes)
} else { } else {
Event::End(t) Event::End(t)
@ -922,7 +931,7 @@ impl<'s> Parser<'s> {
| inline::EventKind::Placeholder => { | inline::EventKind::Placeholder => {
panic!("{:?}", inline) panic!("{:?}", inline)
} }
}) }
}) })
} }
@ -954,8 +963,7 @@ impl<'s> Parser<'s> {
} }
if enter && !matches!(l, block::Leaf::CodeBlock) { if enter && !matches!(l, block::Leaf::CodeBlock) {
self.inlines.set_spans(self.tree.take_inlines()); self.inlines.set_spans(self.tree.take_inlines());
self.inline_parser = self.inline_parser.reset(self.inlines.chars());
Some(inline::Parser::new(self.inlines.chars()));
} }
match l { match l {
block::Leaf::Paragraph => Container::Paragraph, block::Leaf::Paragraph => Container::Paragraph,

View file

@ -170,6 +170,12 @@ impl<'s, I: Iterator<Item = Span>> Iterator for InlineChars<'s, I> {
pub type InlineCharsIter<'s> = InlineChars<'s, std::iter::Copied<std::slice::Iter<'static, Span>>>; pub type InlineCharsIter<'s> = InlineChars<'s, std::iter::Copied<std::slice::Iter<'static, Span>>>;
impl<'s> InlineCharsIter<'s> {
pub fn empty(src: &'s str) -> Self {
InlineChars::new(src, [].iter().copied())
}
}
/// Discontinuous slices of a [`&str`]. /// Discontinuous slices of a [`&str`].
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct InlineSpans<'s> { pub struct InlineSpans<'s> {