Skip to content

Commit 210fe99

Browse files
committed
Improvements to Tuples: New methods
New methods: filter, indicesWhere, reverseOnto
1 parent 123a11d commit 210fe99

File tree

1 file changed

+58
-22
lines changed

1 file changed

+58
-22
lines changed

library/src/scala/Tuple.scala

Lines changed: 58 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import compiletime.*
55
import compiletime.ops.int.*
66

77
/** Tuple of arbitrary arity */
8-
sealed trait Tuple extends Product {
8+
sealed trait Tuple extends Product:
99
import Tuple.*
1010

1111
/** Create a copy of this tuple as an Array */
@@ -83,9 +83,23 @@ sealed trait Tuple extends Product {
8383
*/
8484
inline def reverse[This >: this.type <: Tuple]: Reverse[This] =
8585
runtime.Tuples.reverse(this).asInstanceOf[Reverse[This]]
86-
}
8786

88-
object Tuple {
87+
/** A tuple with the elements 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 type level predicate `P` reduces to the literal
93+
* constant `true`.
94+
*/
95+
inline def filter[This >: this.type <: Tuple, P[_] <: Boolean]: Filter[This, P] =
96+
val toInclude = constValueTuple[IndicesWhere[This, P]].toArray
97+
val arr = new Array[Object](toInclude.length)
98+
for i <- 0 until toInclude.length do
99+
arr(i) = this.productElement(toInclude(i).asInstanceOf[Int]).asInstanceOf[Object]
100+
Tuple.fromArray(arr).asInstanceOf[Filter[This, P]]
101+
102+
object Tuple:
89103

90104
/** Type of a tuple with an element appended */
91105
type Append[X <: Tuple, Y] <: NonEmptyTuple = X match {
@@ -165,25 +179,38 @@ object Tuple {
165179
* ```
166180
* @syntax markdown
167181
*/
168-
type Filter[Tup <: Tuple, P[_] <: Boolean] <: Tuple = Tup match {
182+
type Filter[X <: Tuple, P[_] <: Boolean] <: Tuple = X match
169183
case EmptyTuple => EmptyTuple
170-
case h *: t => P[h] match {
184+
case h *: t => P[h] match
171185
case true => h *: Filter[t, P]
172186
case false => Filter[t, P]
173-
}
174-
}
175187

176-
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
177-
* where at least one of `At` or `Bt` is `EmptyTuple` or `Tuple`,
178-
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`
179-
* where `Ct` is `EmptyTuple` if `At` or `Bt` is `EmptyTuple`, otherwise `Ct` is `Tuple`.
188+
/** A tuple consisting of those indices `N` of tuple `X` where the predicate `P`
189+
* is true for `Elem[X, N]`. Indices are type level values <: Int.
180190
*/
181-
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match {
191+
type IndicesWhere[X <: Tuple, P[_] <: Boolean] =
192+
helpers.IndicesWhereHelper[X, P, 0]
193+
194+
/** The type of the tuple consisting of all element values of
195+
* tuple `X` zipped with corresponding elements of tuple `Y`.
196+
* If the two tuples have different sizes,
197+
* the extra elements of the larger tuple will be disregarded.
198+
* For example, if
199+
* ```
200+
* X = (S1, ..., Si)
201+
* Y = (T1, ..., Tj) where j >= i
202+
* ```
203+
* then
204+
* ```
205+
* Zip[X, Y] = ((S1, T1), ..., (Si, Ti))
206+
* ```
207+
* @syntax markdown
208+
*/
209+
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match
182210
case (h1 *: t1, h2 *: t2) => (h1, h2) *: Zip[t1, t2]
183211
case (EmptyTuple, _) => EmptyTuple
184212
case (_, EmptyTuple) => EmptyTuple
185213
case _ => Tuple
186-
}
187214

188215
/** Converts a tuple `(F[T1], ..., F[Tn])` to `(T1, ... Tn)` */
189216
type InverseMap[X <: Tuple, F[_]] <: Tuple = X match {
@@ -198,15 +225,13 @@ object Tuple {
198225
*/
199226
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F]
200227

201-
/** Type of the reversed tuple */
202-
type Reverse[X <: Tuple] = Helpers.ReverseImpl[EmptyTuple, X]
203-
204-
object Helpers:
228+
/** A tuple with the elements of tuple `X` in reversed order */
229+
type Reverse[X <: Tuple] = ReverseOnto[X, EmptyTuple]
205230

206-
/** Type of the reversed tuple */
207-
type ReverseImpl[Acc <: Tuple, X <: Tuple] <: Tuple = X match
208-
case x *: xs => ReverseImpl[x *: Acc, xs]
209-
case EmptyTuple => Acc
231+
/** A tuple with the elements of tuple `X` in reversed order added in front of `Acc` */
232+
type ReverseOnto[X <: Tuple, Acc <: Tuple] <: Tuple = X match
233+
case x *: xs => ReverseOnto[xs, x *: Acc]
234+
case EmptyTuple => Acc
210235

211236
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
212237
type Take[T <: Tuple, N <: Int] <: Tuple = N match {
@@ -275,7 +300,18 @@ object Tuple {
275300
given canEqualTuple[H1, T1 <: Tuple, H2, T2 <: Tuple](
276301
using eqHead: CanEqual[H1, H2], eqTail: CanEqual[T1, T2]
277302
): CanEqual[H1 *: T1, H2 *: T2] = CanEqual.derived
278-
}
303+
304+
object helpers:
305+
306+
/** Used to implement IndicesWhere */
307+
type IndicesWhereHelper[X <: Tuple, P[_] <: Boolean, N <: Int] <: Tuple = X match
308+
case EmptyTuple => EmptyTuple
309+
case h *: t => P[h] match
310+
case true => N *: IndicesWhereHelper[t, P, S[N]]
311+
case false => IndicesWhereHelper[t, P, S[N]]
312+
313+
end helpers
314+
end Tuple
279315

280316
/** A tuple of 0 elements */
281317
type EmptyTuple = EmptyTuple.type

0 commit comments

Comments
 (0)