@@ -147,71 +147,124 @@ object CodeGen {
147147 | * Copyright (C) 2012-2014 Typesafe Inc. <http://www.typesafe.com>
148148 | */""" .stripMargin.trim
149149
150- private def apply0MethodSpec (r : Type ): String = {
151- val name = " apply$mc" + s " ${r.code}" + " $sp"
152- val applyCall = s " apply(); "
153- def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
154- s """
155- |default ${r.prim} $name() {
156- | $body
157- |}
158- | """ .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)
159162 }
160163
161- private def apply0SpecMethods = {
164+ private val function0Spec = {
162165 val rs = List (Type .Void , Type .Byte , Type .Short , Type .Int , Type .Long , Type .Char , Type .Float , Type .Double , Type .Boolean )
163- val methods = for (r <- rs) yield apply0MethodSpec(r)
164- methods.map(indent).mkString(" \n\n " )
165- }
166-
167- private def apply1MethodSpec (t1 : Type , r : Type ): String = {
168- val name = " apply$mc" + s " ${r.code}${t1.code}" + " $sp"
169- val applyCall = s " apply((T1) (( ${t1.ref}) v1)); "
170- def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
171-
172- s """
173- |default ${r.prim} $name( ${t1.prim} v1) {
174- | $body
175- |}
176- | """ .stripMargin.trim
166+ List (" R" -> rs)
177167 }
178-
179- private def apply1SpecMethods = {
168+ private val function1Spec = {
180169 val ts = List (Type .Int , Type .Long , Type .Float , Type .Double )
181170 val rs = List (Type .Void , Type .Boolean , Type .Int , Type .Float , Type .Long , Type .Double )
182- val methods = for (t1 <- ts; r <- rs) yield apply1MethodSpec(t1, r)
183- methods.map(indent).mkString(" \n\n " )
171+ List (" T1" -> ts, " R" -> rs)
172+ }
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)
184177 }
185178
186- private def apply2MethodSpec (t1 : Type , t2 : Type , r : Type ): String = {
187- val name = " apply$mc" + s " ${r.code}${t1.code}${t2.code}" + " $sp"
188- val applyCall = s " apply((T1) (( ${t1.ref}) v1), (T2) (( ${t2.ref}) v2)); "
189- def body = if (r == Type .Void ) applyCall else s " return ( ${r.ref}) $applyCall"
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 " ))
207+ }
190208
191- s """
192- |default ${r.prim} $name( ${t1.prim} v1, ${t2.prim} v2) {
193- | $body
194- |}
195- | """ .stripMargin.trim
209+ // No longer needed under 2.11 (@unspecialized has been fixed), but harmless to keep around to avoid cross-publishing this artifact.
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 " ))
196237 }
197238
198- private def apply2SpecMethods = {
199- val ts = List (Type .Int , Type .Long , Type .Double )
200- val rs = List (Type .Void , Type .Boolean , Type .Int , Type .Float , Type .Long , Type .Double )
201- val methods = for (t1 <- ts; t2 <- ts; r <- rs) yield apply2MethodSpec(t1, t2, r)
202- methods.map(indent).mkString(" \n\n " )
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 " )
250+ }
251+
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
203256 }
204257
205258 def fN (n : Int ) = {
206259 val header = arity(n).fHeader
207- val applyMethods = n match {
208- case 0 => apply0SpecMethods
209- case 1 => apply1SpecMethods
210- case 2 => apply2SpecMethods
260+ val specializedVariants = n match {
261+ case 0 => function0SpecMethods
262+ case 1 => function1SpecMethods
263+ case 2 => function2SpecMethods
211264 case x => " "
212265 }
213- val trailer = " }\n "
214- List (header, applyMethods , trailer).mkString
266+ val trailer = " \n }\n "
267+ List (header, specializedVariants , trailer).mkString
215268 }
216269
217270 def pN (n : Int ) = arity(n).pN
0 commit comments