Skip to content

Commit 85fc115

Browse files
authored
Merge pull request scala#10816 from samuelchassot/2.13.x
Fix infinite loop bug in the mutable LongMap
2 parents a86ae0a + efe4c2f commit 85fc115

File tree

2 files changed

+42
-17
lines changed

2 files changed

+42
-17
lines changed

src/library/scala/collection/mutable/LongMap.scala

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,14 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff
269269
}
270270

271271
/** Repacks the contents of this `LongMap` for maximum efficiency of lookup.
272-
*
273-
* For maps that undergo a complex creation process with both addition and
274-
* removal of keys, and then are used heavily with no further removal of
275-
* elements, calling `repack` after the end of the creation can result in
276-
* improved performance. Repacking takes time proportional to the number
277-
* of entries in the map.
278-
*/
279-
def repack(): Unit = {
280-
var m = mask
281-
if (_size + _vacant >= 0.5*mask && !(_vacant > 0.2*mask)) m = ((m << 1) + 1) & IndexMask
282-
while (m > 8 && 8*_size < m) m = m >>> 1
283-
repack(m)
284-
}
272+
*
273+
* For maps that undergo a complex creation process with both addition and
274+
* removal of keys, and then are used heavily with no further removal of
275+
* elements, calling `repack` after the end of the creation can result in
276+
* improved performance. Repacking takes time proportional to the number
277+
* of entries in the map.
278+
*/
279+
def repack(): Unit = repack(repackMask(mask, _size = _size, _vacant = _vacant))
285280

286281
override def put(key: Long, value: V): Option[V] = {
287282
if (key == -key) {
@@ -587,10 +582,10 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff
587582
}
588583

589584
object LongMap {
590-
private final val IndexMask = 0x3FFFFFFF
591-
private final val MissingBit = 0x80000000
592-
private final val VacantBit = 0x40000000
593-
private final val MissVacant = 0xC0000000
585+
private final val IndexMask = 0x3FFF_FFFF
586+
private final val MissingBit = 0x8000_0000
587+
private final val VacantBit = 0x4000_0000
588+
private final val MissVacant = 0xC000_0000
594589

595590
private val exceptionDefault: Long => Nothing = (k: Long) => throw new NoSuchElementException(k.toString)
596591

@@ -682,4 +677,11 @@ object LongMap {
682677

683678
implicit def iterableFactory[V]: Factory[(Long, V), LongMap[V]] = toFactory(this)
684679
implicit def buildFromLongMap[V]: BuildFrom[LongMap[_], (Long, V), LongMap[V]] = toBuildFrom(this)
680+
681+
private def repackMask(mask: Int, _size: Int, _vacant: Int): Int = {
682+
var m = mask
683+
if (_size + _vacant >= 0.5*mask && !(_vacant > 0.2*mask)) m = ((m << 1) + 1) & IndexMask
684+
while (m > 8 && _size < (m >>> 3)) m = m >>> 1
685+
m /*.ensuring(_size <= _ + 1)*/
686+
}
685687
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package scala.collection
2+
package mutable
3+
4+
import org.junit.Assert._
5+
import org.junit.Test
6+
7+
import scala.tools.testkit.ReflectUtil.getMethodAccessible
8+
9+
class LongMapTest {
10+
11+
@Test
12+
def `repack calculation must complete`: Unit = {
13+
val vacant: Int = 10256777
14+
val mask: Int = 1073741823
15+
val size: Int = 603979777
16+
//LongMap.repackMask
17+
val name = "scala$collection$mutable$LongMap$$repackMask"
18+
val sut = getMethodAccessible[LongMap.type](name)
19+
val res = sut.invoke(LongMap, mask, size, vacant)
20+
assertEquals(1073741823, res)
21+
}
22+
23+
}

0 commit comments

Comments
 (0)