1 (* Copyright (C) 1999-2006 Henry Cejtin, Matthew Fluet, Suresh
2 * Jagannathan, and Stephen Weeks.
4 * MLton is released under a BSD-style license.
5 * See the file MLton-LICENSE for details.
8 structure UniqueSetRep =
10 datatype 'a t = T of {elements: 'a list,
11 plist: PropertyList.t}
15 functor UniqueSet (S: UNIQUE_SET_STRUCTS): UNIQUE_SET =
20 val _ = Assert.assert ("UniqueSet: cacheSize, bits", fn () =>
21 cacheSize >= 1 andalso bits >= 1)
23 type elements = Element.t list
30 val equals: t * t -> bool
31 val toList: t -> elements
32 val plist: t -> PropertyList.t
38 val insert: t * elements -> Set.t
47 fun new elements = T {elements = elements,
48 plist = PropertyList.new()}
50 fun elements (T {elements, ...}) = elements
51 fun plist (T {plist, ...}) = plist
55 fun equals (s, s') = PropertyList.equals (plist s, plist s')
59 Node of {element: Element.t,
63 withtype t = node option ref
65 fun new(): t = ref NONE
71 | SOME(Node{isIn, isNotIn, ...}) => size isIn + size isNotIn
73 fun contains(es, e) = List.exists(es, fn e' => Element.equals(e, e'))
75 fun insert(tree, elements) =
79 NONE => let val s = Set.new elements
80 in tree := SOME(Leaf s); s
82 | SOME(Node{element, isIn, isNotIn}) =>
83 if contains(elements, element)
90 ([], []) => s' (* same set *)
92 let val s = Set.new elements
94 SOME(Node{element = x',
95 isIn = ref(SOME(Leaf s')),
96 isNotIn = ref(SOME(Leaf s))})
101 fun loop2(xs', accum) =
104 let val s = Set.new elements
106 SOME(Node{element = x,
107 isIn = ref(SOME(Leaf s)),
113 if Element.equals(x, x')
114 then loop(xs, accum @ xs')
115 else loop2(xs', x' :: accum)
118 in loop(elements, Set.elements s')
127 val tableSize = Int.pow (2, bits)
129 val maxIndex = tableSize - 1
131 val mask = Word.fromInt maxIndex
133 val table = Array.tabulate(tableSize, fn _ => Tree.new())
135 fun hashToIndex(w: Word.t): int = Word.toInt(Word.andb(w, mask))
137 fun intern(l: Element.t list, h: Word.t) =
138 Tree.insert(Array.sub(table, hashToIndex h), l)
140 (* the hash of a set is the xorb of the hash of its members *)
141 fun hash(l: Element.t list) =
142 List.fold(l, 0w0, fn (e, w) => Word.xorb(w, Element.hash e))
145 let val l = List.fold(l, [], fn (x, l) =>
146 if List.exists(l, fn x' => Element.equals(x, x'))
152 val empty = fromList []
154 fun isEmpty s = equals(s, empty)
156 fun foreach(s, f) = List.foreach(toList s, f)
158 fun singleton x = fromList [x]
160 val cacheHits: int ref = ref 0
161 val cacheMisses: int ref = ref 0
163 fun stats() = {hits = !cacheHits, misses = !cacheMisses}
165 (* need to clear out and reset the tables *)
168 ; Int.for(0, tableSize, fn i => Array.update(table, i, Tree.new())))
170 (* Int.foreach(0, maxIndex, fn i =>
171 let val n = Tree.size(Vector.sub(table, i))
173 then Control.message(seq[Int.layout i,
180 fun binary (oper: elements * elements -> elements) =
182 val cache = Array.new(cacheSize, NONE)
190 val s'' = fromList(oper(toList s, toList s'))
191 val () = Int.inc cacheMisses
194 Random.natLessThan cacheSize,
199 else case Array.sub(cache, i) of
201 | SOME(s1, s1', s'') =>
202 if equals(s, s1) andalso equals(s', s1')
203 then (Int.inc cacheHits; s'')
209 val {+, -, intersect, layout, ...} =
210 List.set{equals = Element.equals,
211 layout = Element.layout}
213 val op + = binary op +
214 val op - = binary op -
215 val op intersect = binary intersect
217 val layout = layout o toList
220 (* val fromList = Trace.trace("fromList", List.layout Element.layout, layout) fromList *)
222 fun traceBinary (name, f) = Trace.trace2 (name, layout, layout, layout) f
224 val op + = traceBinary ("UniqueSet.+", op +)
225 val op - = traceBinary ("UniqueSet.-", op -)
226 val op intersect = traceBinary ("UniqueSet.intersect", intersect)