summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn MacFarlane <jgm@berkeley.edu>2015-06-10 12:58:27 -0700
committerJohn MacFarlane <jgm@berkeley.edu>2015-06-10 12:58:27 -0700
commite1db44b114620c5a23708d851d64fb53dd84bde9 (patch)
tree305c3d2382a0608af5874b5a80b1d43ecafcdb6e
parenta79b2ed9b7051b259f1ab874e5168a853723c314 (diff)
process_inlines: remove closers from delim stack when possible.
When they have no matching openers and cannot be openers themselves, we can safely remove them. This helps with a performance case: "a_ " * 20000. See jgm/commonmark.js#43.
-rw-r--r--src/inlines.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/src/inlines.c b/src/inlines.c
index 7e8f806..a1f0356 100644
--- a/src/inlines.c
+++ b/src/inlines.c
@@ -439,6 +439,8 @@ static void process_emphasis(subject *subj, delimiter *start_delim)
{
delimiter *closer = subj->last_delim;
delimiter *opener;
+ delimiter *old_closer;
+ bool opener_not_found;
// move back to first relevant delim.
while (closer != NULL && closer->previous != start_delim) {
@@ -459,6 +461,9 @@ static void process_emphasis(subject *subj, delimiter *start_delim)
}
opener = opener->previous;
}
+ opener_not_found = opener == NULL ||
+ opener == start_delim;
+ old_closer = closer;
if (closer->delim_char == '*' || closer->delim_char == '_') {
if (opener != NULL && opener != start_delim) {
closer = S_insert_emph(subj, opener, closer);
@@ -486,6 +491,12 @@ static void process_emphasis(subject *subj, delimiter *start_delim)
}
closer = closer->next;
}
+ if (opener_not_found && !old_closer->can_open) {
+ // we can remove a closer that can't be an
+ // opener, once we've seen there's no
+ // matching opener:
+ remove_delimiter(subj, old_closer);
+ }
} else {
closer = closer->next;
}