Skip to content

Commit 2bc4024

Browse files
committed
Use staged macros to implement parts of Tuple
1 parent 8ce3ea2 commit 2bc4024

File tree

2 files changed

+276
-234
lines changed

2 files changed

+276
-234
lines changed
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
package scala
2+
3+
import scala.quoted._
4+
5+
object StagedTuple {
6+
import Tuple._
7+
import NonEmptyTuple._
8+
9+
def toArrayStaged(tup: Expr[Tuple], size: Option[Int]): Expr[Array[Object]] = {
10+
if (!specialize) '(dynamicToArray(~tup))
11+
else size match {
12+
case Some(0) =>
13+
'($emptyArray)
14+
case Some(1) =>
15+
tup.as[Tuple1[Object]].bind(t => '(Array((~t)._1)))
16+
case Some(2) =>
17+
tup.as[Tuple2[Object, Object]].bind(t => '(Array((~t)._1, (~t)._2)))
18+
case Some(3) =>
19+
tup.as[Tuple3[Object, Object, Object]].bind(t => '(Array((~t)._1, (~t)._2, (~t)._3)))
20+
case Some(4) =>
21+
tup.as[Tuple4[Object, Object, Object, Object]].bind(t => '(Array((~t)._1, (~t)._2, (~t)._3, (~t)._4)))
22+
case Some(n) if n <= $MaxSpecialized =>
23+
'($toArray(~tup, ~n.toExpr))
24+
case Some(n) =>
25+
'((~tup.as[TupleXXL]).elems)
26+
case None =>
27+
'(dynamicToArray(~tup))
28+
}
29+
}
30+
31+
def fromArrayStaged[T <: Tuple : Type](xs: Expr[Array[Object]], size: Option[Int]): Expr[T] = {
32+
if (!specialize) '(dynamicFromArray[T](~xs))
33+
else {
34+
val tup = size match {
35+
case Some(0) => '()
36+
case Some(1) => '(Tuple1( (~xs)(0)))
37+
case Some(2) => '(Tuple2( (~xs)(0), (~xs)(1)))
38+
case Some(3) => '(Tuple3( (~xs)(0), (~xs)(1), (~xs)(2)))
39+
case Some(4) => '(Tuple4( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3)))
40+
case Some(5) => '(Tuple5( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4)))
41+
case Some(6) => '(Tuple6( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5)))
42+
case Some(7) => '(Tuple7( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6)))
43+
case Some(8) => '(Tuple8( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7)))
44+
case Some(9) => '(Tuple9( (~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8)))
45+
case Some(10) => '(Tuple10((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9)))
46+
case Some(11) => '(Tuple11((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10)))
47+
case Some(12) => '(Tuple12((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11)))
48+
case Some(13) => '(Tuple13((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12)))
49+
case Some(14) => '(Tuple14((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13)))
50+
case Some(15) => '(Tuple15((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14)))
51+
case Some(16) => '(Tuple16((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15)))
52+
case Some(17) => '(Tuple17((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16)))
53+
case Some(18) => '(Tuple18((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17)))
54+
case Some(19) => '(Tuple19((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17), (~xs)(18)))
55+
case Some(20) => '(Tuple20((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17), (~xs)(18), (~xs)(19)))
56+
case Some(21) => '(Tuple21((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17), (~xs)(18), (~xs)(19), (~xs)(20)))
57+
case Some(22) => '(Tuple22((~xs)(0), (~xs)(1), (~xs)(2), (~xs)(3), (~xs)(4), (~xs)(5), (~xs)(6), (~xs)(7), (~xs)(8), (~xs)(9), (~xs)(10), (~xs)(11), (~xs)(12), (~xs)(13), (~xs)(14), (~xs)(15), (~xs)(16), (~xs)(17), (~xs)(18), (~xs)(19), (~xs)(20), (~xs)(21)))
58+
case Some(_) => '(TupleXXL(~xs))
59+
case None => '(dynamicFromArray[T](~xs))
60+
}
61+
tup.as[T]
62+
}
63+
}
64+
65+
def sizeStaged[Res <: Int : Type](tup: Expr[Tuple], size: Option[Int]): Expr[Res] = {
66+
val res =
67+
if (!specialize) '(dynamicSize(~tup))
68+
else size match {
69+
case Some(n) => n.toExpr
70+
case None => '(dynamicSize(~tup))
71+
}
72+
res.as[Res]
73+
}
74+
75+
def headStaged[Tup <: NonEmptyTuple : Type](tup: Expr[Tup], size: Option[Int]): Expr[Head[Tup]] = {
76+
if (!specialize) '(dynamicHead(~tup))
77+
else {
78+
val resVal = size match {
79+
case Some(1) =>
80+
'((~tup.as[Tuple1[_]])._1)
81+
case Some(2) =>
82+
'((~tup.as[Tuple2[_, _]])._1)
83+
case Some(3) =>
84+
'((~tup.as[Tuple3[_, _, _]])._1)
85+
case Some(4) =>
86+
'((~tup.as[Tuple4[_, _, _, _]])._1)
87+
case Some(n) if n > 4 && n <= $MaxSpecialized =>
88+
'((~tup.as[Product]).productElement(0))
89+
case Some(n) if n > $MaxSpecialized =>
90+
'((~tup.as[TupleXXL]).elems(0))
91+
case None =>
92+
'(dynamicHead(~tup))
93+
}
94+
resVal.as[Head[Tup]]
95+
}
96+
}
97+
98+
def tailStaged[Tup <: NonEmptyTuple : Type](tup: Expr[Tup], size: Option[Int]): Expr[Tail[Tup]] = {
99+
if (!specialize) '(dynamicTail[Tup](~tup))
100+
else {
101+
val res = size match {
102+
case Some(1) =>
103+
'()
104+
case Some(2) =>
105+
tup.as[Tuple2[_, _]].bind(t => '(Tuple1((~t)._2)))
106+
case Some(3) =>
107+
tup.as[Tuple3[_, _, _]].bind(t => '(Tuple2((~t)._2, (~t)._3)))
108+
case Some(4) =>
109+
tup.as[Tuple4[_, _, _, _]].bind(t => '(Tuple3((~t)._2, (~t)._3, (~t)._4)))
110+
case Some(5) =>
111+
tup.as[Tuple5[_, _, _, _, _]].bind(t => '(Tuple4((~t)._2, (~t)._3, (~t)._4, (~t)._5)))
112+
case Some(n) if n > 5 =>
113+
val arr = toArrayStaged(tup, size)
114+
fromArrayStaged('((~arr).tail) , Some(n - 1))
115+
case None =>
116+
'(dynamicTail(~tup))
117+
}
118+
res.as[Tail[Tup]]
119+
}
120+
}
121+
122+
def applyStaged[Tup <: NonEmptyTuple : Type, N <: Int : Type](tup: Expr[Tup], size: Option[Int], n: Expr[N], nValue: Option[Int]): Expr[Elem[Tup, N]] = {
123+
if (!specialize) '(dynamicApply(~tup, ~n))
124+
else {
125+
def fallbackApply(): Expr[Elem[Tup, N]] = nValue match {
126+
case Some(n) => quoted.QuoteError("index out of bounds: " + n)
127+
case None => '(dynamicApply(~tup, ~n))
128+
}
129+
val res = size match {
130+
case Some(1) =>
131+
val t = tup.as[Tuple1[_]]
132+
nValue match {
133+
case Some(0) => '((~t)._1)
134+
case _ => fallbackApply()
135+
}
136+
case Some(2) =>
137+
val t = tup.as[Tuple2[_, _]]
138+
nValue match {
139+
case Some(0) => '((~t)._1)
140+
case Some(1) => '((~t)._2)
141+
case _ => fallbackApply()
142+
}
143+
case Some(3) =>
144+
val t = tup.as[Tuple3[_, _, _]]
145+
nValue match {
146+
case Some(0) => '((~t)._1)
147+
case Some(1) => '((~t)._2)
148+
case Some(2) => '((~t)._3)
149+
case _ => fallbackApply()
150+
}
151+
case Some(4) =>
152+
val t = tup.as[Tuple4[_, _, _, _]]
153+
nValue match {
154+
case Some(0) => '((~t)._1)
155+
case Some(1) => '((~t)._2)
156+
case Some(2) => '((~t)._3)
157+
case Some(3) => '((~t)._4)
158+
case _ => fallbackApply()
159+
}
160+
case Some(s) if s > 4 && s <= $MaxSpecialized =>
161+
val t = tup.as[Product]
162+
nValue match {
163+
case Some(n) if n >= 0 && n < s => '((~t).productElement(~n.toExpr))
164+
case _ => fallbackApply()
165+
}
166+
case Some(s) if s > $MaxSpecialized =>
167+
val t = tup.as[TupleXXL]
168+
nValue match {
169+
case Some(n) if n >= 0 && n < s => '((~t).elems(~n.toExpr))
170+
case _ => fallbackApply()
171+
}
172+
case _ => fallbackApply()
173+
}
174+
res.as[Elem[Tup, N]]
175+
}
176+
}
177+
178+
def stagedCons[T <: Tuple & Singleton : Type, H : Type](self: Expr[T], x: Expr[H], tailSize: Option[Int]): Expr[H *: T] =
179+
if (!specialize) '(dynamic_*:[T, H](~self, ~x))
180+
else {
181+
val res = tailSize match {
182+
case Some(0) =>
183+
'(Tuple1(~x))
184+
case Some(1) =>
185+
self.as[Tuple1[_]].bind(t => '(Tuple2(~x, (~t)._1)))
186+
case Some(2) =>
187+
self.as[Tuple2[_, _]].bind(t => '(Tuple3(~x, (~t)._1, (~t)._2)))
188+
case Some(3) =>
189+
self.as[Tuple3[_, _, _]].bind(t => '(Tuple4(~x, (~t)._1, (~t)._2, (~t)._3)))
190+
case Some(4) =>
191+
self.as[Tuple4[_, _, _, _]].bind(t => '(Tuple5(~x, (~t)._1, (~t)._2, (~t)._3, (~t)._4)))
192+
case Some(n) =>
193+
fromArrayStaged('($consArray(~x, ~toArrayStaged(self, tailSize))), Some(n + 1))
194+
case _ =>
195+
'(dynamic_*:[T, H](~self, ~x))
196+
}
197+
res.as[H *: T]
198+
}
199+
200+
def stagedConcat[Self <: Tuple & Singleton : Type, That <: Tuple & Singleton : Type](self: Expr[Self], selfSize: Option[Int], that: Expr[That], thatSize: Option[Int]): Expr[Concat[Self, That]] = {
201+
if (!specialize) '(dynamic_++[Self, That](~self, ~that))
202+
else {
203+
def genericConcat(xs: Expr[Tuple], ys: Expr[Tuple]): Expr[Tuple] =
204+
fromArrayStaged[Tuple]('((~toArrayStaged(xs, None)) ++ (~toArrayStaged(ys, None))), None)
205+
206+
val res = selfSize match {
207+
case Some(0) =>
208+
that
209+
case Some(1) =>
210+
if (thatSize.contains(0)) self
211+
else stagedCons(that, self.as[Tuple1[_]], thatSize)
212+
case Some(2) =>
213+
val self2 = self.as[Tuple2[_, _]]
214+
thatSize match {
215+
case Some(0) => self
216+
case Some(1) =>
217+
self2.bind { t =>
218+
that.as[Tuple1[_]].bind(u => '(Tuple3((~t)._1, (~t)._2, (~u)._1)))
219+
}
220+
case Some(2) =>
221+
self2.bind { t =>
222+
that.as[Tuple2[_, _]].bind(u => '(Tuple4((~t)._1, (~t)._2, (~u)._1, (~u)._2)))
223+
}
224+
case _ =>
225+
genericConcat(self, that)
226+
}
227+
case Some(3) =>
228+
val self2 = self.as[Tuple3[_, _, _]]
229+
thatSize match {
230+
case Some(0) => self
231+
case Some(1) =>
232+
self2.bind { t =>
233+
that.as[Tuple1[_]].bind(u => '(Tuple4((~t)._1, (~t)._2, (~t)._3, (~u)._1)))
234+
}
235+
case _ =>
236+
genericConcat(self, that)
237+
}
238+
case Some(_) =>
239+
if (thatSize.contains(0)) self
240+
else genericConcat(self, that)
241+
case None =>
242+
'(dynamic_++(~self, ~that))
243+
}
244+
res.as[Concat[Self, That]]
245+
}
246+
}
247+
248+
private implicit class ExprOps[U: Type](expr: Expr[U]) {
249+
250+
def as[T: Type]: Expr[T] = '{ (~expr).asInstanceOf[T] }
251+
252+
def bind[T](in: Expr[U] => Expr[T]): Expr[T] = '{
253+
val t: U = (~expr)
254+
~(in('(t)))
255+
}
256+
257+
}
258+
259+
}

0 commit comments

Comments
 (0)