done implementing functionality to get PersistentVector.prevMatch working. We use the call stack to try the node at the previous index if we receive an invalid state from the recursive call.

This commit is contained in:
2025-10-08 11:10:06 +01:00
parent 088c5c3d98
commit 70215fbc0a

View File

@@ -105,6 +105,7 @@ struct
BRANCH (#[tree, newNode], #[maxSize, finish]) BRANCH (#[tree, newNode], #[maxSize, finish])
end end
fun getStart tree = fun getStart tree =
case tree of case tree of
LEAF (values, _) => Vector.sub (values, 0) LEAF (values, _) => Vector.sub (values, 0)
@@ -181,57 +182,78 @@ struct
fun getLast tree = fun getLast tree =
case tree of case tree of
LEAF (values, _) => LEAF (values, _) => Vector.sub (values, Vector.length values - 1)
Vector.sub (values, Vector.length values - 1) | BRANCH (nodes, _) => getLast (Vector.sub (nodes, Vector.length nodes - 1))
| BRANCH (nodes, _) =>
getLast (Vector.sub (nodes, Vector.length nodes - 1))
(* slightly tricky.
* The `sizes` vector contains the last/finish position of the item
* at the corresponding index in the `nodes` or `values` vector
* However, what we when searching for the previous match
* is different: we want the node that has a start prior
* to the cursorIdx.
* This information cannot be retrieved with 100% accuracy
* using the `sizes` vector.
* To get what we want, we recurse downwards using the `sizes` vector.
* If we found the node we want, we return it.
* Otherwise, we return a state meaning "no node at this position"
* and we use the call stack to descend down the node at the previous index.
* There might not be a previous index because the current index is 0.
* In this case, either the call stack will handle it,
* or the caller to `helpPrevMatch` will. *)
fun helpPrevMatch (cursorIdx, tree) = fun helpPrevMatch (cursorIdx, tree) =
case tree of case tree of
LEAF (values, sizes) => LEAF (values, sizes) =>
let let
val idx = BinSearch.equalOrMore (cursorIdx, sizes) val idx = BinSearch.equalOrMore (cursorIdx, sizes)
in in
if idx < 0 then {start = ~1, finish = ~1} if idx < 0 then
else if idx = 0 then Vector.sub (values, 0) {start = ~1, finish = ~1}
else if idx = 0 then
let
val result = Vector.sub (values, 0)
in
if #start result < cursorIdx then result
else {start = ~1, finish = ~1}
end
else else
let let
val current = Vector.sub (values, idx) val current = Vector.sub (values, idx)
val prev = Vector.sub (values, idx - 1)
in in
if cursorIdx > #start current then if cursorIdx > #start current then current
current else Vector.sub (values, idx - 1)
else
prev
end end
end end
| BRANCH (nodes, sizes) => | BRANCH (nodes, sizes) =>
let let
val idx = BinSearch.equalOrMore (cursorIdx, sizes) val idx = BinSearch.equalOrMore (cursorIdx, sizes)
in in
if idx < 0 then {start = ~1, finish = ~1} if idx < 0 then
{start = ~1, finish = ~1}
else if idx = 0 then
helpPrevMatch (cursorIdx, Vector.sub (nodes, idx))
else else
let let
val node = Vector.sub (nodes, idx) val node = Vector.sub (nodes, idx)
val result = helpPrevMatch (cursorIdx, node) val result = helpPrevMatch (cursorIdx, node)
in in
result if #start result = ~1 then getLast (Vector.sub (nodes, idx - 1))
else result
end end
end end
fun loopPrevMatch (prevStart, tree, count) = fun loopPrevMatch (prevStart, prevFinish, tree, count) =
if count = 0 then if count = 0 then
prevStart prevStart
else else
let let
val {start, finish} = helpPrevMatch (prevStart - 1, tree) val {start, finish} = helpPrevMatch (prevFinish - 1, tree)
in in
if start = ~1 then if start = ~1 then
let val {start, finish} = getLast tree let val {start, finish} = getLast tree
in loopPrevMatch (start, tree, count - 1) in loopPrevMatch (start, finish, tree, count - 1)
end end
else else
loopPrevMatch (start, tree, count - 1) loopPrevMatch (start, finish, tree, count - 1)
end end
fun prevMatch (cursorIdx, tree, count) = fun prevMatch (cursorIdx, tree, count) =
@@ -243,11 +265,11 @@ struct
in in
if start = ~1 then if start = ~1 then
let val {start, finish} = getLast tree let val {start, finish} = getLast tree
in loopPrevMatch (start, tree, count - 1) in loopPrevMatch (start, finish, tree, count - 1)
end end
else if cursorIdx >= start andalso cursorIdx <= finish then else if cursorIdx >= start andalso cursorIdx <= finish then
loopPrevMatch (start, tree, count) loopPrevMatch (start, finish, tree, count)
else else
loopPrevMatch (start, tree, count - 1) loopPrevMatch (start, finish, tree, count - 1)
end end
end end