Skip to content

Commit 0ae9d46

Browse files
committed
PoC for generic tuples
A PoC how generic tuples can be implemented - no limit of 22 - generic operations are possible - fully backwards compatible with Scala-2 tuples - specializes for small tuple sizes, yielding optimized code
1 parent 38b231b commit 0ae9d46

File tree

1 file changed

+250
-82
lines changed

1 file changed

+250
-82
lines changed

tests/run/TupleAbstract.scala

Lines changed: 250 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,292 @@
1-
package test
1+
package test {
22

33
import annotation.showAsInfix
44

55
class TypeLevel {
66
type Tuple
77
type Empty <: Tuple
8-
type Pair[+H, +T <: Tuple] <: Tuple
8+
9+
@showAsInfix type *:[+H, +T <: Tuple] <: Tuple
910
erased def erasedValue[T]: T = ???
1011
case class Typed[T](val value: T) { type Type = T }
1112
}
1213

14+
class TupleXXL(val elems: Array[Object])
15+
1316
object Tuples {
1417
val typelevel = new TypeLevel
1518
import typelevel._
1619

17-
transparent def _empty: typelevel.Tuple = erasedValue[Empty]
18-
transparent def _pair[H, T <: typelevel.Tuple] (x: H, xs: T): typelevel.Tuple = erasedValue[Pair[H, T]]
20+
final val MaxSpecialized = 7 // 22 in real life
21+
22+
transparent def _empty: Tuple = erasedValue[Empty]
23+
transparent def _pair[H, T <: Tuple] (x: H, xs: T): Tuple = erasedValue[H *: T]
24+
25+
def unit = ().asInstanceOf[Empty]
1926

20-
transparent def _size(xs: typelevel.Tuple): Int = xs match {
21-
case _: typelevel.Empty => 0
22-
case _: typelevel.Pair[_, xs1] => _size(erasedValue[xs1]) + 1
27+
transparent def _size(xs: Tuple): Int = xs match {
28+
case _: Empty => 0
29+
case _: (_ *: xs1) => _size(erasedValue[xs1]) + 1
2330
}
2431

25-
val x = _size(erasedValue[Pair[Int, Pair[String, Empty]]])
26-
/*
32+
erased val xs2 = erasedValue[Int *: String *: Empty]
33+
34+
erased val s = _size(xs2)
35+
2736
transparent def _index(xs: Tuple, n: Int): Any = xs match {
28-
case x *: _ if n == 0 => x
29-
case _ *: xs1 if n > 0 => _index(xs1, n - 1)
37+
case _: (x *: _) if n == 0 => erasedValue[x]
38+
case _: (_ *: xs1) if n > 0 => _index(erasedValue[xs1], n - 1)
39+
}
40+
41+
transparent def _head(xs: Tuple): Any = xs match {
42+
case _: (x *: _) => erasedValue[x]
3043
}
3144

45+
transparent def _tail(xs: Tuple): Tuple = xs match {
46+
case _: (_ *: xs1) => erasedValue[xs1]
47+
}
48+
49+
transparent def _concat(xs: Tuple, ys: Tuple): Tuple = xs match {
50+
case _: Empty => ys
51+
case _: (x1 *: xs1) => _pair(erasedValue[x1], _concat(erasedValue[xs1], ys))
52+
}
53+
54+
erased val e0 = _index(xs2, 0)
55+
erased val e1 = _index(xs2, 1)
56+
57+
transparent def fromArray[T <: Tuple](xs: Array[Object]): T =
58+
_size(erasedValue[T]) match {
59+
case 0 => ().asInstanceOf[T]
60+
case 1 => Tuple1(xs(0)).asInstanceOf[T]
61+
case 2 => Tuple2(xs(0), xs(1)).asInstanceOf[T]
62+
case 3 => Tuple3(xs(0), xs(1), xs(2)).asInstanceOf[T]
63+
case 4 => Tuple4(xs(0), xs(1), xs(2), xs(3)).asInstanceOf[T]
64+
case 5 => Tuple5(xs(0), xs(1), xs(2), xs(3), xs(4)).asInstanceOf[T]
65+
case 6 => Tuple6(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5)).asInstanceOf[T]
66+
case 7 => Tuple7(xs(0), xs(1), xs(2), xs(3), xs(4), xs(5), xs(6)).asInstanceOf[T]
67+
case _ => new TupleXXL(xs).asInstanceOf[T]
68+
}
69+
70+
val emptyArray = Array[Object]()
71+
72+
transparent implicit def tupleDeco(xs: Tuple): TupleOps = new TupleOps(xs)
73+
3274
class TupleOps(val xs: Tuple) extends AnyVal {
3375

34-
transparent def *: [H] (x: H): Tuple = new *:(x, xs)
35-
transparent def size: Int = _size(xs)
76+
transparent def toArray: Array[Object] = _size(xs) match {
77+
case 0 =>
78+
emptyArray
79+
case 1 =>
80+
val t = xs.asInstanceOf[Tuple1[Object]]
81+
Array(t._1)
82+
case 2 =>
83+
val t = xs.asInstanceOf[Tuple2[Object, Object]]
84+
Array(t._1, t._2)
85+
case 3 =>
86+
val t = xs.asInstanceOf[Tuple3[Object, Object, Object]]
87+
Array(t._1, t._2, t._3)
88+
case 4 =>
89+
val t = xs.asInstanceOf[Tuple4[Object, Object, Object, Object]]
90+
Array(t._1, t._2, t._3, t._4)
91+
case 5 =>
92+
val t = xs.asInstanceOf[Tuple5[Object, Object, Object, Object, Object]]
93+
Array(t._1, t._2, t._3, t._4, t._5)
94+
case 6 =>
95+
val t = xs.asInstanceOf[Tuple6[Object, Object, Object, Object, Object, Object]]
96+
Array(t._1, t._2, t._3, t._4, t._5, t._6)
97+
case 7 =>
98+
val t = xs.asInstanceOf[Tuple7[Object, Object, Object, Object, Object, Object, Object]]
99+
Array(t._1, t._2, t._3, t._4, t._5, t._6, t._7)
100+
case _ =>
101+
xs.asInstanceOf[TupleXXL].elems
102+
}
103+
104+
transparent def *: [H] (x: H): Tuple = {
105+
erased val resTpe = Typed(_pair(x, xs))
106+
_size(xs) match {
107+
case 0 =>
108+
Tuple1(x).asInstanceOf[resTpe.Type]
109+
case 1 =>
110+
Tuple2(x, xs.asInstanceOf[Tuple1[_]]._1).asInstanceOf[resTpe.Type]
111+
case 2 =>
112+
val t = xs.asInstanceOf[Tuple2[_, _]]
113+
Tuple3(x, t._1, t._2).asInstanceOf[resTpe.Type]
114+
case 3 =>
115+
val t = xs.asInstanceOf[Tuple3[_, _, _]]
116+
Tuple4(x, t._1, t._2, t._3).asInstanceOf[resTpe.Type]
117+
case 4 =>
118+
val t = xs.asInstanceOf[Tuple4[_, _, _, _]]
119+
Tuple5(x, t._1, t._2, t._3, t._4).asInstanceOf[resTpe.Type]
120+
case n =>
121+
fromArray[resTpe.Type](prepend(x, toArray))
122+
}
123+
}
124+
125+
private def prepend[H](x: H, elems: Array[Object]): Array[Object] = {
126+
val elems1 = new Array[Object](elems.length + 1)
127+
elems1(0) = x.asInstanceOf[Object]
128+
Array.copy(elems, 0, elems1, 1, elems.length)
129+
elems1
130+
}
131+
132+
transparent def head: Any = {
133+
erased val resTpe = Typed(_head(xs))
134+
_size(xs) match {
135+
case 1 =>
136+
val t = xs.asInstanceOf[Tuple1[_]]
137+
t._1.asInstanceOf[resTpe.Type]
138+
case 2 =>
139+
val t = xs.asInstanceOf[Tuple2[_, _]]
140+
t._1.asInstanceOf[resTpe.Type]
141+
case 3 =>
142+
val t = xs.asInstanceOf[Tuple3[_, _, _]]
143+
t._1.asInstanceOf[resTpe.Type]
144+
case 4 =>
145+
val t = xs.asInstanceOf[Tuple4[_, _, _, _]]
146+
t._1.asInstanceOf[resTpe.Type]
147+
case n if n > 4 && n <= MaxSpecialized =>
148+
xs.asInstanceOf[Product].productElement(0).asInstanceOf[resTpe.Type]
149+
case n if n > MaxSpecialized =>
150+
val t = xs.asInstanceOf[TupleXXL]
151+
t.elems(0).asInstanceOf[resTpe.Type]
152+
}
153+
}
154+
155+
transparent def tail: Any = {
156+
erased val resTpe = Typed(_tail(xs))
157+
_size(xs) match {
158+
case 1 =>
159+
unit
160+
case 2 =>
161+
val t = xs.asInstanceOf[Tuple2[_, _]]
162+
Tuple1(t._2).asInstanceOf[resTpe.Type]
163+
case 3 =>
164+
val t = xs.asInstanceOf[Tuple3[_, _, _]]
165+
Tuple2(t._2, t._3).asInstanceOf[resTpe.Type]
166+
case 4 =>
167+
val t = xs.asInstanceOf[Tuple4[_, _, _, _]]
168+
Tuple3(t._2, t._3, t._4).asInstanceOf[resTpe.Type]
169+
case 5 =>
170+
val t = xs.asInstanceOf[Tuple5[_, _, _, _, _]]
171+
Tuple4(t._2, t._3, t._4, t._5).asInstanceOf[resTpe.Type]
172+
case n if n > 5 =>
173+
fromArray[resTpe.Type](toArray.tail)
174+
}
175+
}
36176

37177
transparent def apply(n: Int): Any = {
38-
erased val typed = Typed(_index(xs, n))
39-
val result = _size(xs) match {
178+
erased val resTpe = Typed(_index(xs, n))
179+
_size(xs) match {
40180
case 1 =>
181+
val t = xs.asInstanceOf[Tuple1[_]]
41182
n match {
42-
case 1 => xs.asInstanceOf[Tuple1[_]].__1
183+
case 0 => t._1.asInstanceOf[resTpe.Type]
43184
}
44185
case 2 =>
186+
val t = xs.asInstanceOf[Tuple2[_, _]]
45187
n match {
46-
case 1 => xs.asInstanceOf[Tuple2[_, _]].__1
47-
case 2 => xs.asInstanceOf[Tuple2[_, _]].__2
188+
case 0 => t._1.asInstanceOf[resTpe.Type]
189+
case 1 => t._2.asInstanceOf[resTpe.Type]
48190
}
49191
case 3 =>
192+
val t = xs.asInstanceOf[Tuple3[_, _, _]]
50193
n match {
51-
case 1 => xs.asInstanceOf[Tuple3[_, _, _]].__1
52-
case 2 => xs.asInstanceOf[Tuple3[_, _, _]].__2
53-
case 3 => xs.asInstanceOf[Tuple3[_, _, _]].__3
194+
case 0 => t._1.asInstanceOf[resTpe.Type]
195+
case 1 => t._2.asInstanceOf[resTpe.Type]
196+
case 2 => t._3.asInstanceOf[resTpe.Type]
54197
}
55198
case 4 =>
199+
val t = xs.asInstanceOf[Tuple4[_, _, _, _]]
56200
n match {
57-
case 1 => xs.asInstanceOf[Tuple4[_, _, _, _]].__1
58-
case 2 => xs.asInstanceOf[Tuple4[_, _, _, _]].__2
59-
case 3 => xs.asInstanceOf[Tuple4[_, _, _, _]].__3
60-
case 4 => xs.asInstanceOf[Tuple4[_, _, _, _]].__4
201+
case 0 => t._1.asInstanceOf[resTpe.Type]
202+
case 1 => t._2.asInstanceOf[resTpe.Type]
203+
case 2 => t._3.asInstanceOf[resTpe.Type]
204+
case 3 => t._4.asInstanceOf[resTpe.Type]
61205
}
206+
case s if s > 4 && s <= MaxSpecialized && n >= 0 && n < s =>
207+
xs.asInstanceOf[Product].productElement(n).asInstanceOf[resTpe.Type]
208+
case s if s > MaxSpecialized && n >= 0 && n < s =>
209+
xs.asInstanceOf[TupleXXL].elems(n).asInstanceOf[resTpe.Type]
62210
}
63-
result.asInstanceOf[typed.Type]
64211
}
65-
transparent def **: (ys: Tuple): Tuple = ys match {
66-
case Empty => xs
67-
case y *: ys1 => y *: (ys1 **: xs)
68-
}
69-
transparent def head = xs match {
70-
case x *: _ => x
71-
}
72-
transparent def tail = xs match {
73-
case _ *: xs => xs
74-
}
75-
}
76212

77-
val emptyArray = Array[Object]()
78-
79-
transparent def toObj(t: Any) = t.asInstanceOf[Object]
213+
transparent def ++(ys: Tuple): Tuple = {
214+
erased val resTpe = Typed(_concat(xs, ys))
215+
_size(xs) match {
216+
case 0 => ys
217+
case 1 =>
218+
if (_size(ys) == 0) xs
219+
else xs.head *: ys
220+
case 2 =>
221+
val t = xs.asInstanceOf[Tuple2[_, _]]
222+
_size(ys) match {
223+
case 0 => xs
224+
case 1 =>
225+
val u = ys.asInstanceOf[Tuple1[_]]
226+
Tuple3(t._1, t._2, u._1).asInstanceOf[resTpe.Type]
227+
case 2 =>
228+
val u = ys.asInstanceOf[Tuple2[_, _]]
229+
Tuple4(t._1, t._2, u._1, u._2).asInstanceOf[resTpe.Type]
230+
case _ =>
231+
genericConcat[resTpe.Type](xs, ys)
232+
}
233+
case 3 =>
234+
val t = xs.asInstanceOf[Tuple3[_, _, _]]
235+
_size(ys) match {
236+
case 0 => xs
237+
case 1 =>
238+
val u = ys.asInstanceOf[Tuple1[_]]
239+
Tuple4(t._1, t._2, t._3, u._1).asInstanceOf[resTpe.Type]
240+
case _ =>
241+
genericConcat[resTpe.Type](xs, ys)
242+
}
243+
case _ =>
244+
if (_size(ys) == 0) xs
245+
else genericConcat[resTpe.Type](xs, ys)
246+
}
247+
}
80248

81-
transparent def toArray(t: Tuple): Array[Object] = t.size match {
82-
case 0 => emptyArray
83-
case 1 => Array(toObj(t(0)))
84-
case 2 => Array(toObj(t(0)), toObj(t(1)))
85-
case 3 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2)))
86-
case 4 => Array(toObj(t(0)), toObj(t(1)), toObj(t(2)), toObj(t(3)))
249+
transparent def genericConcat[T <: Tuple](xs: Tuple, ys: Tuple): Tuple =
250+
fromArray[T](xs.toArray ++ ys.toArray)
87251
}
88-
89-
transparent implicit def tupleDeco(xs: Tuple): TupleOps = new TupleOps(xs)
90-
91-
transparent def apply(): Tuple = Empty
92-
transparent def apply(x1: Any): Tuple = x1 *: Empty
93-
transparent def apply(x1: Any, x2: Any) = x1 *: x2 *: Empty
94-
transparent def apply(x1: Any, x2: Any, x3: Any) = x1 *: x2 *: x3 *: Empty
95-
96-
val xs0 = Tuple()
97-
val xs1 = Tuple(2)
98-
val xs2 = Tuple(2, "a")
99-
val xs3 = Tuple(true, 1, 2.0)
100-
transparent val s0 = xs0.size; val s0c: 0 = s0
101-
transparent val s1 = xs1.size; val s1c: 1 = s1
102-
transparent val s2 = xs2.size; val s2c: 2 = s2
103-
transparent val s3 = xs3.size; val s3c: 3 = s3
104-
val e0 = xs3(0); val e0c: Boolean = e0
105-
val e1 = xs3(1); val e1c: Int = e1
106-
val e2 = xs3(2); val e2c: Double = e2
107-
108-
val conc0 = xs0 **: xs3
109-
val conc1 = xs3 **: xs0
110-
val conc2 = xs2 **: xs3
111-
val e3c: Int = conc0(1)
112-
val e4c: Int = conc1(1)
113-
val e5c: Int = conc2(0)
114-
val e6c: Double = conc2(4)
115-
*/
116252
}
117-
/*
118-
class Tuple1[+T1](val __1: T1) extends *:(__1, Empty)
119-
class Tuple2[+T1, +T2](val __1: T1, val __2: T2) extends *:(__1, *:(__2, Empty))
120-
class Tuple3[+T1, +T2, +T3](val __1: T1, val __2: T2, val __3: T3) extends *:(__1, *:(__2, *:(__3, Empty)))
121-
class Tuple4[+T1, +T2, +T3, +T4](val __1: T1, val __2: T2, val __3: T3, val __4: T4) extends *:(__1, *:(__2, *:(__3, *:(__4, Empty))))
122-
123-
object Test extends App
124-
*/
253+
}
254+
object Test extends App {
255+
import test._
256+
import Tuples._
257+
import typelevel._
258+
val x0 = unit
259+
val x1 = 1 *: x0
260+
val x2 = "A" *: x1
261+
val x3 = 2 *: x2
262+
val x4 = "B" *: x3
263+
val x5 = 3 *: x4
264+
val x6 = "C" *: x5
265+
val x7 = 4 *: x6
266+
val x8 = "D" *: x7
267+
val h1 = x1.head; val h1c: Int = h1
268+
val h2 = x2.head; val h2c: String = h2
269+
val h7 = x7.head; val h7c: Int = h7
270+
val h8 = x8.head; val h8c: String = h8
271+
val t1 = x1.tail; val t1c: Empty = t1
272+
val t2 = x2.tail; val t2c: Int *: Empty = t2
273+
val t7 = x7.tail; val t7c: String *: Int *: Empty = t7.tail.tail.tail.tail
274+
val t8 = x8.tail; val t8c: Int = t8(6)
275+
val a1_0 = x1(0); val a1_0c: Int = a1_0
276+
val a2_0 = x2(0); val a2_0c: String = a2_0
277+
val a3_1 = x3(1); val a3_1c: String = a3_1
278+
val a4_3 = x4(3); val a4_3c: Int = a4_3
279+
val a6_4 = x6(4); val a6_4c: String = a6_4
280+
val a8_0 = x8(0); val a8_0c: String = a8_0
281+
val c0_0 = x0 ++ x0; val c0_0c: Empty = c0_0
282+
val c0_1 = x0 ++ x1; val c0_1c: Int *: Empty = c0_1c
283+
val c1_0 = x1 ++ x0; val c1_0c: Int *: Empty = c1_0c
284+
val c0_4 = x0 ++ x4; val c0_4c: String *: Int *: String *: Int *: Empty = c0_4
285+
val c4_0 = x4 ++ x0; val c4_0c: String *: Int *: String *: Int *: Empty = c4_0
286+
val c1_1 = x1 ++ x1; val c1_1c: Int *: Int *: Empty = c1_1
287+
val c1_8 = x1 ++ x8; val c1_8c: Int *: String *: Int *: String *: Int *: String *: Int *: String *: Int *: Empty = c1_8
288+
val c2_1 = x2 ++ x1; val c2_1c: String *: Int *: Int *: Empty = c2_1
289+
val c2_2 = x2 ++ x2; val c2_2c: String *: Int *: String *: Int *: Empty = c2_2
290+
val c2_3 = x2 ++ x3; val c2_3c: String *: Int *: Int *: String *: Int *: Empty = c2_3
291+
val c3_3 = x3 ++ x3; val c3_3c: Int *: String *: Int *: Int *: String *: Int *: Empty = c3_3
292+
}

0 commit comments

Comments
 (0)