1
1
package dotty .tools .dotc .util
2
2
3
- import collection .mutable . ListBuffer
3
+ import collection .mutable
4
4
5
5
/** A simple linked set with `eq` as the comparison, optimized for small sets.
6
6
* It has linear complexity for `contains`, `+`, and `-`.
7
7
*/
8
8
abstract class SimpleIdentitySet [+ Elem <: AnyRef ] {
9
9
def size : Int
10
- def isEmpty : Boolean = size == 0
10
+ final def isEmpty : Boolean = size == 0
11
11
def + [E >: Elem <: AnyRef ](x : E ): SimpleIdentitySet [E ]
12
12
def - [E >: Elem <: AnyRef ](x : E ): SimpleIdentitySet [Elem ]
13
13
def contains [E >: Elem <: AnyRef ](x : E ): Boolean
14
14
def foreach (f : Elem => Unit ): Unit
15
- def toList : List [Elem ] = {
16
- val buf = new ListBuffer [Elem ]
17
- foreach(buf += _)
18
- buf.toList
19
- }
15
+ def exists [E >: Elem <: AnyRef ](p : E => Boolean ): Boolean
16
+ def /: [A , E >: Elem <: AnyRef ](z : A )(f : (A , E ) => A ): A
17
+ def toList : List [Elem ]
20
18
def ++ [E >: Elem <: AnyRef ](that : SimpleIdentitySet [E ]): SimpleIdentitySet [E ] =
21
- ((this : SimpleIdentitySet [E ]) /: that.toList)(_ + _)
22
- def -- [E >: Elem <: AnyRef ](that : SimpleIdentitySet [E ]): SimpleIdentitySet [Elem ] =
23
- (this /: that.toList)(_ - _)
19
+ if (this .size == 0 ) that
20
+ else if (that.size == 0 ) this
21
+ else ((this : SimpleIdentitySet [E ]) /: that)(_ + _)
22
+ def -- [E >: Elem <: AnyRef ](that : SimpleIdentitySet [E ]): SimpleIdentitySet [E ] =
23
+ if (that.size == 0 ) this
24
+ else
25
+ ((SimpleIdentitySet .empty: SimpleIdentitySet [E ]) /: this ) { (s, x) =>
26
+ if (that.contains(x)) s else s + x
27
+ }
24
28
override def toString : String = toList.mkString(" (" , " , " , " )" )
25
29
}
26
30
@@ -33,6 +37,9 @@ object SimpleIdentitySet {
33
37
this
34
38
def contains [E <: AnyRef ](x : E ): Boolean = false
35
39
def foreach (f : Nothing => Unit ): Unit = ()
40
+ def exists [E <: AnyRef ](p : E => Boolean ): Boolean = false
41
+ def /: [A , E <: AnyRef ](z : A )(f : (A , E ) => A ): A = z
42
+ def toList = Nil
36
43
}
37
44
38
45
private class Set1 [+ Elem <: AnyRef ](x0 : AnyRef ) extends SimpleIdentitySet [Elem ] {
@@ -43,6 +50,11 @@ object SimpleIdentitySet {
43
50
if (x `eq` x0) empty else this
44
51
def contains [E >: Elem <: AnyRef ](x : E ): Boolean = x `eq` x0
45
52
def foreach (f : Elem => Unit ): Unit = f(x0.asInstanceOf [Elem ])
53
+ def exists [E >: Elem <: AnyRef ](p : E => Boolean ): Boolean =
54
+ p(x0.asInstanceOf [E ])
55
+ def /: [A , E >: Elem <: AnyRef ](z : A )(f : (A , E ) => A ): A =
56
+ f(z, x0.asInstanceOf [E ])
57
+ def toList = x0.asInstanceOf [Elem ] :: Nil
46
58
}
47
59
48
60
private class Set2 [+ Elem <: AnyRef ](x0 : AnyRef , x1 : AnyRef ) extends SimpleIdentitySet [Elem ] {
@@ -55,6 +67,11 @@ object SimpleIdentitySet {
55
67
else this
56
68
def contains [E >: Elem <: AnyRef ](x : E ): Boolean = (x `eq` x0) || (x `eq` x1)
57
69
def foreach (f : Elem => Unit ): Unit = { f(x0.asInstanceOf [Elem ]); f(x1.asInstanceOf [Elem ]) }
70
+ def exists [E >: Elem <: AnyRef ](p : E => Boolean ): Boolean =
71
+ p(x0.asInstanceOf [E ]) || p(x1.asInstanceOf [E ])
72
+ def /: [A , E >: Elem <: AnyRef ](z : A )(f : (A , E ) => A ): A =
73
+ f(f(z, x0.asInstanceOf [E ]), x1.asInstanceOf [E ])
74
+ def toList = x0.asInstanceOf [Elem ] :: x1.asInstanceOf [Elem ] :: Nil
58
75
}
59
76
60
77
private class Set3 [+ Elem <: AnyRef ](x0 : AnyRef , x1 : AnyRef , x2 : AnyRef ) extends SimpleIdentitySet [Elem ] {
@@ -78,9 +95,14 @@ object SimpleIdentitySet {
78
95
def foreach (f : Elem => Unit ): Unit = {
79
96
f(x0.asInstanceOf [Elem ]); f(x1.asInstanceOf [Elem ]); f(x2.asInstanceOf [Elem ])
80
97
}
98
+ def exists [E >: Elem <: AnyRef ](p : E => Boolean ): Boolean =
99
+ p(x0.asInstanceOf [E ]) || p(x1.asInstanceOf [E ]) || p(x2.asInstanceOf [E ])
100
+ def /: [A , E >: Elem <: AnyRef ](z : A )(f : (A , E ) => A ): A =
101
+ f(f(f(z, x0.asInstanceOf [E ]), x1.asInstanceOf [E ]), x2.asInstanceOf [E ])
102
+ def toList = x0.asInstanceOf [Elem ] :: x1.asInstanceOf [Elem ] :: x2.asInstanceOf [Elem ] :: Nil
81
103
}
82
104
83
- private class SetN [+ Elem <: AnyRef ](xs : Array [AnyRef ]) extends SimpleIdentitySet [Elem ] {
105
+ private class SetN [+ Elem <: AnyRef ](val xs : Array [AnyRef ]) extends SimpleIdentitySet [Elem ] {
84
106
def size = xs.length
85
107
def + [E >: Elem <: AnyRef ](x : E ): SimpleIdentitySet [E ] =
86
108
if (contains(x)) this
@@ -115,5 +137,79 @@ object SimpleIdentitySet {
115
137
var i = 0
116
138
while (i < size) { f(xs(i).asInstanceOf [Elem ]); i += 1 }
117
139
}
140
+ def exists [E >: Elem <: AnyRef ](p : E => Boolean ): Boolean =
141
+ xs.asInstanceOf [Array [E ]].exists(p)
142
+ def /: [A , E >: Elem <: AnyRef ](z : A )(f : (A , E ) => A ): A =
143
+ (z /: xs.asInstanceOf [Array [E ]])(f)
144
+ def toList : List [Elem ] = {
145
+ val buf = new mutable.ListBuffer [Elem ]
146
+ foreach(buf += _)
147
+ buf.toList
148
+ }
149
+ override def ++ [E >: Elem <: AnyRef ](that : SimpleIdentitySet [E ]): SimpleIdentitySet [E ] =
150
+ that match {
151
+ case that : SetN [_] =>
152
+ var toAdd : mutable.ArrayBuffer [AnyRef ] = null
153
+ var i = 0
154
+ val limit = that.xs.length
155
+ while (i < limit) {
156
+ val elem = that.xs(i)
157
+ if (! contains(elem)) {
158
+ if (toAdd == null ) toAdd = new mutable.ArrayBuffer
159
+ toAdd += elem
160
+ }
161
+ i += 1
162
+ }
163
+ if (toAdd == null ) this
164
+ else {
165
+ val numAdded = toAdd.size
166
+ val xs1 = new Array [AnyRef ](size + numAdded)
167
+ System .arraycopy(xs, 0 , xs1, 0 , size)
168
+ var i = 0
169
+ while (i < numAdded) {
170
+ xs1(i + size) = toAdd(i)
171
+ i += 1
172
+ }
173
+ new SetN [E ](xs1)
174
+ }
175
+ case _ => super .++ (that)
176
+ }
177
+ override def -- [E >: Elem <: AnyRef ](that : SimpleIdentitySet [E ]): SimpleIdentitySet [E ] =
178
+ that match {
179
+ case that : SetN [_] =>
180
+ // both sets are large, optimize assuming they are similar
181
+ // by starting from empty set and adding elements
182
+ var toAdd : mutable.ArrayBuffer [AnyRef ] = null
183
+ val thisSize = this .size
184
+ val thatSize = that.size
185
+ val thatElems = that.xs
186
+ var i = 0
187
+ var searchStart = 0
188
+ while (i < thisSize) {
189
+ val elem = this .xs(i)
190
+ var j = searchStart // search thatElems in round robin fashion, starting one after latest hit
191
+ var missing = false
192
+ while (! missing && (elem ne thatElems(j))) {
193
+ j += 1
194
+ if (j == thatSize) j = 0
195
+ missing = j == searchStart
196
+ }
197
+ if (missing) {
198
+ if (toAdd == null ) toAdd = new mutable.ArrayBuffer
199
+ toAdd += elem
200
+ }
201
+ else searchStart = (j + 1 ) % thatSize
202
+ i += 1
203
+ }
204
+ if (toAdd == null ) empty
205
+ else toAdd.size match {
206
+ case 1 => new Set1 [E ](toAdd(0 ))
207
+ case 2 => new Set2 [E ](toAdd(0 ), toAdd(1 ))
208
+ case 3 => new Set3 [E ](toAdd(0 ), toAdd(1 ), toAdd(2 ))
209
+ case _ => new SetN [E ](toAdd.toArray)
210
+ }
211
+ case _ => // this set is large, that set is small: reduce from above using `-`
212
+ ((this : SimpleIdentitySet [E ]) /: that)(_ - _)
213
+ }
118
214
}
119
215
}
0 commit comments