diff --git a/src/gap_set.sml b/src/gap_set.sml index d1804ac..f771192 100644 --- a/src/gap_set.sml +++ b/src/gap_set.sml @@ -16,14 +16,17 @@ sig type t val empty: t + val isEmpty: t -> bool - val insert: Fn.key * t -> t + val add: Fn.key * t -> t + val remove: Fn.key * t -> t val fromList: Fn.key list -> t + val toVector: t -> Fn.key vector val exists: Fn.key * t -> bool - val getMin: t -> Fn.key option - val getMax: t -> Fn.key option + val min: t -> Fn.key option + val max: t -> Fn.key option val moveToStart: t -> t val moveToEnd: t -> t @@ -38,12 +41,15 @@ struct val empty = {left = [], right = []} + fun isEmpty {left = [], right = []} = true + | isEmpty _ = false + + fun singleton x = + {left = [], right = Vector.fromList [x]} + fun isLessThanTarget (v1, v2) = Vector.length v1 + Vector.length v2 <= Fn.maxNodeSize - fun isThreeLessThanTarget (v1, v2, v3) = - Vector.length v1 + Vector.length v2 + Vector.length v3 <= Fn.maxNodeSize - fun joinEndOfLeft (new, left) = case left of hd :: tail => @@ -223,7 +229,7 @@ struct in {left = joinEndOfLeft (new, left), right = right} end - fun insert (new, {left, right}: t) = + fun add (new, {left, right}: t) = (* look at elements to see which way to traverse *) case right of hd :: _ => @@ -236,13 +242,6 @@ struct end | [] => insLeft (new, left, right) - fun helpFromList (lst, acc) = - case lst of - hd :: tl => let val acc = insert (hd, acc) in helpFromList (tl, acc) end - | [] => acc - - fun fromList lst = helpFromList (lst, empty) - fun helpMoveToStart (left, right) = case left of hd :: tl => helpMoveToStart (tl, joinStartOfRight (hd, right)) @@ -298,23 +297,23 @@ struct else {left = left, right = right} end - fun helpGetMin (hd :: tl, prevHd) = helpGetMin (tl, hd) - | helpGetMin ([], prevHd) = + fun helpMin (hd :: tl, prevHd) = helpMin (tl, hd) + | helpMin ([], prevHd) = SOME (Vector.sub (prevHd, 0)) - fun getMin {left = hd :: tl, right = _} = helpGetMin (tl, hd) - | getMin {left = [], right = hd :: _} = + fun min {left = hd :: tl, right = _} = helpMin (tl, hd) + | min {left = [], right = hd :: _} = SOME (Vector.sub (hd, 0)) - | getMin {left = [], right = []} = NONE + | min {left = [], right = []} = NONE - fun helpGetMax (_, hd :: tl) = helpGetMax (hd, tl) - | helpGetMax (hd, []) = + fun helpMax (_, hd :: tl) = helpMax (hd, tl) + | helpMax (hd, []) = SOME (Vector.sub (hd, Vector.length hd - 1)) - fun getMax {left = _, right = hd :: tl} = helpGetMax (hd, tl) - | getMax {left = hd :: _, right = []} = + fun max {left = _, right = hd :: tl} = helpMax (hd, tl) + | max {left = hd :: _, right = []} = SOME (Vector.sub (hd, Vector.length hd - 1)) - | getMax {left = [], right = []} = NONE + | max {left = [], right = []} = NONE fun existsLeft (check, hd :: tl) = let @@ -347,4 +346,94 @@ struct else existsLeft (check, left) end | [] => existsLeft (check, left) + + fun removeLeft (toRemove, left, right) = + case left of + hd :: tl => + let + val insPos = findInsPos (toRemove, hd) + in + if insPos < 0 then + removeLeft (toRemove, tl, joinStartOfRight (hd, right)) + else if insPos = Vector.length hd then + {left = tl, right = joinStartOfRight (hd, right)} + else if Fn.eq (toRemove, Vector.sub (hd, insPos)) then + let + val lhd = VectorSlice.slice (hd, 0, SOME insPos) + val rhdLen = Vector.length hd - insPos + val rhd = VectorSlice.slice (hd, insPos, SOME rhdLen) + + val lhd = VectorSlice.vector lhd + val rhd = VectorSlice.vector rhd + in + { left = joinEndOfLeft (lhd, tl) + , right = joinStartOfRight (rhd, right) + } + end + else + {left = tl, right = joinStartOfRight (hd, right)} + end + | [] => {left = left, right = right} + + fun removeRight (toRemove, left, right) = + case right of + hd :: tl => + let + val insPos = findInsPos (toRemove, hd) + in + if insPos = Vector.length hd then + removeRight (toRemove, joinEndOfLeft (hd, left), right) + else if insPos < 0 then + {left = joinEndOfLeft (hd, left), right = right} + else if Fn.eq (toRemove, Vector.sub (hd, insPos)) then + let + val lhd = VectorSlice.slice (hd, 0, SOME insPos) + val rhdLen = Vector.length hd - insPos + val rhd = VectorSlice.slice (hd, insPos, SOME rhdLen) + + val lhd = VectorSlice.vector lhd + val rhd = VectorSlice.vector rhd + in + { left = joinEndOfLeft (lhd, left) + , right = joinStartOfRight (rhd, tl) + } + end + else + {left = joinEndOfLeft (hd, left), right = tl} + end + | [] => {left = left, right = right} + + fun remove (toRemove, {left, right}) = + case right of + hd :: tl => + let + val rfirst = Vector.sub (hd, 0) + in + if Fn.g (toRemove, rfirst) then + removeRight (toRemove, left, right) + else if Fn.l (toRemove, rfirst) then + removeLeft (toRemove, left, right) + else + let + val len = Vector.length hd - 1 + val hd = VectorSlice.slice (hd, 1, SOME len) + val hd = VectorSlice.vector hd + in + {left = left, right = joinStartOfRight (hd, tl)} + end + end + | [] => removeLeft (toRemove, left, right) + + fun helpFromList (lst, acc) = + case lst of + hd :: tl => let val acc = add (hd, acc) in helpFromList (tl, acc) end + | [] => acc + + fun fromList lst = helpFromList (lst, empty) + + fun helpToVector (hd :: tl, acc) = + helpToVector (tl, hd :: acc) + | helpToVector ([], acc) = Vector.concat acc + + fun toVector {left, right} = helpToVector (left, right) end diff --git a/src/unrolled_gap_buffer.sml b/src/unrolled_gap_buffer.sml deleted file mode 100644 index b669c78..0000000 --- a/src/unrolled_gap_buffer.sml +++ /dev/null @@ -1,452 +0,0 @@ -signature GAP_BUFFER = -sig - type t - val empty: t - val fromString: string -> t - val toString: t -> string - val insert: int * string * t -> t - val delete: int * int * t -> t -end - -structure GapBuffer: GAP_BUFFER = -struct - type t = {idx: int, left: string vector list, right: string vector list} - - val stringLimit = 1025 - val vectorLimit = 33 - - val empty = {idx = 0, left = Vector.fromList [], right = Vector.fromList []} - - fun fromString string = - { idx = String.size string - , left = Vector.fromList [string] - , right = Vector.fromList [] - } - - local - fun fromVectorToList (pos, acc, vec) = - if pos >= 0 then - let val acc = (Vector.sub (vec, pos) :: acc) - in fromVectorToList (pos - 1, acc, vec) - end - else - acc - - fun toList (acc, input) = - case input of - hd :: tl => - let val acc = fromVectorToList (Vector.length hd - 1, acc, hd) - in toList (acc, tl) - end - | [] => acc - in - fun toString ({left, right, ...}: t) = - let - val lst = toList ([], List.rev right) - val lst = toList (lst, left) - in - String.concat lst - end - end - - fun isStringInLimit2 (s1, s2) = - String.size s1 + String.size s2 < stringLimit - - fun isStringInLimit3 (s1, s2, s3) = - String.size s1 + String.size s2 + String.size s3 < stringLimit - - fun isVecInLimit2 (v1, v2) = - Vector.length v1 + Vector.length v2 < vectorLimit - - fun joinEndOfLeft (newVec, left) = - case left of - hd :: tail => - if isVecInLimit2 (newVec, hd) then - let - val startLength = Vector.length hd - val endLength = startLength + Vector.length newVec - val newVector = Vector.tabulate (endLength, fn idx => - if idx < startLength then Vector.sub (left, idx) - else Vector.sub (newVec, idx - startLength)) - in - newVector :: tail - end - else - newVec :: left - | [] => newVec :: left - - fun joinStartOfRight (newVec, right) = - case right of - hd :: tail => - if isStringInLimit2 (hd, newVec) then - let - val startLength = Vector.length newVec - val endLength = startLength + Vector.length hd - val newVector = Vector.tabulate (endLength, fn idx => - if idx < startLength then Vector.sub (newVec, idx) - else Vector.sub (hd, idx - startLength)) - in - newVector :: tail - end - else - newVec :: right - | [] => newVec :: right - - fun preferInsertLeft (curIdx, newVec, left, right) = - case left of - hd :: tail => - if isVecInLimit2 (hd, newVec) then - { idx = curIdx + String.size newString - , left = (hd ^ newString) :: tail - , right = right - } - else - (case right of - hd :: tail => - if isStringInLimit2 (hd, newString) then - {idx = curIdx, left = left, right = (newString ^ hd) :: tail} - else - joinEndOfLeft (curIdx, newString, left, right) - | [] => joinEndOfLeft (curIdx, newString, left, right)) - | [] => joinEndOfLeft (curIdx, newString, left, right) - - fun insLeft (prevIdx, idx, newString, curIdx, hd, tail, right) = - (* The requested index is either: - * - At the start of the left string - * - In the middle of the left string - * Find out which and split the middle of the string if necessary. *) - if idx = prevIdx then - (* At start of string. *) - { idx = curIdx + String.size newString - , right = right - , left = - (* These two meant to look reversed, - * with respect to newString and hd. - * - * The line - * `newString ^ hd` - * places the contents of newString before hd, - * and the line - * `hd :: newString` - * in a zipper also places newString before hd. - * - * Using `newString ^ hd` with `newString :: hd` gives - * different contents in the case of a zipper. - * *) - if isStringInLimit2 (newString, hd) then (newString ^ hd) :: tail - else hd :: newString :: tail - } - else - (* In middle of string. *) - let - val length = idx - prevIdx - val sub1 = String.substring (hd, 0, length) - val sub2 = String.substring (hd, length, String.size hd - length) - in - if isStringInLimit3 (sub1, newString, sub2) then - { idx = curIdx + String.size newString - , left = (sub1 ^ newString ^ sub2) :: tail - , right = right - } - else if isStringInLimit2 (sub1, newString) then - { idx = prevIdx + String.size sub1 + String.size newString - , left = (sub1 ^ newString) :: tail - , right = joinStartOfRight (sub2, right) - } - else if isStringInLimit2 (newString, sub2) then - { idx = prevIdx + String.size sub1 - , left = joinEndOfLeft (sub1, tail) - , right = (newString ^ sub2) :: right - } - else - { idx = prevIdx - , left = tail - , right = sub1 :: newString :: sub2 :: right - } - end - - fun insRight (nextIdx, idx, newString, curIdx, left, hd, tail) = - if idx = nextIdx then - (* At end of next string. *) - { idx = curIdx - , left = left - , right = - if isStringInLimit2 (newString, hd) then (hd ^ newString) :: tail - else hd :: (joinStartOfRight (newString, tail)) - } - else - let - val length = idx - curIdx - val sub1 = String.substring (hd, 0, length) - val sub2 = String.substring (hd, length, String.size hd - length) - in - if isStringInLimit3 (sub1, newString, sub2) then - { idx = - curIdx + String.size sub1 + String.size newString - + String.size sub2 - , left = (sub1 ^ newString ^ sub2) :: left - , right = tail - } - else if isStringInLimit2 (sub1, newString) then - { idx = curIdx + String.size sub1 + String.size newString - , left = (sub1 ^ newString) :: left - , right = joinStartOfRight (sub2, tail) - } - else if isStringInLimit2 (newString, sub2) then - { idx = curIdx + String.size sub1 - , left = sub1 :: left - , right = (newString ^ sub2) :: tail - } - else - { idx = curIdx + String.size sub1 + String.size newString - , left = newString :: sub1 :: left - , right = joinStartOfRight (sub2, tail) - } - end - - - fun ins (idx, newString, curIdx, left, right) : t = - if curIdx = idx then - preferInsertLeft (curIdx, newString, left, right) - else if idx < curIdx then - (* Need to insert on the left. *) - case left of - [] => - (* If there is no string on the left, then add the new string there. *) - {idx = String.size newString, left = [newString], right = right} - | hd :: tail => - let - val prevIdx = curIdx - String.size hd - in - if idx < prevIdx then - (* The requested index is prior to the string on the left, - * so move leftward one string. *) - ins (idx, newString, prevIdx, tail, joinStartOfRight (hd, right)) - else - insLeft (prevIdx, idx, newString, curIdx, hd, tail, right) - end - else - (* Need to insert to the right. *) - case right of - [] => {idx = curIdx, left = left, right = [newString]} - | hd :: tail => - let - val nextIdx = String.size hd + curIdx - in - if idx > nextIdx then - ins (idx, newString, nextIdx, joinEndOfLeft (hd, left), tail) - else - insRight (nextIdx, idx, newString, curIdx, left, hd, tail) - end - - fun insert (idx, newString, buffer: t) = - ins (idx, newString, #idx buffer, #left buffer, #right buffer) - - fun deleteRightFromHere (curIdx, finish, right) = - case right of - hd :: tail => - let - val nextIdx = curIdx + String.size hd - in - if nextIdx < finish then - deleteRightFromHere (nextIdx, finish, tail) - else if nextIdx > finish then - let - val newStrStart = finish - curIdx - val newStr = String.substring - (hd, newStrStart, String.size hd - newStrStart) - in - newStr :: tail - end - else - (* nextIdx = finish - * Delete current head but no further. *) - tail - end - | [] => right - - fun moveRightAndDelete (start, finish, curIdx, left, right) = - case right of - hd :: tail => - let - val nextIdx = curIdx + String.size hd - in - if nextIdx < start then - (* Keep moving right: haven't reached start yet. *) - moveRightAndDelete - (start, finish, nextIdx, joinEndOfLeft (hd, left), tail) - else if nextIdx > start then - if nextIdx < finish then - (* Delete the start range contained in this string, - * and then continue deleting right. *) - let - val length = start - curIdx - val newString = String.substring (hd, 0, length) - in - { idx = curIdx + String.size newString - , left = joinEndOfLeft (newString, left) - , right = deleteRightFromHere (nextIdx, finish, tail) - } - end - else if nextIdx > finish then - (* Have to delete from middle of string. *) - let - val sub1Length = start - curIdx - val sub1 = String.substring (hd, 0, sub1Length) - val sub2Start = finish - curIdx - val sub2 = String.substring - (hd, sub2Start, String.size hd - sub2Start) - in - { idx = curIdx + sub1Length - , left = joinEndOfLeft (sub1, left) - , right = joinStartOfRight (sub2, tail) - } - end - else - (* nextIdx = finish - * Have to delete from end of this string. *) - let - val strLength = start - curIdx - val str = String.substring (hd, 0, strLength) - in - { idx = curIdx + strLength - , left = joinEndOfLeft (str, left) - , right = tail - } - end - else - (* nextIdx = start - * The start range is contained fully at the next node, - * without having to remove part of a string at this node.*) - let - val newRight = deleteRightFromHere (nextIdx, finish, tail) - in - { idx = curIdx - , left = left - , right = joinStartOfRight (hd, newRight) - } - end - end - | [] => {idx = curIdx, left = left, right = right} - - fun deleteLeftFromHere (start, curIdx, left, right) = - case left of - hd :: tail => - let - val prevIdx = curIdx - String.size hd - in - if start < prevIdx then - deleteLeftFromHere (start, prevIdx, tail, right) - else if start > prevIdx then - (* Need to delete from some part of this string. *) - let - val length = start - prevIdx - val newStr = String.substring (hd, 0, length) - in - { idx = prevIdx - , left = tail - , right = joinStartOfRight (newStr, right) - } - end - else - (* if start = prevIdx - * Need to remove the current node without deleting any further. *) - {idx = prevIdx, left = tail, right = right} - end - - | [] => {idx = curIdx, left = left, right = right} - - fun deleteFromLeftAndRight (start, finish, curIdx, left, right) = - let val right = deleteRightFromHere (curIdx, finish, right) - in deleteLeftFromHere (start, curIdx, left, right) - end - - fun moveLeftAndDelete (start, finish, curIdx, left, right) = - case left of - hd :: tail => - let - val prevIdx = curIdx - String.size hd - in - if prevIdx > finish then - moveLeftAndDelete - (start, finish, prevIdx, tail, joinStartOfRight (hd, right)) - else if prevIdx < finish then - if prevIdx > start then - (* Delete from start point of this string, - * and then call function to continue deleting leftward. *) - let - val hdStart = finish - prevIdx - val newHd = String.substring - (hd, hdStart, String.size hd - hdStart) - val right = joinStartOfRight (newHd, right) - in - deleteLeftFromHere (start, prevIdx, tail, right) - end - else if prevIdx < start then - (* We want to delete in the middle of this current string. *) - let - val sub1Length = start - prevIdx - val sub1 = String.substring (hd, 0, sub1Length) - val sub2Start = finish - prevIdx - val sub2 = String.substring - (hd, sub2Start, String.size hd - sub2Start) - in - { idx = prevIdx + sub1Length - , left = joinEndOfLeft (sub1, tail) - , right = joinStartOfRight (sub2, right) - } - end - else - (* prevIdx = start - * We want to delete from the start of this string and stop. *) - let - val strStart = finish - prevIdx - val str = String.substring - (hd, strStart, String.size hd - strStart) - in - { idx = prevIdx - , left = tail - , right = joinStartOfRight (str, right) - } - end - else - (* prevIdx = finish *) - deleteLeftFromHere - (start, prevIdx, tail, joinStartOfRight (hd, right)) - end - | [] => {idx = curIdx, left = left, right = right} - - fun del (start, finish, curIdx, left, right) : t = - if start > curIdx then - (* If start is greater than current index, - * then finish must be greater too. - * Move buffer rightwards until finish is reached, - * and delete along the way. *) - moveRightAndDelete (start, finish, curIdx, left, right) - else if start < curIdx then - (* If start is less than current index, - * then finish could be either less than or equal/greater - * than the current index. - * We can treat equal/greater than as one case. *) - if finish <= curIdx then - (* Move leftward and delete along the way. *) - moveLeftAndDelete (start, finish, curIdx, left, right) - else - (* Delete rightward up to finish index, - * and then delete leftward until start index.*) - deleteFromLeftAndRight (start, finish, curIdx, left, right) - else - (* If start is equal to the current index, - * then only examine the right list. - * Just need to delete until reaching the finish index. *) - { idx = curIdx - , left = left - , right = deleteRightFromHere (curIdx, finish, right) - } - - fun delete (start, length, buffer: t) = - if length > 0 then - del (start, start + length, #idx buffer, #left buffer, #right buffer) - else - buffer -end