cmark

My personal build of CMark ✏️

Commit
e1db44b114620c5a23708d851d64fb53dd84bde9
Parent
a79b2ed9b7051b259f1ab874e5168a853723c314
Author
John MacFarlane <jgm@berkeley.edu>
Date

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.

Diffstat

1 file changed, 11 insertions, 0 deletions

Status File Name N° Changes Insertions Deletions
Modified src/inlines.c 11 11 0
diff --git 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;
 		}