Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Commit 33c7e67

Browse files
committed
optimize prependAll and insertAll
1 parent 87ea88b commit 33c7e67

File tree

2 files changed

+26
-14
lines changed

2 files changed

+26
-14
lines changed

src/main/scala/strawman/collection/mutable/ArrayDeque.scala

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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
/**

src/test/scala/strawman/collection/test/ArrayDequeTest.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,15 @@ class ArrayDequeTest {
2828
apply(_.trimEnd(3))
2929
apply(_.insertAll(0, Seq(9, 10, 11)))
3030
apply(_.insertAll(1, Seq(12, 13)))
31+
apply(_.insertAll(1, IndexedSeq(18, 2113)))
3132
apply(_.remove(2))
3233
apply(_.prependAll(Seq(14, 15, 16, 17)))
3334
apply(_.remove(1, 5))
3435
apply(_.prependAll(Seq.tabulate(100)(identity)))
3536
buffer.trimToSize()
3637
apply(_.appendAll(Seq.tabulate(100)(identity)))
38+
apply(_.appendAll(Iterator.tabulate(100)(identity)))
39+
apply(_.prependAll(Vector.tabulate(10)(identity)))
3740

3841
(-100 to 100) foreach {i =>
3942
assert(buffer.splitAt(i) == buffer2.splitAt(i))

0 commit comments

Comments
 (0)