@@ -14,10 +14,7 @@ package scala
1414package collection
1515package immutable
1616
17- import java .io .{ObjectInputStream , ObjectOutputStream }
18- import java .util
19-
20- import scala .collection .mutable .{Builder , ReusableBuilder }
17+ import scala .collection .mutable .ReusableBuilder
2118import scala .annotation .unchecked .uncheckedVariance
2219import scala .collection .generic .DefaultSerializable
2320import scala .runtime .Statics .releaseFence
@@ -77,7 +74,7 @@ object Vector extends StrictOptimizedSeqFactory[Vector] {
7774 * @define mayNotTerminateInf
7875 * @define willNotTerminateInf
7976 */
80- final class Vector [+ A ] private [immutable] (private [collection] val startIndex : Int , private [collection] val endIndex : Int , focus : Int )
77+ final class Vector [+ A ] private [immutable] (private [collection] val startIndex : Int , private [collection] val endIndex : Int , private [immutable] val focus : Int )
8178 extends AbstractSeq [A ]
8279 with IndexedSeq [A ]
8380 with IndexedSeqOps [A , Vector , Vector [A ]]
@@ -228,30 +225,51 @@ final class Vector[+A] private[immutable] (private[collection] val startIndex: I
228225 dropRight(1 )
229226 }
230227
231- // appendAll (suboptimal but avoids worst performance gotchas)
232- override def appendedAll [B >: A ](suffix : collection.IterableOnce [B ]): Vector [B ] = {
233- import Vector .{Log2ConcatFaster , TinyAppendFaster }
234- if (suffix.iterator.isEmpty) this
235- else {
236- suffix match {
237- case suffix : collection.Iterable [B ] =>
238- suffix.size match {
239- // Often it's better to append small numbers of elements (or prepend if RHS is a vector)
240- case n if n <= TinyAppendFaster || n < (this .size >>> Log2ConcatFaster ) =>
241- var v : Vector [B ] = this
242- for (x <- suffix) v = v :+ x
243- v
244- case n if this .size < (n >>> Log2ConcatFaster ) && suffix.isInstanceOf [Vector [_]] =>
245- var v = suffix.asInstanceOf [Vector [B ]]
246- val ri = this .reverseIterator
247- while (ri.hasNext) v = ri.next() +: v
248- v
249- case _ => super .appendedAll(suffix)
228+ override def appendedAll [B >: A ](suffix : collection.IterableOnce [B ]): Vector [B ] =
229+ suffix match {
230+ case v : Vector [B ] =>
231+ val thisLength = this .length
232+ val thatLength = v.length
233+ if (thisLength == 0 ) v
234+ else if (thatLength == 0 ) this
235+ else if (thatLength <= Vector .TinyAppendFaster ) {
236+ // Often it's better to append small numbers of elements (or prepend if RHS is a vector)
237+ var v0 : Vector [B ] = this
238+ var i = 0
239+ while (i < thatLength) {
240+ v0 = v0.appended(v(i))
241+ i += 1
250242 }
251- case _ => super .appendedAll(suffix)
252- }
243+ v0
244+ } else {
245+ if (thisLength < (thatLength >>> Vector .Log2ConcatFaster )) {
246+ var v0 = v
247+ val iter = this .reverseIterator
248+ while (iter.hasNext) {
249+ v0 = iter.next() +: v0
250+ }
251+ v0
252+ } else {
253+ new VectorBuilder [B ]().addAll(this ).addAll(suffix).result()
254+ }
255+ }
256+ case _ =>
257+ val thatKnownSize = suffix.knownSize
258+ if (thatKnownSize == 0 ) this
259+ else if (thatKnownSize > 0 && thatKnownSize <= Vector .TinyAppendFaster ) {
260+ var v0 : Vector [B ] = this
261+ val iter = suffix.iterator
262+ while (iter.hasNext) {
263+ v0 = v0.appended(iter.next())
264+ }
265+ v0
266+ } else {
267+ val iter = suffix.iterator
268+ if (iter.hasNext) {
269+ new VectorBuilder [B ]().addAll(this ).addAll(suffix).result()
270+ } else this
271+ }
253272 }
254- }
255273
256274 override def prependedAll [B >: A ](prefix : collection.IterableOnce [B ]): Vector [B ] = {
257275 // Implementation similar to `appendAll`: when of the collections to concatenate (either `this` or `prefix`)
@@ -755,10 +773,21 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
755773 display0 = new Array [AnyRef ](32 )
756774 depth = 1
757775
776+ /** The index within the final Vector of `this.display0(0)` */
758777 private [this ] var blockIndex = 0
778+ /** The index within `this.display0` which is the next available index to write to.
779+ * This value may be equal to display0.length, in which case before writing, a new block
780+ * should be created (see advanceToNextBlockIfNecessary)*/
759781 private [this ] var lo = 0
760-
761- def size : Int = blockIndex + lo
782+ /** Indicates an offset of the final vector from the actual underlying array elements. This is
783+ * used for example in `drop(1)` where instead of copying the entire Vector, only the startIndex is changed.
784+ *
785+ * This is present in the Builder because we may be able to share structure with a Vector that is `addAll`'d to this.
786+ * In which case we must track that Vector's startIndex offset.
787+ * */
788+ private [this ] var startIndex = 0
789+
790+ def size : Int = (blockIndex & ~ 31 ) + lo - startIndex
762791 def isEmpty : Boolean = size == 0
763792 def nonEmpty : Boolean = size != 0
764793
@@ -781,10 +810,49 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
781810 }
782811
783812 override def addAll (xs : IterableOnce [A ]): this .type = {
784- val it = (xs.iterator : Iterator [A ]).asInstanceOf [Iterator [AnyRef ]]
785- while (it.hasNext) {
786- advanceToNextBlockIfNecessary()
787- lo += it.copyToArray(xs = display0, start = lo, len = display0.length - lo)
813+
814+ xs match {
815+ case v : Vector [A ] if this .isEmpty && v.length >= 32 =>
816+ depth = v.depth
817+ blockIndex = (v.endIndex - 1 ) & ~ 31
818+ lo = v.endIndex - blockIndex
819+ startIndex = v.startIndex
820+
821+ /** `initFrom` will overwrite display0. Keep reference to it so we can reuse the array.*/
822+ val initialDisplay0 = display0
823+ initFrom(v)
824+ stabilize(v.focus)
825+ gotoPosWritable1(v.focus, blockIndex, v.focus ^ blockIndex, initialDisplay0)
826+
827+ depth match {
828+ case 2 =>
829+ display1((blockIndex >>> 5 ) & 31 ) = display0
830+ case 3 =>
831+ display1((blockIndex >>> 5 ) & 31 ) = display0
832+ display2((blockIndex >>> 10 ) & 31 ) = display1
833+ case 4 =>
834+ display1((blockIndex >>> 5 ) & 31 ) = display0
835+ display2((blockIndex >>> 10 ) & 31 ) = display1
836+ display3((blockIndex >>> 15 ) & 31 ) = display2
837+ case 5 =>
838+ display1((blockIndex >>> 5 ) & 31 ) = display0
839+ display2((blockIndex >>> 10 ) & 31 ) = display1
840+ display3((blockIndex >>> 15 ) & 31 ) = display2
841+ display4((blockIndex >>> 20 ) & 31 ) = display3
842+ case 6 =>
843+ display1((blockIndex >>> 5 ) & 31 ) = display0
844+ display2((blockIndex >>> 10 ) & 31 ) = display1
845+ display3((blockIndex >>> 15 ) & 31 ) = display2
846+ display4((blockIndex >>> 20 ) & 31 ) = display3
847+ display5((blockIndex >>> 25 ) & 31 ) = display4
848+ case _ => ()
849+ }
850+ case _ =>
851+ val it = (xs.iterator : Iterator [A ]).asInstanceOf [Iterator [AnyRef ]]
852+ while (it.hasNext) {
853+ advanceToNextBlockIfNecessary()
854+ lo += it.copyToArray(xs = display0, start = lo, len = display0.length - lo)
855+ }
788856 }
789857 this
790858 }
@@ -793,9 +861,9 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
793861 val size = this .size
794862 if (size == 0 )
795863 return Vector .empty
796- val s = new Vector [A ](0 , size , 0 ) // should focus front or back?
864+ val s = new Vector [A ](startIndex, blockIndex + lo , 0 ) // should focus front or back?
797865 s.initFrom(this )
798- if (depth > 1 ) s.gotoPos(0 , size - 1 ) // we're currently focused to size - 1, not size!
866+ if (depth > 1 ) s.gotoPos(startIndex, blockIndex + lo - 1 ) // we're currently focused to size - 1, not size!
799867 releaseFence()
800868 s
801869 }
@@ -805,6 +873,7 @@ final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with Vector
805873 display0 = new Array [AnyRef ](32 )
806874 blockIndex = 0
807875 lo = 0
876+ startIndex = 0
808877 }
809878}
810879
@@ -1000,10 +1069,19 @@ private[immutable] trait VectorPointer[T] {
10001069
10011070 // STUFF BELOW USED BY APPEND / UPDATE
10021071
1003- private [immutable] final def nullSlotAndCopy [T <: AnyRef ](array : Array [Array [T ]], index : Int ): Array [T ] = {
1072+ /** Sets array(index) to null and returns an array with same contents as what was previously at array(index)
1073+ *
1074+ * If `destination` array is not null, original contents of array(index) will be copied to it, and it will be returned.
1075+ * Otherwise array(index).clone() is returned
1076+ */
1077+ private [immutable] final def nullSlotAndCopy [T <: AnyRef ](array : Array [Array [T ]], index : Int , destination : Array [T ] = null ): Array [T ] = {
10041078 val x = array(index)
10051079 array(index) = null
1006- x.clone()
1080+ if (destination == null ) x.clone()
1081+ else {
1082+ x.copyToArray(destination, 0 )
1083+ destination
1084+ }
10071085 }
10081086
10091087 // make sure there is no aliasing
@@ -1086,10 +1164,9 @@ private[immutable] trait VectorPointer[T] {
10861164 display0 = display0.clone()
10871165 }
10881166
1089-
10901167 // requires structure is dirty and at pos oldIndex,
10911168 // ensures structure is dirty and at pos newIndex and writable at level 0
1092- private [immutable] final def gotoPosWritable1 (oldIndex : Int , newIndex : Int , xor : Int ): Unit = {
1169+ private [immutable] final def gotoPosWritable1 (oldIndex : Int , newIndex : Int , xor : Int , reuseDisplay0 : Array [ AnyRef ] = null ): Unit = {
10931170 if (xor < (1 << 5 )) { // level = 0
10941171 display0 = display0.clone()
10951172 } else if (xor < (1 << 10 )) { // level = 1
@@ -1102,7 +1179,7 @@ private[immutable] trait VectorPointer[T] {
11021179 display1((oldIndex >>> 5 ) & 31 ) = display0
11031180 display2((oldIndex >>> 10 ) & 31 ) = display1
11041181 display1 = nullSlotAndCopy(display2, (newIndex >>> 10 ) & 31 )
1105- display0 = nullSlotAndCopy(display1, (newIndex >>> 5 ) & 31 )
1182+ display0 = nullSlotAndCopy(display1, (newIndex >>> 5 ) & 31 , reuseDisplay0 )
11061183 } else if (xor < (1 << 20 )) { // level = 3
11071184 display1 = display1.clone()
11081185 display2 = display2.clone()
@@ -1112,7 +1189,7 @@ private[immutable] trait VectorPointer[T] {
11121189 display3((oldIndex >>> 15 ) & 31 ) = display2
11131190 display2 = nullSlotAndCopy(display3, (newIndex >>> 15 ) & 31 )
11141191 display1 = nullSlotAndCopy(display2, (newIndex >>> 10 ) & 31 )
1115- display0 = nullSlotAndCopy(display1, (newIndex >>> 5 ) & 31 )
1192+ display0 = nullSlotAndCopy(display1, (newIndex >>> 5 ) & 31 , reuseDisplay0 )
11161193 } else if (xor < (1 << 25 )) { // level = 4
11171194 display1 = display1.clone()
11181195 display2 = display2.clone()
@@ -1125,7 +1202,7 @@ private[immutable] trait VectorPointer[T] {
11251202 display3 = nullSlotAndCopy(display4, (newIndex >>> 20 ) & 31 )
11261203 display2 = nullSlotAndCopy(display3, (newIndex >>> 15 ) & 31 )
11271204 display1 = nullSlotAndCopy(display2, (newIndex >>> 10 ) & 31 )
1128- display0 = nullSlotAndCopy(display1, (newIndex >>> 5 ) & 31 )
1205+ display0 = nullSlotAndCopy(display1, (newIndex >>> 5 ) & 31 , reuseDisplay0 )
11291206 } else if (xor < (1 << 30 )) { // level = 5
11301207 display1 = display1.clone()
11311208 display2 = display2.clone()
@@ -1141,7 +1218,7 @@ private[immutable] trait VectorPointer[T] {
11411218 display3 = nullSlotAndCopy(display4, (newIndex >>> 20 ) & 31 )
11421219 display2 = nullSlotAndCopy(display3, (newIndex >>> 15 ) & 31 )
11431220 display1 = nullSlotAndCopy(display2, (newIndex >>> 10 ) & 31 )
1144- display0 = nullSlotAndCopy(display1, (newIndex >>> 5 ) & 31 )
1221+ display0 = nullSlotAndCopy(display1, (newIndex >>> 5 ) & 31 , reuseDisplay0 )
11451222 } else { // level = 6
11461223 throw new IllegalArgumentException ()
11471224 }
0 commit comments