|
| 1 | +package scala |
| 2 | +import reflect.ClassTag |
| 3 | + |
| 4 | +object opaques: |
| 5 | + opaque type IArray[+T] = Array[_ <: T] |
| 6 | + |
| 7 | + private[scala] type Sub[A] >: Array[A] <: IArray[A] |
| 8 | + private[scala] type Sup[A] >: IArray[A] <: Array[_ <: A] |
| 9 | + |
| 10 | + given arrayOps: Object with { |
| 11 | + |
| 12 | + extension (arr: IArray[Byte]) def apply(n: Int): Byte = arr.asInstanceOf[Array[Byte]].apply(n) |
| 13 | + extension (arr: IArray[Short]) def apply(n: Int): Short = arr.asInstanceOf[Array[Short]].apply(n) |
| 14 | + extension (arr: IArray[Char]) def apply(n: Int): Char = arr.asInstanceOf[Array[Char]].apply(n) |
| 15 | + extension (arr: IArray[Int]) def apply(n: Int): Int = arr.asInstanceOf[Array[Int]].apply(n) |
| 16 | + extension (arr: IArray[Long]) def apply(n: Int): Long = arr.asInstanceOf[Array[Long]].apply(n) |
| 17 | + extension (arr: IArray[Float]) def apply(n: Int): Float = arr.asInstanceOf[Array[Float]].apply(n) |
| 18 | + extension (arr: IArray[Double]) def apply(n: Int): Double = arr.asInstanceOf[Array[Double]].apply(n) |
| 19 | + extension [T <: Object](arr: IArray[T]) def apply (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) |
| 20 | + extension [T](arr: IArray[T]) def apply (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) |
| 21 | + |
| 22 | + extension (arr: IArray[Byte]) def length: Int = arr.asInstanceOf[Array[Byte]].length |
| 23 | + extension (arr: IArray[Short]) def length: Int = arr.asInstanceOf[Array[Short]].length |
| 24 | + extension (arr: IArray[Char]) def length: Int = arr.asInstanceOf[Array[Char]].length |
| 25 | + extension (arr: IArray[Int]) def length: Int = arr.asInstanceOf[Array[Int]].length |
| 26 | + extension (arr: IArray[Long]) def length: Int = arr.asInstanceOf[Array[Long]].length |
| 27 | + extension (arr: IArray[Float]) def length: Int = arr.asInstanceOf[Array[Float]].length |
| 28 | + extension (arr: IArray[Double]) def length: Int = arr.asInstanceOf[Array[Double]].length |
| 29 | + extension (arr: IArray[Object]) def length: Int = arr.asInstanceOf[Array[Object]].length |
| 30 | + extension [T](arr: IArray[T]) def length: Int = arr.asInstanceOf[Array[T]].length |
| 31 | + |
| 32 | + extension [T, U >: T: ClassTag](arr: IArray[T]) def ++(that: IArray[U]): IArray[U] = |
| 33 | + genericArrayOps(arr) ++ that |
| 34 | + |
| 35 | + extension [T](arr: IArray[T]) def contains(elem: T): Boolean = |
| 36 | + genericArrayOps(arr).exists(_ == elem) |
| 37 | + |
| 38 | + extension [T, U >: T](arr: IArray[T]) def copyToArray(xs: Array[U]): Int = |
| 39 | + genericArrayOps(arr).copyToArray(xs) |
| 40 | + |
| 41 | + extension [T, U >: T](arr: IArray[T]) def copyToArray(xs: Array[U], start: Int): Int = |
| 42 | + genericArrayOps(arr).copyToArray(xs, start) |
| 43 | + |
| 44 | + extension [T, U >: T](arr: IArray[T]) def copyToArray(xs: Array[U], start: Int, len: Int): Int = |
| 45 | + genericArrayOps(arr).copyToArray(xs, start, len) |
| 46 | + |
| 47 | + extension [T](arr: IArray[T]) def count(p: T => Boolean): Int = |
| 48 | + genericArrayOps(arr).count(p) |
| 49 | + |
| 50 | + extension [T](arr: IArray[T]) def drop(n: Int): IArray[T] = |
| 51 | + genericArrayOps(arr).drop(n) |
| 52 | + |
| 53 | + extension [T](arr: IArray[T]) def dropRight(n: Int): IArray[T] = |
| 54 | + genericArrayOps(arr).dropRight(n) |
| 55 | + |
| 56 | + extension [T](arr: IArray[T]) def dropWhile(p: T => Boolean): IArray[T] = |
| 57 | + genericArrayOps(arr).dropWhile(p) |
| 58 | + |
| 59 | + extension [T](arr: IArray[T]) def exists(p: T => Boolean): Boolean = |
| 60 | + genericArrayOps(arr).exists(p) |
| 61 | + |
| 62 | + extension [T](arr: IArray[T]) def filter(p: T => Boolean): IArray[T] = |
| 63 | + genericArrayOps(arr).filter(p) |
| 64 | + |
| 65 | + extension [T](arr: IArray[T]) def filterNot(p: T => Boolean): IArray[T] = |
| 66 | + genericArrayOps(arr).filterNot(p) |
| 67 | + |
| 68 | + extension [T](arr: IArray[T]) def find(p: T => Boolean): Option[T] = |
| 69 | + genericArrayOps(arr).find(p) |
| 70 | + |
| 71 | + extension [T, U: ClassTag](arr: IArray[T]) def flatMap(f: T => IterableOnce[U]): IArray[U] = |
| 72 | + genericArrayOps(arr).flatMap(f) |
| 73 | + |
| 74 | + extension [T, U: ClassTag](arr: IArray[T]) def flatten(using T => Iterable[U]): IArray[U] = |
| 75 | + genericArrayOps(arr).flatten |
| 76 | + |
| 77 | + extension [T, U >: T: ClassTag](arr: IArray[T]) def fold(z: U)(op: (U, U) => U): U = |
| 78 | + genericArrayOps(arr).fold(z)(op) |
| 79 | + |
| 80 | + extension [T, U: ClassTag](arr: IArray[T]) def foldLeft(z: U)(op: (U, T) => U): U = |
| 81 | + genericArrayOps(arr).foldLeft(z)(op) |
| 82 | + |
| 83 | + extension [T, U: ClassTag](arr: IArray[T]) def foldRight(z: U)(op: (T, U) => U): U = |
| 84 | + genericArrayOps(arr).foldRight(z)(op) |
| 85 | + |
| 86 | + extension [T](arr: IArray[T]) def forall(p: T => Boolean): Boolean = |
| 87 | + genericArrayOps(arr).forall(p) |
| 88 | + |
| 89 | + extension [T, U](arr: IArray[T]) def foreach(f: T => U): Unit = |
| 90 | + genericArrayOps(arr).foreach(f) |
| 91 | + |
| 92 | + extension [T](arr: IArray[T]) def head: T = |
| 93 | + genericArrayOps(arr).head |
| 94 | + |
| 95 | + extension [T](arr: IArray[T]) def headOption: Option[T] = |
| 96 | + genericArrayOps(arr).headOption |
| 97 | + |
| 98 | + extension [T](arr: IArray[T]) def indexOf(elem: T, from: Int = 0): Int = |
| 99 | + // `asInstanceOf` needed because `elem` does not have type `arr.T` |
| 100 | + // We could use `arr.iterator.indexOf(elem, from)` or `arr.indexWhere(_ == elem, from)` |
| 101 | + // but these would incur some overhead. |
| 102 | + genericArrayOps(arr).indexOf(elem.asInstanceOf, from) |
| 103 | + |
| 104 | + extension [T](arr: IArray[T]) def indexWhere(p: T => Boolean, from: Int = 0): Int = |
| 105 | + genericArrayOps(arr).indexWhere(p, from) |
| 106 | + |
| 107 | + extension [T](arr: IArray[T]) def indices: Range = |
| 108 | + genericArrayOps(arr).indices |
| 109 | + |
| 110 | + extension [T](arr: IArray[T]) def init: IArray[T] = |
| 111 | + genericArrayOps(arr).init |
| 112 | + |
| 113 | + extension [T](arr: IArray[T]) def isEmpty: Boolean = |
| 114 | + genericArrayOps(arr).isEmpty |
| 115 | + |
| 116 | + extension [T](arr: IArray[T]) def iterator: Iterator[T] = |
| 117 | + genericArrayOps(arr).iterator |
| 118 | + |
| 119 | + extension [T](arr: IArray[T]) def last: T = |
| 120 | + genericArrayOps(arr).last |
| 121 | + |
| 122 | + extension [T](arr: IArray[T]) def lastOption: Option[T] = |
| 123 | + genericArrayOps(arr).lastOption |
| 124 | + |
| 125 | + extension [T](arr: IArray[T]) def lastIndexOf(elem: T, end: Int = arr.length - 1): Int = |
| 126 | + // see: same issue in `indexOf` |
| 127 | + genericArrayOps(arr).lastIndexOf(elem.asInstanceOf, end) |
| 128 | + |
| 129 | + extension [T](arr: IArray[T]) def lastIndexWhere(p: T => Boolean, end: Int = arr.length - 1): Int = |
| 130 | + genericArrayOps(arr).lastIndexWhere(p, end) |
| 131 | + |
| 132 | + extension [T, U: ClassTag](arr: IArray[T]) def map(f: T => U): IArray[U] = |
| 133 | + genericArrayOps(arr).map(f) |
| 134 | + |
| 135 | + extension [T](arr: IArray[T]) def nonEmpty: Boolean = |
| 136 | + genericArrayOps(arr).nonEmpty |
| 137 | + |
| 138 | + extension [T](arr: IArray[T]) def partition(p: T => Boolean): (IArray[T], IArray[T]) = |
| 139 | + genericArrayOps(arr).partition(p) |
| 140 | + |
| 141 | + extension [T](arr: IArray[T]) def reverse: IArray[T] = |
| 142 | + genericArrayOps(arr).reverse |
| 143 | + |
| 144 | + extension [T, U >: T: ClassTag](arr: IArray[T]) def scan(z: U)(op: (U, U) => U): IArray[U] = |
| 145 | + genericArrayOps(arr).scan(z)(op) |
| 146 | + |
| 147 | + extension [T, U: ClassTag](arr: IArray[T]) def scanLeft(z: U)(op: (U, T) => U): IArray[U] = |
| 148 | + genericArrayOps(arr).scanLeft(z)(op) |
| 149 | + |
| 150 | + extension [T, U: ClassTag](arr: IArray[T]) def scanRight(z: U)(op: (T, U) => U): IArray[U] = |
| 151 | + genericArrayOps(arr).scanRight(z)(op) |
| 152 | + |
| 153 | + extension [T](arr: IArray[T]) def size: Int = |
| 154 | + arr.length |
| 155 | + |
| 156 | + extension [T](arr: IArray[T]) def slice(from: Int, until: Int): IArray[T] = |
| 157 | + genericArrayOps(arr).slice(from, until) |
| 158 | + |
| 159 | + extension [T, U: ClassTag](arr: IArray[T]) def sortBy(f: T => U)(using math.Ordering[U]): IArray[T] = |
| 160 | + genericArrayOps(arr).sortBy(f) |
| 161 | + |
| 162 | + extension [T](arr: IArray[T]) def sortWith(f: (T, T) => Boolean): IArray[T] = |
| 163 | + genericArrayOps(arr).sortWith(f) |
| 164 | + |
| 165 | + extension [T](arr: IArray[T]) def sorted(using math.Ordering[T]): IArray[T] = |
| 166 | + genericArrayOps(arr).sorted |
| 167 | + |
| 168 | + extension [T](arr: IArray[T]) def span(p: T => Boolean): (IArray[T], IArray[T]) = |
| 169 | + genericArrayOps(arr).span(p) |
| 170 | + |
| 171 | + extension [T](arr: IArray[T]) def splitAt(n: Int): (IArray[T], IArray[T]) = |
| 172 | + genericArrayOps(arr).splitAt(n) |
| 173 | + |
| 174 | + extension [T, U >: T: ClassTag](arr: IArray[T]) def startsWith(that: IArray[U], offset: Int = 0): Boolean = |
| 175 | + genericArrayOps(arr).startsWith(that) |
| 176 | + |
| 177 | + extension [T](arr: IArray[T]) def tail: IArray[T] = |
| 178 | + genericArrayOps(arr).tail |
| 179 | + |
| 180 | + extension [T](arr: IArray[T]) def take(n: Int): IArray[T] = |
| 181 | + genericArrayOps(arr).take(n) |
| 182 | + |
| 183 | + extension [T](arr: IArray[T]) def takeRight(n: Int): IArray[T] = |
| 184 | + genericArrayOps(arr).takeRight(n) |
| 185 | + |
| 186 | + extension [T](arr: IArray[T]) def takeWhile(p: T => Boolean): IArray[T] = |
| 187 | + genericArrayOps(arr).takeWhile(p) |
| 188 | + |
| 189 | + extension [T](arr: IArray[T]) def toArray: Array[T] = |
| 190 | + arr.clone.asInstanceOf[Array[T]] |
| 191 | + |
| 192 | + extension [U: ClassTag, V: ClassTag](arr: IArray[(U, V)]) def unzip: (IArray[U], IArray[V]) = |
| 193 | + genericArrayOps(arr).unzip |
| 194 | + |
| 195 | + extension [T, U: ClassTag](arr: IArray[T]) def zip(that: IArray[U]): IArray[(T, U)] = |
| 196 | + genericArrayOps(arr).zip(that) |
| 197 | + } |
| 198 | +end opaques |
| 199 | + |
| 200 | +type IArray[+T] = opaques.IArray[T] |
| 201 | + |
| 202 | +object IArray { |
| 203 | + import opaques.Sub |
| 204 | + import opaques.Sup |
| 205 | + |
| 206 | + private given [A]: Conversion[Array[A], IArray[A]] = identity[Sub[A]] |
| 207 | + |
| 208 | + def unsafeFromArray[T](s: Array[T]): IArray[T] = s |
| 209 | + |
| 210 | + def empty[T: ClassTag]: IArray[T] = new Array[T](0) |
| 211 | + |
| 212 | + def emptyBooleanIArray: IArray[Boolean] = Array.emptyBooleanArray |
| 213 | + def emptyByteIArray: IArray[Byte] = Array.emptyByteArray |
| 214 | + def emptyCharIArray: IArray[Char] = Array.emptyCharArray |
| 215 | + def emptyDoubleIArray: IArray[Double] = Array.emptyDoubleArray |
| 216 | + def emptyFloatIArray: IArray[Float] = Array.emptyFloatArray |
| 217 | + def emptyIntIArray: IArray[Int] = Array.emptyIntArray |
| 218 | + def emptyLongIArray: IArray[Long] = Array.emptyLongArray |
| 219 | + def emptyShortIArray: IArray[Short] = Array.emptyShortArray |
| 220 | + def emptyObjectIArray: IArray[Object] = Array.emptyObjectArray |
| 221 | + |
| 222 | + inline def apply[T](inline xs: T*)(using inline ct: ClassTag[T]): IArray[T] = Array(xs: _*).asInstanceOf |
| 223 | + inline def apply(inline x: Boolean, inline xs: Boolean*): IArray[Boolean] = Array(x, xs: _*).asInstanceOf |
| 224 | + inline def apply(inline x: Byte, inline xs: Byte*): IArray[Byte] = Array(x, xs: _*).asInstanceOf |
| 225 | + inline def apply(inline x: Short, inline xs: Short*): IArray[Short] = Array(x, xs: _*).asInstanceOf |
| 226 | + inline def apply(inline x: Char, inline xs: Char*): IArray[Char] = Array(x, xs: _*).asInstanceOf |
| 227 | + inline def apply(inline x: Int, inline xs: Int*): IArray[Int] = Array(x, xs: _*).asInstanceOf |
| 228 | + inline def apply(inline x: Long, inline xs: Long*): IArray[Long] = Array(x, xs: _*).asInstanceOf |
| 229 | + inline def apply(inline x: Float, inline xs: Float*): IArray[Float] = Array(x, xs: _*).asInstanceOf |
| 230 | + inline def apply(inline x: Double, inline xs: Double*): IArray[Double] = Array(x, xs: _*).asInstanceOf |
| 231 | + inline def apply(inline x: Unit, inline xs: Unit*): IArray[Unit] = Array(x, xs: _*).asInstanceOf |
| 232 | + |
| 233 | + def concat[T: ClassTag](xss: IArray[T]*): IArray[T] = |
| 234 | + // `Array.concat` should arguably take in a `Seq[Array[_ <: T]]`, |
| 235 | + // but since it currently takes a `Seq[Array[T]]` we have to perform a cast, |
| 236 | + // knowing tacitly that `concat` is not going to do the wrong thing. |
| 237 | + Array.concat[T](xss.asInstanceOf[Seq[Array[T]]]: _*) |
| 238 | + |
| 239 | + def fill[T: ClassTag](n: Int)(elem: => T): IArray[T] = |
| 240 | + Array.fill(n)(elem) |
| 241 | + |
| 242 | + def fill[T: ClassTag](n1: Int, n2: Int)(elem: => T): IArray[IArray[T]] = |
| 243 | + // We cannot avoid a cast here as Array.fill creates inner arrays out of our control: |
| 244 | + Array.fill(n1, n2)(elem).asInstanceOf |
| 245 | + |
| 246 | + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int)(elem: => T): IArray[IArray[IArray[T]]] = |
| 247 | + Array.fill(n1, n2, n3)(elem).asInstanceOf |
| 248 | + |
| 249 | + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => T): IArray[IArray[IArray[IArray[T]]]] = |
| 250 | + Array.fill(n1, n2, n3, n4)(elem).asInstanceOf |
| 251 | + |
| 252 | + def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => T): IArray[IArray[IArray[IArray[IArray[T]]]]] = |
| 253 | + Array.fill(n1, n2, n3, n4, n5)(elem).asInstanceOf |
| 254 | + |
| 255 | + def tabulate[T: ClassTag](n: Int)(f: Int => T): IArray[T] = |
| 256 | + Array.tabulate(n)(f) |
| 257 | + |
| 258 | + def tabulate[T: ClassTag](n1: Int, n2: Int)(f: (Int, Int) => T): IArray[IArray[T]] = |
| 259 | + Array.tabulate(n1, n2)(f).asInstanceOf |
| 260 | + |
| 261 | + def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => T): IArray[IArray[IArray[T]]] = |
| 262 | + Array.tabulate(n1, n2, n3)(f).asInstanceOf |
| 263 | + |
| 264 | + def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => T): IArray[IArray[IArray[IArray[T]]]] = |
| 265 | + Array.tabulate(n1, n2, n3, n4)(f).asInstanceOf |
| 266 | + |
| 267 | + 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]]]]] = |
| 268 | + Array.tabulate(n1, n2, n3, n4, n5)(f).asInstanceOf |
| 269 | + |
| 270 | + def range(start: Int, end: Int): IArray[Int] = Array.range(start, end) |
| 271 | + |
| 272 | + def range(start: Int, end: Int, step: Int): IArray[Int] = Array.range(start, end, step) |
| 273 | + |
| 274 | + def iterate[T: ClassTag](start: T, len: Int)(f: T => T): IArray[T] = Array.iterate(start, len)(f) |
| 275 | + |
| 276 | + def unapplySeq[T](x: IArray[T]) = |
| 277 | + Array.unapplySeq((x: Sup[T]): Array[_ <: T]) |
| 278 | +} |
0 commit comments