From 1ee193de1ba93a40df663ced44341f3441212565 Mon Sep 17 00:00:00 2001 From: Wilson Lin Date: Fri, 3 Jul 2020 22:32:16 +1000 Subject: [PATCH] Fix tricky subtle bugs in trie matching --- src/pattern.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pattern.rs b/src/pattern.rs index aa80e31..efbf05f 100644 --- a/src/pattern.rs +++ b/src/pattern.rs @@ -2,7 +2,7 @@ pub struct TrieNode { // Using a children array of size 256 would probably be fastest, but waste too much memory and cause slow compiles // and large binaries. Instead, we only store the children between the first and last defined (see `gen/trie.ts`). - // When getting a child, use `index + offset`. + // When getting a child, use `index - offset`. pub offset: usize, pub value: Option, pub children: &'static [Option<&'static TrieNode>], @@ -29,7 +29,8 @@ impl TrieNode { let mut node: &TrieNode = self; let mut next_pos = from; while let Some(&c) = text.get(next_pos) { - match node.children.get(c as usize + node.offset) { + // Let it underflow for performance, it should be safe as the largest index is 256. + match node.children.get((c as usize).wrapping_sub(node.offset)) { Some(Some(child)) => node = child, None | Some(None) => return None, }; @@ -47,9 +48,12 @@ impl TrieNode { let mut value: Option> = None; let mut pos = 0; while let Some((new_node, new_pos)) = node.next_matching_node(text, pos) { - value = Some(TrieNodeMatch::Found { len: pos, value: new_node.value.unwrap() }); + if new_pos == pos || new_node.value.is_none() { + break; + }; node = new_node; pos = new_pos; + value = Some(TrieNodeMatch::Found { len: pos, value: node.value.unwrap() }); }; value.unwrap_or(TrieNodeMatch::NotFound { reached: pos }) }