Skip to content

Commit 868f8e1

Browse files
committed
Add SimpleIdentitySet data structure
Used for small, linked sets. Normal immutable sets are about as fast for 0 - 4 elements, but are not linked for larger sizes.
1 parent ad59c70 commit 868f8e1

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

compiler/src/dotty/tools/dotc/util/SimpleMap.scala renamed to compiler/src/dotty/tools/dotc/util/SimpleIdentityMap.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package dotty.tools.dotc.util
22

33
import collection.mutable.ListBuffer
44

5+
/** A simple linked map with `eq` as the key comparison, optimized for small maps.
6+
* It has linear complexity for `apply`, `updated`, and `remove`.
7+
*/
58
abstract class SimpleIdentityMap[K <: AnyRef, +V >: Null <: AnyRef] extends (K => V) {
69
def size: Int
710
def apply(k: K): V
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package dotty.tools.dotc.util
2+
3+
import collection.mutable.ListBuffer
4+
5+
/** A simple linked set with `eq` as the comparison, optimized for small sets.
6+
* It has linear complexity for `contains`, `+`, and `-`.
7+
*/
8+
abstract class SimpleIdentitySet[+Elem <: AnyRef] {
9+
def size: Int
10+
def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E]
11+
def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem]
12+
def contains[E >: Elem <: AnyRef](x: E): Boolean
13+
def foreach(f: Elem => Unit): Unit
14+
def toList: List[Elem] = {
15+
val buf = new ListBuffer[Elem]
16+
foreach(buf += _)
17+
buf.toList
18+
}
19+
def ++ [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]) =
20+
((this: SimpleIdentitySet[E]) /: that.toList)(_ + _)
21+
def -- [E >: Elem <: AnyRef](that: SimpleIdentitySet[E]) =
22+
(this /: that.toList)(_ - _)
23+
override def toString = toList.mkString("(", ", ", ")")
24+
}
25+
26+
object SimpleIdentitySet {
27+
object empty extends SimpleIdentitySet[Nothing] {
28+
def size = 0
29+
def + [E <: AnyRef](x: E): SimpleIdentitySet[E] =
30+
new Set1[E](x)
31+
def - [E <: AnyRef](x: E): SimpleIdentitySet[Nothing] =
32+
this
33+
def contains[E <: AnyRef](x: E): Boolean = false
34+
def foreach(f: Nothing => Unit): Unit = ()
35+
}
36+
37+
private class Set1[+Elem <: AnyRef](x0: AnyRef) extends SimpleIdentitySet[Elem] {
38+
def size = 1
39+
def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E] =
40+
new Set2[E](x0, x)
41+
def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem] =
42+
if (x `eq` x0) empty else this
43+
def contains[E >: Elem <: AnyRef](x: E): Boolean = x `eq` x0
44+
def foreach(f: Elem => Unit): Unit = f(x0.asInstanceOf[Elem])
45+
}
46+
47+
private class Set2[+Elem <: AnyRef](x0: AnyRef, x1: AnyRef) extends SimpleIdentitySet[Elem] {
48+
def size = 2
49+
def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E] = {
50+
val xs = new Array[AnyRef](3)
51+
xs(0) = x0
52+
xs(1) = x1
53+
xs(2) = x
54+
new SetN[E](xs)
55+
}
56+
def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem] =
57+
if (x `eq` x0) new Set1(x1)
58+
else if (x `eq` x1) new Set1(x0)
59+
else this
60+
def contains[E >: Elem <: AnyRef](x: E): Boolean = (x `eq` x0) || (x `eq` x1)
61+
def foreach(f: Elem => Unit): Unit = { f(x0.asInstanceOf[Elem]); f(x1.asInstanceOf[Elem]) }
62+
}
63+
64+
private class SetN[+Elem <: AnyRef](xs: Array[AnyRef]) extends SimpleIdentitySet[Elem] {
65+
def size = xs.length
66+
def + [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[E] = {
67+
val xs1 = new Array[AnyRef](size + 1)
68+
Array.copy(xs, 0, xs1, 0, size)
69+
xs1(size) = x
70+
new SetN[E](xs1)
71+
}
72+
def - [E >: Elem <: AnyRef](x: E): SimpleIdentitySet[Elem] = {
73+
var i = 0
74+
while (i < size && (xs(i) `ne` x)) i += 1
75+
if (i == size) this
76+
else if (size == 3)
77+
if (i == 0) new Set2(xs(1), xs(2))
78+
else if (i == 1) new Set2(xs(0), xs(2))
79+
else new Set2(xs(0), xs(1))
80+
else {
81+
val xs1 = new Array[AnyRef](size - 1)
82+
Array.copy(xs, 0, xs1, 0, i)
83+
Array.copy(xs, i + 1, xs1, i, size - (i + 1))
84+
new SetN(xs1)
85+
}
86+
}
87+
def contains[E >: Elem <: AnyRef](x: E): Boolean = {
88+
var i = 0
89+
while (i < size && (xs(i) `ne` x)) i += 1
90+
i < size
91+
}
92+
def foreach(f: Elem => Unit): Unit = {
93+
var i = 0
94+
while (i < size) { f(xs(i).asInstanceOf[Elem]); i += 1 }
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)