diff options
author | Rex Kerr <ichoran@gmail.com> | 2014-01-15 20:16:39 -0800 |
---|---|---|
committer | Rex Kerr <ichoran@gmail.com> | 2014-02-09 08:20:30 -0800 |
commit | 2dfbbf55688d17fd3daa15341da878b98783ba3c (patch) | |
tree | cf56982aaf726c3ee66b6edebd8c213ebc234b78 | |
parent | 08e51dfec50842253afb87cc5ae3c7400dc18ced (diff) | |
download | scala-2dfbbf55688d17fd3daa15341da878b98783ba3c.tar.gz scala-2dfbbf55688d17fd3daa15341da878b98783ba3c.tar.bz2 scala-2dfbbf55688d17fd3daa15341da878b98783ba3c.zip |
SI-8154 AnyRefMap iterates its way to ((null, null))
Changed logic to prevent mutation between hasNext and next from delivering invalid results.
Also fixed superscripts in scaladoc.
-rw-r--r-- | src/library/scala/collection/mutable/AnyRefMap.scala | 27 | ||||
-rw-r--r-- | test/junit/scala/collection/SetMapConsistencyTest.scala | 21 |
2 files changed, 32 insertions, 16 deletions
diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala index 29c92a111c..47fb66744e 100644 --- a/src/library/scala/collection/mutable/AnyRefMap.scala +++ b/src/library/scala/collection/mutable/AnyRefMap.scala @@ -22,9 +22,9 @@ import generic.CanBuildFrom * on a map that will no longer have elements removed but will be * used heavily may save both time and storage space. * - * This map is not indended to contain more than 2^29 entries (approximately - * 500 million). The maximum capacity is 2^30, but performance will degrade - * rapidly as 2^30 is approached. + * This map is not intended to contain more than 2^29^ entries (approximately + * 500 million). The maximum capacity is 2^30^, but performance will degrade + * rapidly as 2^30^ is approached. * */ final class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initialBufferSize: Int, initBlank: Boolean) @@ -291,24 +291,21 @@ extends AbstractMap[K, V] private[this] val vz = _values private[this] var index = 0 - private[this] var found = false - def hasNext = found || (index<hz.length && { + def hasNext: Boolean = index<hz.length && { var h = hz(index) - if (h+h != 0) found = true - else { + while (h+h == 0) { index += 1 - while (index < hz.length && { h = hz(index); h+h == 0 }) index += 1 - found = (index < hz.length) + if (index >= hz.length) return false + h = hz(index) } - found - }) + true + } - def next = { - if (found || hasNext) { - val ans = (_keys(index).asInstanceOf[K], _values(index).asInstanceOf[V]) + def next: (K, V) = { + if (hasNext) { + val ans = (kz(index).asInstanceOf[K], vz(index).asInstanceOf[V]) index += 1 - found = false ans } else throw new NoSuchElementException("next") diff --git a/test/junit/scala/collection/SetMapConsistencyTest.scala b/test/junit/scala/collection/SetMapConsistencyTest.scala index 7bb8ca958b..0d6f43db06 100644 --- a/test/junit/scala/collection/SetMapConsistencyTest.scala +++ b/test/junit/scala/collection/SetMapConsistencyTest.scala @@ -478,7 +478,7 @@ class SetMapConsistencyTest { } @Test - def si8213() { + def testSI8213() { val am = new scala.collection.mutable.AnyRefMap[String, Int] for (i <- 0 until 1024) am += i.toString -> i am.getOrElseUpdate("1024", { am.clear; -1 }) @@ -488,4 +488,23 @@ class SetMapConsistencyTest { lm.getOrElseUpdate(1024, { lm.clear; -1 }) assert(lm == scala.collection.mutable.LongMap(1024L -> -1)) } + + // Mutating when an iterator is in the wild shouldn't produce random junk in the iterator + // Todo: test all sets/maps this way + @Test + def testSI8154() { + def f() = { + val xs = scala.collection.mutable.AnyRefMap[String, Int]("a" -> 1) + val it = xs.iterator + it.hasNext + xs.clear() + + if (it.hasNext) Some(it.next) + else None + } + assert(f() match { + case Some((a,b)) if (a==null || b==null) => false + case _ => true + }) + } } |