Skip to content

Commit 3ad633c

Browse files
authored
Merge pull request scala/scala#8410 from szeiger/wip/revert-7588
Revert "VectorBuilder avoids copying data if possible"
2 parents 4372e22 + 44dea21 commit 3ad633c

File tree

1 file changed

+38
-118
lines changed

1 file changed

+38
-118
lines changed

library/src/scala/collection/immutable/Vector.scala

Lines changed: 38 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -290,51 +290,30 @@ final class Vector[+A] private[immutable] (private[collection] val startIndex: I
290290
dropRight(1)
291291
}
292292

293-
override def appendedAll[B >: A](suffix: collection.IterableOnce[B]): Vector[B] =
294-
suffix match {
295-
case v: Vector[B] =>
296-
val thisLength = this.length
297-
val thatLength = v.length
298-
if (thisLength == 0) v
299-
else if (thatLength == 0) this
300-
else if (thatLength <= Vector.TinyAppendFaster) {
301-
// Often it's better to append small numbers of elements (or prepend if RHS is a vector)
302-
var v0: Vector[B] = this
303-
var i = 0
304-
while (i < thatLength) {
305-
v0 = v0.appended(v(i))
306-
i += 1
307-
}
308-
v0
309-
} else {
310-
if (thisLength < (thatLength >>> Vector.Log2ConcatFaster)) {
311-
var v0 = v
312-
val iter = this.reverseIterator
313-
while(iter.hasNext) {
314-
v0 = iter.next() +: v0
315-
}
316-
v0
317-
} else {
318-
new VectorBuilder[B]().addAll(this).addAll(suffix).result()
319-
}
320-
}
321-
case _ =>
322-
val thatKnownSize = suffix.knownSize
323-
if (thatKnownSize == 0) this
324-
else if (thatKnownSize > 0 && thatKnownSize <= Vector.TinyAppendFaster) {
325-
var v0: Vector[B] = this
326-
val iter = suffix.iterator
327-
while (iter.hasNext) {
328-
v0 = v0.appended(iter.next())
293+
// appendAll (suboptimal but avoids worst performance gotchas)
294+
override def appendedAll[B >: A](suffix: collection.IterableOnce[B]): Vector[B] = {
295+
import Vector.{Log2ConcatFaster, TinyAppendFaster}
296+
if (suffix.iterator.isEmpty) this
297+
else {
298+
suffix match {
299+
case suffix: collection.Iterable[B] =>
300+
suffix.size match {
301+
// Often it's better to append small numbers of elements (or prepend if RHS is a vector)
302+
case n if n <= TinyAppendFaster || n < (this.size >>> Log2ConcatFaster) =>
303+
var v: Vector[B] = this
304+
for (x <- suffix) v = v :+ x
305+
v
306+
case n if this.size < (n >>> Log2ConcatFaster) && suffix.isInstanceOf[Vector[_]] =>
307+
var v = suffix.asInstanceOf[Vector[B]]
308+
val ri = this.reverseIterator
309+
while (ri.hasNext) v = ri.next() +: v
310+
v
311+
case _ => super.appendedAll(suffix)
329312
}
330-
v0
331-
} else {
332-
val iter = suffix.iterator
333-
if (iter.hasNext) {
334-
new VectorBuilder[B]().addAll(this).addAll(suffix).result()
335-
} else this
336-
}
313+
case _ => super.appendedAll(suffix)
314+
}
337315
}
316+
}
338317

339318
override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): Vector[B] = {
340319
// Implementation similar to `appendAll`: when of the collections to concatenate (either `this` or `prefix`)
@@ -851,21 +830,10 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
851830
display0 = new Array[AnyRef](32)
852831
depth = 1
853832

854-
/** The index within the final Vector of `this.display0(0)` */
855833
private[this] var blockIndex = 0
856-
/** The index within `this.display0` which is the next available index to write to.
857-
* This value may be equal to display0.length, in which case before writing, a new block
858-
* should be created (see advanceToNextBlockIfNecessary)*/
859834
private[this] var lo = 0
860-
/** Indicates an offset of the final vector from the actual underlying array elements. This is
861-
* used for example in `drop(1)` where instead of copying the entire Vector, only the startIndex is changed.
862-
*
863-
* This is present in the Builder because we may be able to share structure with a Vector that is `addAll`'d to this.
864-
* In which case we must track that Vector's startIndex offset.
865-
* */
866-
private[this] var startIndex = 0
867-
868-
def size: Int = (blockIndex & ~31) + lo - startIndex
835+
836+
def size: Int = blockIndex + lo
869837
def isEmpty: Boolean = size == 0
870838
def nonEmpty: Boolean = size != 0
871839

@@ -888,49 +856,10 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
888856
}
889857

890858
override def addAll(xs: IterableOnce[A]): this.type = {
891-
892-
xs match {
893-
case v: Vector[A] if this.isEmpty && v.length >= 32 =>
894-
depth = v.depth
895-
blockIndex = (v.endIndex - 1) & ~31
896-
lo = v.endIndex - blockIndex
897-
startIndex = v.startIndex
898-
899-
/** `initFrom` will overwrite display0. Keep reference to it so we can reuse the array.*/
900-
val initialDisplay0 = display0
901-
initFrom(v)
902-
stabilize(v.focus)
903-
gotoPosWritable1(v.focus, blockIndex, v.focus ^ blockIndex, initialDisplay0)
904-
905-
depth match {
906-
case 2 =>
907-
display1((blockIndex >>> 5) & 31) = display0
908-
case 3 =>
909-
display1((blockIndex >>> 5) & 31) = display0
910-
display2((blockIndex >>> 10) & 31) = display1
911-
case 4 =>
912-
display1((blockIndex >>> 5) & 31) = display0
913-
display2((blockIndex >>> 10) & 31) = display1
914-
display3((blockIndex >>> 15) & 31) = display2
915-
case 5 =>
916-
display1((blockIndex >>> 5) & 31) = display0
917-
display2((blockIndex >>> 10) & 31) = display1
918-
display3((blockIndex >>> 15) & 31) = display2
919-
display4((blockIndex >>> 20) & 31) = display3
920-
case 6 =>
921-
display1((blockIndex >>> 5) & 31) = display0
922-
display2((blockIndex >>> 10) & 31) = display1
923-
display3((blockIndex >>> 15) & 31) = display2
924-
display4((blockIndex >>> 20) & 31) = display3
925-
display5((blockIndex >>> 25) & 31) = display4
926-
case _ => ()
927-
}
928-
case _ =>
929-
val it = (xs.iterator : Iterator[A]).asInstanceOf[Iterator[AnyRef]]
930-
while (it.hasNext) {
931-
advanceToNextBlockIfNecessary()
932-
lo += it.copyToArray(xs = display0, start = lo, len = display0.length - lo)
933-
}
859+
val it = (xs.iterator : Iterator[A]).asInstanceOf[Iterator[AnyRef]]
860+
while (it.hasNext) {
861+
advanceToNextBlockIfNecessary()
862+
lo += it.copyToArray(xs = display0, start = lo, len = display0.length - lo)
934863
}
935864
this
936865
}
@@ -939,9 +868,9 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
939868
val size = this.size
940869
if (size == 0)
941870
return Vector.empty
942-
val s = new Vector[A](startIndex, blockIndex + lo, 0) // should focus front or back?
871+
val s = new Vector[A](0, size, 0) // should focus front or back?
943872
s.initFrom(this)
944-
if (depth > 1) s.gotoPos(startIndex, blockIndex + lo - 1) // we're currently focused to size - 1, not size!
873+
if (depth > 1) s.gotoPos(0, size - 1) // we're currently focused to size - 1, not size!
945874
releaseFence()
946875
s
947876
}
@@ -951,7 +880,6 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
951880
display0 = new Array[AnyRef](32)
952881
blockIndex = 0
953882
lo = 0
954-
startIndex = 0
955883
}
956884
}
957885

@@ -1147,19 +1075,10 @@ private[immutable] trait VectorPointer[+T] {
11471075

11481076
// STUFF BELOW USED BY APPEND / UPDATE
11491077

1150-
/** Sets array(index) to null and returns an array with same contents as what was previously at array(index)
1151-
*
1152-
* If `destination` array is not null, original contents of array(index) will be copied to it, and it will be returned.
1153-
* Otherwise array(index).clone() is returned
1154-
*/
1155-
private[immutable] final def nullSlotAndCopy[T <: AnyRef](array: Array[Array[T]], index: Int, destination: Array[T] = null): Array[T] = {
1078+
private[immutable] final def nullSlotAndCopy[T <: AnyRef](array: Array[Array[T]], index: Int): Array[T] = {
11561079
val x = array(index)
11571080
array(index) = null
1158-
if (destination == null) x.clone()
1159-
else {
1160-
x.copyToArray(destination, 0)
1161-
destination
1162-
}
1081+
x.clone()
11631082
}
11641083

11651084
// make sure there is no aliasing
@@ -1242,9 +1161,10 @@ private[immutable] trait VectorPointer[+T] {
12421161
display0 = display0.clone()
12431162
}
12441163

1164+
12451165
// requires structure is dirty and at pos oldIndex,
12461166
// ensures structure is dirty and at pos newIndex and writable at level 0
1247-
private[immutable] final def gotoPosWritable1(oldIndex: Int, newIndex: Int, xor: Int, reuseDisplay0: Array[AnyRef] = null): Unit = {
1167+
private[immutable] final def gotoPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = {
12481168
if (xor < (1 << 5)) { // level = 0
12491169
display0 = display0.clone()
12501170
} else if (xor < (1 << 10)) { // level = 1
@@ -1257,7 +1177,7 @@ private[immutable] trait VectorPointer[+T] {
12571177
display1((oldIndex >>> 5) & 31) = display0
12581178
display2((oldIndex >>> 10) & 31) = display1
12591179
display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31)
1260-
display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31, reuseDisplay0)
1180+
display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31)
12611181
} else if (xor < (1 << 20)) { // level = 3
12621182
display1 = display1.clone()
12631183
display2 = display2.clone()
@@ -1267,7 +1187,7 @@ private[immutable] trait VectorPointer[+T] {
12671187
display3((oldIndex >>> 15) & 31) = display2
12681188
display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31)
12691189
display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31)
1270-
display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31, reuseDisplay0)
1190+
display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31)
12711191
} else if (xor < (1 << 25)) { // level = 4
12721192
display1 = display1.clone()
12731193
display2 = display2.clone()
@@ -1280,7 +1200,7 @@ private[immutable] trait VectorPointer[+T] {
12801200
display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31)
12811201
display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31)
12821202
display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31)
1283-
display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31, reuseDisplay0)
1203+
display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31)
12841204
} else if (xor < (1 << 30)) { // level = 5
12851205
display1 = display1.clone()
12861206
display2 = display2.clone()
@@ -1296,7 +1216,7 @@ private[immutable] trait VectorPointer[+T] {
12961216
display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31)
12971217
display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31)
12981218
display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31)
1299-
display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31, reuseDisplay0)
1219+
display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31)
13001220
} else { // level = 6
13011221
throw new IllegalArgumentException()
13021222
}

0 commit comments

Comments
 (0)