Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add append operator to Tuple #13786

Merged
merged 1 commit into from Oct 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions library/src/scala/Tuple.scala
Expand Up @@ -21,6 +21,11 @@ sealed trait Tuple extends Product {
inline def toIArray: IArray[Object] =
runtime.Tuples.toIArray(this)

/** Return a copy of `this` tuple with an element appended */
@experimental
inline def :* [This >: this.type <: Tuple, L] (x: L): Append[This, L] =
runtime.Tuples.append(x, this).asInstanceOf[Append[This, L]]

/** Return a new tuple by prepending the element to `this` tuple.
* This operation is O(this.size)
*/
Expand Down Expand Up @@ -78,6 +83,13 @@ sealed trait Tuple extends Product {

object Tuple {

/** Type of a tuple with an element appended */
@experimental
type Append[X <: Tuple, Y] <: Tuple = X match {
case EmptyTuple => Y *: EmptyTuple
case x *: xs => x *: Append[xs, Y]
}

/** Type of the head of a tuple */
type Head[X <: NonEmptyTuple] = X match {
case x *: _ => x
Expand Down
76 changes: 76 additions & 0 deletions library/src/scala/runtime/Tuples.scala
Expand Up @@ -357,6 +357,82 @@ object Tuples {
case _ => specialCaseTail(self)
}

// Append for TupleXXL
private def xxlAppend(x: Any, xxl: TupleXXL): TupleXXL = {
val arr = new Array[Object](xxl.productArity + 1)
arr(xxl.productArity) = x.asInstanceOf[Object]
System.arraycopy(xxl.elems, 0, arr, 0, xxl.productArity)
TupleXXL.fromIArray(arr.asInstanceOf[IArray[Object]])
}

// Append for Tuple1 to Tuple22
private def specialCaseAppend(x: Any, self: Tuple): Tuple = {
(self: Any) match {
case EmptyTuple =>
Tuple1(x)
case self: Tuple1[_] =>
Tuple2(self._1, x)
case self: Tuple2[_, _] =>
Tuple3(self._1, self._2, x)
case self: Tuple3[_, _, _] =>
Tuple4(self._1, self._2, self._3, x)
case self: Tuple4[_, _, _, _] =>
Tuple5(self._1, self._2, self._3, self._4, x)
case self: Tuple5[_, _, _, _, _] =>
Tuple6(self._1, self._2, self._3, self._4, self._5, x)
case self: Tuple6[_, _, _, _, _, _] =>
Tuple7(self._1, self._2, self._3, self._4, self._5, self._6, x)
case self: Tuple7[_, _, _, _, _, _, _] =>
Tuple8(self._1, self._2, self._3, self._4, self._5, self._6, self._7, x)
case self: Tuple8[_, _, _, _, _, _, _, _] =>
Tuple9(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, x)
case self: Tuple9[_, _, _, _, _, _, _, _, _] =>
Tuple10(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, x)
case self: Tuple10[_, _, _, _, _, _, _, _, _, _] =>
Tuple11(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, x)
case self: Tuple11[_, _, _, _, _, _, _, _, _, _, _] =>
Tuple12(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, x)
case self: Tuple12[_, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple13(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, x)
case self: Tuple13[_, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple14(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, x)
case self: Tuple14[_, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple15(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, x)
case self: Tuple15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple16(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, x)
case self: Tuple16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple17(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, x)
case self: Tuple17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple18(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, x)
case self: Tuple18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple19(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, x)
case self: Tuple19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple20(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19, x)
case self: Tuple20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple21(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19, self._20, x)
case self: Tuple21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
Tuple22(self._1, self._2, self._3, self._4, self._5, self._6, self._7, self._8, self._9, self._10, self._11, self._12, self._13, self._14, self._15, self._16, self._17, self._18, self._19, self._20, self._21, x)
case self: Tuple22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _] =>
val arr: Array[Object] = Array(
self._1.asInstanceOf[Object], self._2.asInstanceOf[Object],
self._3.asInstanceOf[Object], self._4.asInstanceOf[Object], self._5.asInstanceOf[Object],
self._6.asInstanceOf[Object], self._7.asInstanceOf[Object], self._8.asInstanceOf[Object],
self._9.asInstanceOf[Object], self._10.asInstanceOf[Object], self._11.asInstanceOf[Object],
self._12.asInstanceOf[Object], self._13.asInstanceOf[Object], self._14.asInstanceOf[Object],
self._15.asInstanceOf[Object], self._16.asInstanceOf[Object], self._17.asInstanceOf[Object],
self._18.asInstanceOf[Object], self._19.asInstanceOf[Object], self._20.asInstanceOf[Object],
self._21.asInstanceOf[Object], self._22.asInstanceOf[Object], x.asInstanceOf[Object]
)
TupleXXL.fromIArray(arr.asInstanceOf[IArray[Object]]).asInstanceOf[Tuple]
}
}

@experimental
def append(x: Any, self: Tuple): Tuple = (self: Any) match {
case xxl: TupleXXL => xxlAppend(x, xxl).asInstanceOf[Tuple]
case _ => specialCaseAppend(x, self)
}

// Init for TupleXXL
private def xxlInit(xxl: TupleXXL): Tuple = {
if (xxl.productArity == 23) {
Expand Down
3 changes: 2 additions & 1 deletion project/MiMaFilters.scala
Expand Up @@ -6,6 +6,7 @@ object MiMaFilters {
val Library: Seq[ProblemFilter] = Seq(
// Experimental APIs that can be added in 3.2.0
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.init"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last")
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.last"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.runtime.Tuples.append")
)
}
76 changes: 76 additions & 0 deletions tests/run-deep-subtype/Tuple-append.check
@@ -0,0 +1,76 @@
(0)
(0,1)
(0,1,2)
(0,1,2,3)
(0,1,2,3,4)
(0,1,2,3,4,5)
(0,1,2,3,4,5,6)
(0,1,2,3,4,5,6,7)
(0,1,2,3,4,5,6,7,8)
(0,1,2,3,4,5,6,7,8,9)
(0,1,2,3,4,5,6,7,8,9,10)
(0,1,2,3,4,5,6,7,8,9,10,11)
(0,1,2,3,4,5,6,7,8,9,10,11,12)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24)
(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25)
(1)
(1,2)
(1,2,3)
(1,2,3,4)
(1,2,3,4,5)
(1,2,3,4,5,6)
(1,2,3,4,5,6,7)
(1,2,3,4,5,6,7,8)
(1,2,3,4,5,6,7,8,9)
(1,2,3,4,5,6,7,8,9,10)
(1,2,3,4,5,6,7,8,9,10,11)
(1,2,3,4,5,6,7,8,9,10,11,12)
(1,2,3,4,5,6,7,8,9,10,11,12,13)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25)
(1)
(1,2)
(1,2,3)
(1,2,3,4)
(1,2,3,4,5)
(1,2,3,4,5,6)
(1,2,3,4,5,6,7)
(1,2,3,4,5,6,7,8)
(1,2,3,4,5,6,7,8,9)
(1,2,3,4,5,6,7,8,9,10)
(1,2,3,4,5,6,7,8,9,10,11)
(1,2,3,4,5,6,7,8,9,10,11,12)
(1,2,3,4,5,6,7,8,9,10,11,12,13)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24)
(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25)
65 changes: 65 additions & 0 deletions tests/run-deep-subtype/Tuple-append.scala
@@ -0,0 +1,65 @@
import scala.reflect.ClassTag

object Test {
def main(args: Array[String]): Unit = {
def testArray[T: ClassTag](n: Int, elem: Int => T): Unit = {
val t: Tuple = Tuple.fromArray(Array.tabulate(n)(elem))
println(t :* n)
}

for (i <- 0 to 25)
testArray(i, j => j)

println(Tuple() :* 1)
println(Tuple1(1) :* 2)
println((1, 2) :* 3)
println((1, 2, 3) :* 4)
println((1, 2, 3, 4) :* 5)
println((1, 2, 3, 4, 5) :* 6)
println((1, 2, 3, 4, 5, 6) :* 7)
println((1, 2, 3, 4, 5, 6, 7) :* 8)
println((1, 2, 3, 4, 5, 6, 7, 8) :* 9)
println((1, 2, 3, 4, 5, 6, 7, 8, 9) :* 10)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10) :* 11)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) :* 12)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) :* 13)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13) :* 14)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14) :* 15)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) :* 16)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16) :* 17)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17) :* 18)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) :* 19)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) :* 20)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) :* 21)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21) :* 22)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22) :* 23)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23) :* 24)
println((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24) :* 25)

println(EmptyTuple :* 1)
println((1 *: Tuple()) :* 2)
println((1 *: 2 *: Tuple()) :* 3)
println((1 *: 2 *: 3 *: Tuple()) :* 4)
println((1 *: 2 *: 3 *: 4 *: Tuple()) :* 5)
println((1 *: 2 *: 3 *: 4 *: 5 *: Tuple()) :* 6)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: Tuple()) :* 7)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: Tuple()) :* 8)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: Tuple()) :* 9)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: Tuple()) :* 10)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: Tuple()) :* 11)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: Tuple()) :* 12)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: Tuple()) :* 13)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: Tuple()) :* 14)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: Tuple()) :* 15)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: Tuple()) :* 16)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: Tuple()) :* 17)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: Tuple()) :* 18)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: Tuple()) :* 19)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: Tuple()) :* 20)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: Tuple()) :* 21)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: Tuple()) :* 22)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: Tuple()) :* 23)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: Tuple()) :* 24)
println((1 *: 2 *: 3 *: 4 *: 5 *: 6 *: 7 *: 8 *: 9 *: 10 *: 11 *: 12 *: 13 *: 14 *: 15 *: 16 *: 17 *: 18 *: 19 *: 20 *: 21 *: 22 *: 23 *: 24 *: Tuple()) :* 25)
}
}