inline: reuse event buffer between blocks
make sure not to allocate a new buffer on each block
This commit is contained in:
parent
1e5e56c463
commit
9429f90307
3 changed files with 45 additions and 24 deletions
|
@ -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 {
|
||||||
|
|
36
src/lib.rs
36
src/lib.rs
|
@ -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,
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Reference in a new issue