@@ -61,7 +61,7 @@ class ArrayDeque[A] private[ArrayDeque](
6161
6262 override def apply (idx : Int ) = {
6363 ArrayDeque .checkIndex(idx, this )
64- _get(idx). asInstanceOf [ A ]
64+ _get(idx)
6565 }
6666
6767 override def update (idx : Int , elem : A ) = {
@@ -94,18 +94,24 @@ class ArrayDeque[A] private[ArrayDeque](
9494 override def ++=: (elems : TraversableOnce [A ]) = {
9595 if (elems.nonEmpty) {
9696 ArrayDeque .knownSize(elems) match {
97+ // Size is too expensive to compute - we need to make one more pass to make it an IndexedSeq and retry
98+ case srcLength if srcLength < 0 =>
99+ elems.toIndexedSeq ++=: this
100+
97101 // We know we need to resize in the end, might as well resize and memcopy upfront
98- case srcLength if srcLength >= 0 && 2 * (srcLength + this .length) >= mask =>
102+ case srcLength if srcLength + this .length >= mask =>
99103 val finalLength = srcLength + this .length
100104 val array2 = ArrayDeque .alloc(finalLength)
101105 elems.copyToArray(array2.asInstanceOf [Array [A ]])
102106 copySliceToArray(srcStart = 0 , dest = array2, destStart = srcLength, maxItems = size)
103107 reset(array = array2, start = 0 , end = finalLength)
104108
105- case _ =>
106- val copy = clone()
107- end = start
108- this ++= elems ++= copy
109+ // We know resizing is not necessary so just fill up from (start - srcLength) to (start - 1) and move back start
110+ case srcLength =>
111+ elems.toIterator.zipWithIndex foreach {
112+ case (elem, i) => _set(i - srcLength, elem)
113+ }
114+ start = start_+(- srcLength)
109115 }
110116 }
111117 this
@@ -117,23 +123,25 @@ class ArrayDeque[A] private[ArrayDeque](
117123 ArrayDeque .knownSize(elems) match {
118124 case srcLength if srcLength >= 0 =>
119125 val finalLength = srcLength + this .length
120- // Either we resize right away or move prefix right or suffix left
121- if (2 * finalLength >= mask) {
126+ // Either we resize right away or move prefix left or suffix right
127+ if (finalLength >= mask) {
122128 val array2 = ArrayDeque .alloc(finalLength)
123129 copySliceToArray(srcStart = 0 , dest = array2, destStart = 0 , maxItems = idx)
124130 elems.copyToArray(array2.asInstanceOf [Array [A ]], idx)
125131 copySliceToArray(srcStart = idx, dest = array2, destStart = idx + srcLength, maxItems = size)
126132 reset(array = array2, start = 0 , end = finalLength)
127- } else {
133+ } else if (idx >= length / 2 ) { // Cheaper to shift the suffix right
128134 val suffix = drop(idx)
129135 end = start_+(idx)
130136 elems.foreach(appendAssumingCapacity)
131137 suffix.foreach(appendAssumingCapacity)
138+ } else { // Cheaper to shift prefix left
139+ val prefix = take(idx)
140+ start = start_+(idx)
141+ prefix ++=: elems ++=: this
132142 }
133- case _ => // expensive to compute size
134- val suffix = drop(idx)
135- end = start_+(idx)
136- this ++= elems ++= suffix
143+ case _ => // Expensive to compute size, retry using IndexedSeq
144+ insertAll(idx, elems.toIndexedSeq)
137145 }
138146 }
139147 }
@@ -363,7 +371,8 @@ object ArrayDeque extends generic.SeqFactory[ArrayDeque] {
363371 final val DefaultInitialSize = 8
364372
365373 private [ArrayDeque ] def knownSize [A ](coll : TraversableOnce [A ]) = {
366- /* coll.sizeHintIfCheap*/ - 1 // TODO: Remove this temporary util when we switch to strawman .sizeHintIfCheap is now .knownSize
374+ // TODO: Remove this temporary util when we switch to strawman .sizeHintIfCheap is now .knownSize
375+ if (coll.isInstanceOf [List [_]] || coll.isInstanceOf [Stream [_]] || coll.isInstanceOf [Iterator [_]]) - 1 else coll.size
367376 }
368377
369378 /**
0 commit comments