add 'append' and 'appendLine' functions to rope
This commit is contained in:
152
rope.sml
152
rope.sml
@@ -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,31 +318,37 @@ 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 isLessThanTarget (oldStr, newStr, oldVec, newVec) then
|
||||||
|
let
|
||||||
|
val str = newStr ^ oldStr
|
||||||
|
val vec = insVecBefore (oldVec, newVec, newStr)
|
||||||
|
in
|
||||||
|
(N0 (str, vec), NoAction)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
let val l2 = L2 (newStr, newVec, oldStr, oldVec)
|
||||||
|
in (l2, AddedNode)
|
||||||
|
end
|
||||||
|
|
||||||
|
fun appLeaf (oldStr, oldVec, newStr, newVec) =
|
||||||
|
if isLessThanTarget (oldStr, newStr, oldVec, newVec) then
|
||||||
|
let
|
||||||
|
val str = oldStr ^ newStr
|
||||||
|
val vec = insVecAfter (oldStr, oldVec, newVec)
|
||||||
|
in
|
||||||
|
(N0 (str, vec), NoAction)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
let val l2 = L2 (oldStr, oldVec, newStr, newVec)
|
||||||
|
in (l2, AddedNode)
|
||||||
|
end
|
||||||
|
|
||||||
|
fun insLeaf (curIdx, newStr, newVec, oldStr, oldVec) =
|
||||||
if curIdx <= 0 then
|
if curIdx <= 0 then
|
||||||
if isLessThanTarget (oldStr, newStr, oldVec, newVec) then
|
preLeaf (oldStr, oldVec, newStr, newVec)
|
||||||
let
|
|
||||||
val str = newStr ^ oldStr
|
|
||||||
val vec = insVecBefore (oldVec, newVec, newStr)
|
|
||||||
in
|
|
||||||
(N0 (str, vec), NoAction)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
let val l2 = L2 (newStr, newVec, oldStr, oldVec)
|
|
||||||
in (l2, AddedNode)
|
|
||||||
end
|
|
||||||
else if curIdx >= String.size oldStr then
|
else if curIdx >= String.size oldStr then
|
||||||
if isLessThanTarget (oldStr, newStr, oldVec, newVec) then
|
appLeaf (oldStr, oldVec, newStr, newVec)
|
||||||
let
|
|
||||||
val str = oldStr ^ newStr
|
|
||||||
val vec = insVecAfter (oldStr, oldVec, newVec)
|
|
||||||
in
|
|
||||||
(N0 (str, vec), NoAction)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
let val l2 = L2 (oldStr, oldVec, newStr, newVec)
|
|
||||||
in (l2, AddedNode)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
(* Need to split in middle of string. *)
|
(* Need to split in middle of string. *)
|
||||||
let
|
let
|
||||||
@@ -444,43 +459,42 @@ struct
|
|||||||
(node, DeletedNode)
|
(node, DeletedNode)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
fun insBalL (l, lms, lmv, newStr, newVec, r, action) =
|
||||||
|
(case action of
|
||||||
|
NoAction =>
|
||||||
|
(case (l, r) of
|
||||||
|
(N0 (s1, v1), N0 (s2, v2)) =>
|
||||||
|
if isLessThanTarget (s1, s2, v1, v2) then
|
||||||
|
insLessThanTarget (s1, s2, v1, v2)
|
||||||
|
else
|
||||||
|
insLMoreThanTarget (lms, newStr, lmv, newVec, l, r, action)
|
||||||
|
| _ => insLMoreThanTarget (lms, newStr, lmv, newVec, l, r, action))
|
||||||
|
| AddedNode => (insN2Left (l, r), action)
|
||||||
|
| DeletedNode => (delN2Left (l, r), action))
|
||||||
|
|
||||||
|
fun insBalR (l, r, action) =
|
||||||
|
(case action of
|
||||||
|
NoAction =>
|
||||||
|
(case (l, r) of
|
||||||
|
(N0 (s1, v1), N0 (s2, v2)) =>
|
||||||
|
if isLessThanTarget (s1, s2, v1, v2) then
|
||||||
|
insLessThanTarget (s1, s2, v1, v2)
|
||||||
|
else
|
||||||
|
(makeN2 (l, r), action)
|
||||||
|
| _ => (makeN2 (l, r), action))
|
||||||
|
| AddedNode => (insN2Right (l, r), action)
|
||||||
|
| DeletedNode => (delN2Right (l, r), action))
|
||||||
|
|
||||||
fun ins (curIdx, newStr, newVec, rope) =
|
fun ins (curIdx, newStr, newVec, rope) =
|
||||||
case rope of
|
case rope of
|
||||||
N2 (l, lms, lmv, r) =>
|
N2 (l, lms, lmv, r) =>
|
||||||
if curIdx < lms then
|
if curIdx < lms then
|
||||||
let
|
let val (l, action) = ins (curIdx, newStr, newVec, l)
|
||||||
val (l, action) = ins (curIdx, newStr, newVec, l)
|
in insBalL (l, lms, lmv, newStr, newVec, r, action)
|
||||||
in
|
|
||||||
(case action of
|
|
||||||
NoAction =>
|
|
||||||
(case (l, r) of
|
|
||||||
(N0 (s1, v1), N0 (s2, v2)) =>
|
|
||||||
if isLessThanTarget (s1, s2, v1, v2) then
|
|
||||||
insLessThanTarget (s1, s2, v1, v2)
|
|
||||||
else
|
|
||||||
insLMoreThanTarget
|
|
||||||
(lms, newStr, lmv, newVec, l, r, action)
|
|
||||||
| _ =>
|
|
||||||
insLMoreThanTarget
|
|
||||||
(lms, newStr, lmv, newVec, l, r, action))
|
|
||||||
| AddedNode => (insN2Left (l, r), action)
|
|
||||||
| DeletedNode => (delN2Left (l, r), action))
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
let
|
let val (r, action) = ins (curIdx - lms, newStr, newVec, r)
|
||||||
val (r, action) = ins (curIdx - lms, newStr, newVec, r)
|
in insBalR (l, r, action)
|
||||||
in
|
|
||||||
(case action of
|
|
||||||
NoAction =>
|
|
||||||
(case (l, r) of
|
|
||||||
(N0 (s1, v1), N0 (s2, v2)) =>
|
|
||||||
if isLessThanTarget (s1, s2, v1, v2) then
|
|
||||||
insLessThanTarget (s1, s2, v1, v2)
|
|
||||||
else
|
|
||||||
(makeN2 (l, r), action)
|
|
||||||
| _ => (makeN2 (l, r), action))
|
|
||||||
| AddedNode => (insN2Right (l, r), action)
|
|
||||||
| DeletedNode => (delN2Right (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) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user