Skip to content

Commit

Permalink
Add immutable array type
Browse files Browse the repository at this point in the history
IArray[T] is an opaque alias for Array[T]
  • Loading branch information
odersky committed Feb 9, 2019
1 parent d7eafe1 commit af2a0e6
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
60 changes: 60 additions & 0 deletions library/src-bootstrapped/scala/IArray.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package scala
import reflect.ClassTag

/** It would be nice it IArray could be covariant, but unfortunately that's not
* possible. The problem is the preculiar behavior of `Array[Any]`.
* `Array[Any]` erases to `Object[]`. So, `IArray[Any]` also erases to `Object[]`.
* Bit this means `IArray[Int]`, which erases to `Int[]`, cannot be a subtype of
* `IArray[Any]`.
*/
opaque type IArray[T] = Array[T]

object IArray {

implied arrayOps {
inline def (arr: IArray[T]) apply[T] (n: Int): T = (arr: Array[T]).apply(n)
inline def (arr: IArray[T]) length[T] : Int = (arr: Array[T]).length
}
def apply[T: ClassTag](xs: T*): IArray[T] = Array(xs: _*)

def apply(x: Boolean, xs: Boolean*): IArray[Boolean] = Array(x, xs: _*)
def apply(x: Byte, xs: Byte*): IArray[Byte] = Array(x, xs: _*)
def apply(x: Short, xs: Short*): IArray[Short] = Array(x, xs: _*)
def apply(x: Char, xs: Char*): IArray[Char] = Array(x, xs: _*)
def apply(x: Int, xs: Int*): IArray[Int] = Array(x, xs: _*)
def apply(x: Long, xs: Long*): IArray[Long] = Array(x, xs: _*)
def apply(x: Float, xs: Float*): IArray[Float] = Array(x, xs: _*)
def apply(x: Double, xs: Double*): IArray[Double] = Array(x, xs: _*)
def apply(x: Unit, xs: Unit*): IArray[Unit] = Array(x, xs: _*)

def concat[T: ClassTag](xss: IArray[T]*): IArray[T] = Array.concat(xss: _*)

def fill[T: ClassTag](n: Int)(elem: => T): IArray[T] =
Array.fill(n)(elem)
def fill[T: ClassTag](n1: Int, n2: Int)(elem: => T): IArray[IArray[T]] =
Array.fill(n1, n2)(elem)
def fill[T: ClassTag](n1: Int, n2: Int, n3: Int)(elem: => T): IArray[IArray[IArray[T]]] =
Array.fill(n1, n2, n3)(elem)
def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => T): IArray[IArray[IArray[IArray[T]]]] =
Array.fill(n1, n2, n3, n4)(elem)
def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => T): IArray[IArray[IArray[IArray[IArray[T]]]]] =
Array.fill(n1, n2, n3, n4, n5)(elem)

def tabulate[T: ClassTag](n: Int)(f: Int => T): IArray[T] =
Array.tabulate(n)(f)
def tabulate[T: ClassTag](n1: Int, n2: Int)(f: (Int, Int) => T): IArray[IArray[T]] =
Array.tabulate(n1, n2)(f)
def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => T): IArray[IArray[IArray[T]]] =
Array.tabulate(n1, n2, n3)(f)
def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => T): IArray[IArray[IArray[IArray[T]]]] =
Array.tabulate(n1, n2, n3, n4)(f)
def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => T): IArray[IArray[IArray[IArray[IArray[T]]]]] =
Array.tabulate(n1, n2, n3, n4, n5)(f)

def range(start: Int, end: Int): IArray[Int] = Array.range(start, end)
def range(start: Int, end: Int, step: Int): IArray[Int] = Array.range(start, end, step)

def iterate[T: ClassTag](start: T, len: Int)(f: T => T): IArray[T] = Array.iterate(start, len)(f)

def unapplySeq[T](x: IArray[T]): Option[IndexedSeq[T]] = Array.unapplySeq(x)
}
53 changes: 53 additions & 0 deletions tests/run/iarrays.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import reflect.ClassTag
object Test extends App {

val xs = IArray(1, 2, 3)

def f[T](ys: IArray[T]) = {
assert(ys.length == 3)
var sum = 0
for (i <- 0 until ys.length)
sum += xs(i)
assert(sum == 6)
}

f(xs)

var sum = 0
for (i <- 0 until xs.length)
sum += xs(i)
assert(sum == 6)

def reduce[T](xs: IArray[T], z: T, op: (T, T) => T) = {
var acc = z
for (i <- 0 until xs.length)
acc = op(acc, xs(i))
acc
}

def flatten[T: ClassTag](ys: IArray[IArray[T]]) = {
var len = 0
for (i <- 0 until ys.length) len += ys(i).length
val flat = new Array[T](len)
var k = 0
for (i <- 0 until ys.length) {
for (j <- 0 until ys(i).length) {
flat(k) = ys(i)(j)
k += 1
}
}
IArray(flat: _*)
}

val ys = IArray.concat(xs, xs, xs)
assert(reduce(ys, 0, _ + _) == 18)

val zss = IArray.fill(2, 3)(1)
val zs = flatten(zss)
assert(reduce(zs, 0, _ + _) == 6)

val is = IArray.iterate(0, 4)(_ + 1)
assert(reduce(is, 0, _ + _) == 6)

val IArray(1, 2, 3) = xs
}

0 comments on commit af2a0e6

Please sign in to comment.