1
1
package scala
2
2
import reflect .ClassTag
3
3
4
- import scala .collection .immutable
4
+ import scala .collection .{LazyZip2 , SeqView , Searching , Stepper , StepperShape }
5
+ import scala .collection .immutable .ArraySeq
6
+ import scala .collection .mutable .{ArrayBuilder , Builder }
5
7
6
8
opaque type IArray [+ T ] = Array [_ <: T ]
7
9
@@ -39,15 +41,10 @@ object IArray:
39
41
extension (arr : IArray [Object ]) def length : Int = arr.asInstanceOf [Array [Object ]].length
40
42
extension [T ](arr : IArray [T ]) def length : Int = arr.asInstanceOf [Array [T ]].length
41
43
42
- /** Returns this array concatenated with the given array. */
43
- extension [T ](arr : IArray [T ]) def ++ [U >: T : ClassTag ](that : IArray [U ]): IArray [U ] =
44
- genericArrayOps(arr) ++ that
45
44
46
45
/** Tests whether this array contains a given value as an element. */
47
46
extension [T ](arr : IArray [T ]) def contains (elem : T ): Boolean =
48
- // `genericArrayOps(arr).contains(elem)` does not work because `elem` does not have type `arr.T`
49
- // but we can use `exists` instead, which is how `ArrayOps#contains` itself is implemented:
50
- genericArrayOps(arr).exists(_ == elem)
47
+ genericArrayOps(arr).contains(elem.asInstanceOf )
51
48
52
49
/** Copy elements of this array to another array. */
53
50
extension [T ](arr : IArray [T ]) def copyToArray [U >: T ](xs : Array [U ]): Int =
@@ -100,7 +97,7 @@ object IArray:
100
97
101
98
/** Flattens a two-dimensional array by concatenating all its rows
102
99
* into a single array. */
103
- extension [T ](arr : IArray [T ]) def flatten [U : ClassTag ](using T => Iterable [U ]): IArray [U ] =
100
+ extension [T ](arr : IArray [T ]) def flatten [U ](using asIterable : T => Iterable [ U ], ct : ClassTag [U ]): IArray [U ] =
104
101
genericArrayOps(arr).flatten
105
102
106
103
/** Folds the elements of this array using the specified associative binary operator. */
@@ -236,10 +233,6 @@ object IArray:
236
233
extension [T ](arr : IArray [T ]) def splitAt (n : Int ): (IArray [T ], IArray [T ]) =
237
234
genericArrayOps(arr).splitAt(n)
238
235
239
- /** Tests whether this array starts with the given array. */
240
- extension [T ](arr : IArray [T ]) def startsWith [U >: T ](that : IArray [U ], offset : Int = 0 ): Boolean =
241
- genericArrayOps(arr).startsWith(that)
242
-
243
236
/** The rest of the array without its first element. */
244
237
extension [T ](arr : IArray [T ]) def tail : IArray [T ] =
245
238
genericArrayOps(arr).tail
@@ -260,59 +253,127 @@ object IArray:
260
253
extension [T ](arr : IArray [T ]) def toArray : Array [T ] =
261
254
arr.clone.asInstanceOf [Array [T ]]
262
255
263
- /** Converts an array of pairs into an array of first elements and an array of second elements. */
264
- extension [U : ClassTag , V : ClassTag ](arr : IArray [(U , V )]) def unzip : (IArray [U ], IArray [V ]) =
265
- genericArrayOps(arr).unzip
266
-
267
- /** Returns an array formed from this array and another iterable collection
268
- * by combining corresponding elements in pairs.
269
- * If one of the two collections is longer than the other, its remaining elements are ignored. */
270
- extension [T ](arr : IArray [T ]) def zip [U ](that : IArray [U ]): IArray [(T , U )] =
271
- genericArrayOps(arr).zip(that)
256
+ extension [T ](arr : IArray [T ])
257
+ def ++ [U >: T : ClassTag ](suffix : IArray [U ]): IArray [U ] = genericArrayOps(arr) ++ suffix.toSeq
258
+ def ++ [U >: T : ClassTag ](suffix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr) ++ suffix
259
+ def :+ [U >: T : ClassTag ](x : U ): IArray [U ] = genericArrayOps(arr) :+ x
260
+ def :++ [U >: T : ClassTag ](suffix : IArray [U ]): IArray [U ] = genericArrayOps(arr) :++ suffix
261
+ def :++ [U >: T : ClassTag ](suffix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr) :++ suffix
262
+ def appended [U >: T : ClassTag ](x : U ): IArray [U ] = genericArrayOps(arr).appended(x)
263
+ def appendedAll [U >: T : ClassTag ](suffix : IArray [U ]): IArray [U ] = genericArrayOps(arr).appendedAll(suffix)
264
+ def appendedAll [U >: T : ClassTag ](suffix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr).appendedAll(suffix)
265
+ def collect [U : ClassTag ](pf : PartialFunction [T , U ]): IArray [U ] = genericArrayOps(arr).collect(pf)
266
+ def collectFirst [U ](f : PartialFunction [T , U ]): Option [U ] = genericArrayOps(arr).collectFirst(f)
267
+ def combinations (n : Int ): Iterator [IArray [T ]] = genericArrayOps(arr).combinations(n)
268
+ def concat [U >: T : ClassTag ](suffix : IArray [U ]): IArray [U ] = genericArrayOps(arr).concat(suffix)
269
+ def concat [U >: T : ClassTag ](suffix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr).concat(suffix)
270
+ def diff [U >: T ](that : IArray [U ]): IArray [T ] = genericArrayOps(arr).diff(that.toSeq)
271
+ def diff [U >: T ](that : Seq [U ]): IArray [T ] = genericArrayOps(arr).diff(that)
272
+ def distinct : IArray [T ] = genericArrayOps(arr).distinct
273
+ def distinctBy [U ](f : T => U ): IArray [T ] = genericArrayOps(arr).distinctBy(f)
274
+ def startsWith [U >: T ](that : IArray [U ]): Boolean = genericArrayOps(arr).startsWith(that, 0 )
275
+ def startsWith [U >: T ](that : IArray [U ], offset : Int ): Boolean = genericArrayOps(arr).startsWith(that, offset)
276
+ def startsWith [U >: T ](that : IterableOnce [U ]): Boolean = genericArrayOps(arr).startsWith(that, 0 )
277
+ def startsWith [U >: T ](that : IterableOnce [U ], offset : Int ): Boolean = genericArrayOps(arr).startsWith(that, offset)
278
+ def endsWith [U >: T ](that : IArray [U ]): Boolean = genericArrayOps(arr).endsWith(that)
279
+ def endsWith [U >: T ](that : Iterable [U ]): Boolean = genericArrayOps(arr).endsWith(that)
280
+ def groupBy [K ](f : T => K ): Map [K , IArray [T ]] = genericArrayOps(arr).groupBy(f)
281
+ def groupMap [K , U : ClassTag ](key : T => K )(f : T => U ): Map [K , IArray [U ]] = genericArrayOps(arr).groupMap(key)(f)
282
+ def grouped (size : Int ): Iterator [IArray [T ]] = genericArrayOps(arr).grouped(size)
283
+ def inits : Iterator [IArray [T ]] = genericArrayOps(arr).inits
284
+ def intersect [U >: T ](that : IArray [U ]): IArray [T ] = genericArrayOps(arr).intersect(that)
285
+ def intersect [U >: T ](that : Seq [U ]): IArray [T ] = genericArrayOps(arr).intersect(that)
286
+ def lazyZip [U ](that : IArray [U ]): LazyZip2 [T , U , IArray [T ]] = genericArrayOps(arr).lazyZip[U ](that).asInstanceOf [LazyZip2 [T , U , IArray [T ]]]
287
+ def lazyZip [U ](that : Iterable [U ]): LazyZip2 [T , U , IArray [T ]] = genericArrayOps(arr).lazyZip[U ](that).asInstanceOf [LazyZip2 [T , U , IArray [T ]]]
288
+ def lengthCompare (len : Int ): Int = genericArrayOps(arr).lengthCompare(len)
289
+ def padTo [U >: T : ClassTag ](len : Int , elem : U ): IArray [U ] = genericArrayOps(arr).padTo(len, elem)
290
+ def partitionMap [T1 : ClassTag , T2 : ClassTag ](f : T => Either [T1 , T2 ]): (IArray [T1 ], IArray [T2 ]) = genericArrayOps(arr).partitionMap(f)
291
+ def patch [U >: T : ClassTag ](from : Int , other : IterableOnce [U ], replaced : Int ): IArray [U ] = genericArrayOps(arr).patch(from, other, replaced)
292
+ def permutations : Iterator [IArray [T ]] = genericArrayOps(arr).permutations
293
+ def prepended [U >: T : ClassTag ](x : U ): IArray [U ] = genericArrayOps(arr).prepended(x)
294
+ def prependedAll [U >: T : ClassTag ](prefix : IterableOnce [U ]): IArray [U ] = genericArrayOps(arr).prependedAll(prefix)
295
+ def reverseIterator : Iterator [T ] = genericArrayOps(arr).reverseIterator
296
+ def search [U >: T ](elem : U )(using Ordering [U ]): Searching .SearchResult = arr.toSeq.search(elem)
297
+ def search [U >: T ](elem : U , from : Int , to : Int )(using Ordering [U ]): Searching .SearchResult = arr.toSeq.search(elem, from, to)
298
+ def sizeCompare (that : IArray [Any ]): Int = arr.toSeq.sizeCompare(that)
299
+ def sizeCompare (that : Iterable [_]): Int = arr.toSeq.sizeCompare(that)
300
+ def sizeCompare (otherSize : Int ): Int = genericArrayOps(arr).sizeCompare(otherSize)
301
+ def sliding (size : Int , step : Int = 1 ): Iterator [IArray [T ]] = genericArrayOps(arr).sliding(size, step)
302
+ def stepper [S <: Stepper [_]](using StepperShape [T , S ]): S = genericArrayOps(arr).stepper[S ]
303
+ def tails : Iterator [IArray [T ]] = genericArrayOps(arr).tails
304
+ def tapEach [U ](f : (T ) => U ): IArray [T ] =
305
+ arr.toSeq.foreach(f)
306
+ arr
307
+ def transpose [U ](implicit asArray : T => IArray [U ]): IArray [IArray [U ]] =
308
+ genericArrayOps(arr).transpose(using asArray.asInstanceOf [T => Array [U ]])
309
+ def unzip [T1 , T2 ](using asPair : T => (T1 , T2 ), ct1 : ClassTag [T1 ], ct2 : ClassTag [T2 ]): (IArray [T1 ], IArray [T2 ]) = genericArrayOps(arr).unzip
310
+ 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
311
+ def updated [U >: T : ClassTag ](index : Int , elem : U ): IArray [U ] = genericArrayOps(arr).updated(index, elem)
312
+ def view : SeqView [T ] = genericArrayOps(arr).view
313
+ def withFilter (p : T => Boolean ): WithFilter [T ] = new WithFilter (p, arr)
314
+ def zip [U ](that : IArray [U ]): IArray [(T , U )] = genericArrayOps(arr).zip(that)
315
+ def zip [U ](that : IterableOnce [U ]): IArray [(T , U )] = genericArrayOps(arr).zip(that)
316
+ def zipAll [T1 >: T , U ](that : IArray [U ], thisElem : T1 , thatElem : U ): IArray [(T1 , U )] = genericArrayOps(arr).zipAll(that, thisElem, thatElem)
317
+ def zipAll [T1 >: T , U ](that : Iterable [U ], thisElem : T1 , thatElem : U ): IArray [(T1 , U )] = genericArrayOps(arr).zipAll(that, thisElem, thatElem)
318
+ def zipWithIndex : IArray [(T , Int )] = genericArrayOps(arr).zipWithIndex
319
+
320
+ extension [T , U >: T : ClassTag ](prefix : IterableOnce [T ])
321
+ def ++: (arr : IArray [U ]): IArray [U ] = genericArrayOps(arr).prependedAll(prefix)
322
+
323
+ extension [T , U >: T : ClassTag ](prefix : IArray [T ])
324
+ def ++: (arr : IArray [U ]): IArray [U ] = genericArrayOps(arr).prependedAll(prefix)
325
+
326
+ extension [T , U >: T : ClassTag ](x : T )
327
+ def +: (arr : IArray [U ]): IArray [U ] = genericArrayOps(arr).prepended(x)
272
328
273
329
/** Conversion from IArray to immutable.ArraySeq */
274
- extension [T ](arr : IArray [T ]) def toSeq : immutable. ArraySeq [T ] =
275
- immutable. ArraySeq .unsafeWrapArray(arr. asInstanceOf [ Array [ T ]] )
330
+ implicit def genericWrapArray [T ](arr : IArray [T ]): ArraySeq [T ] =
331
+ if arr eq null then null else ArraySeq .unsafeWrapArray(arr)
276
332
277
333
/** Conversion from IArray to immutable.ArraySeq */
278
- extension [T <: AnyRef ](arr : IArray [T ]) def toSeq : immutable.ArraySeq [T ] =
279
- immutable.ArraySeq .ofRef(arr.asInstanceOf [Array [T ]])
334
+ implicit def wrapRefArray [T <: AnyRef ](arr : IArray [T ]): ArraySeq .ofRef[T ] =
335
+ // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef]
336
+ // is as good as another for all T <: AnyRef. Instead of creating 100,000,000
337
+ // unique ones by way of this implicit, let's share one.
338
+ if (arr eq null ) null
339
+ else if (arr.length == 0 ) ArraySeq .empty[AnyRef ].asInstanceOf [ArraySeq .ofRef[T ]]
340
+ else ArraySeq .ofRef(arr.asInstanceOf [Array [T ]])
280
341
281
342
/** Conversion from IArray to immutable.ArraySeq */
282
- extension (arr : IArray [Int ]) def toSeq : immutable. ArraySeq [ Int ] =
283
- immutable. ArraySeq .ofInt(arr.asInstanceOf [Array [Int ]])
343
+ implicit def wrapIntArray (arr : IArray [Int ]): ArraySeq .ofInt =
344
+ if (arr ne null ) new ArraySeq .ofInt(arr.asInstanceOf [Array [Int ]]) else null
284
345
285
346
/** Conversion from IArray to immutable.ArraySeq */
286
- extension (arr : IArray [Double ]) def toSeq : immutable. ArraySeq [ Double ] =
287
- immutable. ArraySeq .ofDouble(arr.asInstanceOf [Array [Double ]])
347
+ implicit def wrapDoubleIArray (arr : IArray [Double ]): ArraySeq .ofDouble =
348
+ if (arr ne null ) new ArraySeq .ofDouble(arr.asInstanceOf [Array [Double ]]) else null
288
349
289
350
/** Conversion from IArray to immutable.ArraySeq */
290
- extension (arr : IArray [Long ]) def toSeq : immutable. ArraySeq [ Long ] =
291
- immutable. ArraySeq .ofLong(arr.asInstanceOf [Array [Long ]])
351
+ implicit def wrapLongIArray (arr : IArray [Long ]): ArraySeq .ofLong =
352
+ if (arr ne null ) new ArraySeq .ofLong(arr.asInstanceOf [Array [Long ]]) else null
292
353
293
354
/** Conversion from IArray to immutable.ArraySeq */
294
- extension (arr : IArray [Float ]) def toSeq : immutable. ArraySeq [ Float ] =
295
- immutable. ArraySeq .ofFloat(arr.asInstanceOf [Array [Float ]])
355
+ implicit def wrapFloatIArray (arr : IArray [Float ]): ArraySeq .ofFloat =
356
+ if (arr ne null ) new ArraySeq .ofFloat(arr.asInstanceOf [Array [Float ]]) else null
296
357
297
358
/** Conversion from IArray to immutable.ArraySeq */
298
- extension (arr : IArray [Char ]) def toSeq : immutable. ArraySeq [ Char ] =
299
- immutable. ArraySeq .ofChar(arr.asInstanceOf [Array [Char ]])
359
+ implicit def wrapCharIArray (arr : IArray [Char ]): ArraySeq .ofChar =
360
+ if (arr ne null ) new ArraySeq .ofChar(arr.asInstanceOf [Array [Char ]]) else null
300
361
301
362
/** Conversion from IArray to immutable.ArraySeq */
302
- extension (arr : IArray [Byte ]) def toSeq : immutable. ArraySeq [ Byte ] =
303
- immutable. ArraySeq .ofByte(arr.asInstanceOf [Array [Byte ]])
363
+ implicit def wrapByteIArray (arr : IArray [Byte ]): ArraySeq .ofByte =
364
+ if (arr ne null ) new ArraySeq .ofByte(arr.asInstanceOf [Array [Byte ]]) else null
304
365
305
366
/** Conversion from IArray to immutable.ArraySeq */
306
- extension (arr : IArray [Short ]) def toSeq : immutable. ArraySeq [ Short ] =
307
- immutable. ArraySeq .ofShort(arr.asInstanceOf [Array [Short ]])
367
+ implicit def wrapShortIArray (arr : IArray [Short ]): ArraySeq .ofShort =
368
+ if (arr ne null ) new ArraySeq .ofShort(arr.asInstanceOf [Array [Short ]]) else null
308
369
309
370
/** Conversion from IArray to immutable.ArraySeq */
310
- extension (arr : IArray [Boolean ]) def toSeq : immutable. ArraySeq [ Boolean ] =
311
- immutable. ArraySeq .ofBoolean(arr.asInstanceOf [Array [Boolean ]])
371
+ implicit def wrapBooleanIArray (arr : IArray [Boolean ]): ArraySeq .ofBoolean =
372
+ if (arr ne null ) new ArraySeq .ofBoolean(arr.asInstanceOf [Array [Boolean ]]) else null
312
373
313
374
/** Conversion from IArray to immutable.ArraySeq */
314
- extension (arr : IArray [Unit ]) def toSeq : immutable. ArraySeq [ Unit ] =
315
- immutable. ArraySeq .ofUnit(arr.asInstanceOf [Array [Unit ]])
375
+ implicit def wrapUnitIArray (arr : IArray [Unit ]): ArraySeq .ofUnit =
376
+ if (arr ne null ) new ArraySeq .ofUnit(arr.asInstanceOf [Array [Unit ]]) else null
316
377
317
378
/** Convert an array into an immutable array without copying, the original array
318
379
* must _not_ be mutated after this or the guaranteed immutablity of IArray will
@@ -363,6 +424,25 @@ object IArray:
363
424
/** An immutable array with given elements. */
364
425
def apply (x : Unit , xs : Unit * ): IArray [Unit ] = Array (x, xs : _* )
365
426
427
+ /** Build an array from the iterable collection.
428
+ *
429
+ * {{{
430
+ * scala> val a = Array.from(Seq(1, 5))
431
+ * val a: Array[Int] = Array(1, 5)
432
+ *
433
+ * scala> val b = Array.from(Range(1, 5))
434
+ * val b: Array[Int] = Array(1, 2, 3, 4)
435
+ * }}}
436
+ *
437
+ * @param it the iterable collection
438
+ * @return an array consisting of elements of the iterable collection
439
+ */
440
+ def from [A : ClassTag ](it : IterableOnce [A ]): Array [A ] =
441
+ Array .from(it)
442
+
443
+ def newBuilder [T ](using t : ClassTag [T ]): Builder [T , IArray [T ]] =
444
+ ArrayBuilder .make[T ].mapResult(IArray .unsafeFromArray)
445
+
366
446
/** Concatenates all arrays into a single immutable array.
367
447
*
368
448
* @param xss the given immutable arrays
@@ -391,7 +471,6 @@ object IArray:
391
471
* @param elem the element computation
392
472
*/
393
473
def fill [T : ClassTag ](n1 : Int , n2 : Int )(elem : => T ): IArray [IArray [T ]] =
394
- // We cannot avoid a cast here as Array.fill creates inner arrays out of our control:
395
474
Array .fill(n1, n2)(elem)
396
475
397
476
/** Returns a three-dimensional immutable array that contains the results of some element computation a number
@@ -512,6 +591,17 @@ object IArray:
512
591
*/
513
592
def iterate [T : ClassTag ](start : T , len : Int )(f : T => T ): IArray [T ] = Array .iterate(start, len)(f)
514
593
594
+ /** Compare two arrays per element.
595
+ *
596
+ * A more efficient version of `xs.sameElements(ys)`.
597
+ *
598
+ * @param xs an array of AnyRef
599
+ * @param ys an array of AnyRef
600
+ * @return true if corresponding elements are equal
601
+ */
602
+ def equals (xs : IArray [AnyRef ], ys : IArray [AnyRef ]): Boolean =
603
+ Array .equals(xs.asInstanceOf [Array [AnyRef ]], ys.asInstanceOf [Array [AnyRef ]])
604
+
515
605
/** Returns a decomposition of the array into a sequence. This supports
516
606
* a pattern match like `{ case IArray(x,y,z) => println('3 elements')}`.
517
607
*
@@ -521,4 +611,65 @@ object IArray:
521
611
def unapplySeq [T ](x : IArray [T ]): Array .UnapplySeqWrapper [_ <: T ] =
522
612
Array .unapplySeq(x)
523
613
524
- end IArray
614
+ /** A lazy filtered array. No filtering is applied until one of `foreach`, `map` or `flatMap` is called. */
615
+ class WithFilter [T ](p : T => Boolean , xs : IArray [T ]):
616
+
617
+ /** Apply `f` to each element for its side effects.
618
+ * Note: [U] parameter needed to help scalac's type inference.
619
+ */
620
+ def foreach [U ](f : T => U ): Unit = {
621
+ val len = xs.length
622
+ var i = 0
623
+ while (i < len) {
624
+ val x = xs(i)
625
+ if (p(x)) f(x)
626
+ i += 1
627
+ }
628
+ }
629
+
630
+ /** Builds a new array by applying a function to all elements of this array.
631
+ *
632
+ * @param f the function to apply to each element.
633
+ * @tparam U the element type of the returned array.
634
+ * @return a new array resulting from applying the given function
635
+ * `f` to each element of this array and collecting the results.
636
+ */
637
+ def map [U : ClassTag ](f : T => U ): IArray [U ] = {
638
+ val b = IArray .newBuilder[U ]
639
+ var i = 0
640
+ while (i < xs.length) {
641
+ val x = xs(i)
642
+ if (p(x)) b += f(x)
643
+ i = i + 1
644
+ }
645
+ b.result()
646
+ }
647
+
648
+ /** Builds a new array by applying a function to all elements of this array
649
+ * and using the elements of the resulting collections.
650
+ *
651
+ * @param f the function to apply to each element.
652
+ * @tparam U the element type of the returned array.
653
+ * @return a new array resulting from applying the given collection-valued function
654
+ * `f` to each element of this array and concatenating the results.
655
+ */
656
+ def flatMap [U : ClassTag ](f : T => IterableOnce [U ]): IArray [U ] = {
657
+ val b = IArray .newBuilder[U ]
658
+ var i = 0
659
+ while (i < xs.length) {
660
+ val x = xs(i)
661
+ if (p(x)) b ++= f(xs(i))
662
+ i += 1
663
+ }
664
+ b.result()
665
+ }
666
+
667
+ def flatMap [BS , U ](f : T => BS )(using asIterable : BS => Iterable [U ], m : ClassTag [U ]): IArray [U ] =
668
+ flatMap[U ](x => asIterable(f(x)))
669
+
670
+ /** Creates a new non-strict filter which combines this filter with the given predicate. */
671
+ def withFilter (q : T => Boolean ): WithFilter [T ] = new WithFilter [T ](a => p(a) && q(a), xs)
672
+
673
+ end WithFilter
674
+
675
+ end IArray
0 commit comments