diff options
author | Martin Odersky <odersky@gmail.com> | 2009-02-13 11:59:49 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2009-02-13 11:59:49 +0000 |
commit | 04840e2ed4530df9a5ca59b984bf2b37a976dc70 (patch) | |
tree | 61394762e202f8ab60e0d3a8e8ac688404241bc3 /src/library/scalax/collection/generic | |
parent | 708baf94764e2a839e24ca6204060a8d0664d88c (diff) | |
download | scala-04840e2ed4530df9a5ca59b984bf2b37a976dc70.tar.gz scala-04840e2ed4530df9a5ca59b984bf2b37a976dc70.tar.bz2 scala-04840e2ed4530df9a5ca59b984bf2b37a976dc70.zip |
new version of collection libraries
Diffstat (limited to 'src/library/scalax/collection/generic')
29 files changed, 1297 insertions, 395 deletions
diff --git a/src/library/scalax/collection/generic/Addable.scala b/src/library/scalax/collection/generic/Addable.scala new file mode 100755 index 0000000000..40a4f60e6e --- /dev/null +++ b/src/library/scalax/collection/generic/Addable.scala @@ -0,0 +1,64 @@ +/* __ *\ +** ________ ___ / / ___ 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 + +/** This class represents collections that can be augmented using a += operator. + * + * @autor Martin Odersky + * @owner Martin Odersky + * @version 2.8 + */ +trait Addable[+C <: Addable[C, A], A] { + + protected def thisCC: C + + /** Adds a single element to this collection and returns + * either the collection itself (if it is mutable), or a new collection + * with the added element. + * + * @param elem the element to add. + */ + def +(elem: A): C + + /** Adds two or more elements to this collection and returns + * either the collection itself (if it is mutable), or a new collection + * with the added elements. + * + * @param elem1 the first element to add. + * @param elem2 the second element to add. + * @param elems the remaining elements to add. + */ + def +(elem1: A, elem2: A, elems: A*): C = + thisCC + elem1 + elem2 ++ elems.asInstanceOf[Iterable[A]] // !@! + + /** Adds a number of elements provided by an iterable object + * via its <code>elements</code> method and returns + * either the collection itself (if it is mutable), or a new collection + * with the added elements. + * + * @param iter the iterable object. + */ + def ++(iter: Iterable[A]): C = (thisCC /: iter) (_ + _) + + /** Adds a number of elements provided by an iterator + * via its <code>elements</code> method and returns + * either the collection itself (if it is mutable), or a new collection + * with the added elements. + * + * @param iter the iterator + */ + def ++(iter: Iterator[A]): C = (thisCC /: iter) (_ + _) + +} + + + + diff --git a/src/library/scalax/collection/generic/AddableBuilder.scala b/src/library/scalax/collection/generic/AddableBuilder.scala new file mode 100644 index 0000000000..b1f3e4e522 --- /dev/null +++ b/src/library/scalax/collection/generic/AddableBuilder.scala @@ -0,0 +1,22 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: ListBuffer.scala 14378 2008-03-13 11:39:05Z dragos $ + +package scalax.collection.generic + +import collection.mutable.ListBuffer +import collection.immutable.{List, Nil, ::} + +class AddableBuilder[CC[B] <: Iterable[B] with Addable[CC[B], B], A](empty: CC[A]) extends Builder[CC, A] { + protected var elems: CC[A] = empty + def +=(x: A) { elems = elems + x } + def elements: Iterator[A] = elems.elements + def clear() { elems = empty } + def result: CC[A] = elems +} diff --git a/src/library/scalax/collection/generic/Builder.scala b/src/library/scalax/collection/generic/Builder.scala new file mode 100755 index 0000000000..155ca553fa --- /dev/null +++ b/src/library/scalax/collection/generic/Builder.scala @@ -0,0 +1,31 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: ListBuffer.scala 14378 2008-03-13 11:39:05Z dragos $ + +package scalax.collection.generic + +import generic._ + +trait Builder[+CC[B], A] extends Growable[A] { + def +=(x: A) + def elements: Iterator[A] + def result: CC[A] + + def mapResult[DD[B]](f: CC[A] => DD[A]) = + new Builder[DD, A] with Proxy { + val self = Builder.this + def +=(x: A) = self += x + def elements: Iterator[A] = self.elements + def clear() = self.clear() + override def ++=(xs: Iterator[A]) = self ++= xs + override def ++=(xs: collection.Iterable[A]) = self ++= xs + def result: DD[A] = f(Builder.this.result) + } +} + diff --git a/src/library/scalax/collection/generic/Cloneable.scala b/src/library/scalax/collection/generic/Cloneable.scala index 455c88e47b..acf9a16686 100644 --- a/src/library/scalax/collection/generic/Cloneable.scala +++ b/src/library/scalax/collection/generic/Cloneable.scala @@ -9,10 +9,11 @@ // $Id: CloneableCollection.scala 16893 2009-01-13 13:09:22Z cunei $ -package scala.collection.generic +package scalax.collection.generic /** A trait for cloneable collections. */ -trait Cloneable[A <: AnyRef] extends java.lang.Cloneable { +@cloneable +trait Cloneable[A <: AnyRef] { override def clone(): A = super.clone().asInstanceOf[A] } diff --git a/src/library/scalax/collection/generic/EmptyIterableFactory.scala b/src/library/scalax/collection/generic/EmptyIterableFactory.scala new file mode 100755 index 0000000000..7f110d13d2 --- /dev/null +++ b/src/library/scalax/collection/generic/EmptyIterableFactory.scala @@ -0,0 +1,17 @@ +package scalax.collection.generic + +import annotation.unchecked.uncheckedVariance + +trait EmptyIterableFactory[CC[+A] <: Iterable[A] with IterableTemplate[CC, A @uncheckedVariance]] extends IterableFactory[CC] { + + /** The empty collection of type CC */ + val empty: CC[Nothing] + + /** An override of newBuilder, to work off the empty object */ + override protected def newBuilder[A]: Builder[CC, A] = + empty.newBuilder[A] + + /** Create CC collection of specified elements */ + override def apply[A](args: A*): CC[A] = + empty ++ args.asInstanceOf[Iterable[A]] +} diff --git a/src/library/scalax/collection/generic/Growable.scala b/src/library/scalax/collection/generic/Growable.scala new file mode 100755 index 0000000000..960384f9d0 --- /dev/null +++ b/src/library/scalax/collection/generic/Growable.scala @@ -0,0 +1,58 @@ +/* __ *\ +** ________ ___ / / ___ 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 + +/** This class represents collections that can be augmented using a += operator. + * + * @autor Martin Odersky + * @owner Martin Odersky + * @version 2.8 + */ +trait Growable[A] { + + /** Adds a single element to this collection. + * + * @param elem the element to add. + */ + def +=(elem: A): Unit + + /** Adds two or more elements to this collection. + * + * @param elem1 the first element to add. + * @param elem2 the second element to add. + * @param elems the remaining elements to add. + */ + def +=(elem1: A, elem2: A, elems: A*) { + this += elem1 + this += elem2 + this ++= elems.asInstanceOf[Iterable[A]] // !@! + } + + /** Adds a number of elements provided by an iterator to this collection. + * + * @param iter the iterator. + */ + def ++=(iter: collection.Iterator[A]) { iter foreach += } + + /** Adds a number of elements provided by an iterable object to this collection. + * + * @param iter the iterable object. + */ + def ++=(iter: collection.Iterable[A]) { iter foreach += } + + /** Clears the collection contents. + */ + def clear() +} + + + + diff --git a/src/library/scalax/collection/generic/IterableFactory.scala b/src/library/scalax/collection/generic/IterableFactory.scala index 9570970abe..0cf9c8ac95 100755 --- a/src/library/scalax/collection/generic/IterableFactory.scala +++ b/src/library/scalax/collection/generic/IterableFactory.scala @@ -8,7 +8,7 @@ trait IterableFactory[CC[A] <: Iterable[A]] { protected def newBuilder[A]: Builder[CC, A] = apply().newBuilder[A].asInstanceOf[Builder[CC, A]] - // can't have an empty here because it is defined in subclass covariant.IterableFactory with type + // can't have an empty here because it is defined in subclass EmptyIterableFactory with type // CC[Nothing]. This type does not make sense for immutable iterables. /** Concatenate all the argument lists into a single list. @@ -88,10 +88,10 @@ trait IterableFactory[CC[A] <: Iterable[A]] { * increasing n. If `step > 0` the sequence terminates * with the largest value less than `end`. If `step < 0` * the sequence terminates with the smallest value greater than `end`. - * If `step == 0`, the sequence gors on infinitely (in that - * case the `range` operation might not terminate. + * If `step == 0`, an IllegalArgumentException is thrown. */ def range(start: Int, end: Int, step: Int): CC[Int] = { + if (step == 0) throw new IllegalArgumentException("zero step") val b = newBuilder[Int] var i = start while ((step <= 0 || i < end) && (step >= 0 || i > end)) { diff --git a/src/library/scalax/collection/generic/IterableForwarder.scala b/src/library/scalax/collection/generic/IterableForwarder.scala index 8613b18345..e38f030414 100644 --- a/src/library/scalax/collection/generic/IterableForwarder.scala +++ b/src/library/scalax/collection/generic/IterableForwarder.scala @@ -56,6 +56,4 @@ trait IterableForwarder[+A] extends Iterable[A] { override def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = underlying.addString(b, start, sep, end) override def head: A = underlying.head - override def last: A = underlying.last - override def sameElements[B >: A](that: OrderedIterable[B]): Boolean = underlying.sameElements(that) } diff --git a/src/library/scalax/collection/generic/IterableTemplate.scala b/src/library/scalax/collection/generic/IterableTemplate.scala index adbf5d2de7..cc562c308a 100755 --- a/src/library/scalax/collection/generic/IterableTemplate.scala +++ b/src/library/scalax/collection/generic/IterableTemplate.scala @@ -646,76 +646,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the 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 - * <code>None</code> 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 <code>n</code> 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 <code>n</code> 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. * @@ -732,71 +662,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the (l.result, r.result) } - /** Returns the longest prefix of this iterable whose elements satisfy - * the predicate <code>p</code>. - * - * @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 <code>p</code>. - * - * @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 <code>p</code>, 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`. * diff --git a/src/library/scalax/collection/generic/IterableView.scala b/src/library/scalax/collection/generic/IterableView.scala index 45a0a50be2..bb111e2252 100755 --- a/src/library/scalax/collection/generic/IterableView.scala +++ b/src/library/scalax/collection/generic/IterableView.scala @@ -25,7 +25,7 @@ trait IterableView[+UC[/*+*/B] <: Iterable[B], /*+*/A] extends Iterable[A] { sel case _ => origin } - private def isDelay = elements eq underlying.elements + protected def isDelay = elements eq underlying.elements private[this] var forced: UC[A] = _ private[this] var wasForced = false @@ -100,15 +100,6 @@ trait IterableView[+UC[/*+*/B] <: Iterable[B], /*+*/A] extends Iterable[A] { sel /** Non-strict variant of @see Iterable.slice */ override def slice(from: Int, until: Int): IterableView[UC, A] = newView(elements slice (from, until)) - /** Non-strict variant of @see Iterable.takeWhile */ - override def takeWhile(p: A => Boolean): IterableView[UC, A] = newView(elements takeWhile p) - - /** Non-strict variant of @see Iterable.dropWhile */ - override def dropWhile(p: A => Boolean): IterableView[UC, A] = newView(elements dropWhile p) - - /** Non-strict variant of @see Iterable.span */ - override def span(p: A => Boolean): (IterableView[UC, A], IterableView[UC, A]) = (takeWhile(p), dropWhile(p)) - /** The projection resulting from the concatenation of this projection with the <code>rest</code> projection. * @param rest The projection that gets appended to this projection * @deprecated Use ++ instead diff --git a/src/library/scalax/collection/generic/LazyBuilder.scala b/src/library/scalax/collection/generic/LazyBuilder.scala new file mode 100755 index 0000000000..74764351b6 --- /dev/null +++ b/src/library/scalax/collection/generic/LazyBuilder.scala @@ -0,0 +1,24 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: ListBuffer.scala 14378 2008-03-13 11:39:05Z dragos $ + +package scalax.collection.generic + +import collection.mutable.ListBuffer +import collection.immutable.{List, Nil, ::} + +abstract class LazyBuilder[+CC[B], A] extends Builder[CC, A] { + protected var parts = new ListBuffer[Iterator[A]] + def +=(x: A) = { parts += Iterator.single(x) } + override def ++=(xs: Iterator[A]) { parts += xs } + override def ++=(xs: Iterable[A]) { parts += xs.elements } + def elements: Iterator[A] = Iterator.iteratorIteratorWrapper(parts.elements).flatten // !!! can remove the wrapper once new compiler is in starr + def result: CC[A] + def clear() { parts.clear() } +} diff --git a/src/library/scalax/collection/generic/MapFactory.scala b/src/library/scalax/collection/generic/MapFactory.scala new file mode 100755 index 0000000000..d7413b8928 --- /dev/null +++ b/src/library/scalax/collection/generic/MapFactory.scala @@ -0,0 +1,9 @@ +package scalax.collection.generic + +trait MapFactory[CC[A, B] <: MapTemplate[A, B, CC]] { + + def empty[A, B]: CC[A, B] + + def apply[A, B](elems: (A, B)*): CC[A, B] = empty[A, B] ++ elems.asInstanceOf[Iterable[(A, B)]] // !@! + +} diff --git a/src/library/scalax/collection/generic/MapTemplate.scala b/src/library/scalax/collection/generic/MapTemplate.scala new file mode 100755 index 0000000000..6d1a9e3c93 --- /dev/null +++ b/src/library/scalax/collection/generic/MapTemplate.scala @@ -0,0 +1,247 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: Map.scala 16884 2009-01-09 16:52:09Z cunei $ + + +package scalax.collection.generic + +import collection.immutable.Set +import collection.mutable.ArrayBuffer +import annotation.unchecked.uncheckedVariance + +/** <p> +* A map is a collection that maps each key to one or zero values. + * </p> + * <p> + * This trait provides a limited interface, only allowing reading of elements. + * There are two extensions of this trait, in packages + * <code><a href="mutable$content.html" target="contentFrame"> + * scala.collection.mutable</a></code> + * and <code><a href="immutable$content.html" target="contentFrame"> + * scala.collection.immutable</a></code>, which provide functionality for + * adding new key/value mappings to a map. The trait in the first package is + * for maps that are modified destructively, whereas the trait in + * the second package is for immutable maps which create a new map + * when something is added or removed from them. + * </p> + * + * @author Matthias Zenger + * @author Martin Odersky + * @version 1.2, 31/12/2006 + */ +trait MapTemplate[A, B, +CC[A1, B1] <: Map[A1, B1] with MapTemplate[A1, B1, CC]] + extends PartialFunction[A, B] + with SizedIterable[(A, B)] + with Addable[CC[A, B], (A, B)] + with Subtractable[CC[A, B], A] { +self: CC[A, B] => + + def newBuilder[B]: Builder[SizedIterable, B] = new ArrayBuffer[B] + + override def thisCC: CC[A, B] = this + + /** This method returns a new map instance of the same class + * mapping keys of the same type to values of type <code>C</code>. + */ + def empty[C]: CC[A, C] + + /** Compute the number of key-to-value mappings. + * + * @return the number of mappings + */ + def size: Int + + /** Check if this map maps <code>key</code> to a value and return the + * value if it exists. + * + * @param key the key of the mapping of interest + * @return the value of the mapping, if it exists + */ + def get(key: A): Option[B] + + /** Check if this map maps <code>key</code> to a value. + * Return that value if it exists, otherwise return <code>default</code>. + */ + def getOrElse[B2 >: B](key: A, default: => B2): B2 = + get(key) match { + case Some(v) => v + case None => default + } + + /** Is this an empty map? + * + * @return <code>true</code> iff the map is empty. + */ + override def isEmpty: Boolean = size == 0 + + /** Retrieve the value which is associated with the given key. This + * method throws an exception if there is no mapping from the given + * key to a value. + * + * @param key the key + * @return the value associated with the given key. + */ + def apply(key: A): B = get(key) match { + case None => default(key) + case Some(value) => value + } + + /** Is the given key mapped to a value by this map? + * + * @param key the key + * @return <code>true</code> iff there is a mapping for key in this map + */ + def contains(key: A): Boolean = get(key) match { + case None => false + case Some(_) => true + } + + /** Does this map contain a mapping from the given key to a value? + * + * @param key the key + * @return <code>true</code> iff there is a mapping for key in this map + */ + def isDefinedAt(key: A) = contains(key) + + /** Creates an iterator for all keys. + * + * @return an iterator over all keys. + */ + def keys: Iterator[A] = new Iterator[A] { + val iter = self.elements + def hasNext = iter.hasNext + def next = iter.next._1 + } + + /** @return the keys of this map as a set. + */ + def keySet: Set[A] = new Set[A] { + def size = self.size + def contains(key : A) = self.contains(key) + def elements = self.elements.map(_._1) + def + (elem: A): Set[A] = immutable.Set[A]() ++ this + elem + def - (elem: A): Set[A] = immutable.Set[A]() ++ this - elem + override def newBuilder[B]: Builder[Set, B] = Set.newBuilder[B] + } + + /** Creates an iterator for a contained values. + * + * @return an iterator over all values. + */ + def values: Iterator[B] = new Iterator[B] { + val iter = self.elements + def hasNext = iter.hasNext + def next = iter.next._2 + } + + /** Creates a string representation for this map. + * + * @return a string showing all mappings + */ + override def toString() = + elements.toList.map(kv => kv._1 + " -> " + kv._2).mkString(stringPrefix + "(", ", ", ")") + + /** The default value for the map, returned when a key is not found + * The method implemented here yields an error, + * but it might be overridden in subclasses. + * + * @param key the given key value + * @throws Predef.NoSuchElementException + */ + def default(key: A): B = + throw new NoSuchElementException("key not found: " + key) + +/* + override def view: Map.View[A,B] = new Map.View[A, B] { + override def elements = self.elements + override def size = self.size + override def get(key: A): Option[B] = self.get(key) + } +*/ + def filterKeys(p: A => Boolean) = new MapView[CC, A, B] { + val origin = self + override def foreach(f: ((A, B)) => Unit): Unit = for (kv <- self) if (p(kv._1)) f(kv) + def elements = self.elements.filter(kv => p(kv._1)) + def size = { var sz = 0; foreach(_ => sz += 1); sz } + override def contains(key: A) = self.contains(key) && p(key) + def get(key: A) = if (!p(key)) None else self.get(key) + } + + def mapElements[C](f: B => C) = new MapView[CC, A,C] { + val origin = self + override def foreach(g: ((A, C)) => Unit): Unit = for ((k, v) <- self) g((k, f(v))) + def elements = for ((k, v) <- self.elements) yield (k, f(v)) + def size = self.size + override def contains(key: A) = self.contains(key) + def get(key: A) = self.get(key).map(f) + } + + /** Defines the prefix of this object's <code>toString</code> representation. + */ + override def stringPrefix: String = "Map" + + /** Add a key/value pair to this map. + * @param key the key + * @param value the value + * @return A new map with the new binding added to this map + */ + def update (key: A, value: B): CC[A, B] + + /** Add a key/value pair to this map. + * @param kv the key/value pair. + * @return A new map with the new binding added to this map + */ + def + (kv: (A, B)): CC[A, B] = update(kv._1, kv._2) + + /** Remove a key from this map + * @param key the key to be removed + * @return If the map does not contain a binding for <code>key</code> + * it is returned unchanged. Otherwise, return a new map + * without a binding for <code>key</code> + */ + def - (key: A): CC[A, B] + + /** This function transforms all the values of mappings contained + * in this map with function <code>f</code>. + * + * @param f A function over keys and values + * @return the updated map + */ + def transform[C](f: (A, B) => C): CC[A, C] = { + var res = empty[C] + for ((key, value) <- this) res += ((key, f(key, value))) + res + } + + /** Builds a new map with all key/value pairs of this map + * for which the predicate <code>p</code> returns <code>true</code>. + * + * @param p A predicate over key-value pairs + * @return the updated map + */ + override def filter(p: ((A, B)) => Boolean): CC[A, B] = { + var res = empty[B] + for (kv <- this) + if (p(kv)) res += kv + res + } + + /** Removes all the mappings for which the predicate + * <code>p</code> returns <code>false</code>. + * + * @param p A predicate over key-value pairs + * @return the updated map + */ + override def remove(p: ((A, B)) => Boolean): CC[A, B] = { + var res = this + for (kv <- this) + if (!p(kv)) res -= kv._1 + res + } +} diff --git a/src/library/scalax/collection/generic/MapView.scala b/src/library/scalax/collection/generic/MapView.scala new file mode 100644 index 0000000000..924fd1173e --- /dev/null +++ b/src/library/scalax/collection/generic/MapView.scala @@ -0,0 +1,44 @@ +/* __ *\ +** ________ ___ / / ___ 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 + +/** A non-strict view of a map. + * @author Martin Odersky + * @version 2.8 + */ +trait MapView[+UC[A1, B1] <: MapTemplate[A1, B1, UC] with Map[A1, B1], A, B] extends Map[A, B] { self => + + val origin: Map[A, _] + + def empty[C] = origin.empty[C] + + def elements: Iterator[(A, B)] + + val underlying: Map[A, _] = origin match { + case v: MapView[t, _, _] => v.underlying + case _ => origin + } + private[this] var forced: UC[A, B] = _ + private[this] var wasForced = false + + def force: UC[A, B] = { + if (!wasForced) { + forced = underlying.empty[B].asInstanceOf[UC[A, B]] ++ elements + wasForced = true + } + forced + } + + def update (key: A, value: B): UC[A, B] = force update (key, value) + def - (key: A): UC[A, B] = force - key +} + + diff --git a/src/library/scalax/collection/generic/MutableVectorTemplate.scala b/src/library/scalax/collection/generic/MutableVectorTemplate.scala new file mode 100755 index 0000000000..71c3f7bdf8 --- /dev/null +++ b/src/library/scalax/collection/generic/MutableVectorTemplate.scala @@ -0,0 +1,56 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: Vector.scala 15437 2008-06-25 16:22:45Z stepancheg $ + +package scalax.collection.generic + +import collection.mutable.Vector +import collection.mutable.Vector._ + +/** Sequences that support O(1) element access and O(1) length computation. + * plus an update operation. + * @author Sean McDirmid + * @author Martin Odersky + * @version 2.8 + */ +trait MutableVectorTemplate[+CC[B] <: MutableVectorTemplate[CC, B] with Vector[B], A] extends VectorTemplate[CC, A] { +self => + + def update(idx: Int, elem: A) + + /** Creates a view of this iterable @see OrderedIterable.View + */ + override def view: MutableVectorView[CC, A] = new MutableVectorView[CC, A] { // !!! Martin: We should maybe infer the type parameters here? + val origin: Vector[_] = thisCC + val length: Int = self.length + def apply(idx: Int): A = self.apply(idx) + def update(idx: Int, elem: A) = self.update(idx, elem) + } + + /** A sub-sequence 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 sequence, whereas `slice` produces a new sequence. + * + * @note view(from, to) is equivalent to view.slice(from, to) + */ + override def view(from: Int, until: Int): MutableVectorView[CC, A] = view.slice(from, until) + + def readOnly: collection.Vector[A] = new collection.Vector[A] { //!!! just use a VectorProxy? + def length = self.length + def apply(idx : Int) = self.apply(idx) + def newBuilder[B]: Builder[collection.Vector, B] = self.newBuilder[B] //mapResult (_.readOnly) + override def foreach(f: A => Unit) = self.foreach(f) + override def stringPrefix = self.stringPrefix+"RO" + } +} + diff --git a/src/library/scalax/collection/generic/MutableVectorView.scala b/src/library/scalax/collection/generic/MutableVectorView.scala new file mode 100755 index 0000000000..450943f61d --- /dev/null +++ b/src/library/scalax/collection/generic/MutableVectorView.scala @@ -0,0 +1,95 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: Sequence.scala 16092 2008-09-12 10:37:06Z nielsen $ + + +package scalax.collection.generic + +import collection.mutable.Vector +import collection.mutable.Vector._ + +/** A non-strict projection of an iterable. + * @author Sean McDirmid + * @author Martin Odersky + * @note this should really be a virtual class of SequenceFactory + */ +trait MutableVectorView[+UC[B] <: Vector[B], A] extends SequenceView[UC, A] with Vector[A] { +self => + + /** refined from Iterable.View */ + val origin: Vector[_] + + trait Transformed[B] extends super.Transformed[B] with MutableVectorView[UC, B] { + override val origin = self + override def elements: Iterator[B] = new Elements(0, length) + override protected def asCC = asInstanceOf[MutableVectorView[UC, B]] + } + + class Appended(that: Vector[A]) extends super.Appended[A](that) with Transformed[A] { + override def update(idx: Int, elem: A) { + val ll = self.length + if (idx < ll) self.update(idx, elem) else that.update(idx - ll, elem) + } + } + + class Sliced(from: Int, to: Int) extends super.Sliced(from, to) with Transformed[A] { + override def update(idx: Int, elem: A) { + if (idx >= 0 && idx < length) self.update(idx + from, elem) + else throw new IndexOutOfBoundsException(idx.toString) + } + override def slice(from1: Int, to1: Int) = + new self.Sliced(from + (from1 min length max 0) , to + (to1 min length max 0)) + } + + class Reversed extends super.Reversed with Transformed[A] { + override def update(idx: Int, elem: A) { + self.update(length - 1 - idx, elem) + } + } + + class Zipped[B](that: Vector[B]) extends super.Zipped[B](that) with Transformed[(A, B)] { + override def update(idx: Int, elem: (A, B)) { + self.update(idx, elem._1) + that.update(idx, elem._2) + } + } + + def ++(that: Vector[A]): MutableVectorView[UC, A] = + new Appended(that).asCC + + override def reverse: MutableVectorView[UC, A] = + (new Reversed).asCC + + private def toVector[B](xs: Iterable[B]): Vector[B] = xs match { + case ras: Vector[_] => ras.asInstanceOf[Vector[B]] + case _ => Vector() ++ xs + } + + override def zip[B](that: Iterable[B]): MutableVectorView[UC, (A, B)] = + new Zipped(toVector(that)).asCC + + override def zipWithIndex: MutableVectorView[UC, (A, Int)] = + zip((0 until length).asInstanceOf[Null]) // !@! + override def take(n: Int): MutableVectorView[UC, A] = + slice(0, n) + override def drop(n: Int): MutableVectorView[UC, A] = + slice(n, Math.MAX_INT) + override def splitAt(n: Int): (MutableVectorView[UC, A], MutableVectorView[UC, A]) = (take(n), drop(n)) + override def slice(from: Int, until: Int): MutableVectorView[UC, A] = + new Sliced(from, until).asCC + override def takeWhile(p: A => Boolean): MutableVectorView[UC, A] = + take(prefixLength(p)) + override def dropWhile(p: A => Boolean): MutableVectorView[UC, A] = + drop(prefixLength(p)) + override def span(p: A => Boolean): (MutableVectorView[UC, A], MutableVectorView[UC, A]) = { + val n = prefixLength(p) + (take(n), drop(n)) + } +} + diff --git a/src/library/scalax/collection/generic/OrderedIterableForwarder.scala b/src/library/scalax/collection/generic/OrderedIterableForwarder.scala new file mode 100755 index 0000000000..643f31d861 --- /dev/null +++ b/src/library/scalax/collection/generic/OrderedIterableForwarder.scala @@ -0,0 +1,37 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: IterableProxy.scala 15458 2008-06-28 20:23:22Z stepancheg $ + + +package scalax.collection.generic + +/** This trait implements a forwarder for iterable objects. It forwards + * all calls to a different iterable object, except for + * + * - toString, hashCode, equals, stringPrefix + * - newBuilder, view + * - all calls creating a new iterable object of the same kind + * + * The above methods are forwarded by subclass IterableProxy + * + * @author Martin Odersky + * @version 2.8 + */ +trait OrderedIterableForwarder[+A] extends OrderedIterable[A] with IterableForwarder[A] { + + /** The iterable object to which calls are forwarded */ + protected def underlying: OrderedIterable[A] + + // Iterable delegates + // Iterable methods could be printed by cat IterableTemplate.scala | sed -n '/trait Iterable/,$ p' | egrep '^ (override )?def' + + override def last: A = underlying.last + override def lastOption: Option[A] = underlying.lastOption + override def sameElements[B >: A](that: OrderedIterable[B]): Boolean = underlying.sameElements(that) +} diff --git a/src/library/scalax/collection/generic/OrderedIterableTemplate.scala b/src/library/scalax/collection/generic/OrderedIterableTemplate.scala index 9e61daa418..501cbf6447 100755 --- a/src/library/scalax/collection/generic/OrderedIterableTemplate.scala +++ b/src/library/scalax/collection/generic/OrderedIterableTemplate.scala @@ -13,6 +13,8 @@ package scalax.collection.generic import OrderedIterable._ +import util.control.Breaks._ + /** Ordered iterables are iterables where the `elements` method always returns elements in the same * order (namely the order in which elements were appended to the iterable). In particular, one has * for every two ordered iterables `xs` and `ys`: @@ -20,4 +22,140 @@ import OrderedIterable._ * `(xs ++ ys).elements = xs.elements ++ ys.elements */ trait OrderedIterableTemplate[+CC[/*+*/B] <: OrderedIterableTemplate[CC, B] with OrderedIterable[B], /*+*/A] - extends IterableTemplate[CC, A] + extends IterableTemplate[CC, A] { + + /** 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 + * <code>None</code> 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 <code>n</code> 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 <code>n</code> 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 + } + + /** Returns the longest prefix of this iterable whose elements satisfy + * the predicate <code>p</code>. + * + * @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 <code>p</code>. + * + * @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 <code>p</code>, 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 + } +} diff --git a/src/library/scalax/collection/generic/OrderedIterableView.scala b/src/library/scalax/collection/generic/OrderedIterableView.scala new file mode 100755 index 0000000000..fd04daa0b6 --- /dev/null +++ b/src/library/scalax/collection/generic/OrderedIterableView.scala @@ -0,0 +1,85 @@ +/* __ *\ +** ________ ___ / / ___ 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 + +/** A non-strict projection of an iterable. + * @author Sean McDirmid + * @author Martin Odersky + * @note this should really be a virtual class of SequenceFactory + */ +trait OrderedIterableView[+UC[/*+*/B] <: Iterable[B], /*+*/A] extends IterableView[UC, A] with OrderedIterable[A] { self => + + val origin: OrderedIterable[_] + + /** Builds a new view object. This method needs to be overridden in subclasses + * which refine in IterableView type + */ + protected override def newView[B](elems: Iterator[B]) = new OrderedIterableView[UC, B] { + val origin = if (self.isDelay) self.origin else self + val elements = elems + } + + /** Non-strict variant of @see IterableLike.++ */ + override def ++[B >: A](that: Iterator[B]): OrderedIterableView[UC, B] = newView(elements ++ that) + + /** Non-strict variant of @see IterableLike.++ */ + override def ++[B >: A](that: Iterable[B]): OrderedIterableView[UC, B] = newView(elements ++ that.elements) + + /** Non-strict variant of @see IterableLike.map */ + override def map[B](f: A => B): OrderedIterableView[UC, B] = newView(elements map f) + + /** Non-strict variant of @see IterableLike.flatMap */ + override def flatMap[B](f: A => Iterable[B]): OrderedIterableView[UC, B] = newView(elements flatMap (f(_).elements)) + + /** Non-strict variant of @see IterableLike.filter */ + override def filter(p: A => Boolean): OrderedIterableView[UC, A] = newView(elements filter p) + + /** Non-strict variant of @see IterableLike.partition */ + override def partition(p: A => Boolean): (OrderedIterableView[UC, A], OrderedIterableView[UC, A]) = { + val (li, ri) = elements partition p + (newView(li), newView(ri)) + } + + /** Non-strict variant of @see IterableLike.zip */ + override def zip[B](other: Iterable[B]): OrderedIterableView[UC, (A, B)] = newView(elements zip other.elements) + + /** Non-strict variant of @see IterableLike.zipWithIndex */ + override def zipWithIndex: OrderedIterableView[UC, (A, Int)] = newView(elements.zipWithIndex) + + /* Non-strict variant of @see IterableLike.zipAll + * This is not enabled because it can't be specialized in VectorView: + * VectorView is not covariant, yet must maintain updatability. Impossible to do this + * with this type signature. + override def zipAll[B, A1 >: A, B1 >: B](that: Iterable[B], thisElem: A1, thatElem: B1): OrderedIterableView[UC, (A1, B1)] = + newView(elements zipAll (that.elements, thisElem, thatElem)) + */ + + /** Non-strict variant of @see Iterable.take */ + override def take(n: Int): OrderedIterableView[UC, A] = newView(elements take n) + + /** Non-strict variant of @see Iterable.drop */ + override def drop(n: Int): OrderedIterableView[UC, A] = newView(elements drop n) + + /** Non-strict variant of @see Iterable.splitAt */ + override def splitAt(n: Int): (OrderedIterableView[UC, A], OrderedIterableView[UC, A]) = (take(n), drop(n)) + + /** Non-strict variant of @see Iterable.slice */ + override def slice(from: Int, until: Int): OrderedIterableView[UC, A] = newView(elements slice (from, until)) + + /** Non-strict variant of @see Iterable.takeWhile */ + override def takeWhile(p: A => Boolean): OrderedIterableView[UC, A] = newView(elements takeWhile p) + + /** Non-strict variant of @see Iterable.dropWhile */ + override def dropWhile(p: A => Boolean): OrderedIterableView[UC, A] = newView(elements dropWhile p) + + /** Non-strict variant of @see Iterable.span */ + override def span(p: A => Boolean): (OrderedIterableView[UC, A], OrderedIterableView[UC, A]) = (takeWhile(p), dropWhile(p)) +} diff --git a/src/library/scalax/collection/generic/SetFactory.scala b/src/library/scalax/collection/generic/SetFactory.scala index 0fbcf68466..458d4bbade 100644 --- a/src/library/scalax/collection/generic/SetFactory.scala +++ b/src/library/scalax/collection/generic/SetFactory.scala @@ -6,4 +6,6 @@ trait SetFactory[CC[A] <: SetTemplate[CC, A] with Set[A]] extends IterableFactor def apply[A](elems: A*): CC[A] = empty[A] ++ elems.asInstanceOf[Iterable[A]] // !@! + override def newBuilder[B]: Builder[CC, B] = new AddableBuilder[CC, B](empty) + } diff --git a/src/library/scalax/collection/generic/SetTemplate.scala b/src/library/scalax/collection/generic/SetTemplate.scala index 9c3056cc04..bd94f10fc0 100755 --- a/src/library/scalax/collection/generic/SetTemplate.scala +++ b/src/library/scalax/collection/generic/SetTemplate.scala @@ -31,7 +31,12 @@ package scalax.collection.generic * @author Martin Odersky * @version 2.8 */ -trait SetTemplate[+CC[B] <: SetTemplate[CC, B] with Set[B], A] extends (A => Boolean) with SizedIterable[A] with OrderedIterableTemplate[CC, A] { +trait SetTemplate[+CC[B] <: SetTemplate[CC, B] with Set[B], A] + extends (A => Boolean) + with SizedIterable[A] + with IterableTemplate[CC, A] + with Addable[CC[A], A] + with Subtractable[CC[A], A] { /** Returns the number of elements in this set. * @@ -52,13 +57,13 @@ trait SetTemplate[+CC[B] <: SetTemplate[CC, B] with Set[B], A] extends (A => Boo /** Create a new set with an additional element. */ - def +(elem: A): CC[A] + def + (elem: A): CC[A] /** Remove a single element from a set. * @param elem the element to be removed * @return a new set with the element removed. */ - def -(elem: A): CC[A] + def - (elem: A): CC[A] /** Checks if this set is empty. * @@ -76,43 +81,6 @@ trait SetTemplate[+CC[B] <: SetTemplate[CC, B] with Set[B], A] extends (A => Boo */ def apply(elem: A): Boolean = contains(elem) - /** Add two or more elements to this set. - * @param elem1 the first element. - * @param elem2 the second element. - * @param elems the remaining elements. - * @return a new set with the elements added. - */ - def + (elem1: A, elem2: A, elems: A*): CC[A] = { - thisCC + elem1 + elem2 ++ elems.asInstanceOf[Iterable[A]] - } - - /** Remove two or more elements from this set. - * - * @param elem1 the first element. - * @param elem2 the second element. - * @param elems the remaining elements. - * @return a new set with the elements removed. - */ - def - (elem1: A, elem2: A, elems: A*): CC[A] = - this - elem1 - elem2 -- elems.asInstanceOf[Iterable[A]] - - /** Remove all the elements provided by an iterator - * of the iterable object <code>elems</code> from the set. - * - * @param elems An iterable object containing the elements to remove from the set. - * @return a new set with the elements removed. - */ - def -- (elems: Iterable[A]): CC[A] = this -- elems.elements - - /** Remove all the elements provided by an iterator - * <code>elems</code> from the set. - * - * @param elems An iterator containing the elements to remove from the set. - * @return a new set with the elements removed. - */ - def -- (elems: Iterator[A]): CC[A] = - (thisCC /: elems) (_ - _) - /** This method computes an intersection with set <code>that</code>. * It removes all the elements that are not present in <code>that</code>. * @@ -137,6 +105,9 @@ trait SetTemplate[+CC[B] <: SetTemplate[CC, B] with Set[B], A] extends (A => Boo */ def subsetOf(that: Set[A]): Boolean = forall(that.contains) +/* What a mess! We need to remove these methods, but can't without breaking + * existing code. What to do? + /** Compares this set with another object and returns true, iff the * other object is also a set which contains the same elements as * this set. @@ -156,18 +127,22 @@ trait SetTemplate[+CC[B] <: SetTemplate[CC, B] with Set[B], A] extends (A => Boo false } - /* @deprecated hashCode is not stable for mutable sets. - * if you intend to have object identity hashCode and wish the deprecated warning + /* @deprecated Since the previous hashCode is not stable for mutable sets, + * the implementation of this method has been changed to + * standard address-based hashCode from java.lang.Object. + * If you relied on the old behavior, y + * IT has been + * if you intend to have object identity hashCode and wish the deprecated warning * to go away, cast this set to AnyRef before calling hashCode. */ @deprecated override def hashCode() = (0 /: this)((hash, e) => hash + e.hashCode()) - +*/ /** Defines the prefix of this object's <code>toString</code> representation. */ override def stringPrefix: String = "Set" /** Need to override string, so that it's not the Function1's string that gets mixed in. */ - override def toString = super[OrderedIterableTemplate].toString + override def toString = super[IterableTemplate].toString } diff --git a/src/library/scalax/collection/generic/Shrinkable.scala b/src/library/scalax/collection/generic/Shrinkable.scala new file mode 100755 index 0000000000..e6d3b085f3 --- /dev/null +++ b/src/library/scalax/collection/generic/Shrinkable.scala @@ -0,0 +1,54 @@ +/* __ *\ +** ________ ___ / / ___ 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 + +/** This class represents collections that can be reduced using a -= operator. + * + * @autor Martin Odersky + * @owner Martin Odersky + * @version 2.8 + */ +trait Shrinkable[A] { + + /** Removes a single element from this collection. + * + * @param elem the element to remove. + */ + def -=(elem: A): Unit + + /** Removes two or more elements from this collection. + * + * @param elem1 the first element to remove. + * @param elem2 the second element to remove. + * @param elems the remaining elements to remove. + */ + def -=(elem1: A, elem2: A, elems: A*) { + this -= elem1 + this -= elem2 + this --= elems.asInstanceOf[Iterable[A]] // !@! + } + + /** Removes a number of elements provided by an iterator from this collection. + * + * @param iter the iterator. + */ + def --=(iter: collection.Iterator[A]) { iter foreach -= } + + /** Removes a number of elements provided by an iterable object from this collection. + * + * @param iter the iterable object. + */ + def --=(iter: collection.Iterable[A]) { iter foreach -= } +} + + + + diff --git a/src/library/scalax/collection/generic/Subtractable.scala b/src/library/scalax/collection/generic/Subtractable.scala new file mode 100755 index 0000000000..93fe2f8190 --- /dev/null +++ b/src/library/scalax/collection/generic/Subtractable.scala @@ -0,0 +1,64 @@ +/* __ *\ +** ________ ___ / / ___ 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 + +/** This class represents collections that can be reduced using a -= operator. + * + * @autor Martin Odersky + * @owner Martin Odersky + * @version 2.8 + */ +trait Subtractable[+C <: Subtractable[C, A], A] { + + protected def thisCC: C + + /** Removes a single element from this collection and returns + * either the collection itself (if it is mutable), or a new collection + * with the removed element. + * + * @param elem the element to remove. + */ + def -(elem: A): C + + /** Removes two or more elements from this collection and returns + * either the collection itself (if it is mutable), or a new collection + * with the removed elements. + * + * @param elem1 the first element to remove. + * @param elem2 the second element to remove. + * @param elems the remaining elements to remove. + */ + def -(elem1: A, elem2: A, elems: A*): C = + thisCC - elem1 - elem2 -- elems.asInstanceOf[Iterable[A]] // !@! + + /** Removes a number of elements provided by an iterable object + * via its <code>elements</code> method and returns + * either the collection itself (if it is mutable), or a new collection + * with the removed elements. + * + * @param iter the iterable object. + */ + def --(iter: Iterable[A]): C = (thisCC /: iter) (_ - _) + + /** Removes a number of elements provided by an iterator + * via its <code>elements</code> method and returns + * either the collection itself (if it is mutable), or a new collection + * with the removed elements. + * + * @param iter the iterator + */ + def --(iter: Iterator[A]): C = (thisCC /: iter) (_ - _) + +} + + + + diff --git a/src/library/scalax/collection/generic/covartest/IterableForwarder.scala b/src/library/scalax/collection/generic/covartest/IterableForwarder.scala index cd4a754e97..58290cfc68 100755 --- a/src/library/scalax/collection/generic/covartest/IterableForwarder.scala +++ b/src/library/scalax/collection/generic/covartest/IterableForwarder.scala @@ -56,6 +56,4 @@ trait IterableForwarder[+A] extends Iterable[A] { override def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = underlying.addString(b, start, sep, end) override def head: A = underlying.head - override def last: A = underlying.last - override def sameElements[B >: A](that: OrderedIterable[B]): Boolean = underlying.sameElements(that) } diff --git a/src/library/scalax/collection/generic/covartest/IterableTemplate.scala b/src/library/scalax/collection/generic/covartest/IterableTemplate.scala index 27772b2ece..791d698a75 100755 --- a/src/library/scalax/collection/generic/covartest/IterableTemplate.scala +++ b/src/library/scalax/collection/generic/covartest/IterableTemplate.scala @@ -56,6 +56,11 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] */ def newBuilder[B]: Builder[CC, B] + /** Create a new builder for this IterableType + * with a hint what that its size should be size `sizeHint` + */ + def newBuilder[B](sizeHint: Int): Builder[CC, B] = newBuilder[B] + /** Is this collection empty? */ def isEmpty: Boolean = !elements.hasNext @@ -65,7 +70,7 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] */ def hasDefiniteSize = true - /** Create a new sequence of type CC which contains all elements of this sequence + /** 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] = { @@ -75,7 +80,7 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] b.result } - /** Create a new sequence of type IterableType which contains all elements of this sequence + /** 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] = { @@ -85,12 +90,12 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] b.result } - /** Returns the sequence resulting from applying the given function - * <code>f</code> to each element of this sequence. + /** Returns the iterable resulting from applying the given function + * <code>f</code> to each element of this iterable. * * @param f function to apply to each element. * @return <code>f(a<sub>0</sub>), ..., f(a<sub>n</sub>)</code> if this - * sequence is <code>a<sub>0</sub>, ..., a<sub>n</sub></code>. + * iterable is <code>a<sub>0</sub>, ..., a<sub>n</sub></code>. */ def map[B](f: A => B): CC[B] = { val b = newBuilder[B] @@ -99,11 +104,11 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] } /** Applies the given function <code>f</code> to each element of - * this sequence, then concatenates the results. + * this iterable, then concatenates the results. * * @param f the function to apply on each element. * @return <code>f(a<sub>0</sub>) ::: ... ::: f(a<sub>n</sub>)</code> if - * this sequence is <code>a<sub>0</sub>, ..., a<sub>n</sub></code>. + * this iterable is <code>a<sub>0</sub>, ..., a<sub>n</sub></code>. */ def flatMap[B](f: A => Iterable[B]): CC[B] = { val b = newBuilder[B] @@ -111,10 +116,10 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] b.result } - /** Returns all the elements of this sequence that satisfy the + /** Returns all the elements of this iterable that satisfy the * predicate <code>p</code>. The order of the elements is preserved. - * @param p the predicate used to filter the list. - * @return the elements of this list satisfying <code>p</code>. + * @param p the predicate used to filter the iterable. + * @return the elements of this iterable satisfying <code>p</code>. */ def filter(p: A => Boolean): CC[A] = { val b = newBuilder[A] @@ -128,7 +133,7 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] * predicate inversed. * * @param p the predicate to use to test elements - * @return the list without all elements which satisfy <code>p</code> + * @return the iterable without all elements which satisfy <code>p</code> */ def remove(p: A => Boolean): CC[A] = filter(!p(_)) @@ -203,6 +208,8 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +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 <code>p</code>, or <code>None</code> if none exists. @@ -221,8 +228,10 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] * the value <code>z</code>. * * @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 <code>f(... (f(f(z, a<sub>0</sub>), a<sub>1</sub>) ...), - * a<sub>n</sub>)</code> if the list is + * a<sub>n</sub>)</code> if the iterable is * <code>[a<sub>0</sub>, a<sub>1</sub>, ..., a<sub>n</sub>]</code>. */ def foldLeft[B](z: B)(op: (B, A) => B): B = { @@ -232,32 +241,40 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] result } - /** Combines the elements of this list together using the binary + /** Combines the elements of this iterable together using the binary * function <code>f</code>, from right to left, and starting with * the value <code>z</code>. * * @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 <code>f(a<sub>0</sub>, f(a<sub>1</sub>, f(..., f(a<sub>n</sub>, z)...)))</code> - * if the list is <code>[a<sub>0</sub>, a1, ..., a<sub>n</sub>]</code>. + * if the iterable is <code>[a<sub>0</sub>, a1, ..., a<sub>n</sub>]</code>. */ def foldRight[B](z: B)(op: (A, B) => B): B = elements.foldRight(z)(op) /** Similar to <code>foldLeft</code> but can be used as - * an operator with the order of list and zero arguments reversed. + * an operator with the order of iterable and zero arguments reversed. * That is, <code>z /: xs</code> is the same as <code>xs foldLeft z</code> * @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 <code>foldRight</code>. * That is, <code>xs :\ z</code> is the same as <code>xs foldRight z</code> * @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 <code>op</code>, 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 <code>op(... op(a<sub>0</sub>,a<sub>1</sub>), ..., a<sub>n</sub>)</code> if the iterable object has elements @@ -277,6 +294,8 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] /** Combines the elements of this iterable object together using the binary * operator <code>op</code>, 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 <code>a<sub>0</sub> op (... op (a<sub>n-1</sub> op a<sub>n</sub>)...)</code> @@ -288,7 +307,7 @@ trait IterableTemplate[+CC[+B] <: IterableTemplate[CC, B] with Iterable[B], +A] def reduceRight[B >: A](op: (A, B) => B): B = elements.reduceRight(op) - /** Returns an iterable formed from this iterable and the specified list + /** 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. @@ -356,7 +375,7 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the } /** Fills the given array <code>xs</code> with at most `len` elements of - * this sequence starting at position `start`. + * 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. * @@ -378,7 +397,7 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the } /** Fills the given array <code>xs</code> with the elements of - * this sequence starting at position <code>start</code> + * this iterable starting at position <code>start</code> * until either the end of the current iterable or the end of array `xs` is reached. * * @note Will not terminate for infinite-sized collections. @@ -431,7 +450,7 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the * same order in the sorted iterable as in the original. * * @param lt the comparison function - * @return a list sorted according to the comparison function + * @return a iterable sorted according to the comparison function * <code><(e1: a, e2: a) => Boolean</code>. * @ex <pre> * List("Steve", "Tom", "John", "Bob") @@ -454,7 +473,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the * <code>sep</code>. * * @ex <code>List(1, 2, 3).mkString("(", "; ", ")") = "(1; 2; 3)"</code> - * @note Will not terminate for infinite-sized collections. * @param start starting string. * @param sep separator string. * @param end ending string. @@ -467,7 +485,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the * representations of elements (w.r.t. the method <code>toString()</code>) * are separated by the string <code>sep</code>. * - * @note Will not terminate for infinite-sized collections. * @param sep separator string. * @return a string representation of this iterable object. */ @@ -475,7 +492,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the addString(new StringBuilder(), sep).toString /** Converts a collection into a flat <code>String</code> by each element's toString method. - * @note Will not terminate for infinite-sized collections. */ def mkString = addString(new StringBuilder()).toString @@ -485,7 +501,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the * <code>end</code>. Inside, the string representations of elements (w.r.t. * the method <code>toString()</code>) are separated by the string * <code>sep</code>. - * @note Will not terminate for infinite-sized collections. */ def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = { b append start @@ -501,28 +516,13 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the /** Write all elements of this string into given string builder. * The string representations of elements (w.r.t. the method <code>toString()</code>) * are separated by the string <code>sep</code>. - * @note Will not terminate for infinite-sized collections. */ - def addString(b: StringBuilder, sep: String): StringBuilder = { - var first = true - for (x <- this) { - if (first) first = false - else b append sep - b append x - } - b - } + 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. - * @note Will not terminate for infinite-sized collections. */ - def addString(b: StringBuilder): StringBuilder = { - for (x <- this) { - b append x - } - b - } + def addString(b: StringBuilder): StringBuilder = addString(b, "") /** * returns a projection that can be used to call non-strict <code>filter</code>, @@ -547,7 +547,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the 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? @@ -557,10 +556,10 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the // The following methods return non-deterministic results, unless this iterable is an OrderedIterable - /** The first element of this sequence. + /** The first element of this iterable. * * @note Might return different results for different runs, unless this iterable is ordered - * @throws Predef.NoSuchAentException if the sequence is empty. + * @throws Predef.NoSuchElementException if the iterable is empty. */ def head: A = if (isEmpty) throw new NoSuchElementException else elements.next @@ -574,7 +573,7 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the def headOption: Option[A] = if (isEmpty) None else Some(head) /** @deprecated use headOption instead - * <code>None</code> if list is empty. + * <code>None</code> if iterable is empty. */ @deprecated def firstOption: Option[A] = headOption @@ -589,7 +588,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the * than <code>n</code> elements. * * @param n the number of elements to take - * @return a possibly projected sequence * @note Might return different results for different runs, unless this iterable is ordered */ def take(n: Int): CC[A] = { @@ -648,74 +646,6 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the b.result } - /** The last element of this iterable. - * - * @throws Predef.NoSuchElementException if the sequence 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 - * <code>None</code> 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. - * @note Might return different results for different runs, unless this iterable is ordered - */ - def init: CC[A] = { - var lst = head - val b = newBuilder[A] - for (x <- this) { - b += lst - lst = x - } - b.result - } - - /** Returns the rightmost <code>n</code> 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 <code>n</code> 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. * @@ -732,82 +662,13 @@ b * @param thatElem element <code>thatElem</code> is used to fill up the (l.result, r.result) } - /** Returns the longest prefix of this sequence whose elements satisfy - * the predicate <code>p</code>. - * - * @param p the test predicate. - * @return the longest prefix of this sequence whose elements satisfy - * the predicate <code>p</code>. - * @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 sequence whose first element - * does not satisfy the predicate <code>p</code>. - * - * @param p the test predicate. - * @return the longest suffix of the sequence whose first element - * does not satisfy the predicate <code>p</code>. - * @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 list whose - * elements all satisfy the given predicate, and the rest of the list. - * - * @param p the test predicate - * @return a pair consisting of the longest prefix of the list whose - * elements all satisfy <code>p</code>, and the rest of the list. - * @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-sequence view starting at index `from` + /** 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 sequence, whereas `slice` produces a new sequence. + * 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) diff --git a/src/library/scalax/collection/generic/covartest/IterableView.scala b/src/library/scalax/collection/generic/covartest/IterableView.scala index 855e4d259b..43a1f68dc0 100755 --- a/src/library/scalax/collection/generic/covartest/IterableView.scala +++ b/src/library/scalax/collection/generic/covartest/IterableView.scala @@ -25,7 +25,7 @@ trait IterableView[+UC[+B] <: Iterable[B], +A] extends Iterable[A] { self => case _ => origin } - private def isDelay = elements eq underlying.elements + protected def isDelay = elements eq underlying.elements private[this] var forced: UC[A] = _ private[this] var wasForced = false @@ -100,15 +100,6 @@ trait IterableView[+UC[+B] <: Iterable[B], +A] extends Iterable[A] { self => /** Non-strict variant of @see Iterable.slice */ override def slice(from: Int, until: Int): IterableView[UC, A] = newView(elements slice (from, until)) - /** Non-strict variant of @see Iterable.takeWhile */ - override def takeWhile(p: A => Boolean): IterableView[UC, A] = newView(elements takeWhile p) - - /** Non-strict variant of @see Iterable.dropWhile */ - override def dropWhile(p: A => Boolean): IterableView[UC, A] = newView(elements dropWhile p) - - /** Non-strict variant of @see Iterable.span */ - override def span(p: A => Boolean): (IterableView[UC, A], IterableView[UC, A]) = (takeWhile(p), dropWhile(p)) - /** The projection resulting from the concatenation of this projection with the <code>rest</code> projection. * @param rest The projection that gets appended to this projection * @deprecated Use ++ instead diff --git a/src/library/scalax/collection/generic/covartest/OrderedIterableForwarder.scala b/src/library/scalax/collection/generic/covartest/OrderedIterableForwarder.scala new file mode 100755 index 0000000000..3a33dc6694 --- /dev/null +++ b/src/library/scalax/collection/generic/covartest/OrderedIterableForwarder.scala @@ -0,0 +1,37 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2009, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: IterableProxy.scala 15458 2008-06-28 20:23:22Z stepancheg $ + + +package scalax.collection.generic.covartest + +/** This trait implements a forwarder for iterable objects. It forwards + * all calls to a different iterable object, except for + * + * - toString, hashCode, equals, stringPrefix + * - newBuilder, view + * - all calls creating a new iterable object of the same kind + * + * The above methods are forwarded by subclass IterableProxy + * + * @author Martin Odersky + * @version 2.8 + */ +trait OrderedIterableForwarder[+A] extends OrderedIterable[A] with IterableForwarder[A] { + + /** The iterable object to which calls are forwarded */ + protected def underlying: OrderedIterable[A] + + // Iterable delegates + // Iterable methods could be printed by cat IterableTemplate.scala | sed -n '/trait Iterable/,$ p' | egrep '^ (override )?def' + + override def last: A = underlying.last + override def lastOption: Option[A] = underlying.lastOption + override def sameElements[B >: A](that: OrderedIterable[B]): Boolean = underlying.sameElements(that) +} diff --git a/src/library/scalax/collection/generic/covartest/OrderedIterableTemplate.scala b/src/library/scalax/collection/generic/covartest/OrderedIterableTemplate.scala index 4316c9b34d..f3c509887c 100755 --- a/src/library/scalax/collection/generic/covartest/OrderedIterableTemplate.scala +++ b/src/library/scalax/collection/generic/covartest/OrderedIterableTemplate.scala @@ -13,6 +13,8 @@ package scalax.collection.generic.covartest import OrderedIterable._ +import util.control.Breaks._ + /** Ordered iterables are iterables where the `elements` method always returns elements in the same * order (namely the order in which elements were appended to the iterable). In particular, one has * for every two ordered iterables `xs` and `ys`: @@ -20,4 +22,140 @@ import OrderedIterable._ * `(xs ++ ys).elements = xs.elements ++ ys.elements */ trait OrderedIterableTemplate[+CC[+B] <: OrderedIterableTemplate[CC, B] with OrderedIterable[B], +A] - extends IterableTemplate[CC, A] + extends IterableTemplate[CC, A] { + + /** 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 + * <code>None</code> 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 <code>n</code> 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 <code>n</code> 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 + } + + /** Returns the longest prefix of this iterable whose elements satisfy + * the predicate <code>p</code>. + * + * @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 <code>p</code>. + * + * @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 <code>p</code>, 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 + } +} diff --git a/src/library/scalax/collection/generic/covartest/SequenceForwarder.scala b/src/library/scalax/collection/generic/covartest/SequenceForwarder.scala index 5ada55f62d..47c512545d 100644 --- a/src/library/scalax/collection/generic/covartest/SequenceForwarder.scala +++ b/src/library/scalax/collection/generic/covartest/SequenceForwarder.scala @@ -23,7 +23,7 @@ package scalax.collection.generic.covartest * @author Martin Odersky * @version 2.8 */ -trait SequenceForwarder[+A] extends Sequence[A] with IterableForwarder[A] { +trait SequenceForwarder[+A] extends Sequence[A] with OrderedIterableForwarder[A] { protected override def underlying: Sequence[A] |