Skip to content

Commit 1da69e8

Browse files
committed
SI-8815 mutable.LongMap makes different choices for splitAt vs etc.
It turns out that take/drop/splitAt/takeWhile/dropWhile inherit a smattering of foreach vs. iterator-based implementations. These aren't consistent unless they iterate in the same order. This probably reflects an undesirable underlying weakness, but in this particular case it was easy to make LongMap's foreach order agree with iterator. Made traversal order of other foreach-like methods match also. Also fixed a bug where Long.MinValue wasn't iterated. Added unit test for iteration coverage of extreme values.
1 parent 7c8eaef commit 1da69e8

File tree

2 files changed

+26
-27
lines changed

2 files changed

+26
-27
lines changed

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

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -388,12 +388,14 @@ extends AbstractMap[Long, V]
388388
nextPair = anotherPair
389389
anotherPair = null
390390
}
391-
nextPair = null
391+
else nextPair = null
392392
ans
393393
}
394394
}
395395

396396
override def foreach[A](f: ((Long,V)) => A) {
397+
if ((extraKeys & 1) == 1) f((0L, zeroValue.asInstanceOf[V]))
398+
if ((extraKeys & 2) == 2) f((Long.MinValue, minValue.asInstanceOf[V]))
397399
var i,j = 0
398400
while (i < _keys.length & j < _size) {
399401
val k = _keys(i)
@@ -403,8 +405,6 @@ extends AbstractMap[Long, V]
403405
}
404406
i += 1
405407
}
406-
if ((extraKeys & 1) == 1) f((0L, zeroValue.asInstanceOf[V]))
407-
if ((extraKeys & 2) == 2) f((Long.MinValue, minValue.asInstanceOf[V]))
408408
}
409409

410410
override def clone(): LongMap[V] = {
@@ -417,6 +417,8 @@ extends AbstractMap[Long, V]
417417

418418
/** Applies a function to all keys of this map. */
419419
def foreachKey[A](f: Long => A) {
420+
if ((extraKeys & 1) == 1) f(0L)
421+
if ((extraKeys & 2) == 2) f(Long.MinValue)
420422
var i,j = 0
421423
while (i < _keys.length & j < _size) {
422424
val k = _keys(i)
@@ -426,12 +428,12 @@ extends AbstractMap[Long, V]
426428
}
427429
i += 1
428430
}
429-
if ((extraKeys & 1) == 1) f(0L)
430-
if ((extraKeys & 2) == 2) f(Long.MinValue)
431431
}
432432

433433
/** Applies a function to all values of this map. */
434434
def foreachValue[A](f: V => A) {
435+
if ((extraKeys & 1) == 1) f(zeroValue.asInstanceOf[V])
436+
if ((extraKeys & 2) == 2) f(minValue.asInstanceOf[V])
435437
var i,j = 0
436438
while (i < _keys.length & j < _size) {
437439
val k = _keys(i)
@@ -441,15 +443,15 @@ extends AbstractMap[Long, V]
441443
}
442444
i += 1
443445
}
444-
if ((extraKeys & 1) == 1) f(zeroValue.asInstanceOf[V])
445-
if ((extraKeys & 2) == 2) f(minValue.asInstanceOf[V])
446446
}
447447

448448
/** Creates a new `LongMap` with different values.
449449
* Unlike `mapValues`, this method generates a new
450450
* collection immediately.
451451
*/
452452
def mapValuesNow[V1](f: V => V1): LongMap[V1] = {
453+
val zv = if ((extraKeys & 1) == 1) f(zeroValue.asInstanceOf[V]).asInstanceOf[AnyRef] else null
454+
val mv = if ((extraKeys & 2) == 2) f(minValue.asInstanceOf[V]).asInstanceOf[AnyRef] else null
453455
val lm = new LongMap[V1](LongMap.exceptionDefault, 1, false)
454456
val kz = java.util.Arrays.copyOf(_keys, _keys.length)
455457
val vz = new Array[AnyRef](_values.length)
@@ -462,8 +464,6 @@ extends AbstractMap[Long, V]
462464
}
463465
i += 1
464466
}
465-
val zv = if ((extraKeys & 1) == 1) f(zeroValue.asInstanceOf[V]).asInstanceOf[AnyRef] else null
466-
val mv = if ((extraKeys & 2) == 2) f(minValue.asInstanceOf[V]).asInstanceOf[AnyRef] else null
467467
lm.initializeTo(mask, extraKeys, zv, mv, _size, _vacant, kz, vz)
468468
lm
469469
}
@@ -472,6 +472,8 @@ extends AbstractMap[Long, V]
472472
* Note: the default, if any, is not transformed.
473473
*/
474474
def transformValues(f: V => V): this.type = {
475+
if ((extraKeys & 1) == 1) zeroValue = f(zeroValue.asInstanceOf[V]).asInstanceOf[AnyRef]
476+
if ((extraKeys & 2) == 2) minValue = f(minValue.asInstanceOf[V]).asInstanceOf[AnyRef]
475477
var i,j = 0
476478
while (i < _keys.length & j < _size) {
477479
val k = _keys(i)
@@ -481,26 +483,8 @@ extends AbstractMap[Long, V]
481483
}
482484
i += 1
483485
}
484-
if ((extraKeys & 1) == 1) zeroValue = f(zeroValue.asInstanceOf[V]).asInstanceOf[AnyRef]
485-
if ((extraKeys & 2) == 2) minValue = f(minValue.asInstanceOf[V]).asInstanceOf[AnyRef]
486486
this
487487
}
488-
489-
/*
490-
override def toString = {
491-
val sb = new StringBuilder("LongMap(")
492-
var n = 0
493-
foreach{ case (k,v) =>
494-
if (n > 0) sb ++= ", "
495-
sb ++= k.toString
496-
sb ++= " -> "
497-
sb ++= v.toString
498-
n += 1
499-
}
500-
sb += ')'
501-
sb.result
502-
}
503-
*/
504488
}
505489

506490
object LongMap {

test/junit/scala/collection/SetMapConsistencyTest.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,4 +514,19 @@ class SetMapConsistencyTest {
514514
assert( hs.toList.toSet == hs )
515515
assert( hs == hs.toList.toSet )
516516
}
517+
518+
@Test
519+
def testSI8815() {
520+
val lm = new scala.collection.mutable.LongMap[String]
521+
lm += (Long.MinValue, "min")
522+
lm += (-1, "neg-one")
523+
lm += (0, "zero")
524+
lm += (Long.MaxValue, "max")
525+
var nit = 0
526+
lm.iterator.foreach(_ => nit += 1)
527+
var nfe = 0
528+
lm.foreach(_ => nfe += 1)
529+
assert(nit == 4)
530+
assert(nfe == 4)
531+
}
517532
}

0 commit comments

Comments
 (0)