/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ // $Id: Iterable.scala 15188 2008-05-24 15:01:02Z stepancheg $ package scalax.collection.generic import scalax.collection.mutable.{Buffer, ArrayBuffer, ListBuffer} import scalax.collection.immutable.{List, Nil, ::, Stream} import util.control.Breaks._ import Iterable._ /** Collection classes mixing in this class provide a method * elements which returns an iterator over all the * elements contained in the collection. * * @note If a collection has a known size, it should also sub-type Collection. * Only potentially unbounded collections should directly sub-class Iterable. * @author Matthias Zenger * @author Martin Odersky * @version 2.8 */ trait IterableTemplate[+CC[/*+*/B] <: IterableTemplate[CC, B] with Iterable[B], /*+*/A] { self/*: CC[A]*/ => /** The template itself seen as an instance of `CC[A]`. * @note: It would be logical to have a self type `CC[A]` instead, then we would not need * this method. Unfortunately, tyis runs afoul some pecularities in Scala's member resolution * algorithm: If the self type is a CC, then Iterable is one of its supertypes. Iterable * defines a number of concrete methods such as newBuilder which are abstract here. * The newBuilder method in Iterable[A] has type Builder[Iterable, A]. Because Scala * prefers concrete over abstract members, it is this newBuilder which is chosen, instead of * the abstract newBuilder in class IterableTemplate of type Builder[CC, A]. * Even for concrete methods we have a problem because the last mixin in the parents of CC is * Iterable, not IterableTemplate. So resolution picks the version in Iterable, which returns * again an Iterable, not a CC, as would be required. * These problems would be avoided if Scala computed the type of a member as the glb of the types * all members in the class and its superclasses types. * I think overall this would be a better design. */ protected[this] def thisCC: CC[A] = this.asInstanceOf[CC[A]] /** Creates a new iterator over all elements contained in this * object. * * @return the new iterator */ def elements: Iterator[A] /** Create a new builder for this IterableType */ def newBuilder[B]: Builder[CC, B] /** Is this collection empty? */ def isEmpty: Boolean = !elements.hasNext /** returns true iff this collection has a bound size. * Many APIs in this trait will not work on collections of * unbound sizes. */ def hasDefiniteSize = true /** Create a new iterable of type CC which contains all elements of this iterable * followed by all elements of Iterable `that' */ def ++[B >: A](that: Iterable[B]): CC[B] = { val b: Builder[CC, B] = (this: IterableTemplate[CC, A]).newBuilder[B] b ++= thisCC b ++= that b.result } /** Create a new iterable of type CC which contains all elements of this iterable * followed by all elements of Iterator `that' */ def ++[B >: A](that: Iterator[B]): CC[B] = { val b = newBuilder[B] b ++= thisCC b ++= that b.result } /** Returns the iterable resulting from applying the given function * f to each element of this iterable. * * @param f function to apply to each element. * @return f(a0), ..., f(an) if this * iterable is a0, ..., an. */ def map[B](f: A => B): CC[B] = { val b = newBuilder[B] for (x <- this) b += f(x) b.result } /** Applies the given function f to each element of * this iterable, then concatenates the results. * * @param f the function to apply on each element. * @return f(a0) ::: ... ::: f(an) if * this iterable is a0, ..., an. */ def flatMap[B](f: A => Iterable[B]): CC[B] = { val b = newBuilder[B] for (x <- this) b ++= f(x) b.result } /** Returns all the elements of this iterable that satisfy the * predicate p. The order of the elements is preserved. * @param p the predicate used to filter the iterable. * @return the elements of this iterable satisfying p. */ def filter(p: A => Boolean): CC[A] = { val b = newBuilder[A] for (x <- this) if (p(x)) b += x b.result } /** Removes all elements of the iterable which satisfy the predicate * p. This is like filter with the * predicate inversed. * * @param p the predicate to use to test elements * @return the iterable without all elements which satisfy p */ def remove(p: A => Boolean): CC[A] = filter(!p(_)) /** Partitions this iterable in two iterables according to a predicate. * * @param p the predicate on which to partition * @return a pair of iterables: the iterable that satisfies the predicate * p and the iterable that does not. * The relative order of the elements in the resulting iterables * is the same as in the original iterable. */ def partition(p: A => Boolean): (CC[A], CC[A]) = { val l, r = newBuilder[A] for (x <- this) (if (p(x)) l else r) += x (l.result, r.result) } /** Apply a function f to all elements of this * iterable object. * * @note Will not terminate for infinite-sized collections. * @param f a function that is applied to every element. * Note this function underlies the implementation of most other bulk operations. * It should be overridden in concrete collectionc classes with efficient implementations. */ def foreach(f: A => Unit): Unit = elements.foreach(f) /** Return true iff the given predicate `p` yields true for all elements * of this iterable. * * @note May not terminate for infinite-sized collections. * @param p the predicate */ def forall(p: A => Boolean): Boolean = { var result = true breakable { for (x <- this) if (!p(x)) { result = false; break } } result } /** Return true iff there is an element in this iterable for which the * given predicate `p` yields true. * * @note May not terminate for infinite-sized collections. * @param p the predicate */ def exists(p: A => Boolean): Boolean = { var result = false breakable { for (x <- this) if (p(x)) { result = true; break } } result } /** Count the number of elements in the iterable which satisfy a predicate. * * @param p the predicate for which to count * @return the number of elements satisfying the predicate p. */ def count(p: A => Boolean): Int = { var cnt = 0 for (x <- this) { if (p(x)) cnt += 1 } cnt } /** Find and return the first element of the iterable object satisfying a * predicate, if any. * * @note may not terminate for infinite-sized collections. * @note Might return different results for different runs, unless this iterable is ordered, or * the operator is associative and commutative. * @param p the predicate * @return an option containing the first element in the iterable object * satisfying p, or None if none exists. */ def find(p: A => Boolean): Option[A] = { var result: Option[A] = None breakable { for (x <- this) if (p(x)) { result = Some(x); break } } result } /** Combines the elements of this iterable object together using the binary * function f, from left to right, and starting with * the value z. * * @note Will not terminate for infinite-sized collections. * @note Might return different results for different runs, unless this iterable is ordered, or * the operator is associative and commutative. * @return f(... (f(f(z, a0), a1) ...), * an) if the iterable is * [a0, a1, ..., an]. */ def foldLeft[B](z: B)(op: (B, A) => B): B = { var result = z for (x <- this) result = op(result, x) result } /** Combines the elements of this iterable together using the binary * function f, from right to left, and starting with * the value z. * * @note Will not terminate for infinite-sized collections. * @note Might return different results for different runs, unless this iterable is ordered, or * the operator is associative and commutative. * @return f(a0, f(a1, f(..., f(an, z)...))) * if the iterable is [a0, a1, ..., an]. */ def foldRight[B](z: B)(op: (A, B) => B): B = elements.foldRight(z)(op) /** Similar to foldLeft but can be used as * an operator with the order of iterable and zero arguments reversed. * That is, z /: xs is the same as xs foldLeft z * @note Will not terminate for infinite-sized collections. * @note Might return different results for different runs, unless this iterable is ordered, or * the operator is associative and commutative. */ def /: [B](z: B)(op: (B, A) => B): B = foldLeft(z)(op) /** An alias for foldRight. * That is, xs :\ z is the same as xs foldRight z * @note Will not terminate for infinite-sized collections. * @note Might return different results for different runs, unless this iterable is ordered, or * the operator is associative and commutative. */ def :\ [B](z: B)(op: (A, B) => B): B = foldRight(z)(op) /** Combines the elements of this iterable object together using the binary * operator op, from left to right * @note Will not terminate for infinite-sized collections. * @note Might return different results for different runs, unless this iterable is ordered, or * the operator is associative and commutative. * @param op The operator to apply * @return op(... op(a0,a1), ..., an) if the iterable object has elements * a0, a1, ..., an. * @throws Predef.UnsupportedOperationException if the iterable object is empty. */ def reduceLeft[B >: A](op: (B, A) => B): B = { if (isEmpty) throw new UnsupportedOperationException("empty.reduceLeft") var result: B = elements.next var first = true for (x <- this) if (first) first = false else result = op(result, x) result } /** Combines the elements of this iterable object together using the binary * operator op, from right to left * @note Will not terminate for infinite-sized collections. * @note Might return different results for different runs, unless this iterable is ordered, or * the operator is associative and commutative. * @param op The operator to apply * * @return a0 op (... op (an-1 op an)...) * if the iterable object has elements a0, a1, ..., * an. * * @throws Predef.UnsupportedOperationException if the iterator is empty. */ def reduceRight[B >: A](op: (A, B) => B): B = elements.reduceRight(op) /** Returns an iterable formed from this iterable and the specified iterable * `other` by associating each element of the former with * the element at the same position in the latter. * If one of the two iterables is longer than the other, its remaining elements are ignored. */ def zip[B](that: Iterable[B]): CC[(A, B)] = { val these = this.elements val those = that.elements val b = this.newBuilder[(A, B)] while (these.hasNext && those.hasNext) b += ((these.next, those.next)) b.result } /** Returns a iterable formed from this iterable and the specified iterable * that by associating each element of the former with * the element at the same position in the latter. * * @param that iterable that may have a different length * as the self iterable. * @param thisElem element thisElem is used to fill up the * resulting iterable if the self iterable is shorter than * that b * @param thatElem element thatElem is used to fill up the * resulting iterable if that is shorter than * the self iterable * @return Iterable((a0,b0), ..., * (an,bn), (elem,bn+1), * ..., {elem,bm}) * when [a0, ..., an] zip * [b0, ..., bm] is * invoked where m > n. */ def zipAll[B, A1 >: A, B1 >: B](that: Iterable[B], thisElem: A1, thatElem: B1): CC[(A1, B1)] = { val these = this.elements val those = that.elements val b = newBuilder[(A1, B1)] while (these.hasNext && those.hasNext) b += ((these.next, those.next)) while (these.hasNext) b += ((these.next, thatElem)) while (those.hasNext) b += ((thisElem, those.next)) b.result } /** Zips this iterable with its indices. `s.zipWithIndex` is equivalent to * `s zip s.indices`, but is usually more efficient. */ def zipWithIndex: CC[(A, Int)] = { val b = newBuilder[(A, Int)] var i = 0 for (x <- this) { b += ((x, i)) i +=1 } b.result } /** Copy all elements to a given buffer * @note Will not terminate for infinite-sized collections. * @param dest The buffer to which elements are copied */ def copyToBuffer[B >: A](dest: Buffer[B]) { for (x <- this) dest += x } /** Fills the given array xs with at most `len` elements of * this iterable starting at position `start`. * Copying will stop oce either the end of the current iterable is reached or * `len` elements have been copied. * * @note Will not terminate for infinite-sized collections. * @param xs the array to fill. * @param start starting index. * @param len number of elements to copy * @pre the array must be large enough to hold all elements. */ def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) { var i = start val end = (start + len) min xs.length for (x <- this) { if (i < end) { xs(i) = x i += 1 } } } /** Fills the given array xs with the elements of * this iterable starting at position start * until either the end of the current iterable or the end of array `xs` is reached. * * @note Will not terminate for infinite-sized collections. * @param xs the array to fill. * @param start starting index. * @pre the array must be large enough to hold all elements. */ def copyToArray[B >: A](xs: Array[B], start: Int) { copyToArray(xs, start, xs.length - start) } /** Converts this collection to a fresh Array elements. * @note Will not terminate for infinite-sized collections. */ def toArray[B >: A]: Array[B] = { var size = 0 for (x <- this) size += 1 val result = new Array[B](size) copyToArray(result, 0) result } /** * Create a fresh list with all the elements of this iterable object. * @note Will not terminate for infinite-sized collections. */ def toList: List[A] = (new ListBuffer[A] ++ thisCC).toList /** * Returns a sequence containing all of the elements in this iterable object. * @note Will not terminate for infinite-sized collections. */ def toSequence: Sequence[A] = toList /** @deprecated use toSequence instead */ @deprecated def toSeq: Sequence[A] = toSequence /** * Create a stream which contains all the elements of this iterable object. * @note consider using projection for lazy behavior. */ def toStream: Stream[A] = elements.toStream /** Sort the iterable according to the comparison function * <(e1: a, e2: a) => Boolean, * which should be true iff e1 is smaller than * e2. * The sort is stable. That is elements that are equal wrt `lt` appear in the * same order in the sorted iterable as in the original. * * @param lt the comparison function * @return a iterable sorted according to the comparison function * <(e1: a, e2: a) => Boolean. * @ex
   *    List("Steve", "Tom", "John", "Bob")
   *      .sort((e1, e2) => (e1 compareTo e2) < 0) =
   *    List("Bob", "John", "Steve", "Tom")
* !!! def sortWith(lt : (A,A) => Boolean): CC[A] = { val arr = toArray Array.sortWith(arr, lt) val b = newBuilder[A] for (x <- arr) b += x b.result } */ /** Returns a string representation of this iterable object. The resulting string * begins with the string start and is finished by the string * end. Inside, the string representations of elements (w.r.t. * the method toString()) are separated by the string * sep. * * @ex List(1, 2, 3).mkString("(", "; ", ")") = "(1; 2; 3)" * @param start starting string. * @param sep separator string. * @param end ending string. * @return a string representation of this iterable object. */ def mkString(start: String, sep: String, end: String): String = addString(new StringBuilder(), start, sep, end).toString /** Returns a string representation of this iterable object. The string * representations of elements (w.r.t. the method toString()) * are separated by the string sep. * * @param sep separator string. * @return a string representation of this iterable object. */ def mkString(sep: String): String = addString(new StringBuilder(), sep).toString /** Converts a collection into a flat String by each element's toString method. */ def mkString = addString(new StringBuilder()).toString /** Write all elements of this iterable into given string builder. * The written text begins with the string start and is finished by the string * end. Inside, the string representations of elements (w.r.t. * the method toString()) are separated by the string * sep. */ def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = { b append start var first = true for (x <- this) { if (first) first = false else b append sep b append x } b append end } /** Write all elements of this string into given string builder. * The string representations of elements (w.r.t. the method toString()) * are separated by the string sep. */ def addString(b: StringBuilder, sep: String): StringBuilder = addString(b, "", sep, "") /** Write all elements of this string into given string builder without using * any separator between consecutive elements. */ def addString(b: StringBuilder): StringBuilder = addString(b, "") /** * returns a projection that can be used to call non-strict filter, * map, and flatMap methods that build projections * of the collection. def projection : Iterable.Projection[A] = new Iterable.Projection[A] { def elements = Iterable.this.elements override def force = Iterable.this } */ override def toString = mkString(stringPrefix + "(", ", ", ")") /** Defines the prefix of this object's toString representation. */ def stringPrefix : String = { var string = this.getClass.getName val idx1 = string.lastIndexOf('.' : Int) if (idx1 != -1) string = string.substring(idx1 + 1) val idx2 = string.indexOf('$') if (idx2 != -1) string = string.substring(0, idx2) string } /** Creates a view of this iterable @see IterableView */ def view: IterableView[CC, A] = new IterableView[CC, A] { // !!! Martin: We should maybe infer the type parameters here? val origin = thisCC val elements: Iterator[A] = self.elements } // The following methods return non-deterministic results, unless this iterable is an OrderedIterable /** The first element of this iterable. * * @note Might return different results for different runs, unless this iterable is ordered * @throws Predef.NoSuchElementException if the iterable is empty. */ def head: A = if (isEmpty) throw new NoSuchElementException else elements.next /** @deprecated use head instead */ @deprecated def first: A = head /** Returns as an option the first element of this iterable * or None if iterable is empty. * @note Might return different results for different runs, unless this iterable is ordered */ def headOption: Option[A] = if (isEmpty) None else Some(head) /** @deprecated use headOption instead * None if iterable is empty. */ @deprecated def firstOption: Option[A] = headOption /** An iterable consisting of all elements of this iterable * except the first one. * @note Might return different results for different runs, unless this iterable is ordered */ def tail: CC[A] = drop(1) /** Return an iterable consisting only of the first n * elements of this iterable, or else the whole iterable, if it has less * than n elements. * * @param n the number of elements to take * @note Might return different results for different runs, unless this iterable is ordered */ def take(n: Int): CC[A] = { val b = newBuilder[A] var i = 0 breakable { for (x <- this) { b += x i += 1 if (i == n) break } } b.result } /** Returns this iterable without its n first elements * If this iterable has less than n elements, the empty * iterable is returned. * * @param n the number of elements to drop * @return the new iterable * @note Might return different results for different runs, unless this iterable is ordered */ def drop(n: Int): CC[A] = { val b = newBuilder[A] var i = 0 for (x <- this) { if (i >= n) b += x i += 1 } b.result } /** A sub-iterable starting at index `from` * and extending up to (but not including) index `until`. * * @note c.slice(from, to) is equivalent to (but possibly more efficient than) * c.drop(from).take(to - from) * * @param from The index of the first element of the returned subsequence * @param until The index of the element following the returned subsequence * @throws IndexOutOfBoundsException if from < 0 * or length < from + len * @note Might return different results for different runs, unless this iterable is ordered */ def slice(from: Int, until: Int): CC[A] = { val b = newBuilder[A] var i = 0 breakable { for (x <- this) { if (i >= from) b += x i += 1 if (i == until) break } } b.result } /** The last element of this iterable. * * @throws Predef.NoSuchElementException if the iterable is empty. * @note Might return different results for different runs, unless this iterable is ordered */ def last: A = { var lst = head for (x <- this) lst = x lst } /** Returns as an option the last element of this iterable or * None if iterable is empty. * * @return the last element as an option. * @note Might return different results for different runs, unless this iterable is ordered */ def lastOption: Option[A] = if (isEmpty) None else Some(last) /** An iterable consisting of all elements of this iterable except the last one. * @throws Predef.UnsupportedOperationException if the stream is empty. * @note Might return different results for different runs, unless this iterable is ordered */ def init: CC[A] = { if (isEmpty) throw new UnsupportedOperationException("empty.init") var lst = head val b = newBuilder[A] for (x <- this) { b += lst lst = x } b.result } /** Returns the rightmost n elements from this iterable. * * @param n the number of elements to take * @note Might return different results for different runs, unless this iterable is ordered */ def takeRight(n: Int): CC[A] = { val b = newBuilder[A] val lead = elements drop n var go = false for (x <- this) { if (go) b += x else if (lead.hasNext) lead.next else go = true } b.result } /** Returns the iterable wihtout its rightmost n elements. * * @param n the number of elements to take * @note Might return different results for different runs, unless this iterable is ordered */ def dropRight(n: Int): CC[A] = { val b = newBuilder[A] val lead = elements drop n breakable { for (x <- this) { if (!lead.hasNext) break lead.next b += x } } b.result } /** Split the iterable at a given point and return the two parts thus * created. * * @param n the position at which to split * @return a pair of iterables composed of the first n * elements, and the other elements. * @note Might return different results for different runs, unless this iterable is ordered */ def splitAt(n: Int): (CC[A], CC[A]) = { val l, r = newBuilder[A] var i = 0 for (x <- this) (if (i < n) l else r) += x (l.result, r.result) } /** Returns the longest prefix of this iterable whose elements satisfy * the predicate p. * * @param p the test predicate. * @note Might return different results for different runs, unless this iterable is ordered */ def takeWhile(p: A => Boolean): CC[A] = { val b = newBuilder[A] breakable { for (x <- this) { if (!p(x)) break b += x } } b.result } /** Returns the longest suffix of this iterable whose first element * does not satisfy the predicate p. * * @param p the test predicate. * @note Might return different results for different runs, unless this iterable is ordered */ def dropWhile(p: A => Boolean): CC[A] = { val b = newBuilder[A] var go = false for (x <- this) { if (go) b += x else if (!p(x)) { go = true; b += x } } b.result } /** Returns a pair consisting of the longest prefix of the iterable whose * elements all satisfy the given predicate, and the rest of the iterable. * * @param p the test predicate * @return a pair consisting of the longest prefix of the iterable whose * elements all satisfy p, and the rest of the iterable. * @note Might return different results for different runs, unless this iterable is ordered */ def span(p: A => Boolean): (CC[A], CC[A]) = { val l, r = newBuilder[A] var toLeft = true for (x <- this) { toLeft = toLeft && p(x) (if (toLeft) l else r) += x } (l.result, r.result) } /** Checks if the other iterable object contains the same elements as this one. * * @note will not terminate for infinite-sized iterables. * @param that the other iterable * @return true, iff both iterables contain the same elements. * @note Might return different results for different runs, unless this iterable is ordered */ def sameElements[B >: A](that: OrderedIterable[B]): Boolean = { val these = this.elements val those = that.elements while (these.hasNext && those.hasNext && these.next() == those.next()) {} !these.hasNext && !those.hasNext } /** A sub-iterable view starting at index `from` * and extending up to (but not including) index `until`. * * @param from The index of the first element of the slice * @param until The index of the element following the slice * @note The difference between `view` and `slice` is that `view` produces * a view of the current iterable, whereas `slice` produces a new iterable. * * @note Might return different results for different runs, unless this iterable is ordered * @note view(from, to) is equivalent to view.slice(from, to) */ def view(from: Int, until: Int): IterableView[CC, A] = view.slice(from, until) }