aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Titus Wormer <tituswormer@gmail.com>2022-07-21 17:48:26 +0200
committerLibravatar Titus Wormer <tituswormer@gmail.com>2022-07-21 17:48:26 +0200
commit37fad739ba73d488d4c3652caee01f1ec5d0aaaa (patch)
tree04ffc3e16799d5706276ecf57992126a073bedeb
parent1d48e14b70f59bbb3daa5d8dcce176500400965b (diff)
downloadmarkdown-rs-37fad739ba73d488d4c3652caee01f1ec5d0aaaa.tar.gz
markdown-rs-37fad739ba73d488d4c3652caee01f1ec5d0aaaa.tar.bz2
markdown-rs-37fad739ba73d488d4c3652caee01f1ec5d0aaaa.zip
Refactor performance around links in subtokenize
-rw-r--r--src/util/edit_map.rs63
-rw-r--r--tests/definition.rs8
2 files changed, 42 insertions, 29 deletions
diff --git a/src/util/edit_map.rs b/src/util/edit_map.rs
index 6085f18..38ece01 100644
--- a/src/util/edit_map.rs
+++ b/src/util/edit_map.rs
@@ -14,33 +14,42 @@ use crate::tokenizer::Event;
///
/// This fixes links in case there are events removed or added between them.
fn shift_links(events: &mut [Event], jumps: &[(usize, usize, usize)]) {
- let map = |before| {
- // To do: this theoretically gets slow, investigate how to improve it.
- let mut jump_index = 0;
- let mut remove = 0;
- let mut add = 0;
-
- while jump_index < jumps.len() {
- if jumps[jump_index].0 > before {
- break;
- }
+ let mut jump_index = 0;
+ let mut index = 0;
+ let mut add = 0;
+ let mut rm = 0;
+
+ while index < events.len() {
+ let rm_curr = rm;
- (_, remove, add) = jumps[jump_index];
+ while jump_index < jumps.len() && jumps[jump_index].0 <= index {
+ add = jumps[jump_index].2;
+ rm = jumps[jump_index].1;
jump_index += 1;
}
- before + add - remove
- };
-
- let mut index = 0;
+ // Ignore items that will be removed.
+ if rm > rm_curr {
+ index += rm - rm_curr;
+ } else {
+ if let Some(link) = &events[index].link {
+ if let Some(next) = link.next {
+ events[next].link.as_mut().unwrap().previous = Some(index + add - rm);
+
+ while jump_index < jumps.len() && jumps[jump_index].0 <= next {
+ add = jumps[jump_index].2;
+ rm = jumps[jump_index].1;
+ jump_index += 1;
+ }
+
+ events[index].link.as_mut().unwrap().next = Some(next + add - rm);
+ index = next;
+ continue;
+ }
+ }
- while index < events.len() {
- if let Some(link) = &mut events[index].link {
- link.previous = link.previous.map(map);
- link.next = link.next.map(map);
+ index += 1;
}
-
- index += 1;
}
}
@@ -85,25 +94,23 @@ impl EditMap {
let mut remove_acc = 0;
while index < self.map.len() {
let (at, remove, add) = &self.map[index];
- add_acc += add.len();
remove_acc += remove;
+ add_acc += add.len();
jumps.push((*at, remove_acc, add_acc));
index += 1;
}
+ shift_links(events, &jumps);
+
let len_before = events.len();
let mut index = self.map.len();
let mut vecs: Vec<Vec<Event>> = Vec::with_capacity(index * 2 + 1);
while index > 0 {
index -= 1;
- let (at, remove, _) = self.map[index];
- let mut keep = events.split_off(at + remove);
- shift_links(&mut keep, &jumps);
- vecs.push(keep);
+ vecs.push(events.split_off(self.map[index].0 + self.map[index].1));
vecs.push(self.map[index].2.split_off(0));
- events.truncate(at);
+ events.truncate(self.map[index].0);
}
- shift_links(events, &jumps);
vecs.push(events.split_off(0));
events.reserve(len_before + add_acc - remove_acc);
diff --git a/tests/definition.rs b/tests/definition.rs
index 620ab69..27c1fed 100644
--- a/tests/definition.rs
+++ b/tests/definition.rs
@@ -219,7 +219,13 @@ fn definition() {
assert_eq!(
micromark("> [foo]: /url\n\n[foo]"),
"<blockquote>\n</blockquote>\n<p><a href=\"/url\">foo</a></p>",
- "should support definitions in block quotes"
+ "should support definitions in block quotes (1)"
+ );
+
+ assert_eq!(
+ micromark("> [a]: <> 'b\n> c'"),
+ "<blockquote>\n</blockquote>",
+ "should support definitions in block quotes (2)"
);
// Extra