Skip to content

IArray extension methods #7795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Dec 29, 2019
160 changes: 160 additions & 0 deletions library/src-bootstrapped/scala/IArray.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,166 @@ object opaques
def (arr: IArray[Double]) length: Int = arr.asInstanceOf[Array[Double]].length
def (arr: IArray[Object]) length: Int = arr.asInstanceOf[Array[Object]].length
def [T](arr: IArray[T]) length: Int = arr.asInstanceOf[Array[T]].length

/** All the methods on Array[T] that don't mutate in-place can be used with IArray[T].
*/
def [T, U >: T: ClassTag](arr: IArray[T]) ++(that: IArray[U]): IArray[U] =
(genericArrayOps(arr) ++ that.asInstanceOf[Array[U]]).asInstanceOf[IArray[U]]

def [T](arr: IArray[T]) contains(elem: T): Boolean =
genericArrayOps(arr.asInstanceOf[Array[T]]).contains(elem)

def [T](arr: IArray[T]) count(p: T => Boolean): Int =
genericArrayOps(arr).count(p)

def [T](arr: IArray[T]) drop(n: Int): IArray[T] =
genericArrayOps(arr).drop(n).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) dropRight(n: Int): IArray[T] =
genericArrayOps(arr).dropRight(n).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) dropWhile(p: T => Boolean): IArray[T] =
genericArrayOps(arr).dropWhile(p).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) exists(p: T => Boolean): IArray[T] =
genericArrayOps(arr).exists(p).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) filter(p: T => Boolean): IArray[T] =
genericArrayOps(arr).filter(p).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) filterNot(p: T => Boolean): IArray[T] =
genericArrayOps(arr).filterNot(p).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) find(p: T => Boolean): Option[T] =
genericArrayOps(arr).find(p)

def [T, U: ClassTag](arr: IArray[T]) flatMap(f: T => IterableOnce[U]): IArray[U] =
genericArrayOps(arr).flatMap(f).asInstanceOf[IArray[U]]

def [T, U: ClassTag](arr: IArray[T]) flatten(given T => Iterable[U]): IArray[U] =
genericArrayOps(arr).flatten.asInstanceOf[IArray[U]]

def [T, U >: T: ClassTag](arr: IArray[T]) fold(z: U)(op: (U, U) => U): U =
genericArrayOps(arr).fold(z)(op)

def [T, U: ClassTag](arr: IArray[T]) foldLeft(z: U)(op: (U, T) => U): U =
genericArrayOps(arr).foldLeft(z)(op)

def [T, U: ClassTag](arr: IArray[T]) foldRight(z: U)(op: (T, U) => U): U =
genericArrayOps(arr).foldRight(z)(op)

def [T](arr: IArray[T]) forall(p: T => Boolean): Boolean =
genericArrayOps(arr).forall(p)

def [T, U](arr: IArray[T]) foreach(f: T => U): Unit =
genericArrayOps(arr).foreach(f)

def [T](arr: IArray[T]) head: T =
genericArrayOps(arr).head

def [T](arr: IArray[T]) headOption: Option[T] =
genericArrayOps(arr).headOption

def [T](arr: IArray[T]) indexOf(elem: T, from: Int = 0): Int =
genericArrayOps(arr.asInstanceOf[Array[T]]).indexOf(elem, from)

def [T](arr: IArray[T]) indexWhere(p: T => Boolean, from: Int = 0): Int =
genericArrayOps(arr).indexWhere(p, from)

def [T](arr: IArray[T]) indices: Range =
genericArrayOps(arr).indices

def [T](arr: IArray[T]) init: IArray[T] =
genericArrayOps(arr).init.asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) isEmpty: Boolean =
genericArrayOps(arr).isEmpty

def [T](arr: IArray[T]) iterator: Iterator[T] =
genericArrayOps(arr).iterator

def [T](arr: IArray[T]) last: T =
genericArrayOps(arr).last

def [T](arr: IArray[T]) lastOption: Option[T] =
genericArrayOps(arr).lastOption

def [T](arr: IArray[T]) lastIndexOf(elem: T, end: Int = arr.length - 1): Int =
genericArrayOps(arr.asInstanceOf[Array[T]]).lastIndexOf(elem, end)

def [T](arr: IArray[T]) lastIndexWhere(p: T => Boolean, end: Int = arr.length - 1): Int =
genericArrayOps(arr).lastIndexWhere(p, end)

def [T, U: ClassTag](arr: IArray[T]) map(f: T => U): IArray[U] =
genericArrayOps(arr).map(f).asInstanceOf[IArray[U]]

def [T](arr: IArray[T]) nonEmpty: Boolean =
genericArrayOps(arr).nonEmpty

def [T](arr: IArray[T]) partition(p: T => Boolean): (IArray[T], IArray[T]) =
genericArrayOps(arr).partition(p) match {
case (x, y) => (x.asInstanceOf[IArray[T]], y.asInstanceOf[IArray[T]])
}

def [T](arr: IArray[T]) reverse: IArray[T] =
genericArrayOps(arr).reverse.asInstanceOf[IArray[T]]

def [T, U >: T: ClassTag](arr: IArray[T]) scan(z: U)(op: (U, U) => U): IArray[U] =
genericArrayOps(arr).scan(z)(op).asInstanceOf[IArray[U]]

def [T, U: ClassTag](arr: IArray[T]) scanLeft(z: U)(op: (U, T) => U): IArray[U] =
genericArrayOps(arr).scanLeft(z)(op).asInstanceOf[IArray[U]]

def [T, U: ClassTag](arr: IArray[T]) scanRight(z: U)(op: (T, U) => U): IArray[U] =
genericArrayOps(arr).scanRight(z)(op).asInstanceOf[IArray[U]]

def [T](arr: IArray[T]) size: Int =
arr.length

def [T](arr: IArray[T]) slice(from: Int, until: Int): IArray[T] =
genericArrayOps(arr).slice(from, until).asInstanceOf[IArray[T]]

def [T, U: ClassTag](arr: IArray[T]) sortBy(f: T => U)(given math.Ordering[U]): IArray[T] =
genericArrayOps(arr).sortBy(f).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) sortWith(f: (T, T) => Boolean): IArray[T] =
genericArrayOps(arr).sortWith(f).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) sorted(given math.Ordering[T]): IArray[T] =
genericArrayOps(arr).sorted.asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) span(p: T => Boolean): (IArray[T], IArray[T]) =
genericArrayOps(arr).span(p) match {
case (x, y) => (x.asInstanceOf[IArray[T]], y.asInstanceOf[IArray[T]])
}

def [T](arr: IArray[T]) splitAt(n: Int): (IArray[T], IArray[T]) =
genericArrayOps(arr).splitAt(n) match {
case (x, y) => (x.asInstanceOf[IArray[T]], y.asInstanceOf[IArray[T]])
}

def [T, U >: T: ClassTag](arr: IArray[T]) startsWith(that: IArray[U], offset: Int = 0): Boolean =
genericArrayOps(arr).startsWith(that.asInstanceOf[Array[U]])

def [T](arr: IArray[T]) tail: IArray[T] =
genericArrayOps(arr).tail.asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) take(n: Int): IArray[T] =
genericArrayOps(arr).take(n).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) takeRight(n: Int): IArray[T] =
genericArrayOps(arr).takeRight(n).asInstanceOf[IArray[T]]

def [T](arr: IArray[T]) takeWhile(p: T => Boolean): IArray[T] =
genericArrayOps(arr).takeWhile(p).asInstanceOf[IArray[T]]

def [U: ClassTag, V: ClassTag](arr: IArray[(U, V)]) unzip: (IArray[U], IArray[V]) =
genericArrayOps(arr).unzip match {
case (x, y) => (x.asInstanceOf[IArray[U]], y.asInstanceOf[IArray[V]])
}

def [T, U: ClassTag](arr: IArray[T]) zip(that: IArray[U]): IArray[(T, U)] =
genericArrayOps(arr).zip(that).asInstanceOf[IArray[(T, U)]]
end opaques

type IArray[+T] = opaques.IArray[T]
Expand Down
63 changes: 63 additions & 0 deletions tests/run-bootstrapped/iarray-extmtds.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
IArray(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
true
5
IArray(9,10)
IArray(1,2)
IArray(8,9,10)
true
IArray(2,4,6,8,10)
IArray(1,3,5,7,9)
Some(5)
IArray(1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10)
IArray(1,2,3,4)
55
12345678910
10987654321
false
1
2
3
4
5
6
7
8
9
10
11
Some(1)
-1
3
0,1,2,3,4,5,6,7,8,9
IArray(1,2,3,4,5,6,7,8,9)
false
1,2,3
10
Some(20)
6
3
IArray(11,12,13,14,15,16,17,18,19,20)
true
IArray(2,4,6,8,10)
IArray(1,3,5,7,9)
IArray(10,9,8,7,6,5,4,3,2,1)
IArray(0,1,3,6,10,15,21,28,36,45,55)
IArray(,1,12,123,1234,12345,123456,1234567,12345678,123456789,12345678910)
IArray(10987654321,1098765432,109876543,10987654,1098765,109876,10987,1098,109,10,)
10
IArray(6,7)
IArray(10,9,8,7,6,5,4,3,2,1)
IArray(10,1,2,3,4,5,6,7,8,9)
IArray(1,2,3,4,5,6,7,8,9,10)
IArray(1,2,3,4)
IArray(5,6,7,8,9,10)
IArray(1,2,3,4,5,6,7)
IArray(8,9,10)
false
IArray(2,3,4,5,6,7,8,9,10)
IArray(1,2,3)
IArray(7,8,9,10)
IArray(1,2)
IArray(1,2,3)
IArray(1,2,3)
IArray((1,11),(2,12),(3,13),(4,14),(5,15),(6,16),(7,17),(8,18),(9,19),(10,20))
127 changes: 127 additions & 0 deletions tests/run-bootstrapped/iarray-extmtds.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@

object Test extends App {
def printIArray[T](arr: IArray[T]): Unit =
println(arr.asInstanceOf[Array[T]].mkString("IArray(", ",", ")"))

// This is used to check the correct result, as well as checking that the IArray was not mutated in place
def assertDifferent[T, U](expr: IArray[T], sources: IArray[U]*): Unit = {
sources.foreach(source =>
assert(expr.asInstanceOf[AnyRef] ne source.asInstanceOf[AnyRef], "IArray was mutated in place")
)

printIArray(expr)
}

val arr1 = IArray[Int](1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val arr2 = IArray[Int](11, 12, 13, 14, 15, 16, 17, 18, 19, 20)

assertDifferent(arr1 ++ arr2, arr1, arr2)

println(arr1.contains(7))

println(arr1.count(_ % 2 == 0))

assertDifferent(arr1.drop(8), arr1)

assertDifferent(arr1.dropRight(8), arr1)

assertDifferent(arr1.dropWhile(_ < 8), arr1)

println(arr1.exists(_ % 6 == 0))

assertDifferent(arr1.filter(_ % 2 == 0), arr1)

assertDifferent(arr1.filterNot(_ % 2 == 0), arr1)

println(arr1.find(_ % 5 == 0))

assertDifferent(arr1.flatMap(x => List(x, x)), arr1)

val twoDArr = IArray(List(1, 2), List(3, 4))
assertDifferent(twoDArr.flatten[List[Int], Int], twoDArr)

println(arr1.fold(0)(_ + _))

println(arr1.foldLeft("")((acc, x) => acc + x.toString))

println(arr1.foldRight("")((x, acc) => acc + x.toString))

println(arr1.forall(_ > 5))

arr1.foreach(x => println(x))

println(arr2.head)

println(arr1.headOption)

println(arr1.indexOf(5, 7))

println(arr1.indexWhere(_ > 3, 1))

println(arr2.indices.mkString(","))

assertDifferent(arr1.init, arr1)

println(arr1.isEmpty)

println(arr1.iterator.take(3).mkString(","))

println(arr1.last)

println(arr2.lastOption)

println(arr2.lastIndexOf(17))

println(arr1.lastIndexWhere(_ < 5))

assertDifferent(arr1.map(_ + 10), arr1)

println(arr1.nonEmpty)

val (even, odd) = arr1.partition(_ % 2 == 0)
assertDifferent(even, arr1)
assertDifferent(odd, arr1)

assertDifferent(arr1.reverse, arr1)

assertDifferent(arr1.scan(0)(_ + _), arr1)

assertDifferent(arr1.scanLeft("")((acc, x) => acc + x.toString), arr1)

assertDifferent(arr1.scanRight("")((x, acc) => acc + x.toString), arr1)

println(arr2.size)

assertDifferent(arr1.slice(5,7), arr1)

assertDifferent(arr1.sortBy(- _), arr1)

assertDifferent(arr1.sortWith((x, y) => x.toString.length > y.toString.length || x < y), arr1)

assertDifferent(arr1.sorted, arr1)

val (smaller, greater) = arr1.span(_ < 5)
assertDifferent(smaller, arr1)
assertDifferent(greater, arr1)

val (first, last) = arr1.splitAt(7)
assertDifferent(first, arr1)
assertDifferent(last, arr1)

println(arr1.startsWith(IArray(1,2,3,4,5,6,42)))

assertDifferent(arr1.tail, arr1)

assertDifferent(arr1.take(3), arr1)

assertDifferent(arr1.takeRight(4), arr1)

assertDifferent(arr1.takeWhile(_ < 3), arr1)

val tupArr = IArray[(Int, String)]((1, "1"), (2, "2"), (3, "3"))
val (ints, strings) = tupArr.unzip
assertDifferent(ints, tupArr)
assertDifferent(strings, tupArr)

assertDifferent(arr1.zip(arr2), arr1, arr2)
}