@@ -147,71 +147,124 @@ object CodeGen {
147
147
| * Copyright (C) 2012-2014 Typesafe Inc. <http://www.typesafe.com>
148
148
| */""" .stripMargin.trim
149
149
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)
159
162
}
160
163
161
- private def apply0SpecMethods = {
164
+ private val function0Spec = {
162
165
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)
177
167
}
178
-
179
- private def apply1SpecMethods = {
168
+ private val function1Spec = {
180
169
val ts = List (Type .Int , Type .Long , Type .Float , Type .Double )
181
170
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)
184
177
}
185
178
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
+ }
190
208
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 " ))
196
237
}
197
238
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
203
256
}
204
257
205
258
def fN (n : Int ) = {
206
259
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
211
264
case x => " "
212
265
}
213
- val trailer = " }\n "
214
- List (header, applyMethods , trailer).mkString
266
+ val trailer = " \n }\n "
267
+ List (header, specializedVariants , trailer).mkString
215
268
}
216
269
217
270
def pN (n : Int ) = arity(n).pN
0 commit comments