Skip to content

Commit cbe91fa

Browse files
committed
make VectorBuilder reusable again
* `leftAlignPrefix()` now keeps the length of the outermost array at (LAST)WIDTH. This is necessary because after a call to `result()`, the VB may be used further. * Allow arbitrarily misleading/wrong arguments in `alignTo()` Should not fail now, even if the hint given is completely nonsensical, `leftAlignPrefix()` now compensates for that. Negative alignments are allowed, e.g. if you plan to drop elements of the vector to be added. * Add a bunch of tests to cover previously uncovered branches.
1 parent baa73f9 commit cbe91fa

File tree

1 file changed

+56
-33
lines changed

1 file changed

+56
-33
lines changed

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

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,76 +1593,102 @@ final class VectorBuilder[A] extends ReusableBuilder[A, Vector[A]] {
15931593
* Removes `offset` leading `null`s in the prefix.
15941594
* This is needed after calling `alignTo` and subsequent additions,
15951595
* directly before the result is used for creating a new Vector.
1596+
* Note that the outermost array keeps its length to keep the
1597+
* Builder re-usable.
15961598
*
15971599
* example:
15981600
* a2 = Array(null, ..., null, Array(null, .., null, 0, 1, .., x), Array(x+1, .., x+32), ...)
15991601
* becomes
1600-
* a2 = Array(Array(0, 1, .., x), Array(x+1, .., x+32), ...)
1602+
* a2 = Array(Array(0, 1, .., x), Array(x+1, .., x+32), ..., ?, ..., ?)
16011603
*/
16021604
private[this] def leftAlignPrefix(): Unit = {
1605+
@inline def shrinkOffsetIfToLarge(width: Int): Unit = {
1606+
val newOffset = offset % width
1607+
lenRest -= offset - newOffset
1608+
offset = newOffset
1609+
}
16031610
var a: Array[AnyRef] = null // the array we modify
16041611
var aParent: Array[AnyRef] = null // a's parent, so aParent(0) == a
16051612
if (depth >= 6) {
16061613
a = a6.asInstanceOf[Array[AnyRef]]
16071614
val i = offset >>> BITS5
1608-
if (i > 0) {
1609-
a = copyOfRange(a, i, LASTWIDTH)
1610-
a6 = a.asInstanceOf[Arr6]
1611-
}
1615+
if (i > 0) System.arraycopy(a, i, a, 0, LASTWIDTH - i)
1616+
shrinkOffsetIfToLarge(WIDTH5)
1617+
if ((lenRest >>> BITS5) == 0) depth = 5
16121618
aParent = a
16131619
a = a(0).asInstanceOf[Array[AnyRef]]
16141620
}
16151621
if (depth >= 5) {
16161622
if (a == null) a = a5.asInstanceOf[Array[AnyRef]]
16171623
val i = (offset >>> BITS4) & MASK
1618-
if (i > 0) {
1619-
a = copyOfRange(a, i, WIDTH)
1620-
if (depth == 5) a5 = a.asInstanceOf[Arr5]
1621-
else aParent(0) = a
1624+
if (depth == 5) {
1625+
if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i)
1626+
a5 = a.asInstanceOf[Arr5]
1627+
shrinkOffsetIfToLarge(WIDTH4)
1628+
if ((lenRest >>> BITS4) == 0) depth = 4
1629+
} else {
1630+
if (i > 0) a = copyOfRange(a, i, WIDTH)
1631+
aParent(0) = a
16221632
}
16231633
aParent = a
16241634
a = a(0).asInstanceOf[Array[AnyRef]]
16251635
}
16261636
if (depth >= 4) {
16271637
if (a == null) a = a4.asInstanceOf[Array[AnyRef]]
16281638
val i = (offset >>> BITS3) & MASK
1629-
if (i > 0) {
1630-
a = copyOfRange(a, i, WIDTH)
1631-
if (depth == 4) a4 = a.asInstanceOf[Arr4]
1632-
else aParent(0) = a
1639+
if (depth == 4) {
1640+
if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i)
1641+
a4 = a.asInstanceOf[Arr4]
1642+
shrinkOffsetIfToLarge(WIDTH3)
1643+
if ((lenRest >>> BITS3) == 0) depth = 3
1644+
} else {
1645+
if (i > 0) a = copyOfRange(a, i, WIDTH)
1646+
aParent(0) = a
16331647
}
16341648
aParent = a
16351649
a = a(0).asInstanceOf[Array[AnyRef]]
16361650
}
16371651
if (depth >= 3) {
16381652
if (a == null) a = a3.asInstanceOf[Array[AnyRef]]
16391653
val i = (offset >>> BITS2) & MASK
1640-
if (i > 0) {
1641-
a = copyOfRange(a, i, WIDTH)
1642-
if (depth == 3) a3 = a.asInstanceOf[Arr3]
1643-
else aParent(0) = a
1654+
if (depth == 3) {
1655+
if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i)
1656+
a3 = a.asInstanceOf[Arr3]
1657+
shrinkOffsetIfToLarge(WIDTH2)
1658+
if ((lenRest >>> BITS2) == 0) depth = 2
1659+
} else {
1660+
if (i > 0) a = copyOfRange(a, i, WIDTH)
1661+
aParent(0) = a
16441662
}
16451663
aParent = a
16461664
a = a(0).asInstanceOf[Array[AnyRef]]
16471665
}
16481666
if (depth >= 2) {
16491667
if (a == null) a = a2.asInstanceOf[Array[AnyRef]]
16501668
val i = (offset >>> BITS) & MASK
1651-
if (i > 0) {
1652-
a = copyOfRange(a, i, WIDTH)
1653-
if (depth == 2) a2 = a.asInstanceOf[Arr2]
1654-
else aParent(0) = a
1669+
if (depth == 2) {
1670+
if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i)
1671+
a2 = a.asInstanceOf[Arr2]
1672+
shrinkOffsetIfToLarge(WIDTH)
1673+
if ((lenRest >>> BITS) == 0) depth = 1
1674+
} else {
1675+
if (i > 0) a = copyOfRange(a, i, WIDTH)
1676+
aParent(0) = a
16551677
}
16561678
aParent = a
16571679
a = a(0).asInstanceOf[Array[AnyRef]]
16581680
}
16591681
if (depth >= 1) {
16601682
if (a == null) a = a1.asInstanceOf[Array[AnyRef]]
16611683
val i = offset & MASK
1662-
if (i > 0) {
1663-
a = copyOfRange(a, i, WIDTH)
1664-
if (depth == 1) a1 = a.asInstanceOf[Arr1]
1665-
else aParent(0) = a
1684+
if (depth == 1) {
1685+
if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i)
1686+
a1 = a.asInstanceOf[Arr1]
1687+
len1 -= offset
1688+
offset = 0
1689+
} else {
1690+
if (i > 0) a = copyOfRange(a, i, WIDTH)
1691+
aParent(0) = a
16661692
}
16671693
}
16681694
prefixIsRightAligned = false
@@ -1761,15 +1787,13 @@ final class VectorBuilder[A] extends ReusableBuilder[A, Vector[A]] {
17611787
slice.foreach(e => addArrN(e.asInstanceOf[Array[AnyRef]], 5))
17621788
return
17631789
}
1764-
val copy1 = mmin((BITS * 6 + 1 - lenRest) >>> BITS5, sl)
1765-
val copy2 = sl - copy1
1790+
val copy1 = sl
1791+
// there is no copy2 because there can't be another a6 to copy to
17661792
val destPos = lenRest >>> BITS5
1793+
if (destPos + copy1 > LASTWIDTH)
1794+
throw new IllegalArgumentException("exceeding 2^31 elements")
17671795
System.arraycopy(slice, 0, a6, destPos, copy1)
17681796
advanceN(WIDTH5 * copy1)
1769-
if (copy2 > 0) {
1770-
System.arraycopy(slice, copy1, a6, 0, copy2)
1771-
advanceN(WIDTH5 * copy2)
1772-
}
17731797
}
17741798
}
17751799

@@ -1867,8 +1891,7 @@ final class VectorBuilder[A] extends ReusableBuilder[A, Vector[A]] {
18671891
if(realLen == 0) Vector.empty
18681892
else if(len < 0) throw new IndexOutOfBoundsException(s"Vector cannot have negative size $len")
18691893
else if(len <= WIDTH) {
1870-
if(realLen == WIDTH) new Vector1(a1)
1871-
else new Vector1(copyOf(a1, realLen))
1894+
new Vector1(copyIfDifferentSize(a1, realLen))
18721895
} else if(len <= WIDTH2) {
18731896
val i1 = (len-1) & MASK
18741897
val i2 = (len-1) >>> BITS

0 commit comments

Comments
 (0)