diff --git a/src/main/java/scala/compat/java8/runtime/CollectionInternals.java b/src/main/java/scala/compat/java8/runtime/CollectionInternals.java
index 6f8da89..901a3d5 100644
--- a/src/main/java/scala/compat/java8/runtime/CollectionInternals.java
+++ b/src/main/java/scala/compat/java8/runtime/CollectionInternals.java
@@ -5,12 +5,19 @@
public class CollectionInternals {
public static Object[] getTable(scala.collection.mutable.FlatHashTable fht) { return fht.hashTableContents().table(); }
public static > scala.collection.mutable.HashEntry[] getTable(scala.collection.mutable.HashTable ht) { return ht.hashTableContents().table(); }
+ public static boolean getDirt(scala.collection.immutable.Vector v) { return v.dirty(); }
public static Object[] getDisplay0(scala.collection.immutable.Vector v) { return v.display0(); }
+ public static Object[] getDisplay0(scala.collection.immutable.VectorIterator p) { return p.display0(); }
public static Object[] getDisplay1(scala.collection.immutable.Vector v) { return v.display1(); }
+ public static Object[] getDisplay1(scala.collection.immutable.VectorIterator p) { return p.display1(); }
public static Object[] getDisplay2(scala.collection.immutable.Vector v) { return v.display2(); }
+ public static Object[] getDisplay2(scala.collection.immutable.VectorIterator p) { return p.display2(); }
public static Object[] getDisplay3(scala.collection.immutable.Vector v) { return v.display3(); }
+ public static Object[] getDisplay3(scala.collection.immutable.VectorIterator p) { return p.display3(); }
public static Object[] getDisplay4(scala.collection.immutable.Vector v) { return v.display4(); }
+ public static Object[] getDisplay4(scala.collection.immutable.VectorIterator p) { return p.display4(); }
public static Object[] getDisplay5(scala.collection.immutable.Vector v) { return v.display5(); }
+ public static Object[] getDisplay5(scala.collection.immutable.VectorIterator p) { return p.display5(); }
public static scala.Tuple2< scala.Tuple2< scala.collection.Iterator, Object >, scala.collection.Iterator > trieIteratorSplit(scala.collection.Iterator it) {
if (it instanceof scala.collection.immutable.TrieIterator) {
scala.collection.immutable.TrieIterator trie = (scala.collection.immutable.TrieIterator)it;
diff --git a/src/main/scala/scala/compat/java8/converterImpl/StepsLikeIndexed.scala b/src/main/scala/scala/compat/java8/converterImpl/StepsLikeIndexed.scala
index ed5abfa..8e3d312 100644
--- a/src/main/scala/scala/compat/java8/converterImpl/StepsLikeIndexed.scala
+++ b/src/main/scala/scala/compat/java8/converterImpl/StepsLikeIndexed.scala
@@ -32,16 +32,19 @@ private[java8] abstract class StepsLikeIndexed[A, STA >: Null <: StepsLikeIndexe
private[java8] abstract class StepsDoubleLikeIndexed[STD >: Null <: StepsDoubleLikeIndexed[_]](_i0: Int, _iN: Int)
extends AbstractStepsLikeIndexed[DoubleStepper, STD](_i0, _iN)
with DoubleStepper
+ with java.util.Spliterator.OfDouble // Compiler wants this for mixin forwarder
{}
/** Abstracts the operation of stepping over an indexable collection of Ints */
private[java8] abstract class StepsIntLikeIndexed[STI >: Null <: StepsIntLikeIndexed[_]](_i0: Int, _iN: Int)
extends AbstractStepsLikeIndexed[IntStepper, STI](_i0, _iN)
with IntStepper
+ with java.util.Spliterator.OfInt // Compiler wants this for mixin forwarder
{}
/** Abstracts the operation of stepping over an indexable collection of Longs */
private[java8] abstract class StepsLongLikeIndexed[STL >: Null <: StepsLongLikeIndexed[_]](_i0: Int, _iN: Int)
extends AbstractStepsLikeIndexed[LongStepper, STL](_i0, _iN)
with LongStepper
+ with java.util.Spliterator.OfLong // Compiler wants this for mixin forwarder
{}
diff --git a/src/main/scala/scala/compat/java8/converterImpl/StepsVector.scala b/src/main/scala/scala/compat/java8/converterImpl/StepsVector.scala
index b0abe26..11fe5ec 100644
--- a/src/main/scala/scala/compat/java8/converterImpl/StepsVector.scala
+++ b/src/main/scala/scala/compat/java8/converterImpl/StepsVector.scala
@@ -2,6 +2,8 @@ package scala.compat.java8.converterImpl
import scala.annotation.switch
+import scala.collection.immutable.VectorIterator
+
import scala.compat.java8.collectionImpl._
import scala.compat.java8.runtime._
@@ -13,20 +15,27 @@ import Stepper._
private[java8] trait StepsVectorLike[A] {
protected def myVector: Vector[A]
+ protected def myVectorIterator: VectorIterator[A]
+ protected def myVectorLength: Int
protected var index: Int = 32
protected var data: Array[AnyRef] = null
protected var index1: Int = 32
protected var data1: Array[AnyRef] = null
protected final def advanceData(iX: Int): Unit = {
index1 += 1
- if (index >= 32) initTo(iX)
+ if (index >= 32) {
+ if (myVector != null) initTo(iX)
+ else initVpTo(iX)
+ }
else {
data = data1(index1).asInstanceOf[Array[AnyRef]]
index = 0
}
}
protected final def initTo(iX: Int): Unit = {
- myVector.length match {
+ // WARNING--initVpTo is an exact copy of this except for the type! If you change one you must change the other!
+ // (Manually specialized this way for speed.)
+ myVectorLength match {
case x if x <= 0x20 =>
index = iX
data = CollectionInternals.getDisplay0(myVector)
@@ -52,12 +61,43 @@ private[java8] trait StepsVectorLike[A] {
data = data1(index1).asInstanceOf[Array[AnyRef]]
}
}
+ protected final def initVpTo(iX: Int): Unit = {
+ // WARNING--this is an exact copy of initTo! If you change one you must change the other!
+ // (Manually specialized this way for speed.)
+ myVectorLength match {
+ case x if x <= 0x20 =>
+ index = iX
+ data = CollectionInternals.getDisplay0(myVectorIterator)
+ case x if x <= 0x400 =>
+ index1 = iX >>> 5
+ data1 = CollectionInternals.getDisplay1(myVectorIterator)
+ index = iX & 0x1F
+ data = data1(index1).asInstanceOf[Array[AnyRef]]
+ case x =>
+ var N = 0
+ var dataN: Array[AnyRef] =
+ if (x <= 0x8000) { N = 2; CollectionInternals.getDisplay2(myVectorIterator) }
+ else if (x <= 0x100000) { N = 3; CollectionInternals.getDisplay3(myVectorIterator) }
+ else if (x <= 0x2000000) { N = 4; CollectionInternals.getDisplay4(myVectorIterator) }
+ else /*x <= 0x40000000*/{ N = 5; CollectionInternals.getDisplay5(myVectorIterator) }
+ while (N > 2) {
+ dataN = dataN((iX >>> (5*N))&0x1F).asInstanceOf[Array[AnyRef]]
+ N -= 1
+ }
+ index1 = (iX >>> 5) & 0x1F
+ data1 = dataN((iX >>> 10) & 0x1F).asInstanceOf[Array[AnyRef]]
+ index = iX & 0x1F
+ data = data1(index1).asInstanceOf[Array[AnyRef]]
+ }
+ }
}
private[java8] class StepsAnyVector[A](underlying: Vector[A], _i0: Int, _iN: Int)
extends StepsLikeIndexed[A, StepsAnyVector[A]](_i0, _iN)
with StepsVectorLike[A] {
- protected def myVector = underlying
+ protected val myVector = if (CollectionInternals.getDirt(underlying)) null else underlying
+ protected val myVectorIterator = if (myVector == null) underlying.iterator else null
+ protected val myVectorLength = underlying.length
def next() = if (hasNext()) {
index += 1
if (index >= 32) advanceData(i0)
@@ -76,7 +116,9 @@ with StepsVectorLike[A] {
private[java8] class StepsDoubleVector(underlying: Vector[Double], _i0: Int, _iN: Int)
extends StepsDoubleLikeIndexed[StepsDoubleVector](_i0, _iN)
with StepsVectorLike[Double] {
- protected def myVector = underlying
+ protected val myVector = if (CollectionInternals.getDirt(underlying)) null else underlying
+ protected val myVectorIterator = if (myVector == null) underlying.iterator else null
+ protected val myVectorLength = underlying.length
def nextDouble() = if (hasNext()) {
index += 1
if (index >= 32) advanceData(i0)
@@ -95,7 +137,9 @@ with StepsVectorLike[Double] {
private[java8] class StepsIntVector(underlying: Vector[Int], _i0: Int, _iN: Int)
extends StepsIntLikeIndexed[StepsIntVector](_i0, _iN)
with StepsVectorLike[Int] {
- protected def myVector = underlying
+ protected val myVector = if (CollectionInternals.getDirt(underlying)) null else underlying
+ protected val myVectorIterator = if (myVector == null) underlying.iterator else null
+ protected val myVectorLength = underlying.length
def nextInt() = if (hasNext()) {
index += 1
if (index >= 32) advanceData(i0)
@@ -114,7 +158,9 @@ with StepsVectorLike[Int] {
private[java8] class StepsLongVector(underlying: Vector[Long], _i0: Int, _iN: Int)
extends StepsLongLikeIndexed[StepsLongVector](_i0, _iN)
with StepsVectorLike[Long] {
- protected def myVector = underlying
+ protected val myVector = if (CollectionInternals.getDirt(underlying)) null else underlying
+ protected val myVectorIterator = if (myVector == null) underlying.iterator else null
+ protected val myVectorLength = underlying.length
def nextLong() = if (hasNext()) {
index += 1
if (index >= 32) advanceData(i0)
diff --git a/src/test/scala/scala/compat/java8/StreamConvertersTest.scala b/src/test/scala/scala/compat/java8/StreamConvertersTest.scala
index fbecae5..10a3f08 100644
--- a/src/test/scala/scala/compat/java8/StreamConvertersTest.scala
+++ b/src/test/scala/scala/compat/java8/StreamConvertersTest.scala
@@ -276,4 +276,32 @@ class StreamConvertersTest {
val stepper2 = steppize2(coll2).stepper
assertTrue(stepper2.getClass.getName.contains("StepsIntVector"))
}
+
+ @Test
+ def issue_87(): Unit = {
+ // Vectors that are generated from other vectors tend _not_ to
+ // have all their display vectors consistent; the cached vectors
+ // are correct, but the higher-level vector does _not_ contain
+ // the cached vector in the correct place (for efficiency)! This
+ // is called being "dirty", and needs to be handled specially.
+ val dirtyDisplayVector = Vector.fill(120)("a").slice(0, 40)
+ val shouldNotNPE =
+ dirtyDisplayVector.seqStream.collect(Collectors.toList())
+ assertEq(shouldNotNPE.toArray(new Array[String](0)).toVector, dirtyDisplayVector, "Vector[Any].seqStream (with dirty display)")
+
+ val dirtyDisplayVectorInt = Vector.fill(120)(999).slice(0, 40)
+ val shouldNotNPEInt =
+ dirtyDisplayVectorInt.seqStream.sum()
+ assertEq(shouldNotNPEInt, dirtyDisplayVectorInt.sum, "Vector[Int].seqStream (with dirty display)")
+
+ val dirtyDisplayVectorLong = Vector.fill(120)(99999999999L).slice(0, 40)
+ val shouldNotNPELong =
+ dirtyDisplayVectorLong.seqStream.sum()
+ assertEq(shouldNotNPELong, dirtyDisplayVectorLong.sum, "Vector[Long].seqStream (with dirty display)")
+
+ val dirtyDisplayVectorDouble = Vector.fill(120)(0.1).slice(0, 40)
+ val shouldNotNPEDouble =
+ math.rint(dirtyDisplayVectorDouble.seqStream.sum() * 10)
+ assertEq(shouldNotNPEDouble, math.rint(dirtyDisplayVectorDouble.sum * 10), "Vector[Double].seqStream (with dirty display)")
+ }
}