add 'append' and 'appendLine' functions to rope

This commit is contained in:
2024-03-14 12:22:27 +00:00
parent 224226fea8
commit 8ea6d2c1b7

View File

@@ -2,10 +2,19 @@ signature ROPE =
sig sig
type t type t
val empty: t val empty: t
val fromString: string -> t val fromString: string -> t
val foldr: ('a * string * int vector -> 'a) * 'a * t -> 'a
val insert: int * string * t -> t
val toString: t -> string val toString: t -> string
val foldr: ('a * string * int vector -> 'a) * 'a * t -> 'a
val insert: int * string * t -> t
(* The append and appendLine function both add a string to the end.
* The difference is that append calculates line metadata
* from the given string, while appendLine accepts
* (possibly incorrect) metadata from the caller. *)
val append: string * t -> t
val appendLine: string * int vector * t -> t
(* This below function verifies that line metadata is as expected, (* This below function verifies that line metadata is as expected,
* raising an exception if it is different, * raising an exception if it is different,
@@ -309,8 +318,7 @@ struct
else Vector.sub (newVec, idx - oldLen) + oldStrLen)) else Vector.sub (newVec, idx - oldLen) + oldStrLen))
end end
fun insLeaf (curIdx, newStr, newVec, rope, oldStr, oldVec) = fun preLeaf (oldStr, oldVec, newStr, newVec) =
if curIdx <= 0 then
if isLessThanTarget (oldStr, newStr, oldVec, newVec) then if isLessThanTarget (oldStr, newStr, oldVec, newVec) then
let let
val str = newStr ^ oldStr val str = newStr ^ oldStr
@@ -322,7 +330,8 @@ struct
let val l2 = L2 (newStr, newVec, oldStr, oldVec) let val l2 = L2 (newStr, newVec, oldStr, oldVec)
in (l2, AddedNode) in (l2, AddedNode)
end end
else if curIdx >= String.size oldStr then
fun appLeaf (oldStr, oldVec, newStr, newVec) =
if isLessThanTarget (oldStr, newStr, oldVec, newVec) then if isLessThanTarget (oldStr, newStr, oldVec, newVec) then
let let
val str = oldStr ^ newStr val str = oldStr ^ newStr
@@ -334,6 +343,12 @@ struct
let val l2 = L2 (oldStr, oldVec, newStr, newVec) let val l2 = L2 (oldStr, oldVec, newStr, newVec)
in (l2, AddedNode) in (l2, AddedNode)
end end
fun insLeaf (curIdx, newStr, newVec, oldStr, oldVec) =
if curIdx <= 0 then
preLeaf (oldStr, oldVec, newStr, newVec)
else if curIdx >= String.size oldStr then
appLeaf (oldStr, oldVec, newStr, newVec)
else else
(* Need to split in middle of string. *) (* Need to split in middle of string. *)
let let
@@ -444,13 +459,7 @@ struct
(node, DeletedNode) (node, DeletedNode)
end end
fun ins (curIdx, newStr, newVec, rope) = fun insBalL (l, lms, lmv, newStr, newVec, r, action) =
case rope of
N2 (l, lms, lmv, r) =>
if curIdx < lms then
let
val (l, action) = ins (curIdx, newStr, newVec, l)
in
(case action of (case action of
NoAction => NoAction =>
(case (l, r) of (case (l, r) of
@@ -458,18 +467,12 @@ struct
if isLessThanTarget (s1, s2, v1, v2) then if isLessThanTarget (s1, s2, v1, v2) then
insLessThanTarget (s1, s2, v1, v2) insLessThanTarget (s1, s2, v1, v2)
else else
insLMoreThanTarget insLMoreThanTarget (lms, newStr, lmv, newVec, l, r, action)
(lms, newStr, lmv, newVec, l, r, action) | _ => insLMoreThanTarget (lms, newStr, lmv, newVec, l, r, action))
| _ =>
insLMoreThanTarget
(lms, newStr, lmv, newVec, l, r, action))
| AddedNode => (insN2Left (l, r), action) | AddedNode => (insN2Left (l, r), action)
| DeletedNode => (delN2Left (l, r), action)) | DeletedNode => (delN2Left (l, r), action))
end
else fun insBalR (l, r, action) =
let
val (r, action) = ins (curIdx - lms, newStr, newVec, r)
in
(case action of (case action of
NoAction => NoAction =>
(case (l, r) of (case (l, r) of
@@ -481,6 +484,17 @@ struct
| _ => (makeN2 (l, r), action)) | _ => (makeN2 (l, r), action))
| AddedNode => (insN2Right (l, r), action) | AddedNode => (insN2Right (l, r), action)
| DeletedNode => (delN2Right (l, r), action)) | DeletedNode => (delN2Right (l, r), action))
fun ins (curIdx, newStr, newVec, rope) =
case rope of
N2 (l, lms, lmv, r) =>
if curIdx < lms then
let val (l, action) = ins (curIdx, newStr, newVec, l)
in insBalL (l, lms, lmv, newStr, newVec, r, action)
end
else
let val (r, action) = ins (curIdx - lms, newStr, newVec, r)
in insBalR (l, r, action)
end end
| N1 t => | N1 t =>
let let
@@ -490,8 +504,7 @@ struct
AddedNode => (insN1 t, action) AddedNode => (insN1 t, action)
| _ => (N1 t, action)) | _ => (N1 t, action))
end end
| N0 (oldStr, oldVec) => | N0 (oldStr, oldVec) => insLeaf (curIdx, newStr, newVec, oldStr, oldVec)
insLeaf (curIdx, newStr, newVec, rope, oldStr, oldVec)
| _ => raise AuxConstructor | _ => raise AuxConstructor
fun endInsert (rope, action) = fun endInsert (rope, action) =
@@ -508,6 +521,29 @@ struct
endInsert (rope, action) endInsert (rope, action)
end end
fun app (newStr, newVec, rope) =
case rope of
N2 (l, lms, lmv, r) =>
let val (r, action) = app (newStr, newVec, r)
in insBalR (l, r, action)
end
| N1 t => app (newStr, newVec, t)
| N0 (oldStr, oldVec) => appLeaf (oldStr, oldVec, newStr, newVec)
| _ => raise AuxConstructor
fun append (newStr, rope) =
let
val newVec = countLineBreaks newStr
val (rope, action) = app (newStr, newVec, rope)
in
endInsert (rope, action)
end
fun appendLine (newStr, newVec, rope) =
let val (rope, action) = app (newStr, newVec, rope)
in endInsert (rope, action)
end
fun verifyLines rope = fun verifyLines rope =
foldr foldr
( (fn (_, str, vec) => ( (fn (_, str, vec) =>