134 lines
4.0 KiB
Standard ML
134 lines
4.0 KiB
Standard ML
structure SearchList =
|
|
struct
|
|
type t = {left: int vector list, right: int vector list}
|
|
|
|
val targetLength = 1024
|
|
|
|
val empty: t = {left = [], right = []}
|
|
|
|
fun isLessThanTarget (v1, v2) =
|
|
Vector.length v1 + Vector.length v2 <= targetLength
|
|
|
|
fun isThreeLessThanTarget (v1, v2, v3) =
|
|
Vector.length v1 + Vector.length v2 + Vector.length v3 <= targetLength
|
|
|
|
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 insMiddle (new, hd, tl, left, right) =
|
|
let
|
|
val middle = BinSearch.equalOrMore (new, hd)
|
|
val leftSlice = VectorSlice.slice (hd, 0, SOME middle)
|
|
val rightLength = Vector.length hd - middle
|
|
val rightSlice = VectorSlice.slice (hd, middle, SOME rightLength)
|
|
|
|
val new = Vector.fromList [new]
|
|
val new = VectorSlice.full new
|
|
in
|
|
if Vector.length hd < targetLength then
|
|
let val newHd = VectorSlice.concat [leftSlice, new, rightSlice]
|
|
in {left = joinEndOfLeft (newHd, tl), right = right}
|
|
end
|
|
else if middle < targetLength then
|
|
(* leftSlice is less than targetLength *)
|
|
let
|
|
val hd1 = VectorSlice.concat [leftSlice, new]
|
|
val hd2 = VectorSlice.vector rightSlice
|
|
in
|
|
{ left = joinEndOfLeft (hd1, tl)
|
|
, right = joinStartOfRight (hd2, right)
|
|
}
|
|
end
|
|
else
|
|
let
|
|
val hd1 = VectorSlice.vector leftSlice
|
|
val hd2 = VectorSlice.concat [new, rightSlice]
|
|
in
|
|
{ left = joinEndOfLeft (hd1, tl)
|
|
, right = joinStartOfRight (hd2, right)
|
|
}
|
|
end
|
|
end
|
|
|
|
fun insLeft (new, left, right) =
|
|
case left of
|
|
hd :: tl =>
|
|
let
|
|
val first = Vector.sub (hd, 0)
|
|
in
|
|
if new < first then
|
|
insLeft (new, tl, joinStartOfRight (hd, right))
|
|
else if new > first then
|
|
let
|
|
val last = Vector.sub (hd, Vector.length hd - 1)
|
|
in
|
|
if new < last then
|
|
(* have to insert in middle *)
|
|
insMiddle (new, hd, tl, left, right)
|
|
else if new > last then
|
|
(* have to insert new at end of left
|
|
* or start of right (both are equivalent) *)
|
|
{ left = left
|
|
, right = joinStartOfRight (Vector.fromList [new], right)
|
|
}
|
|
else
|
|
(* new = last so just return *)
|
|
{left = left, right = right}
|
|
end
|
|
else
|
|
(* new = first *)
|
|
{left = left, right = right}
|
|
end
|
|
| [] => {left = left, right = right}
|
|
|
|
fun insRight (new, left, right) =
|
|
case right of
|
|
hd :: tl =>
|
|
let
|
|
val last = Vector.sub (hd, Vector.length hd - 1)
|
|
in
|
|
if new > last then
|
|
insRight (new, joinEndOfLeft (hd, left), tl)
|
|
else if new < last then
|
|
let
|
|
val first = Vector.sub (hd, 0)
|
|
in
|
|
if new > first then
|
|
(* have to insert in middle *)
|
|
insMiddle (new, hd, tl, left, right)
|
|
else if new < first then
|
|
(* have to insert new at start of right
|
|
* or end of left (both are equivalent) *)
|
|
{ left = left
|
|
, right = joinStartOfRight (Vector.fromList [new], right)
|
|
}
|
|
else
|
|
(* new = first so just return *)
|
|
{left = left, right = right}
|
|
end
|
|
else
|
|
(* new = last *)
|
|
{left = left, right = right}
|
|
end
|
|
| [] => {left = left, right = right}
|
|
end
|