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 1 commit
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
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]])
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be nice to support IArray.tail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Adding WrappedIArray would do it. Also imlementing all ArrayOps on IArray would help

}

def toArray: Array[Object] = es.clone
def toArray: Array[Object] = es.asInstanceOf[Array[Object]].clone
}
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]])
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 avoid .asInstanceOf[IArray[Object]], as the Array instance might be aliased, thus break the protocol. Create IArray through its constructors is recommended.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IArray would copy the array at least twice, this is the best we can do for now. We need Iterator.toIArray.

def fromIArray(elems: IArray[Object]) = new TupleXXL(elems)
def apply(elems: Any*) = new TupleXXL(elems.asInstanceOf[Seq[Object]].toArray.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.

def unapplySeq(x: TupleXXL): Option[Seq[Any]] = Some(x.elems.asInstanceOf[Array[Object]].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]])
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.

Same as before, need 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]]
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