Skip to content

VectorBuilder#addAll and VectorIterator#copyToArray/addAll use System.arraycopy #7110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 49 additions & 18 deletions src/library/scala/collection/immutable/Vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,8 @@ final class Vector[+A] private[immutable] (private[collection] val startIndex: I

override def appended[B >: A](value: B): Vector[B] = {
val result = if (endIndex != startIndex) {
val blockIndex = endIndex & ~31
val lo = endIndex & 31
val blockIndex = endIndex & ~31 // round down to nearest 32
val lo = endIndex & 31 // remainder of blockIndex / 32

if (endIndex != blockIndex) {
val s = new Vector(startIndex, endIndex + 1, blockIndex)
Expand Down Expand Up @@ -616,6 +616,8 @@ final class Vector[+A] private[immutable] (private[collection] val startIndex: I
case _ => super.equals(o)
}

override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = iterator.copyToArray(xs, start, len)

override def toVector: Vector[A] = this

override protected[this] def className = "Vector"
Expand All @@ -628,12 +630,27 @@ class VectorIterator[+A](_startIndex: Int, endIndex: Int)
private[this] var blockIndex: Int = _startIndex & ~31
private[this] var lo: Int = _startIndex & 31

private[this] var endLo = math.min(endIndex - blockIndex, 32)
private[this] var endLo = Math.min(endIndex - blockIndex, 32)

def hasNext = _hasNext

private[this] var _hasNext = blockIndex + lo < endIndex

private[this] def advanceToNextBlockIfNecessary(): Unit = {
if (lo == endLo) {
if (blockIndex + lo < endIndex) {
val newBlockIndex = blockIndex + 32
gotoNextBlockStart(newBlockIndex, blockIndex ^ newBlockIndex)

blockIndex = newBlockIndex
endLo = Math.min(endIndex - blockIndex, 32)
lo = 0
} else {
_hasNext = false
}
}
}

override def drop(n: Int): Iterator[A] = {
if (n > 0) {
val longLo = lo.toLong + n
Expand All @@ -657,24 +674,25 @@ class VectorIterator[+A](_startIndex: Int, endIndex: Int)

def next(): A = {
if (!_hasNext) throw new NoSuchElementException("reached iterator end")

val res = display0(lo).asInstanceOf[A]
lo += 1
advanceToNextBlockIfNecessary()
res
}

if (lo == endLo) {
if (blockIndex + lo < endIndex) {
val newBlockIndex = blockIndex + 32
gotoNextBlockStart(newBlockIndex, blockIndex ^ newBlockIndex)

blockIndex = newBlockIndex
endLo = math.min(endIndex - blockIndex, 32)
lo = 0
} else {
_hasNext = false
}
override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = {
val xsLen = xs.length
val totalToBeCopied = IterableOnce.elemsToCopyToArray(remainingElementCount, xsLen, start, len)
var totalCopied = 0
while (hasNext && totalCopied < totalToBeCopied) {
val _start = start + totalCopied
val toBeCopied = IterableOnce.elemsToCopyToArray(endLo - lo, xsLen, _start, len - totalCopied)
Array.copy(display0, lo, xs, _start, toBeCopied)
totalCopied += toBeCopied
lo += toBeCopied
advanceToNextBlockIfNecessary()
}

res
totalCopied
}

private[collection] def remainingElementCount: Int = (endIndex - (blockIndex + lo)) max 0
Expand Down Expand Up @@ -707,18 +725,31 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
def isEmpty: Boolean = size == 0
def nonEmpty: Boolean = size != 0

def addOne(elem: A): this.type = {
private[this] def advanceToNextBlockIfNecessary(): Unit = {
if (lo >= display0.length) {
val newBlockIndex = blockIndex + 32
gotoNextBlockStartWritable(newBlockIndex, blockIndex ^ newBlockIndex)
blockIndex = newBlockIndex
lo = 0
}
}

def addOne(elem: A): this.type = {
advanceToNextBlockIfNecessary()
display0(lo) = elem.asInstanceOf[AnyRef]
lo += 1
this
}

override def addAll(xs: IterableOnce[A]): this.type = {
val it = (xs.iterator : Iterator[A]).asInstanceOf[Iterator[AnyRef]]
while (it.hasNext) {
advanceToNextBlockIfNecessary()
lo += it.copyToArray(xs = display0, start = lo, len = display0.length - lo)
}
this
}

def result(): Vector[A] = {
val size = this.size
if (size == 0)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package scala.collection.immutable

import java.util.concurrent.TimeUnit

import org.openjdk.jmh.infra.Blackhole

import org.openjdk.jmh.annotations._

@BenchmarkMode(Array(Mode.AverageTime))
@Fork(2)
@Threads(1)
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
class VectorBenchmark {
@Param(Array("0", "10", "1000", "1000000"))
var size: Int = _
var vec: Vector[AnyRef] = _
val array = Array.fill(1000000)(new AnyRef)

@Setup(Level.Trial) def initKeys(): Unit = {
vec = Vector.fill(size)(new AnyRef)
}
@Benchmark def concat(bh: Blackhole): Any = {
bh.consume(vec.copyToArray(array, 0, size))
}
}
12 changes: 12 additions & 0 deletions test/junit/scala/collection/immutable/VectorTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,18 @@ class VectorTest {
assertEquals(Vector(1, 2, 3, 0), Vector(0).prependedAll(i))
}

@Test
def concat: Unit = {
assertEquals((1 to 100).toVector, (1 to 7).toVector concat (8 to 100).toVector)
}

@Test
def copyToArray: Unit = {
val array = Array.fill(100)(2)
Vector.fill(100)(1).copyToArray(array, 0, 100)
assertEquals(array.toSeq, Seq.fill(100)(1))
}

@Test
def vectorIteratorDrop(): Unit = {
val underlying = Vector(0 to 10010: _*)
Expand Down