implement removeMany function for gap_set.sml (but it is untested and more complicated than all the other functions)

This commit is contained in:
2025-02-03 06:39:46 +00:00
parent 47c1492136
commit 713d17fdd3

View File

@@ -20,6 +20,7 @@ sig
val add: Fn.key * t -> t
val remove: Fn.key * t -> t
val removeMany: Fn.key * Fn.key * t -> t
val fromList: Fn.key list -> t
val toVector: t -> Fn.key vector
@@ -234,10 +235,10 @@ struct
case right of
hd :: _ =>
let
val rfist = Vector.sub (hd, 0)
val rfirst = Vector.sub (hd, 0)
in
if Fn.g (new, rfist) then insRight (new, left, right)
else if Fn.l (new, rfist) then insLeft (new, left, right)
if Fn.g (new, rfirst) then insRight (new, left, right)
else if Fn.l (new, rfirst) then insLeft (new, left, right)
else {left = left, right = right}
end
| [] => insLeft (new, left, right)
@@ -286,16 +287,28 @@ struct
end
| [] => {left = left, right = right}
fun moveToWhenRightIsEmpty (to, left, right) =
case left of
hd :: _ =>
let
val llast = Vector.sub (hd, Vector.length hd - 1)
in
if Fn.l (to, llast) then moveLeft (to, left, right)
else {left = left, right = right}
end
| [] => {left = left, right = right}
fun moveTo (to, {left, right}) =
case right of
hd :: _ =>
let
val rfist = Vector.sub (hd, 0)
val rfirst = Vector.sub (hd, 0)
in
if Fn.g (to, rfist) then moveRight (to, left, right)
else if Fn.l (to, rfist) then moveLeft (to, left, right)
if Fn.g (to, rfirst) then moveRight (to, left, right)
else if Fn.l (to, rfirst) then moveLeft (to, left, right)
else {left = left, right = right}
end
| [] => moveToWhenRightIsEmpty (to, left, right)
fun helpMin (hd :: tl, prevHd) = helpMin (tl, hd)
| helpMin ([], prevHd) =
@@ -424,6 +437,325 @@ struct
end
| [] => removeLeft (toRemove, left, right)
fun removeRightFromHere (finish, right) =
case right of
hd :: tl =>
let
val finishPos = findInsPos (finish, hd)
in
if finishPos = Vector.length hd then
removeRightFromHere (finish, tl)
else if finishPos < 0 then
right
else
let
(* keep second half of hd / remove first part of hd *)
val finishPos =
if Fn.eq (finish, Vector.sub (hd, finishPos)) then finishPos + 1
else finishPos
val len = Vector.length hd - finishPos
val slice = VectorSlice.slice (hd, finishPos, SOME len)
val newHd = VectorSlice.vector slice
in
joinStartOfRight (newHd, tl)
end
end
| [] => right
fun removeLeftFromHere (start, left) =
case left of
hd :: tl =>
let
val startPos = findInsPos (start, hd)
in
if startPos < 0 then
removeLeftFromHere (start, tl)
else if startPos = Vector.length hd then
left
else
let
(* keep first half of hd / remove last part of hd *)
val slice = VectorSlice.slice (hd, 0, SOME startPos)
val newHd = VectorSlice.vector slice
in
joinEndOfLeft (newHd, tl)
end
end
| [] => left
fun removeManyFromHd (startPos, finish, finishPos, hd, left, right) =
let
val lhd = VectorSlice.slice (hd, 0, SOME startPos)
val rStart =
if Fn.eq (finish, Vector.sub (hd, finishPos)) then finishPos + 1
else finishPos
val rlen = Vector.length hd - rStart
val rhd = VectorSlice.slice (hd, rStart, SOME rlen)
val lhd = VectorSlice.vector lhd
val rhd = VectorSlice.vector rhd
in
{left = joinEndOfLeft (lhd, left), right = joinStartOfRight (rhd, right)}
end
fun moveLeftAndRemove (start, finish, left, right) =
case left of
hd :: tl =>
let
val finishPos = findInsPos (finish, hd)
in
if finishPos < 0 then
moveLeftAndRemove (start, finish, tl, joinStartOfRight (hd, right))
else if finishPos = Vector.length hd then
let
val startPos = findInsPos (start, hd)
in
if startPos < 0 then
(* remove hd and continue removing leftwards *)
let val left = removeLeftFromHere (start, left)
in {left = left, right = right}
end
else if startPos = Vector.length hd then
(* return, not removing anything,
* because there are no elements
* between start and finish.
* We do still join hd to tl if pssible for performace reasons. *)
{left = joinEndOfLeft (hd, tl), right = right}
else
(* have to delete from last part of hd *)
let
val slice = VectorSlice.slice (hd, 0, SOME startPos)
val newHd = VectorSlice.vector slice
in
{left = joinEndOfLeft (newHd, tl), right = right}
end
end
else
(* finish pos is somewhere in middle of hd
* but have to check where startPos is. *)
let
val startPos = findInsPos (start, hd)
in
if startPos < 0 then
let
val slice = VectorSlice.slice (hd, 0, SOME finishPos)
val newHd = VectorSlice.vector slice
val left = removeLeftFromHere (start, tl)
in
{left = left, right = right}
end
else
(* startPos is in middle of hd.
* Does not make sense for startPos = Vector.length hd
* because finishPos is in middle as well.
* So, delete from middle. *)
removeManyFromHd (startPos, finish, finishPos, hd, tl, right)
end
end
| [] => {left = left, right = right}
fun moveRightAndRemove (start, finish, left, right) =
case right of
hd :: tl =>
let
val startPos = findInsPos (start, hd)
in
if startPos = Vector.length hd then
(* keep moving rightwards *)
moveRightAndRemove (start, finish, joinEndOfLeft (hd, left), tl)
else if startPos < 0 then
(* start does not exist as it is before this node.
* Does finish exist, and if it does, what is its position? *)
let
val finishPos = findInsPos (finish, hd)
in
if finishPos = Vector.length hd then
(* remove this node and delete right from here. *)
let val right = removeRightFromHere (finish, tl)
in {left = left, right = right}
end
else if finishPos < 0 then
(* finish is less than first element in this node,
* so return. *)
{left = left, right = right}
else
(* have to delete first part of the hd *)
let
val lhd = VectorSlice.slice (hd, 0, SOME startPos)
val rStart =
if Fn.eq (Vector.sub (hd, finishPos), finish) then
finishPos + 1
else
finishPos
val rLen = Vector.length hd - rStart
val rhd = VectorSlice.slice (hd, rStart, SOME rLen)
val lhd = VectorSlice.vector lhd
val rhd = VectorSlice.vector rhd
in
{ left = joinEndOfLeft (lhd, left)
, right = joinStartOfRight (rhd, right)
}
end
end
else
(* have to delete starting from this node.
* End depends on the `finish` value. *)
let
val finishPos = findInsPos (finish, hd)
in
if finishPos = Vector.length hd then
(* delete last part of this node
* and continue deleting rightwards *)
let
val hd = VectorSlice.slice (hd, 0, SOME startPos)
val hd = VectorSlice.vector hd
val tl = removeRightFromHere (finish, tl)
in
{left = left, right = joinStartOfRight (hd, tl)}
end
else
(* we already checked and found that
* start is somewhere in the middle.
* This means `finish` must be in the middle too,
* if finish is not equal to `Vector.length hd`.
* So we only need to delete some part from the middle of hd. *)
removeManyFromHd (startPos, finish, finishPos, hd, left, tl)
end
end
| [] => {left = left, right = right}
fun removeWhenStartIsLessThanRFirst (start, finish, left, right, rfirst) =
case left of
lhd :: _ =>
let
val llast = Vector.sub (lhd, Vector.length lhd - 1)
in
if Fn.l (start, llast) then
if Fn.g (finish, llast) then
(* have to delete left from here and right from here *)
let
val left = removeLeftFromHere (start, left)
(* removeRightFromHere will not remove anything
* if finish < rfirst *)
val right = removeRightFromHere (finish, right)
in
{left = left, right = right}
end
else
(* either finish < llast or finish = llast
* which means move left and delete
* since finish may be before lhd *)
moveLeftAndRemove (start, finish, left, right)
else if Fn.eq (start, llast) then
if
Fn.eq (finish, llast)
then
(* just need to remove llast as both start and finish range
* are contained in left *)
let val left = removeLeftFromHere (start, left)
in {left = left, right = right}
end
else (* finish > llast
* as finish < llast case is impossible
* since start = llast.
* Check how finish compares to rfirst. *) if
Fn.l (finish, rfirst)
then
(* don't do anything with finish/rfirst,
* because finish is less than rfirst
* but do remove llast from left
* because llast is equal to start *)
let val left = removeLeftFromHere (start, left)
in {left = left, right = right}
end
else
(* finish >= rfirst; in either case, we need to remove
* some elements which are in right. *)
let
val left = removeLeftFromHere (start, left)
val right = removeRightFromHere (finish, right)
in
{left = left, right = right}
end
else (* start > llast *) if Fn.l (finish, rfirst) then
(* no elements in range between start and finish *)
{left = left, right = right}
else
(* whether finish > rfirst or finish = rfirst,
* we have some elements to delete from the right *)
let val right = removeRightFromHere (finish, right)
in {left = left, right = right}
end
end
| [] => {left = left, right = right}
fun removeWhenRightIsEmpty (start, finish, left, right) =
case left of
hd :: tl =>
let
val finishPos = findInsPos (finish, hd)
val startPos = findInsPos (start, hd)
in
if
finishPos = Vector.length hd
then
if startPos = Vector.length hd then
{left = left, right = right}
else if startPos < 0 then
(* remove hd, and continue removing leftwards *)
let val left = removeLeftFromHere (start, left)
in {left = left, right = right}
end
else
(* remove last part of hd, keeping first part *)
let
val slice = VectorSlice.slice (hd, 0, SOME startPos)
val newHd = VectorSlice.vector slice
in
{left = tl, right = [newHd]}
end
else if
finishPos < 0
then
moveLeftAndRemove (start, finish, tl, [hd])
else (* finishPos is in middle; what about startPos? *) if
startPos < 0
then
moveLeftAndRemove (start, finish, left, right)
else
(* startPos is in middle because `start = Vector.length hd`
* is impossible, as finish is in middle already. *)
removeManyFromHd (startPos, finish, finishPos, hd, tl, right)
end
| [] => {left = left, right = right}
(* assumption: 'start' is the minimum element to delete and 'finish' is the
* last element to delete.
* Reason for this assumption is because we don't ask the user for a function
* like `Int.min` or `Int.max` which can be used to get the minimum/maximum.
* So, if the user passes in a `start` that is greater than a `finish`,
* then that's a user error. *)
fun removeMany (start, finish, {left, right}) =
case right of
rhd :: _ =>
let
val rfirst = Vector.sub (rhd, 0)
in
if Fn.g (start, rfirst) then
(* Will need to move rightwards and delete. *)
moveRightAndRemove (start, finish, left, right)
else if Fn.eq (start, rfirst) then
(* need to delete right from here *)
let val right = removeRightFromHere (finish, right)
in {left = left, right = right}
end
else
removeWhenStartIsLessThanRFirst (start, finish, left, right, rfirst)
end
| [] => removeWhenRightIsEmpty (start, finish, left, right)
fun helpFromList (lst, acc) =
case lst of
hd :: tl => let val acc = add (hd, acc) in helpFromList (tl, acc) end