1
1
package scala
2
2
3
- import annotation .{ experimental , showAsInfix }
3
+ import annotation .showAsInfix
4
4
import compiletime .*
5
5
import compiletime .ops .int .*
6
6
@@ -65,7 +65,6 @@ sealed trait Tuple extends Product {
65
65
inline def take [This >: this .type <: Tuple ](n : Int ): Take [This , n.type ] =
66
66
runtime.Tuples .take(this , n).asInstanceOf [Take [This , n.type ]]
67
67
68
-
69
68
/** Given a tuple `(a1, ..., am)`, returns the tuple `(an+1, ..., am)` consisting
70
69
* all its elements except the first n ones.
71
70
*/
@@ -82,9 +81,22 @@ sealed trait Tuple extends Product {
82
81
/** Given a tuple `(a1, ..., am)`, returns the reversed tuple `(am, ..., a1)`
83
82
* consisting all its elements.
84
83
*/
85
- @ experimental
86
84
inline def reverse [This >: this .type <: Tuple ]: Reverse [This ] =
87
85
runtime.Tuples .reverse(this ).asInstanceOf [Reverse [This ]]
86
+
87
+ /** A tuple with the fields of this tuple in reversed order added in front of `acc` */
88
+ inline def reverseOnto [This >: this .type <: Tuple , Acc <: Tuple ](acc : Acc ): ReverseOnto [This , Acc ] =
89
+ (this .reverse ++ acc).asInstanceOf [ReverseOnto [This , Acc ]]
90
+
91
+ /** A tuple consisting of all elements of this tuple that have types
92
+ * for which the given predicate `P` evaluates to truye.
93
+ */
94
+ inline def filter [This >: this .type <: Tuple , P [_] <: Boolean ]: Filter [This , P ] =
95
+ val toInclude = constValueTuple[IndicesWhere [This , P ]].toArray
96
+ val arr = new Array [Object ](toInclude.length)
97
+ for i <- 0 until toInclude.length do
98
+ arr(i) = this .productElement(toInclude(i).asInstanceOf [Int ]).asInstanceOf [Object ]
99
+ Tuple .fromArray(arr).asInstanceOf [Filter [This , P ]]
88
100
}
89
101
90
102
object Tuple {
@@ -133,6 +145,14 @@ object Tuple {
133
145
}
134
146
}
135
147
148
+ /** The index of `Y` in tuple `X` as a literal constant Int,
149
+ * or `Size[X]` if `Y` does not occur in `X`
150
+ */
151
+ type IndexOf [X <: Tuple , Y ] <: Int = X match
152
+ case Y *: _ => 0
153
+ case x *: xs => S [IndexOf [xs, Y ]]
154
+ case EmptyTuple => 0
155
+
136
156
/** Literal constant Int size of a tuple */
137
157
type Size [X <: Tuple ] <: Int = X match {
138
158
case EmptyTuple => 0
@@ -175,6 +195,12 @@ object Tuple {
175
195
}
176
196
}
177
197
198
+ /** A tuple consisting of those indices `N` of tuple `X` where the predicate `P`
199
+ * is true for `Elem[X, N]`. Indices are type level values <: Int.
200
+ */
201
+ type IndicesWhere [X <: Tuple , P [_] <: Boolean ] =
202
+ helpers.IndicesWhereHelper [X , P , 0 ]
203
+
178
204
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
179
205
* where at least one of `At` or `Bt` is `EmptyTuple` or `Tuple`,
180
206
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`
@@ -200,18 +226,13 @@ object Tuple {
200
226
*/
201
227
type IsMappedBy [F [_]] = [X <: Tuple ] =>> X =:= Map [InverseMap [X , F ], F ]
202
228
203
- /** Type of the reversed tuple */
204
- @ experimental
205
- type Reverse [X <: Tuple ] = Helpers .ReverseImpl [EmptyTuple , X ]
229
+ /** A tuple with the fields of tuple `X` in reversed order */
230
+ type Reverse [X <: Tuple ] = ReverseOnto [X , EmptyTuple ]
206
231
207
- @ experimental
208
- object Helpers :
209
-
210
- /** Type of the reversed tuple */
211
- @ experimental
212
- type ReverseImpl [Acc <: Tuple , X <: Tuple ] <: Tuple = X match
213
- case x *: xs => ReverseImpl [x *: Acc , xs]
214
- case EmptyTuple => Acc
232
+ /** A tuple with the fields of tuple `X` in reversed order added in front of `Acc` */
233
+ type ReverseOnto [X <: Tuple , Acc <: Tuple ] <: Tuple = X match
234
+ case x *: xs => ReverseOnto [xs, x *: Acc ]
235
+ case EmptyTuple => Acc
215
236
216
237
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
217
238
type Take [T <: Tuple , N <: Int ] <: Tuple = N match {
@@ -241,6 +262,42 @@ object Tuple {
241
262
*/
242
263
type Union [T <: Tuple ] = Fold [T , Nothing , [x, y] =>> x | y]
243
264
265
+ /** A type level Boolean indicating whether the tuple `X` conforms
266
+ * to the tuple `Y`. This means:
267
+ * - the two tuples have the same number of elements
268
+ * - for corresponding elements `x` in `X` and `y` in `Y`, `x` matches `y`.
269
+ * @pre The elements of `X` are assumed to be singleton types
270
+ */
271
+ type Conforms [X <: Tuple , Y <: Tuple ] <: Boolean = Y match
272
+ case EmptyTuple =>
273
+ X match
274
+ case EmptyTuple => true
275
+ case _ => false
276
+ case y *: ys =>
277
+ X match
278
+ case `y` *: xs => Conforms [xs, ys]
279
+ case _ => false
280
+
281
+ /** A type level Boolean indicating whether the tuple `X` has an element
282
+ * that matches `Y`.
283
+ * @pre The elements of `X` are assumed to be singleton types
284
+ */
285
+ type Contains [X <: Tuple , Y ] <: Boolean = X match
286
+ case Y *: _ => true
287
+ case x *: xs => Contains [xs, Y ]
288
+ case EmptyTuple => false
289
+
290
+ /** A type level Boolean indicating whether the type `Y` contains
291
+ * none of the elements of `X`.
292
+ * @pre The elements of `X` and `Y` are assumed to be singleton types
293
+ */
294
+ type Disjoint [X <: Tuple , Y <: Tuple ] <: Boolean = X match
295
+ case x *: xs =>
296
+ Contains [Y , x] match
297
+ case true => false
298
+ case false => Disjoint [xs, Y ]
299
+ case EmptyTuple => true
300
+
244
301
/** Empty tuple */
245
302
def apply (): EmptyTuple = EmptyTuple
246
303
@@ -251,12 +308,16 @@ object Tuple {
251
308
def unapply (x : EmptyTuple ): true = true
252
309
253
310
/** Convert an array into a tuple of unknown arity and types */
254
- def fromArray [T ](xs : Array [T ]): Tuple = {
311
+ def fromArray [T ](xs : Array [T ]): Tuple =
312
+ fromArray(xs, xs.length)
313
+
314
+ /** Convert the first `n` elements of an array into a tuple of unknown arity and types */
315
+ def fromArray [T ](xs : Array [T ], n : Int ): Tuple = {
255
316
val xs2 = xs match {
256
317
case xs : Array [Object ] => xs
257
318
case xs => xs.map(_.asInstanceOf [Object ])
258
319
}
259
- runtime.Tuples .fromArray(xs2)
320
+ runtime.Tuples .fromArray(xs2, n )
260
321
}
261
322
262
323
/** Convert an immutable array into a tuple of unknown arity and types */
@@ -273,13 +334,49 @@ object Tuple {
273
334
def fromProduct (product : Product ): Tuple =
274
335
runtime.Tuples .fromProduct(product)
275
336
337
+ extension [X <: Tuple ](inline x : X )
338
+
339
+ /** The index (starting at 0) of the first element in the type `X` of `x`
340
+ * that matches type `Y`.
341
+ */
342
+ inline def indexOfType [Y ] = constValue[IndexOf [X , Y ]]
343
+
344
+ /** A boolean indicating whether there is an element in the type `X` of `x`
345
+ * that matches type `Y`.
346
+ */
347
+
348
+ inline def containsType [Y ] = constValue[Contains [X , Y ]]
349
+
350
+ /* Note: It would be nice to add the following two extension methods:
351
+
352
+ inline def indexOf[Y: Precise](y: Y) = constValue[IndexOf[X, Y]]
353
+ inline def containsType[Y: Precise](y: Y) = constValue[Contains[X, Y]]
354
+
355
+ because we could then move indexOf/contains completely to the value level.
356
+ But this requires `Y` to be inferred precisely, and therefore a mechanism
357
+ like the `Precise` context bound used above, which does not yet exist.
358
+ */
359
+
360
+ end extension
361
+
276
362
def fromProductTyped [P <: Product ](p : P )(using m : scala.deriving.Mirror .ProductOf [P ]): m.MirroredElemTypes =
277
363
runtime.Tuples .fromProduct(p).asInstanceOf [m.MirroredElemTypes ]
278
364
279
365
given canEqualEmptyTuple : CanEqual [EmptyTuple , EmptyTuple ] = CanEqual .derived
280
366
given canEqualTuple [H1 , T1 <: Tuple , H2 , T2 <: Tuple ](
281
367
using eqHead : CanEqual [H1 , H2 ], eqTail : CanEqual [T1 , T2 ]
282
368
): CanEqual [H1 *: T1 , H2 *: T2 ] = CanEqual .derived
369
+
370
+ object helpers :
371
+
372
+ /** Used to implement IndicesWhere */
373
+ type IndicesWhereHelper [X <: Tuple , P [_] <: Boolean , N <: Int ] <: Tuple = X match
374
+ case EmptyTuple => EmptyTuple
375
+ case h *: t => P [h] match
376
+ case true => N *: IndicesWhereHelper [t, P , S [N ]]
377
+ case false => IndicesWhereHelper [t, P , S [N ]]
378
+
379
+ end helpers
283
380
}
284
381
285
382
/** A tuple of 0 elements */
0 commit comments