begin implementation of PersistentVector.splitRight function
This commit is contained in:
@@ -328,7 +328,7 @@ struct
|
|||||||
loopPrevMatch (start, finish, tree, count - 1)
|
loopPrevMatch (start, finish, tree, count - 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
fun splitLeft (cursorIdx, tree) =
|
fun splitLeft (splitIdx, tree) =
|
||||||
case tree of
|
case tree of
|
||||||
LEAF (items, sizes) =>
|
LEAF (items, sizes) =>
|
||||||
if Vector.length items = 0 then
|
if Vector.length items = 0 then
|
||||||
@@ -338,20 +338,20 @@ struct
|
|||||||
let
|
let
|
||||||
val {start, ...} = Vector.sub (items, 0)
|
val {start, ...} = Vector.sub (items, 0)
|
||||||
in
|
in
|
||||||
(* if all items are after cursorIdx,
|
(* if all items are after splitIdx,
|
||||||
* then we want to return an empty tree,
|
* then we want to return an empty tree,
|
||||||
* splitting everything *)
|
* splitting everything *)
|
||||||
if cursorIdx < start then
|
if splitIdx < start then
|
||||||
empty
|
empty
|
||||||
else if cursorIdx > Vector.sub (sizes, Vector.length sizes - 1) then
|
else if splitIdx > Vector.sub (sizes, Vector.length sizes - 1) then
|
||||||
(* if all items are before cursorIdx,
|
(* if all items are before splitIdx,
|
||||||
* then we want to return the same tree,
|
* then we want to return the same tree,
|
||||||
* splitting nothing *)
|
* splitting nothing *)
|
||||||
tree
|
tree
|
||||||
else
|
else
|
||||||
(* we want to split from somewhere in middle, keeping left *)
|
(* we want to split from somewhere in middle, keeping left *)
|
||||||
let
|
let
|
||||||
val idx = BinSearch.equalOrMore (cursorIdx, sizes)
|
val idx = BinSearch.equalOrMore (splitIdx, sizes)
|
||||||
val idx = SOME idx
|
val idx = SOME idx
|
||||||
|
|
||||||
val items = VectorSlice.slice (items, 0, idx)
|
val items = VectorSlice.slice (items, 0, idx)
|
||||||
@@ -364,24 +364,24 @@ struct
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
| BRANCH (nodes, sizes) =>
|
| BRANCH (nodes, sizes) =>
|
||||||
if cursorIdx < Vector.sub (sizes, 0) then
|
if splitIdx < Vector.sub (sizes, 0) then
|
||||||
(* we want to split first node from rest *)
|
(* we want to split first node from rest *)
|
||||||
splitLeft (cursorIdx, Vector.sub (nodes, 0))
|
splitLeft (splitIdx, Vector.sub (nodes, 0))
|
||||||
else if cursorIdx > Vector.sub (sizes, Vector.length sizes - 1) then
|
else if splitIdx > Vector.sub (sizes, Vector.length sizes - 1) then
|
||||||
(* split point is after this subtree,
|
(* split point is after this subtree,
|
||||||
* so return this subtree unchanged *)
|
* so return this subtree unchanged *)
|
||||||
tree
|
tree
|
||||||
else
|
else
|
||||||
(* we want to split from somewhere in middle *)
|
(* we want to split from somewhere in middle *)
|
||||||
let
|
let
|
||||||
val idx = BinSearch.equalOrMore (cursorIdx, sizes)
|
val idx = BinSearch.equalOrMore (splitIdx, sizes)
|
||||||
val prevSize =
|
val prevSize =
|
||||||
if idx = 0 then
|
if idx = 0 then
|
||||||
0
|
0
|
||||||
else
|
else
|
||||||
Vector.sub (sizes, idx - 1)
|
Vector.sub (sizes, idx - 1)
|
||||||
val child =
|
val child =
|
||||||
splitLeft (cursorIdx - prevSize, Vector.sub (nodes, idx))
|
splitLeft (splitIdx - prevSize, Vector.sub (nodes, idx))
|
||||||
|
|
||||||
val sizes = VectorSlice.slice (sizes, 0, SOME idx)
|
val sizes = VectorSlice.slice (sizes, 0, SOME idx)
|
||||||
val nodes = VectorSlice.slice (nodes, 0, SOME idx)
|
val nodes = VectorSlice.slice (nodes, 0, SOME idx)
|
||||||
@@ -405,6 +405,64 @@ struct
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
(* When we split in this function,
|
||||||
|
* we always want to update the sizes vector
|
||||||
|
* so that the relative rope-like metadata is valid *)
|
||||||
|
fun splitRight (splitIdx, tree) =
|
||||||
|
case tree of
|
||||||
|
BRANCH (nodes, sizes) =>
|
||||||
|
if splitIdx > Vector.sub (sizes, Vector.length sizes - 1) then
|
||||||
|
(* splitIdx is greater than largest element,
|
||||||
|
* so we want to remove everything;
|
||||||
|
* or, in other words, we want to return an empty vec *)
|
||||||
|
empty
|
||||||
|
else
|
||||||
|
let
|
||||||
|
val idx = BinSearch.equalOrMore (splitIdx, sizes)
|
||||||
|
val prevSize =
|
||||||
|
if idx = 0 then
|
||||||
|
0
|
||||||
|
else
|
||||||
|
Vector.sub (sizes, idx - 1)
|
||||||
|
|
||||||
|
val oldChildSize = Vector.sub (sizes, idx)
|
||||||
|
val child = splitRight (splitIdx - prevSize, Vector.sub (nodes, idx))
|
||||||
|
|
||||||
|
val len = Vector.length nodes - (idx + 1)
|
||||||
|
val sizesSlice = VectorSlice.slice (sizes, idx + 1, SOME len)
|
||||||
|
val nodesSlice = VectorSlice.slice (nodes, idx + 1, SOME len)
|
||||||
|
in
|
||||||
|
if isEmpty child then
|
||||||
|
if VectorSlice.length sizesSlice = 0 then
|
||||||
|
(* if we descended down last node and last node became empty,
|
||||||
|
* then return empty vector *)
|
||||||
|
empty
|
||||||
|
else
|
||||||
|
let
|
||||||
|
val nodes = VectorSlice.vector nodesSlice
|
||||||
|
val sizes = VectorSlice.map (fn el => el - prevSize) sizesSlice
|
||||||
|
in
|
||||||
|
BRANCH (nodes, sizes)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
let
|
||||||
|
val newChildSize = getFinishIdx child
|
||||||
|
val difference = oldChildSize - newChildSize
|
||||||
|
val sizes = Vector.tabulate (VectorSlice.length sizesSlice + 1,
|
||||||
|
fn i =>
|
||||||
|
if i = 0 then
|
||||||
|
newChildSize
|
||||||
|
else
|
||||||
|
VectorSlice.sub (sizesSlice, i - 1) - difference
|
||||||
|
)
|
||||||
|
|
||||||
|
val child = VectorSlice.full #[child]
|
||||||
|
val nodes = VectorSlice.concat [child, nodesSlice]
|
||||||
|
in
|
||||||
|
BRANCH (nodes, sizes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
(* functions only for testing *)
|
(* functions only for testing *)
|
||||||
fun fromListLoop (lst, acc) =
|
fun fromListLoop (lst, acc) =
|
||||||
case lst of
|
case lst of
|
||||||
|
|||||||
Reference in New Issue
Block a user