su4sml/lib/fxp/src/Util/intSets.sml

174 lines
4.7 KiB
Standard ML

signature IntSets =
sig
eqtype IntSet
val emptyIntSet : IntSet
val singleIntSet : int -> IntSet
val fullIntSet : int -> IntSet
val isEmptyIntSet : IntSet -> bool
val inIntSet : int * IntSet -> bool
val compareIntSets: IntSet * IntSet -> order
val hashIntSet : IntSet -> word
val addIntSet : int * IntSet -> IntSet
val delIntSet : int * IntSet -> IntSet
val cupIntSets : IntSet * IntSet -> IntSet
val capIntSets : IntSet * IntSet -> IntSet
val diffIntSets : IntSet * IntSet -> IntSet
val IntSet2List : IntSet -> int list
val IntList2Set : int list -> IntSet
end
structure IntSets : IntSets =
struct
structure W = Word32
val wordSize = W.wordSize
type IntSet = W.word vector
infix 7 << >>
infix 6 &&
infix 5 ||
val op >> = W.>>
val op << = W.<<
val op && = W.andb
val op || = W.orb
val !! = W.notb
fun normalize (vec:IntSet) =
let val max = Vector.foldli
(fn (i,w,max) => if w=0wx0 then i else max) 0 vec
in VectorSlice.vector(VectorSlice.slice (vec,0,SOME max))
end
val emptyIntSet = Vector.fromList nil : IntSet
fun fullIntSet n = let val size = (n+wordSize-1) div wordSize
val full = 0w0-0w1:W.word
val bits = (n-1) mod wordSize+1
val last = full >> (Word.fromInt (wordSize-bits))
in Vector.tabulate(n div wordSize+1,
fn i => if i<size-1 then full else last):IntSet
end
fun singleIntSet n =
let
val idx = n div wordSize
val mask = 0w1 << (Word.fromInt (n mod wordSize))
in
Vector.tabulate(idx+1,fn i => if i=idx then mask else 0w0):IntSet
end
fun isEmptyIntSet vec = Vector.length vec=0
fun inIntSet(n,vec) =
let val idx = n div wordSize
in if idx>=Vector.length vec then false
else let val mask = 0w1 << (Word.fromInt (n mod wordSize))
in Vector.sub(vec,idx) && mask <> 0w0
end
end
fun addIntSet(n,vec) =
let
val idx = n div wordSize
val mask = 0w1 << (Word.fromInt (n mod wordSize))
val size = Vector.length vec
in
if size>idx
then Vector.mapi (fn (i,x) => if i=idx then x||mask else x) vec
else Vector.tabulate
(idx+1,fn i => if i<size then Vector.sub(vec,i) else if i=idx then mask else 0w0)
end
fun delIntSet(n,vec) =
let
val idx = n div wordSize
val size = Vector.length vec
val vec1 = if size<=idx then vec
else let val mask = !! (0w1 << (Word.fromInt (n mod wordSize)))
in Vector.mapi
(fn (i,x) => if i=idx then x && mask else x) vec
end
in normalize vec1
end
fun capIntSets(vec1,vec2) =
let
val l12 = Int.min(Vector.length vec1,Vector.length vec2)
val v12 = Vector.tabulate(l12,fn i => Vector.sub(vec1,i) && Vector.sub(vec2,i))
in
normalize v12
end
fun cupIntSets(vec1,vec2) =
let
val (l1,l2) = (Vector.length vec1,Vector.length vec2)
val (shorter,longer,v) = if l1<=l2 then (l1,l2,vec2) else (l2,l1,vec1)
in
Vector.tabulate (longer,fn i => if i>=shorter then Vector.sub(v,i)
else Vector.sub(vec1,i) || Vector.sub(vec2,i))
end
fun diffIntSets(vec1,vec2) =
let
val (l1,l2) = (Vector.length vec1,Vector.length vec2)
val vec1 = Vector.tabulate
(l1,fn i => if i>=l2 then Vector.sub(vec1,i)
else Vector.sub(vec1,i) && !!(Vector.sub(vec2,i)))
in normalize vec1
end
fun IntList2Set l = List.foldl addIntSet emptyIntSet l
fun IntSet2List vec =
let
val size = Vector.length vec
fun doOne (w,off,yet) =
let fun doit (i,mask) =
if i=wordSize then yet
else if w&&mask=0w0 then doit(i+1,mask<<0wx1)
else (off+i)::doit(i+1,mask<<0wx1)
in doit(0,0wx1)
end
fun doAll i = if i>=size then nil
else doOne(Vector.sub(vec,i),wordSize*i,(doAll (i+1)))
in doAll 0
end
fun compareIntSets (vec1,vec2:IntSet) =
let
val (l1,l2) = (Vector.length vec1,Vector.length vec2)
val (l12,ifEq) = case Int.compare(l1,l2)
of LESS => (l1,LESS)
| order => (l2,order)
fun doit i = if i>=l12 then ifEq
else case W.compare(Vector.sub(vec1,i),Vector.sub(vec2,i))
of EQUAL => doit (i+1)
| order => order
in doit 0
end
val intShift = case Int.precision
of NONE => 0w0
| SOME x => Word.fromInt(Int.max(wordSize-x+1,0))
fun hashIntSet vec =
case Vector.length vec
of 0 => 0w0
| 1 => Word.fromInt(W.toInt(W.>>(Vector.sub(vec,0),intShift)))
| l => Word.fromInt(W.toInt(W.>>(Vector.sub(vec,0)+Vector.sub(vec,l-1),intShift)))
end