8000 Fixes #382 - several entries with the same key in mutable.HashMap (#484) · szeiger/scala@0c30c04 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0c30c04

Browse files
opticianjulienrf
authored andcommitted
Fixes scala#382 - several entries with the same key in mutable.HashMap (scala#484)
* * Add HashMap test to check scala/collection-strawman#382 * Clean code. * Repeat search of key after evaluating default value. * * Fix code style.
1 parent 765fd8a commit 0c30c04

File tree

3 files changed

+21
-11
lines changed

3 files changed

+21
-11
lines changed

collections/src/main/scala/strawman/collection/mutable/HashMap.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,20 @@ class HashMap[K, V] private[collection] (contents: HashTable.Contents[K, Default
8080
override def getOrElseUpdate(key: K, defaultValue: => V): V = {
8181
val hash = table.elemHashCode(key)
8282
val i = table.index(hash)
83-
val entry = table.findEntry0(key, i)
84-
if (entry != null) entry.value
83+
val firstEntry = table.findEntry0(key, i)
84+
if (firstEntry != null) firstEntry.value
8585
else {
8686
val table0 = table.table
8787
val default = defaultValue
8888
// Avoid recomputing index if the `defaultValue()` hasn't triggered
8989
// a table resize.
9090
val newEntryIndex = if (table0 eq table.table) i else table.index(hash)
9191
val e = table.createNewEntry(key, default)
92-
if (table.tableSize >= table.threshold) table.addEntry(e)
93-
else table.addEntry2(e, newEntryIndex)
92+
// Repeat search
93+
// because evaluation of `default` can bring entry with `key`
94+
val secondEntry = table.findEntry0(key, newEntryIndex)
95+
if (secondEntry == null) table.addEntry0(e, newEntryIndex)
96+
else secondEntry.value = default
9497
default
9598
}
9699
}

collections/src/main/scala/strawman/collection/mutable/HashTable.scala

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,6 @@ private[mutable] abstract class HashTable[A, B, Entry >: Null <: HashEntry[A, En
158158
resize(2 * table.length)
159159
}
160160

161-
protected[collection] def addEntry2(e: Entry, h: Int): Unit = {
162-
e.next = table(h).asInstanceOf[Entry]
163-
table(h) = e
164-
tableSize += 1
165-
nnSizeMapAdd(h)
166-
}
167-
168161
/** Find entry with given key in table, or add new one if not found.
169162
* May be somewhat faster then `findEntry`/`addEntry` pair as it
170163
* computes entry's hash index only once.

test/junit/src/test/scala/strawman/collection/mutable/HashMapTest.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import org.junit.Assert._
55
import org.junit.Test
66
import org.junit.runner.RunWith
77
import org.junit.runners.JUnit4
8+
import strawman.collection.immutable.List
89

910
@RunWith(classOf[JUnit4])
1011
class HashMapTest {
@@ -35,4 +36,17 @@ class HashMapTest {
3536
hm.put(0, 0)
3637
hm.getOrElseUpdate(0, throw new AssertionError())
3738
}
39+
40+
@Test
41+
def getOrElseUpdate_keyIdempotence(): Unit = {
42+
val map = mutable.HashMap[String, String]()
43+
44+
val key = "key"
45+
map.getOrElseUpdate(key, {
46+
map.getOrElseUpdate(key, "value1")
47+
"value2"
48+
})
49+
50+
assertEquals(List((key, "value2")), map.toList)
51+
}
3852
}

0 commit comments

Comments
 (0)
0