diff --git a/tasks-standard/src/main/scala/sbt/std/TaskExtra.scala b/tasks-standard/src/main/scala/sbt/std/TaskExtra.scala index d7d86a385..89cf3a18a 100644 --- a/tasks-standard/src/main/scala/sbt/std/TaskExtra.scala +++ b/tasks-standard/src/main/scala/sbt/std/TaskExtra.scala @@ -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) diff --git a/tasks-standard/src/main/scala/sbt/std/Transform.scala b/tasks-standard/src/main/scala/sbt/std/Transform.scala index 4c1790d3d..c29abcd90 100644 --- a/tasks-standard/src/main/scala/sbt/std/Transform.scala +++ b/tasks-standard/src/main/scala/sbt/std/Transform.scala @@ -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) diff --git a/util-collection/src/main/scala/sbt/internal/util/Settings.scala b/util-collection/src/main/scala/sbt/internal/util/Settings.scala index eadd1c21a..a4fb63f6b 100644 --- a/util-collection/src/main/scala/sbt/internal/util/Settings.scala +++ b/util-collection/src/main/scala/sbt/internal/util/Settings.scala @@ -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) diff --git a/util-collection/src/main/scala/sbt/internal/util/TupleMapExtension.scala b/util-collection/src/main/scala/sbt/internal/util/TupleMapExtension.scala index f86508ef6..ca0ceb71d 100644 --- a/util-collection/src/main/scala/sbt/internal/util/TupleMapExtension.scala +++ b/util-collection/src/main/scala/sbt/internal/util/TupleMapExtension.scala @@ -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