From 20de15b349dd8f8995632f1dea0bece928f061b5 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Wed, 4 Sep 2024 16:38:27 +0100 Subject: [PATCH] fixed 'helpExists' function; error was in the FOUND case which checked 'keyPos = String.size searchKey' instead of 'keyPos = String.size searchKey - 1'. The latter is correct, because it checks that the keyPos ended at the last character, which is the intended meaning --- src/string-set.sml | 137 +++++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/src/string-set.sml b/src/string-set.sml index fe5fde6..f11b867 100644 --- a/src/string-set.sml +++ b/src/string-set.sml @@ -79,58 +79,64 @@ struct fun helpExists (searchKey, keyPos, trie) = case trie of CHILDREN {keys, children} => - let - val findChr = String.sub (searchKey, keyPos) - in - (case findBinSearch (findChr, keyPos, keys) of - SOME idx => - let - val trieKey = Vector.sub (keys, idx) - in - (case searchKeyMatch (searchKey, trieKey, keyPos + 1) of - NO_SEARCH_MATCH => false - | FULL_SEARCH_MATCH => - let val trieChild = Vector.sub (children, idx) - in isFoundNode trieChild - end - | SEARCH_KEY_CONTAINS_TRIE_KEY => - let - val trieChild = Vector.sub (children, idx) - in - helpExists - (searchKey, keyPos + String.size trieKey, trieChild) - end - | TRIE_KEY_CONTAINS_SEARCH_KEY => false) - end - | NONE => false) - end + if keyPos = String.size searchKey then + false + else + let + val findChr = String.sub (searchKey, keyPos) + in + (case findBinSearch (findChr, keyPos, keys) of + SOME idx => + let + val trieKey = Vector.sub (keys, idx) + in + (case searchKeyMatch (searchKey, trieKey, keyPos + 1) of + NO_SEARCH_MATCH => false + | FULL_SEARCH_MATCH => + let val trieChild = Vector.sub (children, idx) + in isFoundNode trieChild + end + | SEARCH_KEY_CONTAINS_TRIE_KEY => + let + val trieChild = Vector.sub (children, idx) + in + helpExists + (searchKey, keyPos + String.size trieKey, trieChild) + end + | TRIE_KEY_CONTAINS_SEARCH_KEY => false) + end + | NONE => false) + end | FOUND_WITH_CHILDREN {keys, children} => - let - val findChr = String.sub (searchKey, keyPos) - in - (case findBinSearch (findChr, keyPos, keys) of - SOME idx => - let - val trieKey = Vector.sub (keys, idx) - in - (case searchKeyMatch (searchKey, trieKey, keyPos + 1) of - NO_SEARCH_MATCH => false - | FULL_SEARCH_MATCH => - let val trieChild = Vector.sub (children, idx) - in isFoundNode trieChild - end - | SEARCH_KEY_CONTAINS_TRIE_KEY => - let - val trieChild = Vector.sub (children, idx) - in - helpExists - (searchKey, keyPos + String.size trieKey, trieChild) - end - | TRIE_KEY_CONTAINS_SEARCH_KEY => false) - end - | NONE => false) - end - | FOUND => keyPos = String.size searchKey + if keyPos = String.size searchKey then + true + else + let + val findChr = String.sub (searchKey, keyPos) + in + (case findBinSearch (findChr, keyPos, keys) of + SOME idx => + let + val trieKey = Vector.sub (keys, idx) + in + (case searchKeyMatch (searchKey, trieKey, keyPos + 1) of + NO_SEARCH_MATCH => false + | FULL_SEARCH_MATCH => + let val trieChild = Vector.sub (children, idx) + in isFoundNode trieChild + end + | SEARCH_KEY_CONTAINS_TRIE_KEY => + let + val trieChild = Vector.sub (children, idx) + in + helpExists + (searchKey, keyPos + String.size trieKey, trieChild) + end + | TRIE_KEY_CONTAINS_SEARCH_KEY => false) + end + | NONE => false) + end + | FOUND => keyPos = String.size searchKey - 1 fun exists (searchKey, trie) = helpExists (searchKey, 0, trie) @@ -402,8 +408,16 @@ struct FOUND_WITH_CHILDREN {keys = keys, children = children} (* if insert key contains trie key, need to recurse down node *) | INSERT_KEY_CONTAINS_TRIE_KEY => - let val trieChild = Vector.sub (children, insIdx) - in helpInsert (insKey, keyPos + String.size trieKey, trieChild) + let + val trieChild = Vector.sub (children, insIdx) + val newTrieChild = helpInsert + (insKey, keyPos + String.size trieKey, trieChild) + val newChildren = + Vector.mapi + (fn (idx, elt) => if idx <> insIdx then elt else newTrieChild) + children + in + constructor {keys = keys, children = newChildren} end (* if trie key contains insert key, need to split node *) | TRIE_KEY_CONTAINS_INSERT_KEY => @@ -411,7 +425,7 @@ struct val trieChild = Vector.sub (children, insIdx) val newKeys = Vector.mapi - (fn (idx, key) => if idx <> insIdx then insKey else key) keys + (fn (idx, key) => if idx <> insIdx then key else insKey) keys (* newTrieChild should always be FOUND_WITH_CHILDREN, * because previous part matches insert key, @@ -492,13 +506,16 @@ struct (* * todo: - * - Fix insert function. - * - Once insert is fixed, test prefix searching, - * which turns found strings to list. + * - Fix exists function + * - Test prefix searching, which turns found strings to list. * - * Problem with insert function: - * The "trie" value below does not contain "hello". It somehow disappeared. - * Should probably attempt to create a test suite, to catch regressions as well. + * Problem with exists function: + * exists ("hello", trie) returns true as expected + * but exists ("hellop", trie) also returns true + * even though "hellop" was never added. + * + * "helloz" also returns true, although "hellopo" returns false. + * Problem occurs when trieKey length > searchKey length + 1 apparently. *) val trie = fromList ["hello", "hit", "hi"]