summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2014-01-30 13:30:54 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2014-01-30 13:30:54 -0800
commitf59aeb58681d1dba8d32886de4785f6fb8dc9eff (patch)
tree0e3f08c88bb99056d979be4545a3d21223aa2531
parent50f38393af6d5aee3739cc73fdd5c7d22361390a (diff)
parentf97e2d42eb211d429b27f79fe993bf48c92e9740 (diff)
downloadscala-f59aeb58681d1dba8d32886de4785f6fb8dc9eff.tar.gz
scala-f59aeb58681d1dba8d32886de4785f6fb8dc9eff.tar.bz2
scala-f59aeb58681d1dba8d32886de4785f6fb8dc9eff.zip
Merge pull request #3434 from Ichoran/issue/8213
SI-8213 AnyRefMap.getOrElseUpdate is faulty
-rw-r--r--src/library/scala/collection/mutable/AnyRefMap.scala15
-rw-r--r--src/library/scala/collection/mutable/LongMap.scala15
-rw-r--r--test/junit/scala/collection/SetMapConsistencyTest.scala12
3 files changed, 38 insertions, 4 deletions
diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala
index df74bb5187..29c92a111c 100644
--- a/src/library/scala/collection/mutable/AnyRefMap.scala
+++ b/src/library/scala/collection/mutable/AnyRefMap.scala
@@ -129,9 +129,20 @@ extends AbstractMap[K, V]
override def getOrElseUpdate(key: K, defaultValue: => V): V = {
val h = hashOf(key)
- val i = seekEntryOrOpen(h, key)
+ var i = seekEntryOrOpen(h, key)
if (i < 0) {
- val value = defaultValue
+ // It is possible that the default value computation was side-effecting
+ // Our hash table may have resized or even contain what we want now
+ // (but if it does, we'll replace it)
+ val value = {
+ val oh = _hashes
+ val ans = defaultValue
+ if (oh ne _hashes) {
+ i = seekEntryOrOpen(h, key)
+ if (i >= 0) _size -= 1
+ }
+ ans
+ }
_size += 1
val j = i & IndexMask
_hashes(j) = h
diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala
index 81c381279f..984ae6f7cc 100644
--- a/src/library/scala/collection/mutable/LongMap.scala
+++ b/src/library/scala/collection/mutable/LongMap.scala
@@ -160,9 +160,20 @@ extends AbstractMap[Long, V]
else minValue.asInstanceOf[V]
}
else {
- val i = seekEntryOrOpen(key)
+ var i = seekEntryOrOpen(key)
if (i < 0) {
- val value = defaultValue
+ // It is possible that the default value computation was side-effecting
+ // Our hash table may have resized or even contain what we want now
+ // (but if it does, we'll replace it)
+ val value = {
+ val ok = _keys
+ val ans = defaultValue
+ if (ok ne _keys) {
+ i = seekEntryOrOpen(key)
+ if (i >= 0) _size -= 1
+ }
+ ans
+ }
_size += 1
val j = i & IndexMask
_keys(j) = key
diff --git a/test/junit/scala/collection/SetMapConsistencyTest.scala b/test/junit/scala/collection/SetMapConsistencyTest.scala
index c62b074483..7bb8ca958b 100644
--- a/test/junit/scala/collection/SetMapConsistencyTest.scala
+++ b/test/junit/scala/collection/SetMapConsistencyTest.scala
@@ -476,4 +476,16 @@ class SetMapConsistencyTest {
}
assert(test)
}
+
+ @Test
+ def si8213() {
+ val am = new scala.collection.mutable.AnyRefMap[String, Int]
+ for (i <- 0 until 1024) am += i.toString -> i
+ am.getOrElseUpdate("1024", { am.clear; -1 })
+ assert(am == scala.collection.mutable.AnyRefMap("1024" -> -1))
+ val lm = new scala.collection.mutable.LongMap[Int]
+ for (i <- 0 until 1024) lm += i.toLong -> i
+ lm.getOrElseUpdate(1024, { lm.clear; -1 })
+ assert(lm == scala.collection.mutable.LongMap(1024L -> -1))
+ }
}