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> {
let tok = self.lexer.next();
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.
inlines: span::InlineSpans<'s>,
/// Inline parser, recreated for each new inline.
inline_parser: Option<inline::Parser<span::InlineCharsIter<'s>>>,
/// Inline parser.
inline_parser: inline::Parser<span::InlineCharsIter<'s>>,
}
struct Heading {
@ -629,7 +629,11 @@ struct PrePass<'s> {
impl<'s> PrePass<'s> {
#[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 headings: Vec<Heading> = Vec::new();
let mut used_ids: Set<&str> = Set::new();
@ -667,7 +671,8 @@ impl<'s> PrePass<'s> {
inlines.set_spans(tree.take_inlines());
let mut id_auto = String::new();
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 => {
let mut chars = inlines.slice(ev.span).chars().peekable();
while let Some(c) = chars.next() {
@ -767,7 +772,8 @@ impl<'s> Parser<'s> {
#[must_use]
pub fn new(src: &'s str) -> Self {
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 {
src,
@ -780,29 +786,32 @@ impl<'s> Parser<'s> {
footnote_index: 0,
footnote_active: false,
inlines: span::InlineSpans::new(src),
inline_parser: None,
inline_parser,
}
}
fn inline(&mut self) -> Option<Event<'s>> {
self.inline_parser.as_mut().and_then(|parser| {
let mut inline = parser.next();
let mut inline = self.inline_parser.next();
let mut first_is_attr = false;
let mut attributes = inline.as_ref().map_or_else(Attributes::new, |inl| {
if let inline::EventKind::Attributes = inl.kind {
first_is_attr = true;
attr::parse(self.inlines.slice(inl.span))
} else {
Attributes::new()
}
});
inline.as_ref()?;
if first_is_attr {
inline = parser.next();
let mut first_is_attr = false;
let mut attributes = inline.as_ref().map_or_else(Attributes::new, |inl| {
if let inline::EventKind::Attributes = inl.kind {
first_is_attr = true;
attr::parse(self.inlines.slice(inl.span))
} else {
Attributes::new()
}
});
inline.map(|inline| match inline.kind {
if first_is_attr {
inline = self.inline_parser.next();
}
inline.map(|inline| {
let enter = matches!(inline.kind, inline::EventKind::Enter(_));
match inline.kind {
inline::EventKind::Enter(c) | inline::EventKind::Exit(c) => {
let t = match c {
inline::Container::Span => Container::Span,
@ -870,7 +879,7 @@ impl<'s> Parser<'s> {
Container::Link(url, ty)
}
};
if matches!(inline.kind, inline::EventKind::Enter(_)) {
if enter {
Event::Start(t, attributes)
} else {
Event::End(t)
@ -922,7 +931,7 @@ impl<'s> Parser<'s> {
| inline::EventKind::Placeholder => {
panic!("{:?}", inline)
}
})
}
})
}
@ -954,8 +963,7 @@ impl<'s> Parser<'s> {
}
if enter && !matches!(l, block::Leaf::CodeBlock) {
self.inlines.set_spans(self.tree.take_inlines());
self.inline_parser =
Some(inline::Parser::new(self.inlines.chars()));
self.inline_parser.reset(self.inlines.chars());
}
match l {
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>>>;
impl<'s> InlineCharsIter<'s> {
pub fn empty(src: &'s str) -> Self {
InlineChars::new(src, [].iter().copied())
}
}
/// Discontinuous slices of a [`&str`].
#[derive(Default, Debug)]
pub struct InlineSpans<'s> {