From 0ea0d44da3d27dc750c8074c396c856b9f4659a7 Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Sat, 7 Feb 2026 00:29:58 +0000 Subject: [PATCH] add function to extend an existing match, and add tests for it --- fcore/persistent-vector.sml | 27 ++++++++- test/persistent-vector-tests.sml | 94 +++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 2 deletions(-) diff --git a/fcore/persistent-vector.sml b/fcore/persistent-vector.sml index 5da1c91..6da0540 100644 --- a/fcore/persistent-vector.sml +++ b/fcore/persistent-vector.sml @@ -807,7 +807,7 @@ struct val matchAfterFinish = nextMatch (finish, tree, 1) in if matchAfterFinish <= finish then - (* no match after the 'finish', so we just append *) + (* no match after the 'finish', so we can just append to 'tree' *) append (start, finish, tree) else let @@ -825,6 +825,31 @@ struct end end + fun extendExistingMatch (start, newFinish, tree) = + let + val matchAfterFinish = nextMatch (newFinish, tree, 1) + val left = splitLeft (start, tree) + val left = append (start, newFinish, left) + in + if matchAfterFinish <= newFinish then + (* no match after newFinish, so we can return 'left' + * which has the newFinish appended *) + left + else + let + val right = splitRight (newFinish, tree) + + val leftFinish = getFinishIdx left + val rightStartRelative = getStartIdx right + + val rightStartAbsolute = rightStartRelative + leftFinish + val difference = rightStartAbsolute - matchAfterFinish + val right = decrementBy (difference, right) + in + merge (left, right) + end + end + (* functions only for testing *) fun childrenHaveSameDepth (pos, nodes, expectedDepth) = if pos = Vector.length nodes then diff --git a/test/persistent-vector-tests.sml b/test/persistent-vector-tests.sml index f15479d..3c61f1c 100644 --- a/test/persistent-vector-tests.sml +++ b/test/persistent-vector-tests.sml @@ -45,6 +45,19 @@ struct loopInRange lst end + fun printVec pv = + let + val outputList = PersistentVector.toList pv + val str = + List.map + (fn {start, finish} => + "{start = " ^ Int.toString start ^ ", finish = " + ^ Int.toString finish ^ "}") outputList + val str = String.concatWith "\n " str ^ "\n" + in + print str + end + val appendTests = describe "PersistentVector.append" [ test "contains appended values in range" (fn _ => let @@ -508,5 +521,84 @@ struct end) ] - val tests = [appendTests, toListTests, splitLeftTests, deleteTests] + val extendExistingMatchTests = describe "PersistentVector.extendExistingMatch" + [ test + "leaves subsequent matches untouched \ + \if their 'finish' is greater than the extended finish" + (fn _ => + let + (* arrange *) + val inputList = + [ {start = 1, finish = 1} + , {start = 2, finish = 2} + , {start = 3, finish = 3} + , {start = 4, finish = 4} + , {start = 5, finish = 5} + , {start = 60, finish = 60} + , {start = 70, finish = 70} + , {start = 80, finish = 80} + ] + val pv = PersistentVector.fromList inputList + + (* act *) + val pv = PersistentVector.extendExistingMatch (5, 50, pv) + + (* assert *) + val outputList = PersistentVector.toList pv + val expectedOutput = + [ {start = 1, finish = 1} + , {start = 2, finish = 2} + , {start = 3, finish = 3} + , {start = 4, finish = 4} + , {start = 5, finish = 50} + , {start = 60, finish = 60} + , {start = 70, finish = 70} + , {start = 80, finish = 80} + ] + in + Expect.isTrue (outputList = expectedOutput) + end) + , test + "removes subsequent matches whose 'finish' is less than \ + \the newly extended element's 'finish'" + (fn _ => + let + (* arrange *) + val inputList = + [ {start = 1, finish = 1} + , {start = 2, finish = 2} + , {start = 3, finish = 3} + , {start = 4, finish = 4} + , {start = 5, finish = 5} + , {start = 60, finish = 60} + , {start = 70, finish = 70} + , {start = 80, finish = 80} + ] + val pv = PersistentVector.fromList inputList + + (* act *) + val pv = PersistentVector.extendExistingMatch (5, 75, pv) + + (* assert *) + val outputList = PersistentVector.toList pv + val expectedOutput = + [ {start = 1, finish = 1} + , {start = 2, finish = 2} + , {start = 3, finish = 3} + , {start = 4, finish = 4} + , {start = 5, finish = 75} + , {start = 80, finish = 80} + ] + in + Expect.isTrue (outputList = expectedOutput) + end) + ] + + val tests = + [ appendTests + , toListTests + , splitLeftTests + , deleteTests + , extendExistingMatchTests + ] end