Skip to content

Commit 86fbade

Browse files
committed
Fix HashMap/Set remove operation
1 parent 61d4a9b commit 86fbade

File tree

3 files changed

+89
-7
lines changed

3 files changed

+89
-7
lines changed

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ object GenericHashMap:
2323
* once the number of elements reaches the table's size.
2424
*/
2525
abstract class GenericHashMap[Key <: AnyRef, Value >: Null <: AnyRef]
26-
(initialCapacity: Int = 8, capacityMultiple: Int = 3) extends MutableMap[Key, Value]:
26+
(initialCapacity: Int, capacityMultiple: Int) extends MutableMap[Key, Value]:
2727
import GenericHashMap.DenseLimit
2828

2929
protected var used: Int = _
@@ -102,11 +102,15 @@ abstract class GenericHashMap[Key <: AnyRef, Value >: Null <: AnyRef]
102102
while
103103
idx = nextIndex(idx)
104104
k = keyAt(idx)
105-
k != null && (isDense || index(hash(k)) != idx)
105+
k != null
106106
do
107-
table(hole) = k
108-
table(hole + 1) = valueAt(idx)
109-
hole = idx
107+
if isDense
108+
|| index(hole - index(hash(k))) < limit * 2
109+
// hash(k) is then logically at or after hole; can be moved forward to fill hole
110+
then
111+
table(hole) = k
112+
table(hole + 1) = valueAt(idx)
113+
hole = idx
110114
table(hole) = null
111115
used -= 1
112116
return

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,12 @@ class HashSet[T >: Null <: AnyRef](initialCapacity: Int = 8, capacityMultiple: I
108108
e = entryAt(idx)
109109
e != null && (isDense || index(hash(e)) != idx)
110110
do
111-
table(hole) = e
112-
hole = idx
111+
if isDense
112+
|| index(hole - index(hash(k))) < limit
113+
// hash(k) is then logically at or after hole; can be moved forward to fill hole
114+
then
115+
table(hole) = e
116+
hole = idx
113117
table(hole) = null
114118
used -= 1
115119
return

tests/run-with-compiler/maptest.scala

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
trait Generator[+T]:
2+
self =>
3+
def generate: T
4+
def map[S](f: T => S) = new Generator[S]:
5+
def generate: S = f(self.generate)
6+
def flatMap[S](f: T => Generator[S]) = new Generator[S]:
7+
def generate: S = f(self.generate).generate
8+
9+
object Generator:
10+
val NumLimit = 300
11+
val Iterations = 10000
12+
13+
given integers as Generator[Int]:
14+
val rand = new java.util.Random
15+
def generate = rand.nextInt()
16+
17+
given booleans as Generator[Boolean] =
18+
integers.map(x => x > 0)
19+
20+
def range(end: Int): Generator[Int] =
21+
integers.map(x => (x % end).abs)
22+
23+
enum Op:
24+
case Lookup, Update, Remove
25+
export Op._
26+
27+
given ops as Generator[Op] =
28+
range(10).map {
29+
case 0 | 1 | 2 | 3 => Lookup
30+
case 4 | 5 | 6 | 7 => Update
31+
case 8 | 9 => Remove
32+
}
33+
34+
val nums: Generator[Integer] = range(NumLimit).map(Integer(_))
35+
36+
@main def Test =
37+
import Generator._
38+
39+
val map1 = dotty.tools.dotc.util.HashMap[Integer, Integer]()
40+
val map2 = scala.collection.mutable.HashMap[Integer, Integer]()
41+
42+
def checkSame() =
43+
assert(map1.size == map2.size)
44+
for (k, v) <- map1.iterator do
45+
assert(map2.get(k) == Some(v))
46+
for (k, v) <- map2.iterator do
47+
assert(Option(map1.lookup(k)) == Some(v))
48+
49+
def lookupTest(num: Integer) =
50+
//println(s"test lookup $num")
51+
val res1 = Option(map1.lookup(num))
52+
val res2 = map2.get(num)
53+
assert(res1 == res2)
54+
55+
def updateTest(num: Integer) =
56+
//println(s"test update $num")
57+
lookupTest(num)
58+
map1(num) = num
59+
map2(num) = num
60+
checkSame()
61+
62+
def removeTest(num: Integer) =
63+
//println(s"test remove $num")
64+
map1.remove(num)
65+
map2.remove(num)
66+
checkSame()
67+
68+
for i <- 0 until Iterations do
69+
//if i % 1000 == 0 then println(map1.size)
70+
val num = nums.generate
71+
Generator.ops.generate match
72+
case Lookup => lookupTest(num)
73+
case Update => updateTest(num)
74+
case Remove => removeTest(num)

0 commit comments

Comments
 (0)