Skip to content

Define TupleXXL and FunctionXXL using IArray #6929

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

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -710,8 +710,6 @@ class Definitions {
@threadUnsafe lazy val TupleXXLClass: ClassSymbolPerRun = perRunClass(ctx.requiredClassRef("scala.TupleXXL"))
def TupleXXLModule(implicit ctx: Context): Symbol = TupleXXLClass.companionModule

def TupleXXL_apply(implicit ctx: Context): Symbol =
TupleXXLModule.info.member(nme.apply).requiredSymbol("method", nme.apply, TupleXXLModule)(_.info.isVarArgsMethod)
def TupleXXL_fromIterator(implicit ctx: Context): Symbol = TupleXXLModule.requiredMethod("fromIterator")

lazy val DynamicTupleModule: Symbol = ctx.requiredModule("scala.runtime.DynamicTuple")
Expand Down
10 changes: 10 additions & 0 deletions library/src-bootstrapped/scala/IArray.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ object IArray {
*/
def empty[T: ClassTag]: IArray[T] = new Array[T](0).asInstanceOf

def emptyBooleanIArray = Array.emptyBooleanArray.asInstanceOf[IArray[Boolean]]
def emptyByteIArray = Array.emptyByteArray.asInstanceOf[IArray[Byte]]
def emptyCharIArray = Array.emptyCharArray.asInstanceOf[IArray[Char]]
def emptyDoubleIArray = Array.emptyDoubleArray.asInstanceOf[IArray[Double]]
def emptyFloatIArray = Array.emptyFloatArray.asInstanceOf[IArray[Float]]
def emptyIntIArray = Array.emptyIntArray.asInstanceOf[IArray[Int]]
def emptyLongIArray = Array.emptyLongArray.asInstanceOf[IArray[Long]]
def emptyShortIArray = Array.emptyShortArray.asInstanceOf[IArray[Short]]
def emptyObjectIArray = Array.emptyObjectArray.asInstanceOf[IArray[Object]]

/** An immutable array with given elements.
*/
def apply[T: ClassTag](xs: T*): IArray[T] = Array(xs: _*).asInstanceOf
Expand Down
2 changes: 1 addition & 1 deletion library/src/scala/FunctionXXL.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package scala
/** A function with all parameters grouped in an array. */
trait FunctionXXL {

def apply(xs: Array[Object]): Object
def apply(xs: IArray[Object]): Object

override def toString() = "<functionXXL>"
}
15 changes: 15 additions & 0 deletions library/src/scala/Tuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ sealed trait Tuple extends Any {
inline def toArray: Array[Object] =
DynamicTuple.dynamicToArray(this)

/** Create a copy this tuple as an IArray */
inline def toIArray: IArray[Object] =
DynamicTuple.dynamicToIArray(this)

/** Return a new tuple by prepending the element to `this` tuple.
* This opteration is O(this.size)
*/
Expand Down Expand Up @@ -79,6 +83,17 @@ object Tuple {
DynamicTuple.dynamicFromArray[Tuple](xs2)
}

/** Convert an immutable array into a tuple of unknown arity and types */
def fromIArray[T](xs: IArray[T]): Tuple = {
val xs2: IArray[Object] = xs match {
case xs: IArray[Object] => xs
case xs =>
// TODO suport IArray.map
xs.asInstanceOf[Array[T]].map(_.asInstanceOf[Object]).asInstanceOf[IArray[Object]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will a bound on IArray work, like opaque type IArray[+T] <: Seq[T] = Array[_ <: T]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not. We need to do the same as array does and define a WrappedIArray for it.

}
DynamicTuple.dynamicFromIArray[Tuple](xs2)
}

/** Convert a Product into a tuple of unknown arity and types */
def fromProduct(product: Product): Tuple =
runtime.DynamicTuple.dynamicFromProduct[Tuple](product)
Expand Down
22 changes: 11 additions & 11 deletions library/src/scala/TupleXXL.scala
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
package scala
import java.util.Arrays.{deepEquals, deepHashCode}

final class TupleXXL private (es: Array[Object]) extends Product {
final class TupleXXL private (es: IArray[Object]) extends Product {
assert(es.length > 22)

def productElement(n: Int): Any = es(n)
def productArity: Int = es.length

override def toString = elems.mkString("(", ",", ")")
override def hashCode = getClass.hashCode * 41 + deepHashCode(elems)
override def toString = elems.asInstanceOf[Array[Object]].mkString("(", ",", ")")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After the bound on IArray, this cast may be avoided.

override def hashCode = getClass.hashCode * 41 + deepHashCode(elems.asInstanceOf[Array[Object]])
override def canEqual(that: Any): Boolean = that match {
case that: TupleXXL => that.productArity == this.productArity
case _ => false
}

override def equals(that: Any) = that match {
case that: TupleXXL => deepEquals(this.elems, that.elems)
case that: TupleXXL => deepEquals(this.elems.asInstanceOf[Array[Object]], that.elems.asInstanceOf[Array[Object]])
case _ => false
}
def elems: Array[Object] = es
def elems: IArray[Object] = es

def tailXXL: TupleXXL = {
assert(es.length > 23)
new TupleXXL(es.tail)
new TupleXXL(es.asInstanceOf[Array[Object]].tail.asInstanceOf[IArray[Object]]) // TODO use IArray.tail
}

def toArray: Array[Object] = es.clone
def toArray: Array[Object] = es.asInstanceOf[Array[Object]].clone // TODO use IArray.toArray
}
object TupleXXL {
def fromIterator(elems: Iterator[Any]) = new TupleXXL(elems.map(_.asInstanceOf[Object]).toArray)
def apply(elems: Array[Object]) = new TupleXXL(elems.clone)
def apply(elems: Any*) = new TupleXXL(elems.asInstanceOf[Seq[Object]].toArray)
def unapplySeq(x: TupleXXL): Option[Seq[Any]] = Some(x.elems.toSeq)
def fromIterator(elems: Iterator[Any]) = new TupleXXL(elems.map(_.asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) // TODO use Iterator.toIArray
def fromIArray(elems: IArray[Object]) = new TupleXXL(elems)
def apply(elems: Any*) = new TupleXXL(IArray(elems.asInstanceOf[Seq[AnyRef]]: _*))
def unapplySeq(x: TupleXXL): Option[Seq[Any]] = Some(x.elems.asInstanceOf[Array[Object]].toSeq) // TODO use IArray.toSeq
}
2 changes: 1 addition & 1 deletion library/src/scala/TupledFunction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ package internal {
def tupledFunctionXXL[F, G]: TupledFunction[F, G] = new TupledFunction {
def tupled(f: F): G = ((args: TupleXXL) => f.asInstanceOf[FunctionXXL].apply(args.elems)).asInstanceOf[G]
def untupled(g: G): F = new FunctionXXL {
override def apply(xs: Array[Object]): AnyRef = g.asInstanceOf[TupleXXL => AnyRef].apply(TupleXXL(xs))
override def apply(xs: IArray[Object]): AnyRef = g.asInstanceOf[TupleXXL => AnyRef].apply(TupleXXL.fromIArray(xs))
}.asInstanceOf[F]
}

Expand Down
14 changes: 12 additions & 2 deletions library/src/scala/runtime/DynamicTuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,13 @@ object DynamicTuple {
case 20 => Tuple20(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19)).asInstanceOf[T]
case 21 => Tuple21(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19), xs(20)).asInstanceOf[T]
case 22 => Tuple22(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6), xs(7), xs(8), xs(9), xs(10), xs(11), xs(12), xs(13), xs(14), xs(15), xs(16), xs(17), xs(18), xs(19), xs(20), xs(21)).asInstanceOf[T]
case _ => TupleXXL(xs).asInstanceOf[T]
case _ => TupleXXL.fromIArray(xs.clone().asInstanceOf[IArray[Object]]).asInstanceOf[T]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to create IArray through its constructors instead of cast.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. It might also be good to have a toIArray on collections

}

def dynamicFromIArray[T <: Tuple](xs: IArray[Object]): T =
if (xs.length <= 22) dynamicFromArray(xs.asInstanceOf[Array[Object]])
else TupleXXL.fromIArray(xs).asInstanceOf[T]

def dynamicFromProduct[T <: Tuple](xs: Product): T = (xs.productArity match {
case 1 =>
xs match {
Expand Down Expand Up @@ -169,7 +173,7 @@ object DynamicTuple {
case _ =>
xs match {
case xs: TupleXXL => xs
case xs => TupleXXL(xs.productIterator.map(_.asInstanceOf[Object]).toArray)
case xs => TupleXXL.fromIArray(xs.productIterator.map(_.asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) // TODO use Iterator.toIArray
}
}).asInstanceOf[T]

Expand All @@ -180,6 +184,12 @@ object DynamicTuple {
case self: Product => productToArray(self)
}

def dynamicToIArray(self: Tuple): IArray[Object] = (self: Any) match {
case self: Unit => Array.emptyObjectArray.asInstanceOf[IArray[Object]] // TODO use IArray.emptyObjectIArray
case self: TupleXXL => self.elems
case self: Product => productToArray(self).asInstanceOf[IArray[Object]]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to create IArray through its constructors instead of cast.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The array constructor would create a new empty array each time

}

def productToArray(self: Product): Array[Object] = {
val arr = new Array[Object](self.productArity)
for (i <- 0 until arr.length) arr(i) = self.productElement(i).asInstanceOf[Object]
Expand Down
2 changes: 1 addition & 1 deletion tests/run-with-compiler/staged-tuples/StagedTuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ object StagedTuple {
case Some(n) if n <= MaxSpecialized =>
'{to$Array($tup, ${ n.toExpr })}
case Some(n) =>
'{${ tup.as[TupleXXL] }.elems}
'{ ${tup.as[TupleXXL]}.toArray }
case None =>
'{dynamicToArray($tup)}
}
Expand Down