11package scala
22import reflect .ClassTag
33
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 }
57
68opaque type IArray [+ T ] = Array [_ <: T ]
79
@@ -39,15 +41,10 @@ object IArray:
3941 extension (arr : IArray [Object ]) def length : Int = arr.asInstanceOf [Array [Object ]].length
4042 extension [T ](arr : IArray [T ]) def length : Int = arr.asInstanceOf [Array [T ]].length
4143
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
4544
4645 /** Tests whether this array contains a given value as an element. */
4746 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 )
5148
5249 /** Copy elements of this array to another array. */
5350 extension [T ](arr : IArray [T ]) def copyToArray [U >: T ](xs : Array [U ]): Int =
@@ -100,7 +97,7 @@ object IArray:
10097
10198 /** Flattens a two-dimensional array by concatenating all its rows
10299 * 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 ] =
104101 genericArrayOps(arr).flatten
105102
106103 /** Folds the elements of this array using the specified associative binary operator. */
@@ -236,10 +233,6 @@ object IArray:
236233 extension [T ](arr : IArray [T ]) def splitAt (n : Int ): (IArray [T ], IArray [T ]) =
237234 genericArrayOps(arr).splitAt(n)
238235
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-
243236 /** The rest of the array without its first element. */
244237 extension [T ](arr : IArray [T ]) def tail : IArray [T ] =
245238 genericArrayOps(arr).tail
@@ -260,59 +253,127 @@ object IArray:
260253 extension [T ](arr : IArray [T ]) def toArray : Array [T ] =
261254 arr.clone.asInstanceOf [Array [T ]]
262255
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)
272328
273329 /** 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)
276332
277333 /** 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 ]])
280341
281342 /** 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
284345
285346 /** 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
288349
289350 /** 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
292353
293354 /** 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
296357
297358 /** 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
300361
301362 /** 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
304365
305366 /** 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
308369
309370 /** 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
312373
313374 /** 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
316377
317378 /** Convert an array into an immutable array without copying, the original array
318379 * must _not_ be mutated after this or the guaranteed immutablity of IArray will
@@ -363,6 +424,25 @@ object IArray:
363424 /** An immutable array with given elements. */
364425 def apply (x : Unit , xs : Unit * ): IArray [Unit ] = Array (x, xs : _* )
365426
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+
366446 /** Concatenates all arrays into a single immutable array.
367447 *
368448 * @param xss the given immutable arrays
@@ -391,7 +471,6 @@ object IArray:
391471 * @param elem the element computation
392472 */
393473 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:
395474 Array .fill(n1, n2)(elem)
396475
397476 /** Returns a three-dimensional immutable array that contains the results of some element computation a number
@@ -512,6 +591,17 @@ object IArray:
512591 */
513592 def iterate [T : ClassTag ](start : T , len : Int )(f : T => T ): IArray [T ] = Array .iterate(start, len)(f)
514593
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+
515605 /** Returns a decomposition of the array into a sequence. This supports
516606 * a pattern match like `{ case IArray(x,y,z) => println('3 elements')}`.
517607 *
@@ -521,4 +611,65 @@ object IArray:
521611 def unapplySeq [T ](x : IArray [T ]): Array .UnapplySeqWrapper [_ <: T ] =
522612 Array .unapplySeq(x)
523613
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