Skip to content

Commit abeb4e3

Browse files
committed
Drop bounds on HashMap Key type
1 parent 8a5cb06 commit abeb4e3

File tree

4 files changed

+64
-35
lines changed

4 files changed

+64
-35
lines changed

compiler/src/dotty/tools/dotc/util/GenericHashMap.scala

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object GenericHashMap:
2323
* However, a table of size up to DenseLimit will be re-sized only
2424
* once the number of elements reaches the table's size.
2525
*/
26-
abstract class GenericHashMap[Key <: AnyRef, Value]
26+
abstract class GenericHashMap[Key, Value]
2727
(initialCapacity: Int, capacityMultiple: Int) extends MutableMap[Key, Value]:
2828
import GenericHashMap.DenseLimit
2929

@@ -58,18 +58,20 @@ abstract class GenericHashMap[Key <: AnyRef, Value]
5858
protected def isEqual(x: Key, y: Key): Boolean
5959

6060
/** Turn successor index or hash code `x` into a table index */
61-
inline protected def index(x: Int): Int = x & (table.length - 2)
61+
private def index(x: Int): Int = x & (table.length - 2)
6262

63-
inline protected def firstIndex(key: Key) = if isDense then 0 else index(hash(key))
64-
inline protected def nextIndex(idx: Int) =
63+
private def firstIndex(key: Key) = if isDense then 0 else index(hash(key))
64+
private def nextIndex(idx: Int) =
6565
Stats.record(statsItem("miss"))
6666
index(idx + 2)
6767

68-
inline protected def keyAt(idx: Int): Key = table(idx).asInstanceOf[Key]
69-
inline protected def valueAt(idx: Int): Value = table(idx + 1).asInstanceOf[Value]
68+
private def keyAt(idx: Int): Key = table(idx).asInstanceOf[Key]
69+
private def valueAt(idx: Int): Value = table(idx + 1).asInstanceOf[Value]
7070

71-
inline protected def setTable(idx: Int, value: Value) =
72-
table(idx) = value.asInstanceOf[AnyRef]
71+
private def setKey(idx: Int, key: Key) =
72+
table(idx) = key.asInstanceOf[AnyRef]
73+
private def setValue(idx: Int, value: Value) =
74+
table(idx + 1) = value.asInstanceOf[AnyRef]
7375

7476
def lookup(key: Key): Value | Null =
7577
Stats.record(statsItem("lookup"))
@@ -87,12 +89,12 @@ abstract class GenericHashMap[Key <: AnyRef, Value]
8789
var k = keyAt(idx)
8890
while k != null do
8991
if isEqual(k, key) then
90-
setTable(idx + 1, value)
92+
setValue(idx, value)
9193
return
9294
idx = nextIndex(idx)
9395
k = keyAt(idx)
94-
table(idx) = key
95-
setTable(idx + 1, value)
96+
setKey(idx, key)
97+
setValue(idx, value)
9698
used += 1
9799
if used > limit then growTable()
98100

@@ -112,8 +114,8 @@ abstract class GenericHashMap[Key <: AnyRef, Value]
112114
|| index(hole - index(hash(k))) < limit * 2
113115
// hash(k) is then logically at or before hole; can be moved forward to fill hole
114116
then
115-
table(hole) = k
116-
setTable(hole + 1, valueAt(idx))
117+
setKey(hole, k)
118+
setValue(hole, valueAt(idx))
117119
hole = idx
118120
table(hole) = null
119121
used -= 1
@@ -126,15 +128,15 @@ abstract class GenericHashMap[Key <: AnyRef, Value]
126128
if v == null then v = value
127129
v.uncheckedNN
128130

129-
private def addOld(key: Key, value: AnyRef): Unit =
131+
private def addOld(key: Key, value: Value): Unit =
130132
Stats.record(statsItem("re-enter"))
131133
var idx = firstIndex(key)
132134
var k = keyAt(idx)
133135
while k != null do
134136
idx = nextIndex(idx)
135137
k = keyAt(idx)
136-
table(idx) = key
137-
table(idx + 1) = value
138+
setKey(idx, key)
139+
setValue(idx, value)
138140

139141
def copyFrom(oldTable: Array[AnyRef]): Unit =
140142
if isDense then
@@ -143,7 +145,7 @@ abstract class GenericHashMap[Key <: AnyRef, Value]
143145
var idx = 0
144146
while idx < oldTable.length do
145147
val key = oldTable(idx).asInstanceOf[Key]
146-
if key != null then addOld(key, oldTable(idx + 1))
148+
if key != null then addOld(key, oldTable(idx + 1).asInstanceOf[Value])
147149
idx += 2
148150

149151
protected def growTable(): Unit =

compiler/src/dotty/tools/dotc/util/HashMap.scala

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotty.tools.dotc.util
33
/** A specialized implementation of GenericHashMap with standard hashCode and equals
44
* as comparison
55
*/
6-
class HashMap[Key <: AnyRef, Value]
6+
class HashMap[Key, Value]
77
(initialCapacity: Int = 8, capacityMultiple: Int = 2)
88
extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
99
import GenericHashMap.DenseLimit
@@ -17,6 +17,20 @@ extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
1717

1818
// The following methods are duplicated from GenericHashMap
1919
// to avoid polymorphic dispatches
20+
private def index(x: Int): Int = x & (table.length - 2)
21+
22+
private def firstIndex(key: Key) = if isDense then 0 else index(hash(key))
23+
private def nextIndex(idx: Int) =
24+
Stats.record(statsItem("miss"))
25+
index(idx + 2)
26+
27+
private def keyAt(idx: Int): Key = table(idx).asInstanceOf[Key]
28+
private def valueAt(idx: Int): Value = table(idx + 1).asInstanceOf[Value]
29+
30+
private def setKey(idx: Int, key: Key) =
31+
table(idx) = key.asInstanceOf[AnyRef]
32+
private def setValue(idx: Int, value: Value) =
33+
table(idx + 1) = value.asInstanceOf[AnyRef]
2034

2135
override def lookup(key: Key): Value | Null =
2236
Stats.record(statsItem("lookup"))
@@ -34,24 +48,24 @@ extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
3448
var k = keyAt(idx)
3549
while k != null do
3650
if isEqual(k, key) then
37-
setTable(idx + 1, value)
51+
setValue(idx, value)
3852
return
3953
idx = nextIndex(idx)
4054
k = keyAt(idx)
41-
table(idx) = key
42-
setTable(idx + 1, value)
55+
setKey(idx, key)
56+
setValue(idx, value)
4357
used += 1
4458
if used > limit then growTable()
4559

46-
private def addOld(key: Key, value: AnyRef): Unit =
60+
private def addOld(key: Key, value: Value): Unit =
4761
Stats.record(statsItem("re-enter"))
4862
var idx = firstIndex(key)
4963
var k = keyAt(idx)
5064
while k != null do
5165
idx = nextIndex(idx)
5266
k = keyAt(idx)
53-
table(idx) = key
54-
table(idx + 1) = value
67+
setKey(idx, key)
68+
setValue(idx, value)
5569

5670
override def copyFrom(oldTable: Array[AnyRef]): Unit =
5771
if isDense then
@@ -60,6 +74,6 @@ extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
6074
var idx = 0
6175
while idx < oldTable.length do
6276
val key = oldTable(idx).asInstanceOf[Key]
63-
if key != null then addOld(key, oldTable(idx + 1))
77+
if key != null then addOld(key, oldTable(idx + 1).asInstanceOf[Value])
6478
idx += 2
6579
end HashMap

compiler/src/dotty/tools/dotc/util/IdentityHashMap.scala

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotty.tools.dotc.util
33
/** A specialized implementation of GenericHashMap with identity hash and `eq`
44
* as comparison.
55
*/
6-
class IdentityHashMap[Key <: AnyRef, Value]
6+
class IdentityHashMap[Key, Value]
77
(initialCapacity: Int = 8, capacityMultiple: Int = 2)
88
extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
99
import GenericHashMap.DenseLimit
@@ -14,13 +14,26 @@ extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
1414
final def hash(x: Key): Int = System.identityHashCode(x) << 1
1515

1616
/** Equality, by default `eq`, but can be overridden */
17-
final def isEqual(x: Key, y: Key): Boolean = x eq y
17+
final def isEqual(x: Key, y: Key): Boolean = x.asInstanceOf[AnyRef] eq y.asInstanceOf[AnyRef]
1818

1919
// The following methods are duplicated from GenericHashMap
2020
// to avoid polymorphic dispatches.
2121
// Aside: It would be nice to have a @specialized annotation that does
2222
// this automatically
2323

24+
private def index(x: Int): Int = x & (table.length - 2)
25+
26+
private def firstIndex(key: Key) = if isDense then 0 else index(hash(key))
27+
private def nextIndex(idx: Int) =
28+
Stats.record(statsItem("miss"))
29+
index(idx + 2)
30+
31+
private def keyAt(idx: Int): Key = table(idx).asInstanceOf[Key]
32+
private def valueAt(idx: Int): Value = table(idx + 1).asInstanceOf[Value]
33+
34+
private def setKey(idx: Int, key: Key) = table(idx) = key.asInstanceOf[AnyRef]
35+
private def setValue(idx: Int, value: Value) = table(idx + 1) = value.asInstanceOf[AnyRef]
36+
2437
override def lookup(key: Key): Value | Null =
2538
Stats.record(statsItem("lookup"))
2639
var idx = firstIndex(key)
@@ -37,24 +50,24 @@ extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
3750
var k = keyAt(idx)
3851
while k != null do
3952
if isEqual(k, key) then
40-
setTable(idx + 1, value)
53+
setValue(idx, value)
4154
return
4255
idx = nextIndex(idx)
4356
k = keyAt(idx)
44-
table(idx) = key
45-
setTable(idx + 1, value)
57+
setKey(idx, key)
58+
setValue(idx, value)
4659
used += 1
4760
if used > limit then growTable()
4861

49-
private def addOld(key: Key, value: AnyRef): Unit =
62+
private def addOld(key: Key, value: Value): Unit =
5063
Stats.record(statsItem("re-enter"))
5164
var idx = firstIndex(key)
5265
var k = keyAt(idx)
5366
while k != null do
5467
idx = nextIndex(idx)
5568
k = keyAt(idx)
56-
table(idx) = key
57-
table(idx + 1) = value
69+
setKey(idx, key)
70+
setValue(idx, value)
5871

5972
override def copyFrom(oldTable: Array[AnyRef]): Unit =
6073
if isDense then
@@ -63,6 +76,6 @@ extends GenericHashMap[Key, Value](initialCapacity, capacityMultiple):
6376
var idx = 0
6477
while idx < oldTable.length do
6578
val key = oldTable(idx).asInstanceOf[Key]
66-
if key != null then addOld(key, oldTable(idx + 1))
79+
if key != null then addOld(key, oldTable(idx + 1).asInstanceOf[Value])
6780
idx += 2
6881
end IdentityHashMap

compiler/src/dotty/tools/dotc/util/MutableMap.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package dotc.util
33

44
/** A common class for lightweight mutable maps.
55
*/
6-
abstract class MutableMap[Key <: AnyRef, Value]:
6+
abstract class MutableMap[Key, Value]:
77

88
def lookup(x: Key): Value | Null
99

0 commit comments

Comments
 (0)