1
1
package scala
2
2
import reflect .ClassTag
3
3
4
- import scala .collection .immutable
4
+ import scala .collection ._
5
+ import scala .collection .mutable .Buffer
5
6
6
7
/** An immutable array. An `IArray[T]` has the same representation as an `Array[T]`,
7
8
* but it cannot be updated. Unlike regular arrays, immutable arrays are covariant.
@@ -41,9 +42,6 @@ object opaques:
41
42
extension (arr : IArray [Object ]) def length : Int = arr.asInstanceOf [Array [Object ]].length
42
43
extension [T ](arr : IArray [T ]) def length : Int = arr.asInstanceOf [Array [T ]].length
43
44
44
- /** Returns this array concatenated with the given array. */
45
- extension [T ](arr : IArray [T ]) def ++ [U >: T : ClassTag ](that : IArray [U ]): IArray [U ] =
46
- genericArrayOps(arr) ++ that
47
45
48
46
/** Tests whether this array contains a given value as an element. */
49
47
extension [T ](arr : IArray [T ]) def contains (elem : T ): Boolean =
@@ -102,7 +100,7 @@ object opaques:
102
100
103
101
/** Flattens a two-dimensional array by concatenating all its rows
104
102
* into a single array. */
105
- extension [T ](arr : IArray [T ]) def flatten [U : ClassTag ](using T => Iterable [U ]): IArray [U ] =
103
+ extension [T ](arr : IArray [T ]) def flatten [U : ClassTag ](using asIterable : T => Iterable [U ]): IArray [U ] =
106
104
genericArrayOps(arr).flatten
107
105
108
106
/** Folds the elements of this array using the specified associative binary operator. */
@@ -238,10 +236,6 @@ object opaques:
238
236
extension [T ](arr : IArray [T ]) def splitAt (n : Int ): (IArray [T ], IArray [T ]) =
239
237
genericArrayOps(arr).splitAt(n)
240
238
241
- /** Tests whether this array starts with the given array. */
242
- extension [T ](arr : IArray [T ]) def startsWith [U >: T ](that : IArray [U ], offset : Int = 0 ): Boolean =
243
- genericArrayOps(arr).startsWith(that)
244
-
245
239
/** The rest of the array without its first element. */
246
240
extension [T ](arr : IArray [T ]) def tail : IArray [T ] =
247
241
genericArrayOps(arr).tail
@@ -262,15 +256,134 @@ object opaques:
262
256
extension [T ](arr : IArray [T ]) def toArray : Array [T ] =
263
257
arr.clone.asInstanceOf [Array [T ]]
264
258
265
- /** Converts an array of pairs into an array of first elements and an array of second elements. */
266
- extension [U : ClassTag , V : ClassTag ](arr : IArray [(U , V )]) def unzip : (IArray [U ], IArray [V ]) =
267
- genericArrayOps(arr).unzip
268
-
269
- /** Returns an array formed from this array and another iterable collection
270
- * by combining corresponding elements in pairs.
271
- * If one of the two collections is longer than the other, its remaining elements are ignored. */
272
- extension [T ](arr : IArray [T ]) def zip [U ](that : IArray [U ]): IArray [(T , U )] =
273
- genericArrayOps(arr).zip(that)
259
+ extension [T ](arr : IArray [T ])
260
+ // def ++[U >: T: ClassTag](suffix: IArray[U]): IArray[U] = genericArrayOps(arr) ++ suffix.toSeq
261
+ def ++ [U >: T : ClassTag ](suffix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr) ++ suffix
262
+ def :+ [U >: T : ClassTag ](x : U ): IArray [U ] = genericArrayOps(arr) :+ x
263
+ // def :++ [U >: T: ClassTag](suffix: IArray[U]): IArray[U] = genericArrayOps(arr) :++ suffix
264
+ def :++ [U >: T : ClassTag ](suffix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr) :++ suffix
265
+ def addString (b : mutable.StringBuilder ): mutable.StringBuilder = arr.toSeq.addString(b)
266
+ def addString (b : mutable.StringBuilder , sep : String ): mutable.StringBuilder = arr.toSeq.addString(b, sep)
267
+ def addString (b : mutable.StringBuilder , start : String , sep : String , end : String ): mutable.StringBuilder = arr.toSeq.addString(b, start, sep, end)
268
+ def appended [U >: T : ClassTag ](x : U ): IArray [U ] = genericArrayOps(arr).appended(x)
269
+ // def appendedAll[U >: T: ClassTag](suffix: IArray[U]): IArray[U] = genericArrayOps(arr).appendedAll(suffix)
270
+ def appendedAll [U >: T : ClassTag ](suffix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr).appendedAll(suffix)
271
+ def collect [U : ClassTag ](pf : PartialFunction [T , U ]): IArray [U ] = genericArrayOps(arr).collect(pf)
272
+ def collectFirst [U ](f : PartialFunction [T , U ]): Option [U ] = genericArrayOps(arr).collectFirst(f)
273
+ def combinations (n : Int ): Iterator [IArray [T ]] = genericArrayOps(arr).combinations(n)
274
+ // def concat[U >: T: ClassTag](suffix: IArray[U]): IArray[U] = genericArrayOps(arr).concat(suffix)
275
+ def concat [U >: T : ClassTag ](suffix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr).concat(suffix)
276
+ // def containsSlice[U](that: IArray[U]): Boolean = arr.toSeq.containsSlice(that.toSeq)
277
+ def containsSlice [U ](that : Seq [U ]): Boolean = arr.toSeq.containsSlice(that)
278
+ // def corresponds[U](that: IArray[U])(p: (T, U) => Boolean): Boolean = arr.toSeq.corresponds(that.toSeq)(p)
279
+ def corresponds [U ](that : IterableOnce [U ])(p : (T , U ) => Boolean ): Boolean = arr.toSeq.corresponds(that)(p)
280
+ // def diff[U >: T](that: IArray[U]): IArray[T] = genericArrayOps(arr).diff(that.toSeq)
281
+ def diff [U >: T ](that : Seq [U ]): IArray [T ] = genericArrayOps(arr).diff(that)
282
+ def distinct : IArray [T ] = genericArrayOps(arr).distinct
283
+ def distinctBy [U ](f : T => U ): IArray [T ] = genericArrayOps(arr).distinctBy(f)
284
+ def empty : immutable.ArraySeq [T ] = arr.toSeq.empty
285
+ // def startsWith[U >: T](that: IArray[U], offset: Int = 0): Boolean = genericArrayOps(arr).startsWith(that)
286
+ def startsWith [U >: T ](that : IterableOnce [U ], offset : Int = 0 ): Boolean = genericArrayOps(arr).startsWith(that, offset)
287
+ // def endsWith[U >: T](that: IArray[U]): Boolean = genericArrayOps(arr).endsWith(that)
288
+ def endsWith [U >: T ](that : Iterable [U ]): Boolean = genericArrayOps(arr).endsWith(that)
289
+ def findLast (p : T => Boolean ): Option [T ] = arr.toSeq.findLast(p)
290
+ def groupBy [K ](f : T => K ): immutable.Map [K , IArray [T ]] = genericArrayOps(arr).groupBy(f)
291
+ def groupMap [K , U : ClassTag ](key : T => K )(f : T => U ): immutable.Map [K , IArray [U ]] = genericArrayOps(arr).groupMap(key)(f)
292
+ def groupMapReduce [K , U ](key : (T ) => K )(f : (T ) => U )(reduce : (U , U ) => U ): immutable.Map [K , U ] = arr.toSeq.groupMapReduce(key)(f)(reduce)
293
+ def grouped (size : Int ): Iterator [IArray [T ]] = genericArrayOps(arr).grouped(size)
294
+ // def indexOfSlice[U >: T](that: IArray[U]): Int = arr.toSeq.indexOfSlice(that)
295
+ def indexOfSlice [U >: T ](that : Seq [U ]): Int = arr.toSeq.indexOfSlice(that)
296
+ // def indexOfSlice[U >: T](that: IArray[U], from: Int): Int = arr.toSeq.indexOfSlice(that, from)
297
+ def indexOfSlice [U >: T ](that : Seq [U ], from : Int ): Int = arr.toSeq.indexOfSlice(that, from)
298
+ def inits : Iterator [IArray [T ]] = genericArrayOps(arr).inits
299
+ // def intersect[U >: T](that: IArray[U]): IArray[T] = genericArrayOps(arr).intersect(that)
300
+ def intersect [U >: T ](that : Seq [U ]): IArray [T ] = genericArrayOps(arr).intersect(that)
301
+ def isTraversableAgain : Boolean = arr.toSeq.isTraversableAgain
302
+ def knownSize : Int = arr.length
303
+ // def lastIndexOfSlice[U >: T](that: IArray[U]): Int = arr.toSeq.lastIndexOfSlice(that)
304
+ def lastIndexOfSlice [U >: T ](that : Seq [U ]): Int = arr.toSeq.lastIndexOfSlice(that)
305
+ // def lastIndexOfSlice[U >: T](that: IArray[U], end: Int): Int = arr.toSeq.lastIndexOfSlice(that, end)
306
+ def lastIndexOfSlice [U >: T ](that : Seq [U ], end : Int ): Int = arr.toSeq.lastIndexOfSlice(that, end)
307
+ // def lazyZip[U](that: IArray[U]): LazyZip2[T, U, IArray[T]] = genericArrayOps(arr).lazyZip[U](that).asInstanceOf[LazyZip2[T, U, IArray[T]]]
308
+ def lazyZip [U ](that : Iterable [U ]): LazyZip2 [T , U , IArray [T ]] = genericArrayOps(arr).lazyZip[U ](that).asInstanceOf [LazyZip2 [T , U , IArray [T ]]]
309
+ def lengthCompare (len : Int ): Int = genericArrayOps(arr).lengthCompare(len)
310
+ def lengthIs : IterableOps .SizeCompareOps = arr.toSeq.lengthIs
311
+ def max [U >: T ](using math.Ordering [U ]): T = arr.toSeq.max[U ]
312
+ def maxBy [U ](f : T => U )(using math.Ordering [U ]): T = arr.toSeq.maxBy(f)
313
+ def maxByOption [U ](f : T => U )(using math.Ordering [U ]): Option [T ] = arr.toSeq.maxByOption(f)
314
+ def maxOption [U >: T ](using math.Ordering [U ]): Option [U ] = arr.toSeq.maxOption[U ]
315
+ def min [U >: T ](using math.Ordering [U ]): T = arr.toSeq.min[U ]
316
+ def minBy [U ](f : T => U )(using math.Ordering [U ]): T = arr.toSeq.minBy(f)
317
+ def minByOption [U ](f : T => U )(using math.Ordering [U ]): Option [T ] = arr.toSeq.minByOption(f)
318
+ def minOption [U >: T ](using math.Ordering [U ]): Option [U ] = arr.toSeq.minOption[U ]
319
+ def mkString : String = arr.toSeq.mkString
320
+ def mkString (sep : String ): String = arr.toSeq.mkString(sep)
321
+ def mkString (start : String , sep : String , end : String ): String = arr.toSeq.mkString(start, sep, end)
322
+ def padTo [U >: T : ClassTag ](len : Int , elem : U ): IArray [U ] = genericArrayOps(arr).padTo(len, elem)
323
+ def partitionMap [T1 : ClassTag , T2 : ClassTag ](f : T => Either [T1 , T2 ]): (IArray [T1 ], IArray [T2 ]) = genericArrayOps(arr).partitionMap(f)
324
+ def patch [U >: T : ClassTag ](from : Int , other : IterableOnce [U ], replaced : Int ): IArray [U ] = genericArrayOps(arr).patch(from, other, replaced)
325
+ def permutations : Iterator [IArray [T ]] = genericArrayOps(arr).permutations
326
+ def prepended [U >: T : ClassTag ](x : U ): IArray [U ] = genericArrayOps(arr).prepended(x)
327
+ def prependedAll [U >: T : ClassTag ](prefix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr).prependedAll(prefix)
328
+ def product [U >: T ](using math.Numeric [U ]): U = arr.toSeq.product[U ]
329
+ def reduce [U >: T ](op : (U , U ) => U ): U = arr.toSeq.reduce(op)
330
+ def reduceLeft [U >: T ](op : (U , T ) => U ): U = arr.toSeq.reduceLeft(op)
331
+ def reduceRight [U >: T ](op : (T , U ) => U ): U = arr.toSeq.reduceRight(op)
332
+ def reverseIterator : Iterator [T ] = genericArrayOps(arr).reverseIterator
333
+ // def sameElements[U >: T](that: IArray[U]): Boolean = arr.toSeq.sameElements(that)
334
+ def sameElements [U >: T ](that : IterableOnce [U ]): Boolean = arr.toSeq.sameElements(that)
335
+ def search [U >: T ](elem : U )(using Ordering [U ]): Searching .SearchResult = arr.toSeq.search(elem)
336
+ def search [U >: T ](elem : U , from : Int , to : Int )(using Ordering [U ]): Searching .SearchResult = arr.toSeq.search(elem, from, to)
337
+ def segmentLength (p : (T ) => Boolean , from : Int ): Int = arr.toSeq.segmentLength(p, from)
338
+ def segmentLength (p : (T ) => Boolean ): Int = arr.toSeq.segmentLength(p)
339
+ // def sizeCompare(that: IArray[_]): Int = arr.toSeq.sizeCompare(that)
340
+ def sizeCompare (that : Iterable [_]): Int = arr.toSeq.sizeCompare(that)
341
+ def sizeCompare (otherSize : Int ): Int = genericArrayOps(arr).sizeCompare(otherSize)
342
+ def sizeIs : IterableOps .SizeCompareOps = arr.toSeq.sizeIs
343
+ def sliding (size : Int , step : Int = 1 ): Iterator [IArray [T ]] = genericArrayOps(arr).sliding(size, step)
344
+ def stepper [S <: Stepper [_]](using StepperShape [T , S ]): S = genericArrayOps(arr).stepper[S ]
345
+ def sum [U >: T ](using math.Numeric [U ]): U = arr.toSeq.sum[U ]
346
+ def tails : Iterator [IArray [T ]] = genericArrayOps(arr).tails
347
+ def tapEach [U ](f : (T ) => U ): IArray [T ] =
348
+ arr.toSeq.foreach(f)
349
+ arr
350
+ def to [C1 ](factory : Factory [T , C1 ]): C1 = arr.toSeq.to(factory)
351
+ def toBuffer [U >: T ]: Buffer [U ] = arr.toSeq.toBuffer[U ]
352
+ def toIndexedSeq : immutable.IndexedSeq [T ] = arr.toSeq.toIndexedSeq
353
+ def toIterable : Iterable [T ] = arr.toSeq.toIterable
354
+ def toList : List [T ] = arr.toSeq.toList
355
+ def toSet : Set [T ] = arr.toSeq.toSet
356
+ def toVector : Vector [T ] = arr.toSeq.toVector
357
+ def unzip [T1 , T2 ](using asPair : T => (T1 , T2 ), ct1 : ClassTag [T1 ], ct2 : ClassTag [T2 ]): (IArray [T1 ], IArray [T2 ]) = genericArrayOps(arr).unzip
358
+ def unzip3 [T1 , T2 , T3 ](using asTriple : T => (T1 , T2 , T3 ), ct1 : ClassTag [T1 ], ct2 : ClassTag [T2 ], ct3 : ClassTag [T3 ]): (IArray [T1 ], IArray [T2 ], IArray [T3 ]) = genericArrayOps(arr).unzip3
359
+ def updated [U >: T : ClassTag ](index : Int , elem : U ): IArray [U ] = genericArrayOps(arr).updated(index, elem)
360
+ def view : SeqView [T ] = genericArrayOps(arr).view
361
+ def withFilter (p : T => Boolean ): IArray .WithFilter [T ] = new IArray .WithFilter (p, arr)
362
+ // def zip[U](that: IArray[U]): IArray[(T, U)] = genericArrayOps(arr).zip(that)
363
+ def zip [U ](that : IterableOnce [U ]): IArray [(T , U )] = genericArrayOps(arr).zip(that)
364
+ // def zipAll[T1 >: T, U](that: IArray[U], thisElem: T1, thatElem: U): IArray[(T1, U)] = genericArrayOps(arr).zipAll(that, thisElem, thatElem)
365
+ def zipAll [T1 >: T , U ](that : Iterable [U ], thisElem : T1 , thatElem : U ): IArray [(T1 , U )] = genericArrayOps(arr).zipAll(that, thisElem, thatElem)
366
+ def zipWithIndex : IArray [(T , Int )] = genericArrayOps(arr).zipWithIndex
367
+ end extension
368
+
369
+ extension [T ](arr : IArray [T ])
370
+ def transpose [U ](implicit asArray : T => IArray [U ]): IArray [IArray [U ]] =
371
+ genericArrayOps(arr).transpose(using asArray.asInstanceOf [T => Array [U ]])
372
+
373
+ extension [T : ClassTag ](arr : IArray [IterableOnce [T ]])
374
+ def flatten : IArray [T ] = genericArrayOps(arr).flatten
375
+
376
+ extension [T , U >: T : ClassTag ](prefix : IterableOnce [T ])
377
+ def ++: (arr : IArray [U ]): IArray [U ] = genericArrayOps(arr).prependedAll(prefix)
378
+
379
+ extension [T , U >: T : ClassTag ](prefix : IArray [T ])
380
+ def ++: (arr : IArray [U ]): IArray [U ] = genericArrayOps(arr).prependedAll(prefix)
381
+
382
+ extension [T , U >: T : ClassTag ](x : T )
383
+ def +: (arr : IArray [U ]): IArray [U ] = genericArrayOps(arr).prepended(x)
384
+
385
+ extension [T1 , T2 ](arr : IArray [(T1 , T2 )])
386
+ def toMap : Map [T1 , T2 ] = arr.toSeq.toMap
274
387
275
388
/** Conversion from IArray to immutable.ArraySeq */
276
389
extension [T ](arr : IArray [T ]) def toSeq : immutable.ArraySeq [T ] =
@@ -320,7 +433,7 @@ end opaques
320
433
321
434
type IArray [+ T ] = opaques.IArray [T ]
322
435
323
- object IArray {
436
+ object IArray :
324
437
import opaques .Sub
325
438
import opaques .Sup
326
439
@@ -385,7 +498,7 @@ object IArray {
385
498
// `Array.concat` should arguably take in a `Seq[Array[_ <: T]]`,
386
499
// but since it currently takes a `Seq[Array[T]]` we have to perform a cast,
387
500
// knowing tacitly that `concat` is not going to do the wrong thing.
388
- Array .concat[T ](xss.asInstanceOf [Seq [Array [T ]]]: _* )
501
+ Array .concat[T ](xss.asInstanceOf [immutable. Seq [Array [T ]]]: _* )
389
502
390
503
/** Returns an immutable array that contains the results of some element computation a number
391
504
* of times. Each element is determined by a separate computation.
@@ -535,4 +648,67 @@ object IArray {
535
648
// The double type ascription is currently needed,
536
649
// for some reason (see: https://scastie.scala-lang.org/sSsmOhKxSKym405MgNRKqQ)
537
650
Array .unapplySeq((x : Sup [T ]): Array [_ <: T ])
538
- }
651
+
652
+ // TODO where should this class be defined? The WithFilter for Array is in ArrayOps.
653
+ /** A lazy filtered array. No filtering is applied until one of `foreach`, `map` or `flatMap` is called. */
654
+ class WithFilter [T ](p : T => Boolean , xs : IArray [T ]):
655
+
656
+ /** Apply `f` to each element for its side effects.
657
+ * Note: [U] parameter needed to help scalac's type inference.
658
+ */
659
+ def foreach [U ](f : T => U ): Unit = {
660
+ val len = xs.length
661
+ var i = 0
662
+ while (i < len) {
663
+ val x = xs(i)
664
+ if (p(x)) f(x)
665
+ i += 1
666
+ }
667
+ }
668
+
669
+ /** Builds a new array by applying a function to all elements of this array.
670
+ *
671
+ * @param f the function to apply to each element.
672
+ * @tparam U the element type of the returned array.
673
+ * @return a new array resulting from applying the given function
674
+ * `f` to each element of this array and collecting the results.
675
+ */
676
+ def map [U : ClassTag ](f : T => U ): IArray [U ] = {
677
+ val b = mutable.ArrayBuilder .make[U ]
678
+ var i = 0
679
+ while (i < xs.length) {
680
+ val x = xs(i)
681
+ if (p(x)) b += f(x)
682
+ i = i + 1
683
+ }
684
+ b.result()
685
+ }
686
+
687
+ /** Builds a new array by applying a function to all elements of this array
688
+ * and using the elements of the resulting collections.
689
+ *
690
+ * @param f the function to apply to each element.
691
+ * @tparam U the element type of the returned array.
692
+ * @return a new array resulting from applying the given collection-valued function
693
+ * `f` to each element of this array and concatenating the results.
694
+ */
695
+ def flatMap [U : ClassTag ](f : T => IterableOnce [U ]): IArray [U ] = {
696
+ val b = mutable.ArrayBuilder .make[U ]
697
+ var i = 0
698
+ while (i < xs.length) {
699
+ val x = xs(i)
700
+ if (p(x)) b ++= f(xs(i))
701
+ i += 1
702
+ }
703
+ b.result()
704
+ }
705
+
706
+ def flatMap [BS , U ](f : T => BS )(using asIterable : BS => Iterable [U ], m : ClassTag [U ]): IArray [U ] =
707
+ flatMap[U ](x => asIterable(f(x)))
708
+
709
+ /** Creates a new non-strict filter which combines this filter with the given predicate. */
710
+ def withFilter (q : T => Boolean ): WithFilter [T ] = new WithFilter [T ](a => p(a) && q(a), xs)
711
+
712
+ end WithFilter
713
+
714
+ end IArray
0 commit comments