11package dotty .tools .dotc .util
22
3- import collection .mutable . ListBuffer
3+ import collection .mutable
44
55/** A simple linked set with `eq` as the comparison, optimized for small sets.
66 * It has linear complexity for `contains`, `+`, and `-`.
77 */
88abstract class SimpleIdentitySet [+ Elem <: AnyRef ] {
99 def size : Int
10- def isEmpty : Boolean = size == 0
10+ final def isEmpty : Boolean = size == 0
1111 def + [E >: Elem <: AnyRef ](x : E ): SimpleIdentitySet [E ]
1212 def - [E >: Elem <: AnyRef ](x : E ): SimpleIdentitySet [Elem ]
1313 def contains [E >: Elem <: AnyRef ](x : E ): Boolean
1414 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 ]
2018 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+ }
2428 override def toString : String = toList.mkString(" (" , " , " , " )" )
2529}
2630
@@ -33,6 +37,9 @@ object SimpleIdentitySet {
3337 this
3438 def contains [E <: AnyRef ](x : E ): Boolean = false
3539 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
3643 }
3744
3845 private class Set1 [+ Elem <: AnyRef ](x0 : AnyRef ) extends SimpleIdentitySet [Elem ] {
@@ -43,6 +50,11 @@ object SimpleIdentitySet {
4350 if (x `eq` x0) empty else this
4451 def contains [E >: Elem <: AnyRef ](x : E ): Boolean = x `eq` x0
4552 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
4658 }
4759
4860 private class Set2 [+ Elem <: AnyRef ](x0 : AnyRef , x1 : AnyRef ) extends SimpleIdentitySet [Elem ] {
@@ -55,6 +67,11 @@ object SimpleIdentitySet {
5567 else this
5668 def contains [E >: Elem <: AnyRef ](x : E ): Boolean = (x `eq` x0) || (x `eq` x1)
5769 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
5875 }
5976
6077 private class Set3 [+ Elem <: AnyRef ](x0 : AnyRef , x1 : AnyRef , x2 : AnyRef ) extends SimpleIdentitySet [Elem ] {
@@ -78,9 +95,14 @@ object SimpleIdentitySet {
7895 def foreach (f : Elem => Unit ): Unit = {
7996 f(x0.asInstanceOf [Elem ]); f(x1.asInstanceOf [Elem ]); f(x2.asInstanceOf [Elem ])
8097 }
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
81103 }
82104
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 ] {
84106 def size = xs.length
85107 def + [E >: Elem <: AnyRef ](x : E ): SimpleIdentitySet [E ] =
86108 if (contains(x)) this
@@ -115,5 +137,79 @@ object SimpleIdentitySet {
115137 var i = 0
116138 while (i < size) { f(xs(i).asInstanceOf [Elem ]); i += 1 }
117139 }
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+ }
118214 }
119215}
0 commit comments