code insert function for gap-set.sml
This commit is contained in:
231
src/gap_set.sml
Normal file
231
src/gap_set.sml
Normal file
@@ -0,0 +1,231 @@
|
||||
signature GAP_SET_ELEMENT =
|
||||
sig
|
||||
type key
|
||||
|
||||
val l: key * key -> bool
|
||||
val eq: key * key -> bool
|
||||
val g: key * key -> bool
|
||||
|
||||
val maxNodeSize: int
|
||||
end
|
||||
|
||||
signature GAP_SET =
|
||||
sig
|
||||
structure Fn: GAP_SET_ELEMENT
|
||||
|
||||
type t
|
||||
|
||||
val insert: Fn.key * t -> t
|
||||
|
||||
val fromList: Fn.key list -> t
|
||||
end
|
||||
|
||||
functor MakeGapSet(Fn: GAP_SET_ELEMENT): GAP_SET =
|
||||
struct
|
||||
structure Fn = Fn
|
||||
|
||||
type t = {left: Fn.key vector list, right: Fn.key vector list}
|
||||
|
||||
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 =>
|
||||
if isLessThanTarget (new, hd) then
|
||||
let val newHd = Vector.concat [hd, new]
|
||||
in newHd :: tail
|
||||
end
|
||||
else
|
||||
new :: left
|
||||
| [] => new :: left
|
||||
|
||||
fun joinStartOfRight (new, right) =
|
||||
case right of
|
||||
hd :: tail =>
|
||||
if isLessThanTarget (new, hd) then
|
||||
let val newHd = Vector.concat [new, hd]
|
||||
in newHd :: tail
|
||||
end
|
||||
else
|
||||
new :: right
|
||||
| [] => new :: right
|
||||
|
||||
fun reverseLinearSearch (pos, findNum, vec) =
|
||||
if pos < 0 then
|
||||
~1
|
||||
else
|
||||
let
|
||||
val curNum = Vector.sub (vec, pos)
|
||||
in
|
||||
if Fn.l (findNum, curNum) then pos
|
||||
else reverseLinearSearch (pos - 1, findNum, vec)
|
||||
end
|
||||
|
||||
fun forwardLinearSearch (pos, findNum, vec) =
|
||||
if pos = Vector.length vec then
|
||||
Vector.length vec
|
||||
else
|
||||
let
|
||||
val curNum = Vector.sub (vec, pos)
|
||||
in
|
||||
if Fn.g (findNum, curNum) then pos + 1
|
||||
else forwardLinearSearch (pos + 1, findNum, vec)
|
||||
end
|
||||
|
||||
fun helpFindInsPos (findNum, vec, low, high, prevMid) =
|
||||
if high >= low then
|
||||
let
|
||||
val mid = low + ((high - low) div 2)
|
||||
val curNum = Vector.sub (vec, mid)
|
||||
in
|
||||
if Fn.eq (curNum, findNum) then
|
||||
mid
|
||||
else if Fn.l (curNum, findNum) then
|
||||
helpFindInsPos (findNum, vec, mid + 1, high, mid)
|
||||
else
|
||||
helpFindInsPos (findNum, vec, low, mid - 1, mid)
|
||||
end
|
||||
else
|
||||
let
|
||||
val curNum = Vector.sub (vec, prevMid)
|
||||
in
|
||||
if Fn.g (findNum, curNum) then
|
||||
forwardLinearSearch (prevMid, findNum, vec)
|
||||
else
|
||||
reverseLinearSearch (prevMid, findNum, vec)
|
||||
end
|
||||
|
||||
fun findInsPos (findNum, vec) =
|
||||
if Vector.length vec = 0 then ~1
|
||||
else helpFindInsPos (findNum, vec, 0, Vector.length vec - 1, 0)
|
||||
|
||||
fun insWithPos (vec, elem, insPos) =
|
||||
if insPos < 0 then
|
||||
Vector.concat [Vector.fromList [elem], vec]
|
||||
else if insPos = Vector.length vec then
|
||||
Vector.concat [vec, Vector.fromList [elem]]
|
||||
else
|
||||
let
|
||||
val elem = Vector.fromList [elem]
|
||||
val elem = VectorSlice.full elem
|
||||
|
||||
val s2len = Vector.length vec - insPos
|
||||
val slice1 = VectorSlice.slice (vec, 0, SOME insPos)
|
||||
val slice2 = VectorSlice.slice (vec, insPos, SOME s2len)
|
||||
in
|
||||
VectorSlice.concat [slice1, elem, slice2]
|
||||
end
|
||||
|
||||
fun insMiddle (hd, insPos, new, left, right) =
|
||||
(* insert in middle *)
|
||||
if Fn.eq (Vector.sub (hd, insPos), new) then
|
||||
(* already have this key so no need to insert again *)
|
||||
{left = left, right = right}
|
||||
else if Vector.length hd + 1 > Fn.maxNodeSize then
|
||||
let
|
||||
(* split into two vectors and join with new *)
|
||||
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 new = Vector.fromList [new]
|
||||
val new = VectorSlice.full new
|
||||
val rhd = VectorSlice.concat [new, rhd]
|
||||
in
|
||||
{left = joinEndOfLeft (lhd, left), right = rhd :: right}
|
||||
end
|
||||
else
|
||||
let
|
||||
(* insert without splitting *)
|
||||
val newHd = insWithPos (hd, new, insPos)
|
||||
in
|
||||
{left = joinEndOfLeft (newHd, left), right = right}
|
||||
end
|
||||
|
||||
fun insLeft (new, left, right) =
|
||||
case left of
|
||||
hd :: tl =>
|
||||
let
|
||||
val insPos = findInsPos (new, hd)
|
||||
in
|
||||
if insPos = ~1 then
|
||||
insLeft (new, tl, joinStartOfRight (hd, right))
|
||||
else if insPos = Vector.length hd then
|
||||
(* insert at end *)
|
||||
if Vector.length hd + 1 > Fn.maxNodeSize then
|
||||
let
|
||||
(* hd is full so join new to start of right *)
|
||||
val right = joinStartOfRight (Vector.fromList [new], right)
|
||||
in
|
||||
{left = left, right = right}
|
||||
end
|
||||
else
|
||||
let
|
||||
(* join to end without splitting *)
|
||||
val lhd = Vector.concat [hd, Vector.fromList [new]]
|
||||
in
|
||||
{left = joinEndOfLeft (lhd, tl), right = right}
|
||||
end
|
||||
else
|
||||
insMiddle (hd, insPos, new, left, right)
|
||||
end
|
||||
| [] =>
|
||||
let val new = Vector.fromList [new]
|
||||
in {left = left, right = joinStartOfRight (new, right)}
|
||||
end
|
||||
|
||||
fun insRight (new, left, right) =
|
||||
case right of
|
||||
hd :: tl =>
|
||||
let
|
||||
val insPos = findInsPos (new, hd)
|
||||
in
|
||||
if insPos = Vector.length hd then
|
||||
insRight (new, joinEndOfLeft (hd, left), tl)
|
||||
else if insPos < 0 then
|
||||
(* insert at start *)
|
||||
if Vector.length hd + 1 > Fn.maxNodeSize then
|
||||
let
|
||||
(* hd is full so join new to end of left *)
|
||||
val left = joinEndOfLeft (Vector.fromList [new], left)
|
||||
in
|
||||
{left = left, right = right}
|
||||
end
|
||||
else
|
||||
let
|
||||
(* join to start without splitting *)
|
||||
val rhd = Vector.concat [Vector.fromList [new], hd]
|
||||
in
|
||||
{left = left, right = joinStartOfRight (rhd, tl)}
|
||||
end
|
||||
else
|
||||
insMiddle (hd, insPos, new, left, right)
|
||||
end
|
||||
| [] =>
|
||||
let val new = Vector.fromList [new]
|
||||
in {left = joinEndOfLeft (new, left), right = right}
|
||||
end
|
||||
|
||||
fun insert (new, {left, right}: t) =
|
||||
(* look at elements to see which way to traverse *)
|
||||
case right of
|
||||
hd :: _ =>
|
||||
let
|
||||
val rfist = 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)
|
||||
else {left = left, right = right}
|
||||
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
|
||||
end
|
||||
Reference in New Issue
Block a user