From 9a6af34b67e73688f45712fbc4a8ef5a160868a1 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 4 Feb 2021 17:32:01 +0100 Subject: [PATCH 1/2] Remove indirection of IArray operations --- library/src/scala/IArray.scala | 523 ++++++++++++++++----------------- 1 file changed, 260 insertions(+), 263 deletions(-) diff --git a/library/src/scala/IArray.scala b/library/src/scala/IArray.scala index 75fcb758a3dc..d0f45fb9f2bc 100644 --- a/library/src/scala/IArray.scala +++ b/library/src/scala/IArray.scala @@ -10,269 +10,266 @@ object opaques: private[scala] type Sub[A] >: Array[A] <: IArray[A] private[scala] type Sup[A] >: IArray[A] <: Array[_ <: A] - /** Defines extension methods for immutable arrays */ - given arrayOps: Object with { - - /** The selection operation on an immutable array. - * - * @param arr the immutable array - * @param n the index of the element to select - * @return the element of the array at the given index - */ - extension (arr: IArray[Byte]) def apply(n: Int): Byte = arr.asInstanceOf[Array[Byte]].apply(n) - extension (arr: IArray[Short]) def apply(n: Int): Short = arr.asInstanceOf[Array[Short]].apply(n) - extension (arr: IArray[Char]) def apply(n: Int): Char = arr.asInstanceOf[Array[Char]].apply(n) - extension (arr: IArray[Int]) def apply(n: Int): Int = arr.asInstanceOf[Array[Int]].apply(n) - extension (arr: IArray[Long]) def apply(n: Int): Long = arr.asInstanceOf[Array[Long]].apply(n) - extension (arr: IArray[Float]) def apply(n: Int): Float = arr.asInstanceOf[Array[Float]].apply(n) - extension (arr: IArray[Double]) def apply(n: Int): Double = arr.asInstanceOf[Array[Double]].apply(n) - extension [T <: Object](arr: IArray[T]) def apply (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) - extension [T](arr: IArray[T]) def apply (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) - - /** The number of elements in an immutable array - * @param arr the immutable array - */ - extension (arr: IArray[Byte]) def length: Int = arr.asInstanceOf[Array[Byte]].length - extension (arr: IArray[Short]) def length: Int = arr.asInstanceOf[Array[Short]].length - extension (arr: IArray[Char]) def length: Int = arr.asInstanceOf[Array[Char]].length - extension (arr: IArray[Int]) def length: Int = arr.asInstanceOf[Array[Int]].length - extension (arr: IArray[Long]) def length: Int = arr.asInstanceOf[Array[Long]].length - extension (arr: IArray[Float]) def length: Int = arr.asInstanceOf[Array[Float]].length - extension (arr: IArray[Double]) def length: Int = arr.asInstanceOf[Array[Double]].length - extension (arr: IArray[Object]) def length: Int = arr.asInstanceOf[Array[Object]].length - extension [T](arr: IArray[T]) def length: Int = arr.asInstanceOf[Array[T]].length - - /** Returns this array concatenated with the given array. */ - extension [T](arr: IArray[T]) def ++ [U >: T: ClassTag](that: IArray[U]): IArray[U] = - genericArrayOps(arr) ++ that - - /** Tests whether this array contains a given value as an element. */ - extension [T](arr: IArray[T]) def contains(elem: T): Boolean = - // `genericArrayOps(arr).contains(elem)` does not work because `elem` does not have type `arr.T` - // but we can use `exists` instead, which is how `ArrayOps#contains` itself is implemented: - genericArrayOps(arr).exists(_ == elem) - - /** Copy elements of this array to another array. */ - extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U]): Int = - genericArrayOps(arr).copyToArray(xs) - - /** Copy elements of this array to another array. */ - extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U], start: Int): Int = - genericArrayOps(arr).copyToArray(xs, start) - - /** Copy elements of this array to another array. */ - extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U], start: Int, len: Int): Int = - genericArrayOps(arr).copyToArray(xs, start, len) - - /** Counts the number of elements in this array which satisfy a predicate */ - extension [T](arr: IArray[T]) def count(p: T => Boolean): Int = - genericArrayOps(arr).count(p) - - /** The rest of the array without its `n` first elements. */ - extension [T](arr: IArray[T]) def drop(n: Int): IArray[T] = - genericArrayOps(arr).drop(n) - - /** The rest of the array without its `n` last elements. */ - extension [T](arr: IArray[T]) def dropRight(n: Int): IArray[T] = - genericArrayOps(arr).dropRight(n) - - /** Drops longest prefix of elements that satisfy a predicate. */ - extension [T](arr: IArray[T]) def dropWhile(p: T => Boolean): IArray[T] = - genericArrayOps(arr).dropWhile(p) - - /** Tests whether a predicate holds for at least one element of this array. */ - extension [T](arr: IArray[T]) def exists(p: T => Boolean): Boolean = - genericArrayOps(arr).exists(p) - - /** Selects all elements of this array which satisfy a predicate. */ - extension [T](arr: IArray[T]) def filter(p: T => Boolean): IArray[T] = - genericArrayOps(arr).filter(p) - - /** Selects all elements of this array which do not satisfy a predicate. */ - extension [T](arr: IArray[T]) def filterNot(p: T => Boolean): IArray[T] = - genericArrayOps(arr).filterNot(p) - - /** Finds the first element of the array satisfying a predicate, if any. */ - extension [T](arr: IArray[T]) def find(p: T => Boolean): Option[T] = - genericArrayOps(arr).find(p) - - /** Builds a new array by applying a function to all elements of this array - * and using the elements of the resulting collections. */ - extension [T](arr: IArray[T]) def flatMap[U: ClassTag](f: T => IterableOnce[U]): IArray[U] = - genericArrayOps(arr).flatMap(f) - - /** Flattens a two-dimensional array by concatenating all its rows - * into a single array. */ - extension [T](arr: IArray[T]) def flatten[U: ClassTag](using T => Iterable[U]): IArray[U] = - genericArrayOps(arr).flatten - - /** Folds the elements of this array using the specified associative binary operator. */ - extension [T](arr: IArray[T]) def fold[U >: T: ClassTag](z: U)(op: (U, U) => U): U = - genericArrayOps(arr).fold(z)(op) - - /** Applies a binary operator to a start value and all elements of this array, - * going left to right. */ - extension [T](arr: IArray[T]) def foldLeft[U: ClassTag](z: U)(op: (U, T) => U): U = - genericArrayOps(arr).foldLeft(z)(op) - - /** Applies a binary operator to all elements of this array and a start value, - * going right to left. */ - extension [T](arr: IArray[T]) def foldRight[U: ClassTag](z: U)(op: (T, U) => U): U = - genericArrayOps(arr).foldRight(z)(op) - - /** Tests whether a predicate holds for all elements of this array. */ - extension [T](arr: IArray[T]) def forall(p: T => Boolean): Boolean = - genericArrayOps(arr).forall(p) - - /** Apply `f` to each element for its side effects. */ - extension [T](arr: IArray[T]) def foreach[U](f: T => U): Unit = - genericArrayOps(arr).foreach(f) - - /** Selects the first element of this array. */ - extension [T](arr: IArray[T]) def head: T = - genericArrayOps(arr).head - - /** Optionally selects the first element. */ - extension [T](arr: IArray[T]) def headOption: Option[T] = - genericArrayOps(arr).headOption - - /** Finds index of first occurrence of some value in this array after or at some start index. */ - extension [T](arr: IArray[T]) def indexOf(elem: T, from: Int = 0): Int = - // `asInstanceOf` needed because `elem` does not have type `arr.T` - // We could use `arr.iterator.indexOf(elem, from)` or `arr.indexWhere(_ == elem, from)` - // but these would incur some overhead. - genericArrayOps(arr).indexOf(elem.asInstanceOf, from) - - /** Finds index of the first element satisfying some predicate after or at some start index. */ - extension [T](arr: IArray[T]) def indexWhere(p: T => Boolean, from: Int = 0): Int = - genericArrayOps(arr).indexWhere(p, from) - - /** Produces the range of all indices of this sequence. */ - extension [T](arr: IArray[T]) def indices: Range = - genericArrayOps(arr).indices - - /** The initial part of the array without its last element. */ - extension [T](arr: IArray[T]) def init: IArray[T] = - genericArrayOps(arr).init - - /** Tests whether the array is empty. */ - extension [T](arr: IArray[T]) def isEmpty: Boolean = - genericArrayOps(arr).isEmpty - - /** An iterator yielding the elemenst of this array. */ - extension [T](arr: IArray[T]) def iterator: Iterator[T] = - genericArrayOps(arr).iterator - - /** Selects the last element. */ - extension [T](arr: IArray[T]) def last: T = - genericArrayOps(arr).last - - /** Optionally selects the last element. */ - extension [T](arr: IArray[T]) def lastOption: Option[T] = - genericArrayOps(arr).lastOption - - /** Finds index of last occurrence of some value in this array before or at a given end index. */ - extension [T](arr: IArray[T]) def lastIndexOf(elem: T, end: Int = arr.length - 1): Int = - // see: same issue in `indexOf` - genericArrayOps(arr).lastIndexOf(elem.asInstanceOf, end) - - /** Finds index of last element satisfying some predicate before or at given end index. */ - extension [T](arr: IArray[T]) def lastIndexWhere(p: T => Boolean, end: Int = arr.length - 1): Int = - genericArrayOps(arr).lastIndexWhere(p, end) - - /** Builds a new array by applying a function to all elements of this array. */ - extension [T](arr: IArray[T]) def map[U: ClassTag](f: T => U): IArray[U] = - genericArrayOps(arr).map(f) - - /** Tests whether the array is not empty. */ - extension [T](arr: IArray[T]) def nonEmpty: Boolean = - genericArrayOps(arr).nonEmpty - - /** A pair of, first, all elements that satisfy predicate `p` and, second, all elements that do not. */ - extension [T](arr: IArray[T]) def partition(p: T => Boolean): (IArray[T], IArray[T]) = - genericArrayOps(arr).partition(p) - - /** Returns a new array with the elements in reversed order. */ - extension [T](arr: IArray[T]) def reverse: IArray[T] = - genericArrayOps(arr).reverse - - /** Computes a prefix scan of the elements of the array. */ - extension [T](arr: IArray[T]) def scan[U >: T: ClassTag](z: U)(op: (U, U) => U): IArray[U] = - genericArrayOps(arr).scan(z)(op) - - /** Produces an array containing cumulative results of applying the binary - * operator going left to right. */ - extension [T](arr: IArray[T]) def scanLeft[U: ClassTag](z: U)(op: (U, T) => U): IArray[U] = - genericArrayOps(arr).scanLeft(z)(op) - - /** Produces an array containing cumulative results of applying the binary - * operator going right to left. */ - extension [T](arr: IArray[T]) def scanRight[U: ClassTag](z: U)(op: (T, U) => U): IArray[U] = - genericArrayOps(arr).scanRight(z)(op) - - /** The size of this array. */ - extension [T](arr: IArray[T]) def size: Int = - arr.length - - /** Selects the interval of elements between the given indices. */ - extension [T](arr: IArray[T]) def slice(from: Int, until: Int): IArray[T] = - genericArrayOps(arr).slice(from, until) - - /** Sorts this array according to the Ordering which results from transforming - * an implicitly given Ordering with a transformation function. */ - extension [T](arr: IArray[T]) def sortBy[U: ClassTag](f: T => U)(using math.Ordering[U]): IArray[T] = - genericArrayOps(arr).sortBy(f) - - /** Sorts this array according to a comparison function. */ - extension [T](arr: IArray[T]) def sortWith(f: (T, T) => Boolean): IArray[T] = - genericArrayOps(arr).sortWith(f) - - /** Sorts this array according to an Ordering. */ - extension [T](arr: IArray[T]) def sorted(using math.Ordering[T]): IArray[T] = - genericArrayOps(arr).sorted - - /** Splits this array into a prefix/suffix pair according to a predicate. */ - extension [T](arr: IArray[T]) def span(p: T => Boolean): (IArray[T], IArray[T]) = - genericArrayOps(arr).span(p) - - /** Splits this array into two at a given position. */ - extension [T](arr: IArray[T]) def splitAt(n: Int): (IArray[T], IArray[T]) = - genericArrayOps(arr).splitAt(n) - - /** Tests whether this array starts with the given array. */ - extension [T](arr: IArray[T]) def startsWith[U >: T: ClassTag](that: IArray[U], offset: Int = 0): Boolean = - genericArrayOps(arr).startsWith(that) - - /** The rest of the array without its first element. */ - extension [T](arr: IArray[T]) def tail: IArray[T] = - genericArrayOps(arr).tail - - /** An array containing the first `n` elements of this array. */ - extension [T](arr: IArray[T]) def take(n: Int): IArray[T] = - genericArrayOps(arr).take(n) - - /** An array containing the last `n` elements of this array. */ - extension [T](arr: IArray[T]) def takeRight(n: Int): IArray[T] = - genericArrayOps(arr).takeRight(n) - - /** Takes longest prefix of elements that satisfy a predicate. */ - extension [T](arr: IArray[T]) def takeWhile(p: T => Boolean): IArray[T] = - genericArrayOps(arr).takeWhile(p) - - /** Returns a mutable copy of this immutable array. */ - extension [T](arr: IArray[T]) def toArray: Array[T] = - arr.clone.asInstanceOf[Array[T]] - - /** Converts an array of pairs into an array of first elements and an array of second elements. */ - extension [U: ClassTag, V: ClassTag](arr: IArray[(U, V)]) def unzip: (IArray[U], IArray[V]) = - genericArrayOps(arr).unzip - - /** Returns an array formed from this array and another iterable collection - * by combining corresponding elements in pairs. - * If one of the two collections is longer than the other, its remaining elements are ignored. */ - extension [T](arr: IArray[T]) def zip[U: ClassTag](that: IArray[U]): IArray[(T, U)] = - genericArrayOps(arr).zip(that) - } + /** The selection operation on an immutable array. + * + * @param arr the immutable array + * @param n the index of the element to select + * @return the element of the array at the given index + */ + extension (arr: IArray[Byte]) def apply(n: Int): Byte = arr.asInstanceOf[Array[Byte]].apply(n) + extension (arr: IArray[Short]) def apply(n: Int): Short = arr.asInstanceOf[Array[Short]].apply(n) + extension (arr: IArray[Char]) def apply(n: Int): Char = arr.asInstanceOf[Array[Char]].apply(n) + extension (arr: IArray[Int]) def apply(n: Int): Int = arr.asInstanceOf[Array[Int]].apply(n) + extension (arr: IArray[Long]) def apply(n: Int): Long = arr.asInstanceOf[Array[Long]].apply(n) + extension (arr: IArray[Float]) def apply(n: Int): Float = arr.asInstanceOf[Array[Float]].apply(n) + extension (arr: IArray[Double]) def apply(n: Int): Double = arr.asInstanceOf[Array[Double]].apply(n) + extension [T <: Object](arr: IArray[T]) def apply (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) + extension [T](arr: IArray[T]) def apply (n: Int): T = arr.asInstanceOf[Array[T]].apply(n) + + /** The number of elements in an immutable array + * @param arr the immutable array + */ + extension (arr: IArray[Byte]) def length: Int = arr.asInstanceOf[Array[Byte]].length + extension (arr: IArray[Short]) def length: Int = arr.asInstanceOf[Array[Short]].length + extension (arr: IArray[Char]) def length: Int = arr.asInstanceOf[Array[Char]].length + extension (arr: IArray[Int]) def length: Int = arr.asInstanceOf[Array[Int]].length + extension (arr: IArray[Long]) def length: Int = arr.asInstanceOf[Array[Long]].length + extension (arr: IArray[Float]) def length: Int = arr.asInstanceOf[Array[Float]].length + extension (arr: IArray[Double]) def length: Int = arr.asInstanceOf[Array[Double]].length + extension (arr: IArray[Object]) def length: Int = arr.asInstanceOf[Array[Object]].length + extension [T](arr: IArray[T]) def length: Int = arr.asInstanceOf[Array[T]].length + + /** Returns this array concatenated with the given array. */ + extension [T](arr: IArray[T]) def ++ [U >: T: ClassTag](that: IArray[U]): IArray[U] = + genericArrayOps(arr) ++ that + + /** Tests whether this array contains a given value as an element. */ + extension [T](arr: IArray[T]) def contains(elem: T): Boolean = + // `genericArrayOps(arr).contains(elem)` does not work because `elem` does not have type `arr.T` + // but we can use `exists` instead, which is how `ArrayOps#contains` itself is implemented: + genericArrayOps(arr).exists(_ == elem) + + /** Copy elements of this array to another array. */ + extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U]): Int = + genericArrayOps(arr).copyToArray(xs) + + /** Copy elements of this array to another array. */ + extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U], start: Int): Int = + genericArrayOps(arr).copyToArray(xs, start) + + /** Copy elements of this array to another array. */ + extension [T](arr: IArray[T]) def copyToArray[U >: T](xs: Array[U], start: Int, len: Int): Int = + genericArrayOps(arr).copyToArray(xs, start, len) + + /** Counts the number of elements in this array which satisfy a predicate */ + extension [T](arr: IArray[T]) def count(p: T => Boolean): Int = + genericArrayOps(arr).count(p) + + /** The rest of the array without its `n` first elements. */ + extension [T](arr: IArray[T]) def drop(n: Int): IArray[T] = + genericArrayOps(arr).drop(n) + + /** The rest of the array without its `n` last elements. */ + extension [T](arr: IArray[T]) def dropRight(n: Int): IArray[T] = + genericArrayOps(arr).dropRight(n) + + /** Drops longest prefix of elements that satisfy a predicate. */ + extension [T](arr: IArray[T]) def dropWhile(p: T => Boolean): IArray[T] = + genericArrayOps(arr).dropWhile(p) + + /** Tests whether a predicate holds for at least one element of this array. */ + extension [T](arr: IArray[T]) def exists(p: T => Boolean): Boolean = + genericArrayOps(arr).exists(p) + + /** Selects all elements of this array which satisfy a predicate. */ + extension [T](arr: IArray[T]) def filter(p: T => Boolean): IArray[T] = + genericArrayOps(arr).filter(p) + + /** Selects all elements of this array which do not satisfy a predicate. */ + extension [T](arr: IArray[T]) def filterNot(p: T => Boolean): IArray[T] = + genericArrayOps(arr).filterNot(p) + + /** Finds the first element of the array satisfying a predicate, if any. */ + extension [T](arr: IArray[T]) def find(p: T => Boolean): Option[T] = + genericArrayOps(arr).find(p) + + /** Builds a new array by applying a function to all elements of this array + * and using the elements of the resulting collections. */ + extension [T](arr: IArray[T]) def flatMap[U: ClassTag](f: T => IterableOnce[U]): IArray[U] = + genericArrayOps(arr).flatMap(f) + + /** Flattens a two-dimensional array by concatenating all its rows + * into a single array. */ + extension [T](arr: IArray[T]) def flatten[U: ClassTag](using T => Iterable[U]): IArray[U] = + genericArrayOps(arr).flatten + + /** Folds the elements of this array using the specified associative binary operator. */ + extension [T](arr: IArray[T]) def fold[U >: T: ClassTag](z: U)(op: (U, U) => U): U = + genericArrayOps(arr).fold(z)(op) + + /** Applies a binary operator to a start value and all elements of this array, + * going left to right. */ + extension [T](arr: IArray[T]) def foldLeft[U: ClassTag](z: U)(op: (U, T) => U): U = + genericArrayOps(arr).foldLeft(z)(op) + + /** Applies a binary operator to all elements of this array and a start value, + * going right to left. */ + extension [T](arr: IArray[T]) def foldRight[U: ClassTag](z: U)(op: (T, U) => U): U = + genericArrayOps(arr).foldRight(z)(op) + + /** Tests whether a predicate holds for all elements of this array. */ + extension [T](arr: IArray[T]) def forall(p: T => Boolean): Boolean = + genericArrayOps(arr).forall(p) + + /** Apply `f` to each element for its side effects. */ + extension [T](arr: IArray[T]) def foreach[U](f: T => U): Unit = + genericArrayOps(arr).foreach(f) + + /** Selects the first element of this array. */ + extension [T](arr: IArray[T]) def head: T = + genericArrayOps(arr).head + + /** Optionally selects the first element. */ + extension [T](arr: IArray[T]) def headOption: Option[T] = + genericArrayOps(arr).headOption + + /** Finds index of first occurrence of some value in this array after or at some start index. */ + extension [T](arr: IArray[T]) def indexOf(elem: T, from: Int = 0): Int = + // `asInstanceOf` needed because `elem` does not have type `arr.T` + // We could use `arr.iterator.indexOf(elem, from)` or `arr.indexWhere(_ == elem, from)` + // but these would incur some overhead. + genericArrayOps(arr).indexOf(elem.asInstanceOf, from) + + /** Finds index of the first element satisfying some predicate after or at some start index. */ + extension [T](arr: IArray[T]) def indexWhere(p: T => Boolean, from: Int = 0): Int = + genericArrayOps(arr).indexWhere(p, from) + + /** Produces the range of all indices of this sequence. */ + extension [T](arr: IArray[T]) def indices: Range = + genericArrayOps(arr).indices + + /** The initial part of the array without its last element. */ + extension [T](arr: IArray[T]) def init: IArray[T] = + genericArrayOps(arr).init + + /** Tests whether the array is empty. */ + extension [T](arr: IArray[T]) def isEmpty: Boolean = + genericArrayOps(arr).isEmpty + + /** An iterator yielding the elemenst of this array. */ + extension [T](arr: IArray[T]) def iterator: Iterator[T] = + genericArrayOps(arr).iterator + + /** Selects the last element. */ + extension [T](arr: IArray[T]) def last: T = + genericArrayOps(arr).last + + /** Optionally selects the last element. */ + extension [T](arr: IArray[T]) def lastOption: Option[T] = + genericArrayOps(arr).lastOption + + /** Finds index of last occurrence of some value in this array before or at a given end index. */ + extension [T](arr: IArray[T]) def lastIndexOf(elem: T, end: Int = arr.length - 1): Int = + // see: same issue in `indexOf` + genericArrayOps(arr).lastIndexOf(elem.asInstanceOf, end) + + /** Finds index of last element satisfying some predicate before or at given end index. */ + extension [T](arr: IArray[T]) def lastIndexWhere(p: T => Boolean, end: Int = arr.length - 1): Int = + genericArrayOps(arr).lastIndexWhere(p, end) + + /** Builds a new array by applying a function to all elements of this array. */ + extension [T](arr: IArray[T]) def map[U: ClassTag](f: T => U): IArray[U] = + genericArrayOps(arr).map(f) + + /** Tests whether the array is not empty. */ + extension [T](arr: IArray[T]) def nonEmpty: Boolean = + genericArrayOps(arr).nonEmpty + + /** A pair of, first, all elements that satisfy predicate `p` and, second, all elements that do not. */ + extension [T](arr: IArray[T]) def partition(p: T => Boolean): (IArray[T], IArray[T]) = + genericArrayOps(arr).partition(p) + + /** Returns a new array with the elements in reversed order. */ + extension [T](arr: IArray[T]) def reverse: IArray[T] = + genericArrayOps(arr).reverse + + /** Computes a prefix scan of the elements of the array. */ + extension [T](arr: IArray[T]) def scan[U >: T: ClassTag](z: U)(op: (U, U) => U): IArray[U] = + genericArrayOps(arr).scan(z)(op) + + /** Produces an array containing cumulative results of applying the binary + * operator going left to right. */ + extension [T](arr: IArray[T]) def scanLeft[U: ClassTag](z: U)(op: (U, T) => U): IArray[U] = + genericArrayOps(arr).scanLeft(z)(op) + + /** Produces an array containing cumulative results of applying the binary + * operator going right to left. */ + extension [T](arr: IArray[T]) def scanRight[U: ClassTag](z: U)(op: (T, U) => U): IArray[U] = + genericArrayOps(arr).scanRight(z)(op) + + /** The size of this array. */ + extension [T](arr: IArray[T]) def size: Int = + arr.length + + /** Selects the interval of elements between the given indices. */ + extension [T](arr: IArray[T]) def slice(from: Int, until: Int): IArray[T] = + genericArrayOps(arr).slice(from, until) + + /** Sorts this array according to the Ordering which results from transforming + * an implicitly given Ordering with a transformation function. */ + extension [T](arr: IArray[T]) def sortBy[U: ClassTag](f: T => U)(using math.Ordering[U]): IArray[T] = + genericArrayOps(arr).sortBy(f) + + /** Sorts this array according to a comparison function. */ + extension [T](arr: IArray[T]) def sortWith(f: (T, T) => Boolean): IArray[T] = + genericArrayOps(arr).sortWith(f) + + /** Sorts this array according to an Ordering. */ + extension [T](arr: IArray[T]) def sorted(using math.Ordering[T]): IArray[T] = + genericArrayOps(arr).sorted + + /** Splits this array into a prefix/suffix pair according to a predicate. */ + extension [T](arr: IArray[T]) def span(p: T => Boolean): (IArray[T], IArray[T]) = + genericArrayOps(arr).span(p) + + /** Splits this array into two at a given position. */ + extension [T](arr: IArray[T]) def splitAt(n: Int): (IArray[T], IArray[T]) = + genericArrayOps(arr).splitAt(n) + + /** Tests whether this array starts with the given array. */ + extension [T](arr: IArray[T]) def startsWith[U >: T: ClassTag](that: IArray[U], offset: Int = 0): Boolean = + genericArrayOps(arr).startsWith(that) + + /** The rest of the array without its first element. */ + extension [T](arr: IArray[T]) def tail: IArray[T] = + genericArrayOps(arr).tail + + /** An array containing the first `n` elements of this array. */ + extension [T](arr: IArray[T]) def take(n: Int): IArray[T] = + genericArrayOps(arr).take(n) + + /** An array containing the last `n` elements of this array. */ + extension [T](arr: IArray[T]) def takeRight(n: Int): IArray[T] = + genericArrayOps(arr).takeRight(n) + + /** Takes longest prefix of elements that satisfy a predicate. */ + extension [T](arr: IArray[T]) def takeWhile(p: T => Boolean): IArray[T] = + genericArrayOps(arr).takeWhile(p) + + /** Returns a mutable copy of this immutable array. */ + extension [T](arr: IArray[T]) def toArray: Array[T] = + arr.clone.asInstanceOf[Array[T]] + + /** Converts an array of pairs into an array of first elements and an array of second elements. */ + extension [U: ClassTag, V: ClassTag](arr: IArray[(U, V)]) def unzip: (IArray[U], IArray[V]) = + genericArrayOps(arr).unzip + + /** Returns an array formed from this array and another iterable collection + * by combining corresponding elements in pairs. + * If one of the two collections is longer than the other, its remaining elements are ignored. */ + extension [T](arr: IArray[T]) def zip[U: ClassTag](that: IArray[U]): IArray[(T, U)] = + genericArrayOps(arr).zip(that) + end opaques type IArray[+T] = opaques.IArray[T] From b052e8b2b471e74a5dbb72bd5695c9b011092ad6 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 4 Feb 2021 16:36:06 +0100 Subject: [PATCH 2/2] Add implicit conversion from IArray to immutable.ArraySeq --- library/src/scala/IArray.scala | 44 ++++++++++++++++++++++++++++++++ tests/pos/IArrayToArraySeq.scala | 12 +++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/pos/IArrayToArraySeq.scala diff --git a/library/src/scala/IArray.scala b/library/src/scala/IArray.scala index d0f45fb9f2bc..4f63e4c39d72 100644 --- a/library/src/scala/IArray.scala +++ b/library/src/scala/IArray.scala @@ -270,6 +270,50 @@ object opaques: extension [T](arr: IArray[T]) def zip[U: ClassTag](that: IArray[U]): IArray[(T, U)] = genericArrayOps(arr).zip(that) + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapIArray[T](using DummyImplicit): Conversion[IArray[T], scala.collection.immutable.ArraySeq[T]] = + arr => scala.collection.immutable.ArraySeq.unsafeWrapArray(arr.asInstanceOf[Array[T]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapAnyRefIArray[T <: AnyRef](using DummyImplicit): Conversion[IArray[T], scala.collection.immutable.ArraySeq[T]] = + arr => scala.collection.immutable.ArraySeq.ofRef(arr.asInstanceOf[Array[T]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapIntIArray(using DummyImplicit): Conversion[IArray[Int], scala.collection.immutable.ArraySeq[Int]] = + arr => scala.collection.immutable.ArraySeq.ofInt(arr.asInstanceOf[Array[Int]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapDoubleIArray(using DummyImplicit): Conversion[IArray[Double], scala.collection.immutable.ArraySeq[Double]] = + arr => scala.collection.immutable.ArraySeq.ofDouble(arr.asInstanceOf[Array[Double]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapLongIArray(using DummyImplicit): Conversion[IArray[Long], scala.collection.immutable.ArraySeq[Long]] = + arr => scala.collection.immutable.ArraySeq.ofLong(arr.asInstanceOf[Array[Long]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapFloatIArray(using DummyImplicit): Conversion[IArray[Float], scala.collection.immutable.ArraySeq[Float]] = + arr => scala.collection.immutable.ArraySeq.ofFloat(arr.asInstanceOf[Array[Float]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapCharIArray(using DummyImplicit): Conversion[IArray[Char], scala.collection.immutable.ArraySeq[Char]] = + arr => scala.collection.immutable.ArraySeq.ofChar(arr.asInstanceOf[Array[Char]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapByteIArray(using DummyImplicit): Conversion[IArray[Byte], scala.collection.immutable.ArraySeq[Byte]] = + arr => scala.collection.immutable.ArraySeq.ofByte(arr.asInstanceOf[Array[Byte]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapShortIArray(using DummyImplicit): Conversion[IArray[Short], scala.collection.immutable.ArraySeq[Short]] = + arr => scala.collection.immutable.ArraySeq.ofShort(arr.asInstanceOf[Array[Short]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapBooleanIArray(using DummyImplicit): Conversion[IArray[Boolean], scala.collection.immutable.ArraySeq[Boolean]] = + arr => scala.collection.immutable.ArraySeq.ofBoolean(arr.asInstanceOf[Array[Boolean]]) + + /** Conversion from IArray to immutable.ArraySeq */ + given genericWrapUnitIArray(using DummyImplicit): Conversion[IArray[Unit], scala.collection.immutable.ArraySeq[Unit]] = + arr => scala.collection.immutable.ArraySeq.ofUnit(arr.asInstanceOf[Array[Unit]]) + end opaques type IArray[+T] = opaques.IArray[T] diff --git a/tests/pos/IArrayToArraySeq.scala b/tests/pos/IArrayToArraySeq.scala new file mode 100644 index 000000000000..0787d73eca59 --- /dev/null +++ b/tests/pos/IArrayToArraySeq.scala @@ -0,0 +1,12 @@ +def test: Unit = + IArray(2, 1, 3).toList + IArray(2, 1, 3).toSeq + IArray(2, 1, 3).updated(1, 2) + IArray(2, 1, 3).updated(1, "a") + IArray(2, 1, 3).sorted + IArray(2, 1, 3).appended("b") + IArray(2, 1, 3).prepended("b") + IArray(2, 1, 3).appendedAll(IArray(4,5, "a")) + IArray(2, 1, 3).prependedAll(IArray(4,5, "a")) + val x1: Seq[Int] = Array(1, 2) + val x2: Seq[Int] = IArray(1, 2)