Optimize TupleMapExtension

This commit is contained in:
Adrien Piquerez 2024-10-01 12:42:14 +02:00
parent e3449fff02
commit 57db671073
4 changed files with 45 additions and 10 deletions

View File

@ -313,8 +313,7 @@ object TaskExtra extends TaskExtra {
if incs.isEmpty then in.unmap(Result.tryValue)
else throw incompleteDeps(incs)
}
def failuresM[Tup <: Tuple]: Tuple.Map[Tup, Result] => Seq[Incomplete] = x =>
failures(x.iterator.toList)
def failuresM[Tup <: Tuple]: Tuple.Map[Tup, Result] => Seq[Incomplete] = x => failures(x.toList0)
def all[D](in: Seq[Result[D]]): Seq[D] = {
val incs = failures(in)

View File

@ -74,7 +74,7 @@ object Transform:
)(f: Tuple.Map[Tup, Result] => Either[Task[A1], A1]): Node[A1] =
new Node[A1]:
type Inputs = Tuple.Map[Tup, Result]
def dependencies: List[TaskId[?]] = deps.iterator.toList
def dependencies: List[TaskId[?]] = deps.toList0
def computeInputs(f: [a] => TaskId[a] => Result[a]) = deps.transform(f)
def work(inputs: Inputs) = f(inputs)

View File

@ -801,7 +801,8 @@ trait Init[ScopeType]:
(fa: Initialize[A]) => (fa.mapConstant(g))
private[this] def evaluateK(g: Settings[ScopeType]): [A] => Initialize[A] => A = [A] =>
(fa: Initialize[A]) => (fa.evaluate(g))
private[this] def deps(ls: Seq[Initialize[_]]): Seq[ScopedKey[_]] = ls.flatMap(_.dependencies)
private[this] def deps(ls: List[Initialize[_]]): Seq[ScopedKey[_]] =
ls.flatMap(_.dependencies)
/**
* An `Initialize[T]` associated with a `ScopedKey[S]`.
@ -977,7 +978,7 @@ trait Init[ScopeType]:
) extends Initialize[A1]:
import sbt.internal.util.TupleMapExtension.*
override def dependencies: Seq[ScopedKey[_]] = deps(inputs.iterator.toList)
override def dependencies: Seq[ScopedKey[_]] = deps(inputs.toList0)
override def mapReferenced(g: MapScoped): Initialize[A1] =
Apply(f, inputs.transform(mapReferencedK(g)))
override def mapConstant(g: MapConstant): Initialize[A1] =
@ -989,13 +990,13 @@ trait Init[ScopeType]:
override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] =
val tx: Tuple.Map[Tup, ValidatedInit] = inputs.transform(validateKeyReferencedK(g))
val undefs = tx.iterator.flatMap(_.left.toSeq.flatten)
val undefs = tx.iterator.flatMap(_.left.getOrElse(Seq.empty))
val get = [A] => (fa: ValidatedInit[A]) => fa.toOption.get
if undefs.isEmpty then Right(Apply(f, tx.transform(get)))
else Left(undefs.toSeq)
private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 =
inputs.iterator.toList.foldLeft(init) { (v, i) => i.processAttributes(v)(f) }
inputs.toList0.foldLeft(init) { (v, i) => i.processAttributes(v)(f) }
end Apply
private def remove[A](s: Seq[A], v: A) = s.filterNot(_ == v)

View File

@ -14,11 +14,46 @@ object TupleMapExtension:
extension [Tup <: Tuple, F1[_]](tuple: Tuple.Map[Tup, F1])
def iterator: Iterator[F1[Any]] = tuple.productIterator.asInstanceOf[Iterator[F1[Any]]]
def unmap(f: [a] => F1[a] => a): Tup =
Tuple.fromArray(tuple.iterator.map(f(_)).toArray).asInstanceOf[Tup]
// typed version of tuple.toList
def toList0: List[F1[Any]] =
tuple.iterator.toList.asInstanceOf[List[F1[Any]]]
def unmap(f: [a] => F1[a] => a): Tup = transform[[A] =>> A](f).asInstanceOf[Tup]
def transform[F2[_]](f: [a] => F1[a] => F2[a]): Tuple.Map[Tup, F2] =
Tuple.fromArray(tuple.iterator.map(f(_)).toArray).asInstanceOf[Tuple.Map[Tup, F2]]
inline def f0(x: Any) = f(x.asInstanceOf[F1[Any]])
// We could use tuple.map from the scala3-library but it creates temporary arrays
// which has an impact on the performance.
// Instead, for small tuples, of size under 22, we map over each element manually.
// format: off
val res = (tuple: Tuple) match
case EmptyTuple => EmptyTuple
case t: NonEmptyTuple =>
t.size match
case 1 => Tuple1(f0(t(0)))
case 2 => (f0(t(0)), f0(t(1)))
case 3 => (f0(t(0)), f0(t(1)), f0(t(2)))
case 4 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)))
case 5 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)))
case 6 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)))
case 7 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)))
case 8 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)))
case 9 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)))
case 10 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)))
case 11 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)))
case 12 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)))
case 13 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)))
case 14 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)))
case 15 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)))
case 16 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)))
case 17 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)))
case 18 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)))
case 19 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)), f0(t(18)))
case 20 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)), f0(t(18)), f0(t(19)))
case 21 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)), f0(t(18)), f0(t(19)), f0(t(20)))
case 22 => (f0(t(0)), f0(t(1)), f0(t(2)), f0(t(3)), f0(t(4)), f0(t(5)), f0(t(6)), f0(t(7)), f0(t(8)), f0(t(9)), f0(t(10)), f0(t(11)), f0(t(12)), f0(t(13)), f0(t(14)), f0(t(15)), f0(t(16)), f0(t(17)), f0(t(18)), f0(t(19)), f0(t(20)), f0(t(21)))
case _ => scala.runtime.TupleXXL.fromIterator(tuple.iterator.map(f(_)))
// format: on
res.asInstanceOf[Tuple.Map[Tup, F2]]
def traverse[F2[_]](f: [a] => F1[a] => F2[a])(using app: Applicative[F2]): F2[Tup] =
val fxs: F2[List[Any]] = tuple.iterator