@@ -141,115 +141,129 @@ object CodeGen {
141141
142142 private val initName = " $init$"
143143 private val function1ImplClass = " scala.Function1$class"
144- private val function2ImplClass = " scala.Function2$class"
145144 private val copyright =
146145 """
147146 |/*
148147 | * Copyright (C) 2012-2014 Typesafe Inc. <http://www.typesafe.com>
149148 | */""" .stripMargin.trim
150149
151- private def apply0MethodSpec (r : Type ): String = {
152- val name = " apply$mc" + s " ${r.code}" + " $sp"
153- val applyCall = s " apply(); "
154- def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
155- s """
156- |default ${r.prim} $name() {
157- | $body
158- |}
159- | """ .stripMargin.trim
150+ private def function0SpecMethods = {
151+ val apply = specialized(" apply" , function0Spec) {
152+ case (name, List (r)) =>
153+ val applyCall = s " apply(); "
154+ def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
155+ s """
156+ |default ${r.prim} $name() {
157+ | $body
158+ |}
159+ | """ .stripMargin.trim
160+ }
161+ indent(apply)
160162 }
161163
162- private def apply0SpecMethods = {
164+ private val function0Spec = {
163165 val rs = List (Type .Void , Type .Byte , Type .Short , Type .Int , Type .Long , Type .Char , Type .Float , Type .Double , Type .Boolean )
164- val methods = for (r <- rs) yield apply0MethodSpec(r)
165- methods.map(indent).mkString(" \n\n " )
166+ List (" R" -> rs)
166167 }
167-
168- val function1SpecTs = List (Type .Int , Type .Long , Type .Float , Type .Double )
169- val function1SpecRs = List (Type .Void , Type .Boolean , Type .Int , Type .Float , Type .Long , Type .Double )
170-
171- private def apply1MethodSpec (t1 : Type , r : Type ): String = {
172- val name = " apply$mc" + s " ${r.code}${t1.code}" + " $sp"
173- val applyCall = s " apply((T1) (( ${t1.ref}) v1)); "
174- def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
175-
176- s """
177- |default ${r.prim} $name( ${t1.prim} v1) {
178- | $body
179- |}
180- | """ .stripMargin.trim
168+ private val function1Spec = {
169+ val ts = List (Type .Int , Type .Long , Type .Float , Type .Double )
170+ val rs = List (Type .Void , Type .Boolean , Type .Int , Type .Float , Type .Long , Type .Double )
171+ List (" T1" -> ts, " R" -> rs)
181172 }
182-
183- private def apply1SpecMethods = {
184- val methods = for (t1 <- function1SpecTs; r <- function1SpecRs) yield apply1MethodSpec(t1, r )
185- methods.map(indent).mkString( " \n\n " )
173+ private val function2Spec = {
174+ val ts = List ( Type . Int , Type . Long , Type . Double )
175+ val rs = List ( Type . Void , Type . Boolean , Type . Int , Type . Float , Type . Long , Type . Double )
176+ List ( " T1 " -> ts, " T2 " -> ts, " R " -> rs )
186177 }
187178
188- private def andThenComposeMethodSpec (t1 : Type , r : Type ): String = {
189- val suffix = " $mc" + s " ${r.code}${t1.code}" + " $sp"
190- s """
191- |default scala.Function1 compose $suffix(scala.Function1 g) {
192- | return compose(g);
193- |}
194- |default scala.Function1 andThen $suffix(scala.Function1 g) {
195- | return andThen(g);
196- |}
197- | """ .stripMargin.trim
179+ private def function1SpecMethods = {
180+ val apply = specialized(" apply" , function1Spec) {
181+ case (name, List (t1, r)) =>
182+ val applyCall = s " apply((T1) (( ${t1.ref}) v1)); "
183+ def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
184+ s """
185+ |default ${r.prim} $name( ${t1.prim} v1) {
186+ | $body
187+ |}
188+ | """ .stripMargin.trim
189+ }
190+ // andThen / compose variants are no longer needed under 2.11 (@unspecialized has been fixed),
191+ // but harmless. With them, we can use the same artifact for 2.10 and 2.11
192+ val compose = specialized(" compose" , function1Spec) {
193+ case (name, List (t1, r1)) =>
194+ s """
195+ |default scala.Function1 $name(scala.Function1 g) {
196+ | return compose(g);
197+ |} """ .stripMargin.trim
198+ }
199+ val andThen = specialized(" andThen" , function1Spec) {
200+ case (name, List (t1, r1)) =>
201+ s """
202+ |default scala.Function1 $name(scala.Function1 g) {
203+ | return andThen(g);
204+ |} """ .stripMargin.trim
205+ }
206+ indent(List (apply, compose, andThen).mkString(" \n\n " ))
198207 }
199208
200209 // No longer needed under 2.11 (@unspecialized has been fixed), but harmless to keep around to avoid cross-publishing this artifact.
201- private def andThenComposeSpecMethods = {
202- val methods = for (t1 <- function1SpecTs; r <- function1SpecRs) yield andThenComposeMethodSpec(t1, r)
203- methods.map(indent).mkString(" \n\n " )
204- }
205-
206- val function2SpecTs = List (Type .Int , Type .Long , Type .Double )
207- val function2SpecRs = function1SpecRs
208-
209- private def apply2MethodSpec (t1 : Type , t2 : Type , r : Type ): String = {
210- val name = " apply$mc" + s " ${r.code}${t1.code}${t2.code}" + " $sp"
211- val applyCall = s " apply((T1) (( ${t1.ref}) v1), (T2) (( ${t2.ref}) v2)); "
212- def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
213-
214- s """
215- |default ${r.prim} $name( ${t1.prim} v1, ${t2.prim} v2) {
216- | $body
217- |}
218- | """ .stripMargin.trim
219- }
220-
221- private def apply2SpecMethods = {
222- val methods = for (t1 <- function2SpecTs; t2 <- function2SpecTs; r <- function2SpecRs) yield apply2MethodSpec(t1, t2, r)
223- methods.map(indent).mkString(" \n\n " )
210+ private def function2SpecMethods = {
211+ val apply = specialized(" apply" , function2Spec) {
212+ case (name, List (t1, t2, r)) =>
213+ val applyCall = s " apply((T1) (( ${t1.ref}) v1), (T2) (( ${t2.ref}) v2)); "
214+ def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
215+
216+ s """
217+ |default ${r.prim} $name( ${t1.prim} v1, ${t2.prim} v2) {
218+ | $body
219+ |}
220+ | """ .stripMargin.trim
221+ }
222+ val curried = specialized(" curried" , function2Spec) {
223+ case (name, List (t1, t2, r)) =>
224+ s """
225+ |default scala.Function1 $name() {
226+ | return curried();
227+ |} """ .stripMargin.trim
228+ }
229+ val tupled = specialized(" tupled" , function2Spec) {
230+ case (name, List (t1, t2, r)) =>
231+ s """
232+ |default scala.Function1 $name() {
233+ | return tupled();
234+ |} """ .stripMargin.trim
235+ }
236+ indent(List (apply, curried, tupled).mkString(" \n\n " ))
224237 }
225238
226- private def curriedTupled2MethodSpec (t1 : Type , t2 : Type , r : Type ): String = {
227- val suffix = " $mc" + s " ${r.code}${t1.code}${t2.code}" + " $sp"
228- s """
229- |default scala.Function1 curried $suffix() {
230- | return curried();
231- |}
232- |default scala.Function1 tupled $suffix() {
233- | return tupled();
234- |}
235- | """ .stripMargin.trim
239+ private def specialized (name : String , tps : List [(String , List [Type ])])(f : (String , List [Type ]) => String ): String = {
240+ val tparamNames = tps.map(_._1)
241+ def code (tps : List [Type ]) = {
242+ val sorted = (tps zip tparamNames).sortBy(_._2).map(_._1) // as per scalac, sort by tparam name before assembling the code
243+ sorted.map(_.code).mkString
244+ }
245+ val ms = for {
246+ variantTypes <- crossProduct(tps.map(_._2))
247+ specName = name + " $mc" + code(variantTypes) + " $sp"
248+ } yield f(specName, variantTypes)
249+ ms.mkString(" \n " )
236250 }
237251
238- // No longer needed under 2.11 (@unspecialized has been fixed), but harmless to keep around to avoid cross-publishing this artifact.
239- private def curriedTupled2SpecMethods = {
240- val methods = for (t1 <- function2SpecTs; t2 <- function2SpecTs; r <- function2SpecRs) yield curriedTupled2MethodSpec(t1, t2, r )
241- methods.map(indent).mkString( " \n\n " )
252+ def crossProduct [ A ]( input : List [ List [ A ]]) : List [ List [ A ]] = input match {
253+ case Nil => Nil
254+ case head :: Nil => head.map(_ :: Nil )
255+ case head :: tail => for (elem <- head; sub <- crossProduct(tail)) yield elem :: sub
242256 }
243257
244258 def fN (n : Int ) = {
245259 val header = arity(n).fHeader
246260 val specializedVariants = n match {
247- case 0 => apply0SpecMethods
248- case 1 => apply1SpecMethods + " \n\n " + andThenComposeSpecMethods
249- case 2 => apply2SpecMethods + " \n\n " + curriedTupled2SpecMethods
261+ case 0 => function0SpecMethods
262+ case 1 => function1SpecMethods
263+ case 2 => function2SpecMethods
250264 case x => " "
251265 }
252- val trailer = " }\n "
266+ val trailer = " \n }\n "
253267 List (header, specializedVariants, trailer).mkString
254268 }
255269
0 commit comments