diff options
author | Titus Wormer <tituswormer@gmail.com> | 2022-07-21 17:48:26 +0200 |
---|---|---|
committer | Titus Wormer <tituswormer@gmail.com> | 2022-07-21 17:48:26 +0200 |
commit | 37fad739ba73d488d4c3652caee01f1ec5d0aaaa (patch) | |
tree | 04ffc3e16799d5706276ecf57992126a073bedeb | |
parent | 1d48e14b70f59bbb3daa5d8dcce176500400965b (diff) | |
download | markdown-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.rs | 63 | ||||
-rw-r--r-- | tests/definition.rs | 8 |
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 |