diff options
Diffstat (limited to 'src/library')
243 files changed, 7695 insertions, 3991 deletions
diff --git a/src/library/scala/Application.scala b/src/library/scala/Application.scala index e9b97b5356..fdb122f5bf 100644 --- a/src/library/scala/Application.scala +++ b/src/library/scala/Application.scala @@ -11,7 +11,6 @@ package scala -import java.lang.System.getProperty import scala.compat.Platform.currentTime /** <p> @@ -84,7 +83,7 @@ trait Application { * @param args the arguments passed to the main method */ def main(args: Array[String]) { - if (getProperty("scala.time") ne null) { + if (util.Properties.propIsSet("scala.time")) { val total = currentTime - executionStart Console.println("[total " + total + "ms]") } diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala index afaaed7c7c..f89e8b48a5 100644 --- a/src/library/scala/Array.scala +++ b/src/library/scala/Array.scala @@ -12,7 +12,7 @@ package scala import scala.collection.generic._ -import scala.collection.mutable.{ArrayBuilder, GenericArray} +import scala.collection.mutable.{ArrayBuilder, ArraySeq} import compat.Platform.arraycopy import scala.reflect.ClassManifest import scala.runtime.ScalaRunTime.{array_apply, array_update} @@ -24,15 +24,15 @@ class FallbackArrayBuilding { /** A builder factory that generates a generic array. * Called instead of Array.newBuilder if the element type of an array - * does not have a class manifest. Note that fallbackBuilder fcatory + * does not have a class manifest. Note that fallbackBuilder factory * needs an implicit parameter (otherwise it would not be dominated in implicit search * by Array.canBuildFrom). We make sure that that implicit search is always - * succesfull. + * successfull. */ - implicit def fallbackCanBuildFrom[T](implicit m: DummyImplicit): CanBuildFrom[Array[_], T, GenericArray[T]] = - new CanBuildFrom[Array[_], T, GenericArray[T]] { - def apply(from: Array[_]) = GenericArray.newBuilder[T] - def apply() = GenericArray.newBuilder[T] + implicit def fallbackCanBuildFrom[T](implicit m: DummyImplicit): CanBuildFrom[Array[_], T, ArraySeq[T]] = + new CanBuildFrom[Array[_], T, ArraySeq[T]] { + def apply(from: Array[_]) = ArraySeq.newBuilder[T] + def apply() = ArraySeq.newBuilder[T] } } @@ -55,10 +55,13 @@ object Array extends FallbackArrayBuilding { dest : AnyRef, destPos : Int, length : Int) { - var i = 0 - while (i < length) { - array_update(dest, i, array_apply(src, i)) + var i = srcPos + var j = destPos + val srcUntil = srcPos + length + while (i < srcUntil) { + array_update(dest, j, array_apply(src, i)) i += 1 + j += 1 } } diff --git a/src/library/scala/Console.scala b/src/library/scala/Console.scala index 7923b6be65..fc33fa07ef 100644 --- a/src/library/scala/Console.scala +++ b/src/library/scala/Console.scala @@ -83,7 +83,7 @@ object Console { /** Set the default output stream. * - * @param@ out the new output stream. + * @param out the new output stream. */ def setOut(out: OutputStream): Unit = setOut(new PrintStream(out)) diff --git a/src/library/scala/Enumeration.scala b/src/library/scala/Enumeration.scala index dfe48e3d00..3c8f5cf0bd 100644 --- a/src/library/scala/Enumeration.scala +++ b/src/library/scala/Enumeration.scala @@ -16,6 +16,15 @@ import scala.collection.mutable.{Builder, AddingBuilder, Map, HashMap} import scala.collection.immutable.{Set, BitSet} import scala.collection.generic.CanBuildFrom +private object Enumeration { + + /* This map is used to cache enumeration instances for + resolving enumeration _values_ to equal objects (by-reference) + when values are deserialized. */ + private val emap: Map[Class[_], Enumeration] = new HashMap + +} + /** <p> * Defines a finite set of values specific to the enumeration. Typically * these values enumerate all possible forms something can take and provide a @@ -56,11 +65,32 @@ import scala.collection.generic.CanBuildFrom */ @serializable @SerialVersionUID(8476000850333817230L) -abstract class Enumeration(initial: Int, names: String*) { +abstract class Enumeration(initial: Int, names: String*) { thisenum => def this() = this(0, null) def this(names: String*) = this(0, names: _*) + Enumeration.synchronized { + Enumeration.emap.get(getClass) match { + case None => + Enumeration.emap += (getClass -> this) + case Some(_) => + /* do nothing */ + } + } + + /* Note that `readResolve` cannot be private, since otherwise + the JVM does not invoke it when deserializing subclasses. */ + protected def readResolve(): AnyRef = Enumeration.synchronized { + Enumeration.emap.get(getClass) match { + case None => + Enumeration.emap += (getClass -> this) + this + case Some(existing) => + existing + } + } + /** The name of this enumeration. */ override def toString = { @@ -90,7 +120,7 @@ abstract class Enumeration(initial: Int, names: String*) { */ def values: ValueSet = { if (!vsetDefined) { - vset = new ValueSet(BitSet.empty ++ (vmap.valuesIterator map (_.id))) + vset = new ValueSet(BitSet.empty ++ (vmap.values map (_.id))) vsetDefined = true } vset @@ -164,34 +194,41 @@ abstract class Enumeration(initial: Int, names: String*) { /* Obtains the name for the value with id `i`. If no name is cached * in `nmap`, it populates `nmap` using reflection. */ - private def nameOf(i: Int): String = nmap.get(i) match { - case Some(name) => name - case None => - val methods = getClass.getMethods - for (m <- methods - if classOf[Value].isAssignableFrom(m.getReturnType) && - !java.lang.reflect.Modifier.isFinal(m.getModifiers)) { - val name = m.getName - // invoke method to obtain actual `Value` instance - val value = m.invoke(this) - // invoke `id` method - val idMeth = classOf[Val].getMethod("id") - val id: Int = idMeth.invoke(value).asInstanceOf[java.lang.Integer].intValue() - nmap += (id -> name) - } - nmap(i) + private def nameOf(i: Int): String = synchronized { + def isValDef(m: java.lang.reflect.Method) = + getClass.getDeclaredFields.exists(fd => fd.getName == m.getName && + fd.getType == m.getReturnType) + nmap.get(i) match { + case Some(name) => name + case None => + val methods = getClass.getMethods + for (m <- methods + if (classOf[Value].isAssignableFrom(m.getReturnType) && + !java.lang.reflect.Modifier.isFinal(m.getModifiers) && + m.getParameterTypes.isEmpty && + isValDef(m))) { + val name = m.getName + // invoke method to obtain actual `Value` instance + val value = m.invoke(this) + // invoke `id` method + val idMeth = classOf[Val].getMethod("id") + val id: Int = idMeth.invoke(value).asInstanceOf[java.lang.Integer].intValue() + nmap += (id -> name) + } + nmap(i) + } } /** The type of the enumerated values. */ @serializable @SerialVersionUID(7091335633555234129L) - abstract class Value extends Ordered[Enumeration#Value] { + abstract class Value extends Ordered[Value] { /** the id and bit location of this enumeration value */ def id: Int - override def compare(that: Enumeration#Value): Int = this.id - that.id + override def compare(that: Value): Int = this.id - that.id override def equals(other: Any): Boolean = other match { - case that: Enumeration#Value => compare(that) == 0 + case that: thisenum.Value => compare(that) == 0 case _ => false } override def hashCode: Int = id.hashCode @@ -204,7 +241,7 @@ abstract class Enumeration(initial: Int, names: String*) { if (id >= 32) throw new IllegalArgumentException 1 << id } - /** this enumeration value as an <code>Long</code> bit mask. + /** this enumeration value as a <code>Long</code> bit mask. * @throws IllegalArgumentException if <code>id</code> is greater than 63 */ @deprecated("mask64 will be removed") @@ -216,7 +253,7 @@ abstract class Enumeration(initial: Int, names: String*) { /** A class implementing the <a href="Enumeration.Value.html" * target="contentFrame"><code>Value</code></a> type. This class can be - * overriden to change the enumeration's naming and integer identification + * overridden to change the enumeration's naming and integer identification * behaviour. */ @serializable @@ -236,9 +273,16 @@ abstract class Enumeration(initial: Int, names: String*) { override def toString() = if (name eq null) Enumeration.this.nameOf(i) else name - private def readResolve(): AnyRef = - if (vmap ne null) vmap(i) + protected def readResolve(): AnyRef = { + val enum = Enumeration.synchronized { + Enumeration.emap.get(Enumeration.this.getClass) match { + case None => Enumeration.this + case Some(existing) => existing + } + } + if (enum.vmap ne null) enum.vmap(i) else this + } } /** A class for sets of values diff --git a/src/library/scala/Function.scala b/src/library/scala/Function.scala index 0409d938fd..6ef137aa2b 100644 --- a/src/library/scala/Function.scala +++ b/src/library/scala/Function.scala @@ -93,10 +93,13 @@ object Function /** Tupling for functions of arity 2. This transforms a function * of arity 2 into a unary function that takes a pair of arguments. * + * @note These functions are slotted for deprecation, but it is on + * hold pending superior type inference for tupling anonymous functions. + * * @param f ... * @return ... */ - @deprecated("Use `f.tupled` instead") + // @deprecated("Use `f.tupled` instead") def tupled[a1, a2, b](f: (a1, a2) => b): Tuple2[a1, a2] => b = { case Tuple2(x1, x2) => f(x1, x2) } @@ -104,7 +107,7 @@ object Function /** Tupling for functions of arity 3. This transforms a function * of arity 3 into a unary function that takes a triple of arguments. */ - @deprecated("Use `f.tupled` instead") + // @deprecated("Use `f.tupled` instead") def tupled[a1, a2, a3, b](f: (a1, a2, a3) => b): Tuple3[a1, a2, a3] => b = { case Tuple3(x1, x2, x3) => f(x1, x2, x3) } @@ -112,7 +115,7 @@ object Function /** Tupling for functions of arity 4. This transforms a function * of arity 4 into a unary function that takes a 4-tuple of arguments. */ - @deprecated("Use `f.tupled` instead") + // @deprecated("Use `f.tupled` instead") def tupled[a1, a2, a3, a4, b](f: (a1, a2, a3, a4) => b): Tuple4[a1, a2, a3, a4] => b = { case Tuple4(x1, x2, x3, x4) => f(x1, x2, x3, x4) } @@ -120,7 +123,7 @@ object Function /** Tupling for functions of arity 5. This transforms a function * of arity 5 into a unary function that takes a 5-tuple of arguments. */ - @deprecated("Use `f.tupled` instead") + // @deprecated("Use `f.tupled` instead") def tupled[a1, a2, a3, a4, a5, b](f: (a1, a2, a3, a4, a5) => b): Tuple5[a1, a2, a3, a4, a5] => b = { case Tuple5(x1, x2, x3, x4, x5) => f(x1, x2, x3, x4, x5) } diff --git a/src/library/scala/Immutable.scala b/src/library/scala/Immutable.scala index 3b6fe28d52..bc0a6100f6 100644 --- a/src/library/scala/Immutable.scala +++ b/src/library/scala/Immutable.scala @@ -11,7 +11,7 @@ package scala -/** A marker trait for all immutable datastructures such as imutable +/** A marker trait for all immutable datastructures such as immutable * collections. * * @since 2.8 diff --git a/src/library/scala/LowPriorityImplicits.scala b/src/library/scala/LowPriorityImplicits.scala index d5a3727f66..899dbe27d7 100644 --- a/src/library/scala/LowPriorityImplicits.scala +++ b/src/library/scala/LowPriorityImplicits.scala @@ -26,21 +26,21 @@ import collection.generic.CanBuildFrom class LowPriorityImplicits { implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] = - WrappedArray.make(xs) + if (xs ne null) WrappedArray.make(xs) else null - implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](xs) - implicit def wrapIntArray(xs: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(xs) - implicit def wrapDoubleArray(xs: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(xs) - implicit def wrapLongArray(xs: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(xs) - implicit def wrapFloatArray(xs: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(xs) - implicit def wrapCharArray(xs: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(xs) - implicit def wrapByteArray(xs: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(xs) - implicit def wrapShortArray(xs: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(xs) - implicit def wrapBooleanArray(xs: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(xs) - implicit def wrapUnitArray(xs: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(xs) + implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): WrappedArray[T] = if (xs ne null) new WrappedArray.ofRef[T](xs) else null + implicit def wrapIntArray(xs: Array[Int]): WrappedArray[Int] = if (xs ne null) new WrappedArray.ofInt(xs) else null + implicit def wrapDoubleArray(xs: Array[Double]): WrappedArray[Double] = if (xs ne null) new WrappedArray.ofDouble(xs) else null + implicit def wrapLongArray(xs: Array[Long]): WrappedArray[Long] = if (xs ne null) new WrappedArray.ofLong(xs) else null + implicit def wrapFloatArray(xs: Array[Float]): WrappedArray[Float] = if (xs ne null) new WrappedArray.ofFloat(xs) else null + implicit def wrapCharArray(xs: Array[Char]): WrappedArray[Char] = if (xs ne null) new WrappedArray.ofChar(xs) else null + implicit def wrapByteArray(xs: Array[Byte]): WrappedArray[Byte] = if (xs ne null) new WrappedArray.ofByte(xs) else null + implicit def wrapShortArray(xs: Array[Short]): WrappedArray[Short] = if (xs ne null) new WrappedArray.ofShort(xs) else null + implicit def wrapBooleanArray(xs: Array[Boolean]): WrappedArray[Boolean] = if (xs ne null) new WrappedArray.ofBoolean(xs) else null + implicit def wrapUnitArray(xs: Array[Unit]): WrappedArray[Unit] = if (xs ne null) new WrappedArray.ofUnit(xs) else null - implicit def wrapString(s: String): WrappedString = new WrappedString(s) - implicit def unwrapString(ws: WrappedString): String = ws.self + implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null + implicit def unwrapString(ws: WrappedString): String = if (ws ne null) ws.self else null implicit def fallbackStringCanBuildFrom[T]: CanBuildFrom[String, T, collection.immutable.IndexedSeq[T]] = new CanBuildFrom[String, T, collection.immutable.IndexedSeq[T]] { diff --git a/src/library/scala/NotDefinedError.scala b/src/library/scala/NotDefinedError.scala index c1939a4e9a..a47613fb9a 100644 --- a/src/library/scala/NotDefinedError.scala +++ b/src/library/scala/NotDefinedError.scala @@ -14,4 +14,5 @@ package scala /** * @since 2.0 */ +@deprecated("Use a custom Error class instead") final class NotDefinedError(msg: String) extends Error("not defined: " + msg) diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala index 8511fa78a5..f2da220775 100644 --- a/src/library/scala/Option.scala +++ b/src/library/scala/Option.scala @@ -35,6 +35,7 @@ object Option * @version 1.1, 16/01/2007 */ sealed abstract class Option[+A] extends Product { + self => /** True if the option is the <code>None</code> value, false otherwise. */ @@ -45,7 +46,7 @@ sealed abstract class Option[+A] extends Product { def isDefined: Boolean = !isEmpty /** get the value of this option. - * @requires that the option is nonEmpty. + * @note The option must be nonEmpty. * @throws Predef.NoSuchElementException if the option is empty. */ def get: A @@ -89,6 +90,22 @@ sealed abstract class Option[+A] extends Product { def filter(p: A => Boolean): Option[A] = if (isEmpty || p(this.get)) this else None + /** Necessary to keep Option from being implicitly converted to + * Iterable in for comprehensions. + */ + def withFilter(p: A => Boolean): WithFilter = new WithFilter(p) + + /** We need a whole WithFilter class to honor the "doesn't create a new + * collection" contract even though it seems unlikely to matter much in a + * collection with max size 1. + */ + class WithFilter(p: A => Boolean) { + def map[B](f: A => B): Option[B] = self filter p map f + def flatMap[B](f: A => Option[B]): Option[B] = self filter p flatMap f + def foreach[U](f: A => U): Unit = self filter p foreach f + def withFilter(q: A => Boolean): WithFilter = new WithFilter(x => p(x) && q(x)) + } + /** If the option is nonempty, p(value), otherwise false. * * @param p the predicate to test @@ -110,7 +127,7 @@ sealed abstract class Option[+A] extends Product { * * @param pf the partial function. */ - def partialMap[B](pf: PartialFunction[A, B]): Option[B] = + def collect[B](pf: PartialFunction[A, B]): Option[B] = if (!isEmpty && pf.isDefinedAt(this.get)) Some(pf(this.get)) else None /** If the option is nonempty return it, diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala index 5684c91aaa..2037705bab 100644 --- a/src/library/scala/Predef.scala +++ b/src/library/scala/Predef.scala @@ -14,6 +14,8 @@ package scala import collection.immutable.StringOps import collection.mutable.ArrayOps import collection.generic.CanBuildFrom +import annotation.elidable +import annotation.elidable.ASSERTION /** The <code>Predef</code> object provides definitions that are * accessible in all Scala compilation units without explicit @@ -53,22 +55,6 @@ object Predef extends LowPriorityImplicits { @inline def locally[T](x: T): T = x - // hashcode ----------------------------------------------------------- - - @inline def hash(x: Any): Int = - if (x.isInstanceOf[Number]) runtime.BoxesRunTime.hashFromNumber(x.asInstanceOf[Number]) - else x.hashCode - - @inline def hash(x: Number): Int = - runtime.BoxesRunTime.hashFromNumber(x) - - @inline def hash(x: java.lang.Long): Int = { - val iv = x.intValue - if (iv == x.longValue) iv else x.hashCode - } - - @inline def hash(x: Int): Int = x - // errors and asserts ------------------------------------------------- def error(message: String): Nothing = throw new RuntimeException(message) @@ -80,38 +66,82 @@ object Predef extends LowPriorityImplicits { throw new Throwable() } - import annotation.elidable - import annotation.elidable.ASSERTION - + /** Tests an expression, throwing an AssertionError if false. + * Calls to this method will not be generated if -Xelide-below + * is at least ASSERTION. + * + * @see elidable + * @param p the expression to test + */ @elidable(ASSERTION) def assert(assertion: Boolean) { if (!assertion) throw new java.lang.AssertionError("assertion failed") } + /** Tests an expression, throwing an AssertionError if false. + * Calls to this method will not be generated if -Xelide-below + * is at least ASSERTION. + * + * @see elidable + * @param p the expression to test + * @param msg a String to include in the failure message + */ @elidable(ASSERTION) def assert(assertion: Boolean, message: => Any) { if (!assertion) throw new java.lang.AssertionError("assertion failed: "+ message) } + /** Tests an expression, throwing an AssertionError if false. + * This method differs from assert only in the intent expressed: + * assert contains a predicate which needs to be proven, while + * assume contains an axiom for a static checker. Calls to this method + * will not be generated if -Xelide-below is at least ASSERTION. + * + * @see elidable + * @param p the expression to test + */ @elidable(ASSERTION) def assume(assumption: Boolean) { if (!assumption) throw new java.lang.AssertionError("assumption failed") } + /** Tests an expression, throwing an AssertionError if false. + * This method differs from assert only in the intent expressed: + * assert contains a predicate which needs to be proven, while + * assume contains an axiom for a static checker. Calls to this method + * will not be generated if -Xelide-below is at least ASSERTION. + * + * @see elidable + * @param p the expression to test + * @param msg a String to include in the failure message + */ @elidable(ASSERTION) def assume(assumption: Boolean, message: => Any) { if (!assumption) throw new java.lang.AssertionError("assumption failed: "+ message) } + /** Tests an expression, throwing an IllegalArgumentException if false. + * This method is similar to assert, but blames the caller of the method + * for violating the condition. + * + * @param p the expression to test + */ def require(requirement: Boolean) { if (!requirement) throw new IllegalArgumentException("requirement failed") } + /** Tests an expression, throwing an IllegalArgumentException if false. + * This method is similar to assert, but blames the caller of the method + * for violating the condition. + * + * @param p the expression to test + * @param msg a String to include in the failure message + */ def require(requirement: Boolean, message: => Any) { if (!requirement) throw new IllegalArgumentException("requirement failed: "+ message) @@ -150,7 +180,7 @@ object Predef extends LowPriorityImplicits { def print(x: Any) = Console.print(x) def println() = Console.println() def println(x: Any) = Console.println(x) - def printf(text: String, xs: Any*) = Console.printf(format(text, xs: _*)) + def printf(text: String, xs: Any*) = Console.print(format(text, xs: _*)) def format(text: String, xs: Any*) = augmentString(text).format(xs: _*) def readLine(): String = Console.readLine() @@ -291,7 +321,7 @@ object Predef extends LowPriorityImplicits { implicit def conformsOrViewsAs[A <% B, B]: A <%< B = new (A <%< B) {def apply(x: A) = x} } - /** A type for which there is aways an implicit value. + /** A type for which there is always an implicit value. * @see fallbackCanBuildFrom in Array.scala */ class DummyImplicit diff --git a/src/library/scala/Product.scala b/src/library/scala/Product.scala index 8521cf2437..a0503cfe4c 100644 --- a/src/library/scala/Product.scala +++ b/src/library/scala/Product.scala @@ -20,7 +20,7 @@ package scala */ trait Product extends Equals { - /** for a product <code>A(x_1,...,x_k)</code>, returns <code>x_(n+1)</code> + /** For a product <code>A(x_1,...,x_k)</code>, returns <code>x_(n+1)</code> * for <code>0 <= n < k</code> * * @param n the index of the element to return @@ -29,6 +29,21 @@ trait Product extends Equals { */ def productElement(n: Int): Any + // !!! This will be disabled pending reimplementation, but it can't be removed + // until starr forgets about it. + + /** Returns the name of the field at the given index from the definition + * of the class. + * + * @param n the index of the element name to return + * @throws NoSuchElementException if the name data is unavailable for any reason + * @throws IndexOutOfBoundsException if the index is out of range + * @return a String representing the field name + */ + def productElementName(n: Int): String = + // the method implementation is synthetic - if it is not generated we always throw. + throw new NoSuchElementException() + /** return k for a product <code>A(x_1,...,x_k)</code> */ def productArity: Int diff --git a/src/library/scala/Tuple2.scala b/src/library/scala/Tuple2.scala index 2a4797ab5a..8c4e5973c5 100644 --- a/src/library/scala/Tuple2.scala +++ b/src/library/scala/Tuple2.scala @@ -42,6 +42,11 @@ case class Tuple2[+T1, +T2](_1:T1,_2:T2) b1.result } + /** Wraps a tuple in a `Zipped`, which supports 2-ary generalisations of map, flatMap, filter,... + * + * @see Zipped + * $willNotTerminateInf + */ def zipped[Repr1, El1, Repr2, El2](implicit w1: T1 => TraversableLike[El1, Repr1], w2: T2 => IterableLike[El2, Repr2]): Zipped[Repr1, El1, Repr2, El2] = new Zipped[Repr1, El1, Repr2, El2](_1, _2) diff --git a/src/library/scala/Tuple3.scala b/src/library/scala/Tuple3.scala index b70310db3f..a1fca95e4d 100644 --- a/src/library/scala/Tuple3.scala +++ b/src/library/scala/Tuple3.scala @@ -41,6 +41,11 @@ case class Tuple3[+T1, +T2, +T3](_1:T1,_2:T2,_3:T3) b1.result } + /** Wraps a tuple in a `Zipped`, which supports 3-ary generalisations of map, flatMap, filter,... + * + * @see Zipped + * $willNotTerminateInf + */ def zipped[Repr1, El1, Repr2, El2, Repr3, El3](implicit w1: T1 => TraversableLike[El1, Repr1], w2: T2 => IterableLike[El2, Repr2], w3: T3 => IterableLike[El3, Repr3]): Zipped[Repr1, El1, Repr2, El2, Repr3, El3] diff --git a/src/library/scala/annotation/elidable.scala b/src/library/scala/annotation/elidable.scala index 4f29c8f2ab..c75299e9fd 100644 --- a/src/library/scala/annotation/elidable.scala +++ b/src/library/scala/annotation/elidable.scala @@ -13,18 +13,18 @@ import java.util.logging.Level /** An annotation for methods for which invocations might * be removed in the generated code. * - * Behavior is influenced by passing -Xelide-level <arg> + * Behavior is influenced by passing -Xelide-below <arg> * to scalac. Methods marked elidable will be omitted from * generated code if the priority given the annotation is lower * than to the command line argument. Examples: - * + * {{{ * import annotation.elidable._ * * @elidable(WARNING) def foo = log("foo") * @elidable(FINE) def bar = log("bar") * - * scalac -Xelide-methods-below=1000 - * + * scalac -Xelide-below=1000 + * }}} * @since 2.8 */ final class elidable(final val level: Int) extends StaticAnnotation {} diff --git a/src/library/scala/annotation/migration.scala b/src/library/scala/annotation/migration.scala new file mode 100644 index 0000000000..b0915cde34 --- /dev/null +++ b/src/library/scala/annotation/migration.scala @@ -0,0 +1,28 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.annotation + +/** + * An annotation that marks a member as having changed semantics + * between versions. This is intended for methods which for one + * reason or another retain the same name and type signature, + * but some aspect of their behavior is different. An illustrative + * examples is Stack.iterator, which reversed from LIFO to FIFO + * order between scala 2.7 and 2.8. + * + * The version numbers are to mark the scala major/minor release + * version where the change took place. + * + * @since 2.8 + */ +private[scala] final class migration( + majorVersion: Int, + minorVersion: Int, + message: String) +extends StaticAnnotation {} diff --git a/src/library/scala/collection/BitSetLike.scala b/src/library/scala/collection/BitSetLike.scala index aac731fec9..8476ede7b5 100644 --- a/src/library/scala/collection/BitSetLike.scala +++ b/src/library/scala/collection/BitSetLike.scala @@ -28,11 +28,10 @@ import mutable.StringBuilder * @since 2.8 * @define coll bitset * @define Coll BitSet - * define bitsetinfo + * @define bitsetinfo * Bitsets are sets of non-negative integers which are represented as * variable-size arrays of bits packed into 64-bit words. The size of a bitset is * determined by the largest number stored in it. - */ trait BitSetLike[+This <: BitSetLike[This] with Set[Int]] extends SetLike[Int, This] { self => @@ -42,7 +41,7 @@ trait BitSetLike[+This <: BitSetLike[This] with Set[Int]] extends SetLike[Int, T protected def nwords: Int /** The words at index `idx', or 0L if outside the range of the set - * @pre idx >= 0 + * @note Requires `idx >= 0` */ protected def word(idx: Int): Long diff --git a/src/library/scala/collection/IndexedSeq.scala b/src/library/scala/collection/IndexedSeq.scala index 05141fb864..50a66e924c 100644 --- a/src/library/scala/collection/IndexedSeq.scala +++ b/src/library/scala/collection/IndexedSeq.scala @@ -14,15 +14,9 @@ package scala.collection import generic._ import mutable.Builder -/** <p> - * Sequences that support O(1) element access and O(1) length computation. - * </p> - * <p> - * This class does not add any methods to <code>Sequence</code> but - * overrides several methods with optimized implementations. - * </p> +/** A base trait for indexed sequences. + * $indexedSeqInfo * - * @author Sean McDirmid * @author Martin Odersky * @version 2.8 * @since 2.8 diff --git a/src/library/scala/collection/IndexedSeqLike.scala b/src/library/scala/collection/IndexedSeqLike.scala index 8164075629..ea6e1bb493 100644 --- a/src/library/scala/collection/IndexedSeqLike.scala +++ b/src/library/scala/collection/IndexedSeqLike.scala @@ -18,16 +18,23 @@ import scala.annotation.tailrec /** A template trait for indexed sequences of type `IndexedSeq[A]`. * * $indexedSeqInfo + * + * This trait just implements `iterator` in terms of `apply` and `length`. + * However, see `IndexedSeqOptimized` for an implementation trait that overrides operations + * to make them run faster under the assumption of fast random access with `apply`. + * * @author Sean McDirmid * @author Martin Odersky * @version 2.8 * @since 2.8 + * @define Coll IndexedSeq * @define indexedSeqInfo * Indexed sequences support constant-time or near constant-time element - * access and length computation. + * access and length computation. They are defined in terms of abstract methods + * `apply` fpor indexing and `length`. * - * Indexed sequences do not define any new methods wrt `Seq`. However, some `Seq` methods - * are overridden with optimized implementations. + * Indexed sequences do not add any new methods wrt `Seq`, but promise + * efficient implementations of random access patterns. * * @tparam A the element type of the $coll * @tparam Repr the type of the actual $coll containing the elements. @@ -76,267 +83,7 @@ trait IndexedSeqLike[+A, +Repr] extends SeqLike[A, Repr] { self => override /*IterableLike*/ def iterator: Iterator[A] = new Elements(0, length) - - override /*IterableLike*/ - def isEmpty: Boolean = { length == 0 } - - override /*IterableLike*/ - def foreach[U](f: A => U): Unit = { - var i = 0 - val len = length - while (i < len) { f(this(i)); i += 1 } - } - - override /*IterableLike*/ - def forall(p: A => Boolean): Boolean = prefixLength(p(_)) == length - - override /*IterableLike*/ - def exists(p: A => Boolean): Boolean = prefixLength(!p(_)) != length - - override /*IterableLike*/ - def find(p: A => Boolean): Option[A] = { - val i = prefixLength(!p(_)) - if (i < length) Some(this(i)) else None - } /* - override /*IterableLike*/ - def mapFind[B](f: A => Option[B]): Option[B] = { - var i = 0 - var res: Option[B] = None - val len = length - while (res.isEmpty && i < len) { - res = f(this(i)) - i += 1 - } - res - } -*/ - @tailrec - private def foldl[B](start: Int, end: Int, z: B, op: (B, A) => B): B = - if (start == end) z - else foldl(start + 1, end, op(z, this(start)), op) - - @tailrec - private def foldr[B](start: Int, end: Int, z: B, op: (A, B) => B): B = - if (start == end) z - else foldr(start, end - 1, op(this(end - 1), z), op) - - override /*TraversableLike*/ - def foldLeft[B](z: B)(op: (B, A) => B): B = - foldl(0, length, z, op) - - override /*IterableLike*/ - def foldRight[B](z: B)(op: (A, B) => B): B = - foldr(0, length, z, op) - - override /*TraversableLike*/ - def reduceLeft[B >: A](op: (B, A) => B): B = - if (length > 0) foldl(1, length, this(0), op) else super.reduceLeft(op) - - override /*IterableLike*/ - def reduceRight[B >: A](op: (A, B) => B): B = - if (length > 0) foldr(0, length - 1, this(length - 1), op) else super.reduceRight(op) - - override /*IterableLike*/ - def zip[A1 >: A, B, That](that: Iterable[B])(implicit bf: CanBuildFrom[Repr, (A1, B), That]): That = that match { - case that: IndexedSeq[_] => - val b = bf(repr) - var i = 0 - val len = this.length min that.length - b.sizeHint(len) - while (i < len) { - b += ((this(i), that(i).asInstanceOf[B])) - i += 1 - } - b.result - case _ => - super.zip[A1, B, That](that)(bf) - } - - override /*IterableLike*/ - def zipWithIndex[A1 >: A, That](implicit bf: CanBuildFrom[Repr, (A1, Int), That]): That = { - val b = bf(repr) - val len = length - b.sizeHint(len) - var i = 0 - while (i < len) { - b += ((this(i), i)) - i += 1 - } - b.result - } - - override /*IterableLike*/ - def slice(from: Int, until: Int): Repr = { - var i = from max 0 - val end = until min length - val b = newBuilder - b.sizeHint(end - i) - while (i < end) { - b += this(i) - i += 1 - } - b.result - } - - override /*IterableLike*/ - def head: A = if (isEmpty) super.head else this(0) - - override /*TraversableLike*/ - def tail: Repr = if (isEmpty) super.tail else slice(1, length) - - override /*TraversableLike*/ - def last: A = if (length > 0) this(length - 1) else super.last - - override /*IterableLike*/ - def init: Repr = if (length > 0) slice(0, length - 1) else super.init - - override /*TraversableLike*/ - def take(n: Int): Repr = slice(0, n) - - override /*TraversableLike*/ - def drop(n: Int): Repr = slice(n, length) - - override /*IterableLike*/ - def takeRight(n: Int): Repr = slice(length - n, length) - - override /*IterableLike*/ - def dropRight(n: Int): Repr = slice(0, length - n) - - override /*TraversableLike*/ - def splitAt(n: Int): (Repr, Repr) = (take(n), drop(n)) - - override /*IterableLike*/ - def takeWhile(p: A => Boolean): Repr = take(prefixLength(p)) - - override /*TraversableLike*/ - def dropWhile(p: A => Boolean): Repr = drop(prefixLength(p)) - - override /*TraversableLike*/ - def span(p: A => Boolean): (Repr, Repr) = splitAt(prefixLength(p)) - - override /*IterableLike*/ - def sameElements[B >: A](that: Iterable[B]): Boolean = that match { - case that: IndexedSeq[_] => - val len = length - len == that.length && { - var i = 0 - while (i < len && this(i) == that(i)) i += 1 - i == len - } - case _ => - super.sameElements(that) - } - - override /*IterableLike*/ - def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) { - var i = 0 - var j = start - val end = length min len min (xs.length - start) - while (i < end) { - xs(j) = this(i) - i += 1 - j += 1 - } - } - - - // Overridden methods from Seq - - override /*SeqLike*/ - def lengthCompare(len: Int): Int = length - len - - override /*SeqLike*/ - def segmentLength(p: A => Boolean, from: Int): Int = { - val start = from - val len = length - var i = start - while (i < len && p(this(i))) i += 1 - i - start - } - - private def negLength(n: Int) = if (n == length) -1 else n - - override /*SeqLike*/ - def indexWhere(p: A => Boolean, from: Int): Int = { - val start = from max 0 - negLength(start + segmentLength(!p(_), start)) - } - - override /*SeqLike*/ - def lastIndexWhere(p: A => Boolean, end: Int): Int = { - var i = end - while (i >= 0 && !p(this(i))) i -= 1 - i - } - - override /*SeqLike*/ - def reverse: Repr = { - val b = newBuilder - b.sizeHint(length) - var i = length - while (0 < i) { - i -= 1 - b += this(i) - } - b.result - } - - override /*SeqLike*/ - def reverseIterator: Iterator[A] = new Iterator[A] { - private var i = self.length - def hasNext: Boolean = 0 < i - def next: A = - if (0 < i) { - i -= 1 - self(i) - } else Iterator.empty.next - } - - override /*SeqLike*/ - def startsWith[B](that: Seq[B], offset: Int): Boolean = that match { - case that: IndexedSeq[_] => - var i = offset - var j = 0 - val thisLen = length - val thatLen = that.length - while (i < thisLen && j < thatLen && this(i) == that(j)) { - i += 1 - j += 1 - } - j == thatLen - case _ => - var i = offset - val thisLen = length - val thatElems = that.iterator - while (i < thisLen && thatElems.hasNext) { - if (this(i) != thatElems.next()) - return false - - i += 1 - } - !thatElems.hasNext - } - - override /*SeqLike*/ - def endsWith[B](that: Seq[B]): Boolean = that match { - case that: IndexedSeq[_] => - var i = length - 1 - var j = that.length - 1 - - (j <= i) && { - while (j >= 0) { - if (this(i) != that(j)) - return false - i -= 1 - j -= 1 - } - true - } - case _ => - super.endsWith(that) - } - override /*SeqLike*/ def view = new IndexedSeqView[A, Repr] { protected lazy val underlying = self.repr @@ -347,5 +94,6 @@ trait IndexedSeqLike[+A, +Repr] extends SeqLike[A, Repr] { self => override /*SeqLike*/ def view(from: Int, until: Int) = view.slice(from, until) +*/ } diff --git a/src/library/scala/collection/IndexedSeqOptimized.scala b/src/library/scala/collection/IndexedSeqOptimized.scala new file mode 100755 index 0000000000..12b39c8b83 --- /dev/null +++ b/src/library/scala/collection/IndexedSeqOptimized.scala @@ -0,0 +1,293 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: IndexedSeqLike.scala 20129 2009-12-14 17:12:17Z odersky $ + + +package scala.collection + +import generic._ +import mutable.ArrayBuffer +import scala.annotation.tailrec + +/** A template trait for indexed sequences of type `IndexedSeq[A]` which optimizes + * the implementation of several methods under the assumption of fast random access. + * + * $indexedSeqInfo + * @author Martin Odersky + * @version 2.8 + * @since 2.8 + * + * @tparam A the element type of the $coll + * @tparam Repr the type of the actual $coll containing the elements. + * @define willNotTerminateInf + * @define mayNotTerminateInf + */ +trait IndexedSeqOptimized[+A, +Repr] extends IndexedSeqLike[A, Repr] { self => + + override /*IterableLike*/ + def isEmpty: Boolean = { length == 0 } + + override /*IterableLike*/ + def foreach[U](f: A => U): Unit = { + var i = 0 + val len = length + while (i < len) { f(this(i)); i += 1 } + } + + override /*IterableLike*/ + def forall(p: A => Boolean): Boolean = prefixLength(p(_)) == length + + override /*IterableLike*/ + def exists(p: A => Boolean): Boolean = prefixLength(!p(_)) != length + + override /*IterableLike*/ + def find(p: A => Boolean): Option[A] = { + val i = prefixLength(!p(_)) + if (i < length) Some(this(i)) else None + } +/* + override /*IterableLike*/ + def mapFind[B](f: A => Option[B]): Option[B] = { + var i = 0 + var res: Option[B] = None + val len = length + while (res.isEmpty && i < len) { + res = f(this(i)) + i += 1 + } + res + } +*/ + @tailrec + private def foldl[B](start: Int, end: Int, z: B, op: (B, A) => B): B = + if (start == end) z + else foldl(start + 1, end, op(z, this(start)), op) + + @tailrec + private def foldr[B](start: Int, end: Int, z: B, op: (A, B) => B): B = + if (start == end) z + else foldr(start, end - 1, op(this(end - 1), z), op) + + override /*TraversableLike*/ + def foldLeft[B](z: B)(op: (B, A) => B): B = + foldl(0, length, z, op) + + override /*IterableLike*/ + def foldRight[B](z: B)(op: (A, B) => B): B = + foldr(0, length, z, op) + + override /*TraversableLike*/ + def reduceLeft[B >: A](op: (B, A) => B): B = + if (length > 0) foldl(1, length, this(0), op) else super.reduceLeft(op) + + override /*IterableLike*/ + def reduceRight[B >: A](op: (A, B) => B): B = + if (length > 0) foldr(0, length - 1, this(length - 1), op) else super.reduceRight(op) + + override /*IterableLike*/ + def zip[A1 >: A, B, That](that: Iterable[B])(implicit bf: CanBuildFrom[Repr, (A1, B), That]): That = that match { + case that: IndexedSeq[_] => + val b = bf(repr) + var i = 0 + val len = this.length min that.length + b.sizeHint(len) + while (i < len) { + b += ((this(i), that(i).asInstanceOf[B])) + i += 1 + } + b.result + case _ => + super.zip[A1, B, That](that)(bf) + } + + override /*IterableLike*/ + def zipWithIndex[A1 >: A, That](implicit bf: CanBuildFrom[Repr, (A1, Int), That]): That = { + val b = bf(repr) + val len = length + b.sizeHint(len) + var i = 0 + while (i < len) { + b += ((this(i), i)) + i += 1 + } + b.result + } + + override /*IterableLike*/ + def slice(from: Int, until: Int): Repr = { + var i = from max 0 + val end = until min length + val b = newBuilder + b.sizeHint(end - i) + while (i < end) { + b += this(i) + i += 1 + } + b.result + } + + override /*IterableLike*/ + def head: A = if (isEmpty) super.head else this(0) + + override /*TraversableLike*/ + def tail: Repr = if (isEmpty) super.tail else slice(1, length) + + override /*TraversableLike*/ + def last: A = if (length > 0) this(length - 1) else super.last + + override /*IterableLike*/ + def init: Repr = if (length > 0) slice(0, length - 1) else super.init + + override /*TraversableLike*/ + def take(n: Int): Repr = slice(0, n) + + override /*TraversableLike*/ + def drop(n: Int): Repr = slice(n, length) + + override /*IterableLike*/ + def takeRight(n: Int): Repr = slice(length - n, length) + + override /*IterableLike*/ + def dropRight(n: Int): Repr = slice(0, length - n) + + override /*TraversableLike*/ + def splitAt(n: Int): (Repr, Repr) = (take(n), drop(n)) + + override /*IterableLike*/ + def takeWhile(p: A => Boolean): Repr = take(prefixLength(p)) + + override /*TraversableLike*/ + def dropWhile(p: A => Boolean): Repr = drop(prefixLength(p)) + + override /*TraversableLike*/ + def span(p: A => Boolean): (Repr, Repr) = splitAt(prefixLength(p)) + + override /*IterableLike*/ + def sameElements[B >: A](that: Iterable[B]): Boolean = that match { + case that: IndexedSeq[_] => + val len = length + len == that.length && { + var i = 0 + while (i < len && this(i) == that(i)) i += 1 + i == len + } + case _ => + super.sameElements(that) + } + + override /*IterableLike*/ + def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) { + var i = 0 + var j = start + val end = length min len min (xs.length - start) + while (i < end) { + xs(j) = this(i) + i += 1 + j += 1 + } + } + + + // Overridden methods from Seq + + override /*SeqLike*/ + def lengthCompare(len: Int): Int = length - len + + override /*SeqLike*/ + def segmentLength(p: A => Boolean, from: Int): Int = { + val start = from + val len = length + var i = start + while (i < len && p(this(i))) i += 1 + i - start + } + + private def negLength(n: Int) = if (n == length) -1 else n + + override /*SeqLike*/ + def indexWhere(p: A => Boolean, from: Int): Int = { + val start = from max 0 + negLength(start + segmentLength(!p(_), start)) + } + + override /*SeqLike*/ + def lastIndexWhere(p: A => Boolean, end: Int): Int = { + var i = end + while (i >= 0 && !p(this(i))) i -= 1 + i + } + + override /*SeqLike*/ + def reverse: Repr = { + val b = newBuilder + b.sizeHint(length) + var i = length + while (0 < i) { + i -= 1 + b += this(i) + } + b.result + } + + override /*SeqLike*/ + def reverseIterator: Iterator[A] = new Iterator[A] { + private var i = self.length + def hasNext: Boolean = 0 < i + def next: A = + if (0 < i) { + i -= 1 + self(i) + } else Iterator.empty.next + } + + override /*SeqLike*/ + def startsWith[B](that: Seq[B], offset: Int): Boolean = that match { + case that: IndexedSeq[_] => + var i = offset + var j = 0 + val thisLen = length + val thatLen = that.length + while (i < thisLen && j < thatLen && this(i) == that(j)) { + i += 1 + j += 1 + } + j == thatLen + case _ => + var i = offset + val thisLen = length + val thatElems = that.iterator + while (i < thisLen && thatElems.hasNext) { + if (this(i) != thatElems.next()) + return false + + i += 1 + } + !thatElems.hasNext + } + + override /*SeqLike*/ + def endsWith[B](that: Seq[B]): Boolean = that match { + case that: IndexedSeq[_] => + var i = length - 1 + var j = that.length - 1 + + (j <= i) && { + while (j >= 0) { + if (this(i) != that(j)) + return false + i -= 1 + j -= 1 + } + true + } + case _ => + super.endsWith(that) + } +} + diff --git a/src/library/scala/collection/IndexedSeqView.scala b/src/library/scala/collection/IndexedSeqView.scala deleted file mode 100644 index 72f3374e94..0000000000 --- a/src/library/scala/collection/IndexedSeqView.scala +++ /dev/null @@ -1,38 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -// $Id$ - - -package scala.collection - -import TraversableView.NoBuilder -import generic._ - -/** A non-strict projection of an iterable. - * - * @author Sean McDirmid - * @author Martin Odersky - * @version 2.8 - * @since 2.8 - */ -trait IndexedSeqView[+A, +Coll] extends IndexedSeqViewLike[A, Coll, IndexedSeqView[A, Coll]] - -object IndexedSeqView { - type Coll = TraversableView[_, C] forSome {type C <: Traversable[_]} - implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, IndexedSeqView[A, IndexedSeq[_]]] = - new CanBuildFrom[Coll, A, IndexedSeqView[A, IndexedSeq[_]]] { - def apply(from: Coll) = new NoBuilder - def apply() = new NoBuilder - } - implicit def arrCanBuildFrom[A]: CanBuildFrom[TraversableView[_, Array[_]], A, IndexedSeqView[A, Array[A]]] = - new CanBuildFrom[TraversableView[_, Array[_]], A, IndexedSeqView[A, Array[A]]] { - def apply(from: TraversableView[_, Array[_]]) = new NoBuilder - def apply() = new NoBuilder - } -} diff --git a/src/library/scala/collection/IndexedSeqViewLike.scala b/src/library/scala/collection/IndexedSeqViewLike.scala deleted file mode 100644 index 07f63ad2b0..0000000000 --- a/src/library/scala/collection/IndexedSeqViewLike.scala +++ /dev/null @@ -1,113 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -// $Id: Seq.scala 16092 2008-09-12 10:37:06Z nielsen $ - - -package scala.collection - -import generic._ -import TraversableView.NoBuilder - -/** A template trait for a non-strict view of a IndexedSeq. - * - * @author Sean McDirmid - * @author Martin Odersky - * @version 2.8 - * @since 2.8 - */ -trait IndexedSeqViewLike[+A, - +Coll, - +This <: IndexedSeqView[A, Coll] with IndexedSeqViewLike[A, Coll, This]] - extends IndexedSeq[A] with IndexedSeqLike[A, This] with SeqView[A, Coll] with SeqViewLike[A, Coll, This] -{ self => - - trait Transformed[+B] extends IndexedSeqView[B, Coll] with super.Transformed[B] - - trait Sliced extends Transformed[A] with super.Sliced { - /** Override to use IndexedSeq's foreach; todo: see whether this is really faster */ - override def foreach[U](f: A => U) = super[Transformed].foreach(f) - } - - trait Mapped[B] extends Transformed[B] with super.Mapped[B] { - override def foreach[U](f: B => U) = super[Transformed].foreach(f) - } - - trait FlatMapped[B] extends Transformed[B] with super.FlatMapped[B] { - override def foreach[U](f: B => U) = super[Transformed].foreach(f) - } - - trait Appended[B >: A] extends Transformed[B] with super.Appended[B] { - override def foreach[U](f: B => U) = super[Transformed].foreach(f) - } - - trait Filtered extends Transformed[A] with super.Filtered { - override def foreach[U](f: A => U) = super[Transformed].foreach(f) - } - - trait TakenWhile extends Transformed[A] with super.TakenWhile { - override def foreach[U](f: A => U) = super[Transformed].foreach(f) - } - - trait DroppedWhile extends Transformed[A] with super.DroppedWhile { - override def foreach[U](f: A => U) = super[Transformed].foreach(f) - } - - trait Reversed extends Transformed[A] with super.Reversed { - override def foreach[U](f: A => U) = super[Transformed].foreach(f) - } - - trait Patched[B >: A] extends Transformed[B] with super.Patched[B] { - override def foreach[U](f: B => U) = super[Transformed].foreach(f) - } - - trait Zipped[B] extends Transformed[(A, B)] { - protected[this] val other: Iterable[B] - /** Have to be careful here - other may be an infinite sequence. */ - def length = - if (other.hasDefiniteSize) self.length min other.size - else other take self.length size - - def apply(idx: Int): (A, B) = (self.apply(idx), other.iterator drop idx next) - override def stringPrefix = self.stringPrefix+"Z" - } - - trait ZippedAll[A1 >: A, B] extends Transformed[(A1, B)] { - protected[this] val other: Iterable[B] - val thisElem: A1 - val thatElem: B - override def iterator: Iterator[(A1, B)] = - self.iterator.zipAll(other.iterator, thisElem, thatElem) - - def length = self.length max other.size - def apply(idx: Int): (A1, B) = { - val z1 = if (idx < self.length) self.apply(idx) else thisElem - val z2 = if (idx < other.size) other drop idx head else thatElem - (z1, z2) - } - override def stringPrefix = self.stringPrefix+"Z" - } - - /** Boilerplate method, to override in each subclass - * This method could be eliminated if Scala had virtual classes - */ - protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } - protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } - protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } - protected override def newFiltered(p: A => Boolean): Transformed[A] = new Filtered { val pred = p } - protected override def newSliced(_from: Int, _until: Int): Transformed[A] = new Sliced { val from = _from; val until = _until } - protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } - protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } - protected override def newZipped[B](that: Iterable[B]): Transformed[(A, B)] = new Zipped[B] { val other = that } - protected override def newZippedAll[A1 >: A, B](that: Iterable[B], _thisElem: A1, _thatElem: B): Transformed[(A1, B)] = new ZippedAll[A1, B] { val other = that; val thisElem = _thisElem; val thatElem = _thatElem } - protected override def newReversed: Transformed[A] = new Reversed { } - protected override def newPatched[B >: A](_from: Int, _patch: Seq[B], _replaced: Int): Transformed[B] = new Patched[B] { - val from = _from; val patch = _patch; val replaced = _replaced - } - override def stringPrefix = "IndexedSeqView" -} diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala index 8446988821..6f88c72ffd 100644 --- a/src/library/scala/collection/IterableLike.scala +++ b/src/library/scala/collection/IterableLike.scala @@ -69,9 +69,6 @@ self => */ def iterator: Iterator[A] - @deprecated("use `iterator' instead") - def elements = iterator - /** Applies a function `f` to all elements of this $coll. * * Note: this method underlies the implementation of most other bulk operations. @@ -189,7 +186,7 @@ self => b.result } - /** Selects all elements except first ''n'' ones. + /** Selects all elements except last ''n'' ones. * $orderDependent * * @param n The number of elements to take @@ -367,6 +364,9 @@ self => override /*TraversableLike*/ def view(from: Int, until: Int) = view.slice(from, until) + @deprecated("use `iterator' instead") + def elements = iterator + @deprecated("use `head' instead") def first: A = head /** `None` if iterable is empty. diff --git a/src/library/scala/collection/IterableProxyLike.scala b/src/library/scala/collection/IterableProxyLike.scala index 4400237486..fe148339b0 100644 --- a/src/library/scala/collection/IterableProxyLike.scala +++ b/src/library/scala/collection/IterableProxyLike.scala @@ -24,24 +24,20 @@ import mutable.Buffer * @version 2.8 * @since 2.8 */ -trait IterableProxyLike[+A, +This <: IterableLike[A, This] with Iterable[A]] - extends IterableLike[A, This] - with TraversableProxyLike[A, This] +trait IterableProxyLike[+A, +Repr <: IterableLike[A, Repr] with Iterable[A]] + extends IterableLike[A, Repr] + with TraversableProxyLike[A, Repr] { override def iterator: Iterator[A] = self.iterator - override def foreach[U](f: A => U): Unit = self.foreach(f) - override def isEmpty: Boolean = self.isEmpty - override def foldRight[B](z: B)(op: (A, B) => B): B = self.foldRight(z)(op) - override def reduceRight[B >: A](op: (A, B) => B): B = self.reduceRight(op) - override def toIterable: Iterable[A] = self.toIterable - override def zip[A1 >: A, B, That](that: Iterable[B])(implicit bf: CanBuildFrom[This, (A1, B), That]): That = self.zip[A1, B, That](that)(bf) - override def zipAll[B, A1 >: A, That](that: Iterable[B], thisElem: A1, thatElem: B)(implicit bf: CanBuildFrom[This, (A1, B), That]): That = self.zipAll(that, thisElem, thatElem)(bf) - override def zipWithIndex[A1 >: A, That](implicit bf: CanBuildFrom[This, (A1, Int), That]): That = self.zipWithIndex(bf) - override def head: A = self.head - override def takeRight(n: Int): This = self.takeRight(n) - override def dropRight(n: Int): This = self.dropRight(n) + override def grouped(size: Int): Iterator[Repr] = self.grouped(size) + override def sliding[B >: A](size: Int): Iterator[Repr] = self.sliding(size) + override def sliding[B >: A](size: Int, step: Int): Iterator[Repr] = self.sliding(size, step) + override def takeRight(n: Int): Repr = self.takeRight(n) + override def dropRight(n: Int): Repr = self.dropRight(n) + override def zip[A1 >: A, B, That](that: Iterable[B])(implicit bf: CanBuildFrom[Repr, (A1, B), That]): That = self.zip[A1, B, That](that)(bf) + override def zipAll[B, A1 >: A, That](that: Iterable[B], thisElem: A1, thatElem: B)(implicit bf: CanBuildFrom[Repr, (A1, B), That]): That = self.zipAll(that, thisElem, thatElem)(bf) + override def zipWithIndex[A1 >: A, That](implicit bf: CanBuildFrom[Repr, (A1, Int), That]): That = self.zipWithIndex(bf) override def sameElements[B >: A](that: Iterable[B]): Boolean = self.sameElements(that) - override def toStream: Stream[A] = self.toStream override def view = self.view override def view(from: Int, until: Int) = self.view(from, until) } diff --git a/src/library/scala/collection/IterableViewLike.scala b/src/library/scala/collection/IterableViewLike.scala index 27323294c4..09f084d92c 100644 --- a/src/library/scala/collection/IterableViewLike.scala +++ b/src/library/scala/collection/IterableViewLike.scala @@ -29,6 +29,10 @@ extends Iterable[A] with IterableLike[A, This] with TraversableView[A, Coll] wit trait Transformed[+B] extends IterableView[B, Coll] with super.Transformed[B] + trait Forced[B] extends Transformed[B] with super.Forced[B] { + override def iterator = forced.iterator + } + trait Sliced extends Transformed[A] with super.Sliced { override def iterator = self.iterator slice (from, until) } @@ -96,6 +100,7 @@ extends Iterable[A] with IterableLike[A, This] with TraversableView[A, Coll] wit /** Boilerplate method, to override in each subclass * This method could be eliminated if Scala had virtual classes */ + protected override def newForced[B](xs: => Seq[B]): Transformed[B] = new Forced[B] { val forced = xs } protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } @@ -104,5 +109,11 @@ extends Iterable[A] with IterableLike[A, This] with TraversableView[A, Coll] wit protected override def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } protected override def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } + override def grouped(size: Int): Iterator[This] = + self.iterator.grouped(size).map(xs => newForced(xs).asInstanceOf[This]) + + override def sliding[B >: A](size: Int, step: Int): Iterator[This] = + self.iterator.sliding(size).map(xs => newForced(xs).asInstanceOf[This]) + override def stringPrefix = "IterableView" } diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index de0ec5275f..701b24f300 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -13,7 +13,7 @@ package scala.collection import mutable.{Buffer, ArrayBuffer, ListBuffer, StringBuilder} import immutable.{List, Stream} -import annotation.{ tailrec } +import annotation.{ tailrec, migration } /** The `Iterator` object provides various functions for * creating specialized iterators. @@ -135,7 +135,7 @@ object Iterator { } /** Creates an infinite-length iterator returning the results of evaluating - * an expression. The epxression is recomputed for every element. + * an expression. The expression is recomputed for every element. * * @param elem the element computation. * @return the iterator containing an infinite number of results of evaluating `elem`. @@ -145,6 +145,27 @@ object Iterator { def next = elem } + /** With the advent of TraversableOnce, it can be useful to have a builder + * for Iterators so they can be treated uniformly along with the collections. + * See scala.util.Random.shuffle for an example. + */ + class IteratorCanBuildFrom[A] extends generic.CanBuildFrom[Iterator[A], A, Iterator[A]] { + def newIterator = new ArrayBuffer[A] mapResult (_.iterator) + + /** Creates a new builder on request of a collection. + * @param from the collection requesting the builder to be created. + * @return the result of invoking the `genericBuilder` method on `from`. + */ + def apply(from: Iterator[A]) = newIterator + + /** Creates a new builder from scratch + * @return the result of invoking the `newBuilder` method of this factory. + */ + def apply() = newIterator + } + + implicit def iteratorCanBuildFrom[T]: IteratorCanBuildFrom[T] = new IteratorCanBuildFrom[T] + /** A wrapper class for the `flatten` method that is added to * class `Iterator` with implicit conversion * @see iteratorIteratorWrapper. @@ -233,7 +254,7 @@ object Iterator { def next(): Int = { val j = i; i = step(i); j } } - /** Create an iterator that is the concantenation of all iterators + /** Create an iterator that is the concatenation of all iterators * returned by a given iterator of iterators. * @param its The iterator which returns on each call to next * a new iterator whose elements are to be concatenated to the result. @@ -265,7 +286,8 @@ import Iterator.empty * @define mayNotTerminateInf * Note: may not terminate for infinite iterators. */ -trait Iterator[+A] { self => +trait Iterator[+A] extends TraversableOnce[A] { + self => /** Tests whether this iterator can provide another element. * @return `true` if a subsequent call to `next` will yield an element, @@ -279,6 +301,22 @@ trait Iterator[+A] { self => */ def next(): A + /** Tests whether this iterator is empty. + * @return `true` if hasNext is false, `false` otherwise. + */ + def isEmpty: Boolean = !hasNext + + /** Tests whether this Iterator can be repeatedly traversed. + * @return `false` + */ + def isTraversableAgain = false + + /** Tests whether this Iterator has a known size. + * + * @return `true` for empty Iterators, `false` otherwise. + */ + def hasDefiniteSize = isEmpty + /** Selects first ''n'' values of this iterator. * @param n the number of values to take * @return an iterator producing only of the first `n` values of this iterator, or else the @@ -319,8 +357,8 @@ trait Iterator[+A] { self => /** Creates a new iterator that maps all produced values of this iterator * to new values using a transformation function. * @param f the transformation function - * @return a new iterator which transformes every value produced by this - * iterator by applying the functon `f` to it. + * @return a new iterator which transforms every value produced by this + * iterator by applying the function `f` to it. */ def map[B](f: A => B): Iterator[B] = new Iterator[B] { def hasNext = self.hasNext @@ -328,7 +366,7 @@ trait Iterator[+A] { self => } /** Concatenates this iterator with another. - * @that the other iterator + * @param that the other iterator * @return a new iterator that first yields the values produced by this * iterator followed by the values produced by iterator `that`. * @usecase def ++(that: => Iterator[A]): Iterator[A] @@ -411,7 +449,11 @@ trait Iterator[+A] { self => * @return a new iterator which yields each value `x` produced by this iterator for * which `pf` is defined the image `pf(x)`. */ - def partialMap[B](pf: PartialFunction[A, B]): Iterator[B] = { + @migration(2, 8, + "This collect implementation bears no relationship to the one before 2.8.\n"+ + "The previous behavior can be reproduced with toSeq." + ) + def collect[B](pf: PartialFunction[A, B]): Iterator[B] = { val self = buffered new Iterator[B] { private def skip() = while (self.hasNext && !pf.isDefinedAt(self.head)) self.next() @@ -667,12 +709,12 @@ trait Iterator[+A] { self => if (found) i else -1 } - /** Returns the index of the first occurence of the specified + /** Returns the index of the first occurrence of the specified * object in this iterable object. * $mayNotTerminateInf * * @param elem element to search for. - * @return the index of the first occurence of `elem` in the values produced by this iterator, + * @return the index of the first occurrence of `elem` in the values produced by this iterator, * or -1 if such an element does not exist until the end of the iterator is reached. */ def indexOf[B >: A](elem: B): Int = { @@ -688,131 +730,6 @@ trait Iterator[+A] { self => if (found) i else -1 } - /** Applies a binary operator to a start value and all values produced by this iterator, going left to right. - * $willNotTerminateInf - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive values produced by this iterator - * going left to right with the start value `z` on the left: - * {{{ - * op(...op(z, x,,1,,), x,,2,,, ..., x,,n,,) - * }}} - * where `x,,1,,, ..., x,,n,,` are the values produced by this iterator. - */ - def foldLeft[B](z: B)(op: (B, A) => B): B = { - var acc = z - while (hasNext) acc = op(acc, next()) - acc - } - - /** Applies a binary operator to all values produced by this iterator and a start value, going right to left. - * $willNotTerminateInf - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive values produced by this iterator - * going right to left with the start value `z` on the right: - * {{{ - * op(x,,1,,, op(x,,2,,, ... op(x,,n,,, z)...)) - * }}} - * where `x,,1,,, ..., x,,n,,` are the values produced by this iterator. - */ - def foldRight[B](z: B)(op: (A, B) => B): B = - if (hasNext) op(next(), foldRight(z)(op)) else z - - /** Applies a binary operator to a start value and all values produced by this iterator, going left to right. - * - * Note: `/:` is alternate syntax for `foldLeft`; `z /: it` is the same as `it foldLeft z`. - * $willNotTerminateInf - * - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive values produced by this iterator - * going left to right with the start value `z` on the left: - * {{{ - * op(...op(z, x,,1,,), x,,2,,, ..., x,,n,,) - * }}} - * where `x,,1,,, ..., x,,n,,` are the values produced by this iterator. - */ - def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op) - - /** Applies a binary operator to all values produced by this iterator and a start value, going right to left. - * Note: `:\` is alternate syntax for `foldRight`; `it :\ z` is the same as `it foldRight z`. - * $willNotTerminateInf - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive values produced by this iterator - * going right to left with the start value `z` on the right: - * {{{ - * op(x,,1,,, op(x,,2,,, ... op(x,,n,,, z)...)) - * }}} - * where `x,,1,,, ..., x,,n,,` are the values produced by this iterator. - */ - def :\[B](z: B)(op: (A, B) => B): B = foldRight(z)(op) - - /** Applies a binary operator to all values produced by this iterator, going left to right. - * $willNotTerminateInf - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive values produced by this iterator - * going left to right: - * {{{ - * op(...(op(x,,1,,, x,,2,,), ... ) , x,,n,,) - * }}} - * where `x,,1,,, ..., x,,n,,` are the values produced by this iterator. - * @throws `UnsupportedOperationException` if this iterator is empty. - */ - def reduceLeft[B >: A](op: (B, A) => B): B = { - if (hasNext) foldLeft[B](next())(op) - else throw new UnsupportedOperationException("empty.reduceLeft") - } - - /** Applies a binary operator to all values produced by this iterator, going right to left. - * $willNotTerminateInf - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive values produced by this iterator - * going right to left: - * {{{ - * op(x,,1,,, op(x,,2,,, ..., op(x,,n-1,,, x,,n,,)...)) - * }}} - * where `x,,1,,, ..., x,,n,,` are the values produced by this iterator. - * @throws `UnsupportedOperationException` if this iterator is empty. - */ - def reduceRight[B >: A](op: (A, B) => B): B = { - if (hasNext) foldRight[B](next())(op) - else throw new UnsupportedOperationException("empty.reduceRight") - } - - /** Optionally applies a binary operator to all values produced by this iterator, going left to right. - * $willNotTerminateInf - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return an option value containing the result of `reduceLeft(op)` is this iterator is nonempty, - * `None` otherwise. - */ - def reduceLeftOption[B >: A](op: (B, A) => B): Option[B] = { - if (!hasNext) None else Some(reduceLeft(op)) - } - - /** Optionally applies a binary operator to all values produced by this iterator, going right to left. - * $willNotTerminateInf - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return an option value containing the result of `reduceRight(op)` is this iterator is nonempty, - * `None` otherwise. - */ - def reduceRightOption[B >: A](op: (A, B) => B): Option[B] = { - if (!hasNext) None else Some(reduceRight(op)) - } - /** Creates a buffered iterator from this iterator. * @see BufferedIterator * @return a buffered iterator producing the same values as this iterator. @@ -937,6 +854,8 @@ trait Iterator[+A] { self => if (!filled) fill() + if (!filled) + throw new NoSuchElementException("next on empty iterator") filled = false buffer.toList } @@ -985,16 +904,11 @@ trait Iterator[+A] { self => * * Note: The iterator is at its end after this method returns. */ - def length: Int = { - var i = 0 - while (hasNext) { - next(); i += 1 - } - i - } + def length: Int = this.size /** Creates two new iterators that both iterate over the same elements - * as this iterator (in the same order). + * as this iterator (in the same order). The duplicate iterators are + * considered equal if they are positioned at the same element. * * @return a pair of iterators */ @@ -1013,6 +927,14 @@ trait Iterator[+A] { self => e } else gap.dequeue } + // to verify partnerhood we use reference equality on gap because + // type testing does not discriminate based on origin. + private def compareGap(queue: scala.collection.mutable.Queue[A]) = gap eq queue + override def hashCode = gap.hashCode + override def equals(other: Any) = other match { + case x: Partner => x.compareGap(gap) && gap.isEmpty + case _ => super.equals(other) + } } (new Partner, new Partner) } @@ -1063,75 +985,7 @@ trait Iterator[+A] { self => } } - /** Copies values produced by this iterator to an array. - * Fills the given array `xs` with values produced by this iterator, after skipping `start` values. - * Copying will stop once either the end of the current iterator is reached, - * or the end of the array is reached. - * - * $willNotTerminateInf - * - * @param xs the array to fill. - * @param start the starting index. - * @tparam B the type of the elements of the array. - * - * @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit - */ - def copyToArray[B >: A](xs: Array[B], start: Int): Unit = - copyToArray(xs, start, xs.length - start) - - /** Copies values produced by this iterator to an array. - * Fills the given array `xs` with values produced by this iterator. - * Copying will stop once either the end of the current iterator is reached, - * or the end of the array is reached. - * - * $willNotTerminateInf - * - * @param xs the array to fill. - * @tparam B the type of the elements of the array. - * - * @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit - */ - def copyToArray[B >: A](xs: Array[B]): Unit = copyToArray(xs, 0, xs.length) - - /** Copies all values produced by this iterator to a buffer. - * $willNotTerminateInf - * @param dest The buffer to which elements are copied - */ - def copyToBuffer[B >: A](dest: Buffer[B]) { - while (hasNext) dest += next() - } - - /** Traverses this iterator and returns all produced values in a list. - * $willNotTerminateInf - * - * @return a list which contains all values produced by this iterator. - */ - def toList: List[A] = { - val res = new ListBuffer[A] - while (hasNext) res += next - res.toList - } - - /** Lazily wraps a Stream around this iterator so its values are memoized. - * - * @return a Stream which can repeatedly produce all the values - * produced by this iterator. - */ - def toStream: Stream[A] = - if (hasNext) Stream.cons(next, toStream) else Stream.empty - - /** Traverses this iterator and returns all produced values in a sequence. - * $willNotTerminateInf - * - * @return a list which contains all values produced by this iterator. - */ - def toSeq: Seq[A] = { - val buffer = new ArrayBuffer[A] - this copyToBuffer buffer - buffer - } - - /** Tests if another iterator produces the same valeus as this one. + /** Tests if another iterator produces the same values as this one. * $willNotTerminateInf * @param that the other iterator * @return `true`, if both iterators produce the same elements in the same order, `false` otherwise. @@ -1144,76 +998,8 @@ trait Iterator[+A] { self => !hasNext && !that.hasNext } - /** Displays all values produced by this iterator in a string using start, end, and separator strings. - * - * @param start the starting string. - * @param sep the separator string. - * @param end the ending string. - * @return a string representation of this iterator. The resulting string - * begins with the string `start` and ends with the string - * `end`. Inside, the string representations (w.r.t. the method `toString`) - * of all values produced by this iterator are separated by the string `sep`. - */ - def mkString(start: String, sep: String, end: String): String = { - val buf = new StringBuilder - addString(buf, start, sep, end).toString - } - - /** Displays all values produced by this iterator in a string using a separator string. - * - * @param sep the separator string. - * @return a string representation of this iterator. In the resulting string - * the string representations (w.r.t. the method `toString`) - * of all values produced by this iterator are separated by the string `sep`. - */ - def mkString(sep: String): String = mkString("", sep, "") - - /** Displays all values produced by this iterator in a string. - * @return a string representation of this iterator. In the resulting string - * the string representations (w.r.t. the method `toString`) - * of all values produced by this iterator follow each other without any separator string. - */ - def mkString: String = mkString("") - - /** Appends all values produced by this iterator to a string builder using start, end, and separator strings. - * The written text begins with the string `start` and ends with the string - * `end`. Inside, the string representations (w.r.t. the method `toString`) - * of all values produced by this iterator are separated by the string `sep`. - * - * @param b the string builder to which elements are appended. - * @param start the starting string. - * @param sep the separator string. - * @param end the ending string. - * @return the string builder `b` to which elements were appended. - */ - def addString(buf: StringBuilder, start: String, sep: String, end: String): StringBuilder = { - buf.append(start) - val elems = this - if (elems.hasNext) buf.append(elems.next) - while (elems.hasNext) { - buf.append(sep); buf.append(elems.next) - } - buf.append(end) - } - - /** Appends all values produced by this iterator to a string builder using a separator string. - * The written text consists of the string representations (w.r.t. the method `toString`) - * of all values produced by this iterator, separated by the string `sep`. - * - * @param b the string builder to which elements are appended. - * @param sep the separator string. - * @return the string builder `b` to which elements were appended. - */ - def addString(buf: StringBuilder, sep: String): StringBuilder = addString(buf, "", sep, "") - - /** Appends all values produced by this iterator to a string builder. - * The written text consists of the string representations (w.r.t. the method `toString`) - * of all values produced by this iterator without any separator string. - * - * @param b the string builder to which elements are appended. - * @return the string builder `b` to which elements were appended. - */ - def addString(buf: StringBuilder): StringBuilder = addString(buf, "", "", "") + def toTraversable: Traversable[A] = toStream + def toIterator: Iterator[A] = self /** Converts this iterator to a string. * @return `"empty iterator"` or `"non-empty iterator"`, depending on whether or not the iterator is empty. @@ -1230,13 +1016,6 @@ trait Iterator[+A] { self => @deprecated("use `indexWhere` instead") def findIndexOf(p: A => Boolean): Int = indexWhere(p) - /** Collect elements into a seq. - * - * @return a sequence which enumerates all elements of this iterator. - */ - @deprecated("use toSeq instead") - def collect: Seq[A] = toSeq - /** Returns a counted iterator from this iterator. */ @deprecated("use zipWithIndex in Iterator") @@ -1254,7 +1033,7 @@ trait Iterator[+A] { self => * @param xs the array to fill. * @param start the starting index. * @param sz the maximum number of elements to be read. - * @pre the array must be large enough to hold `sz` elements. + * @note the array must be large enough to hold `sz` elements. */ @deprecated("use copyToArray instead") def readInto[B >: A](xs: Array[B], start: Int, sz: Int) { diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 7af138067b..00f2d745af 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -40,7 +40,7 @@ package scala.collection * <p> * Note that no conversion is provided from <code>scala.collection.immutable.List</code> * to <code>java.util.List</code>. Instead it is convertible to an immutable - * <code>java.util.Collection</code> which provides size and interation + * <code>java.util.Collection</code> which provides size and interaction * capabilities, but not access by index as would be provided by * <code>java.util.List</code>.<br/> * This is intentional: in combination the implementation of @@ -497,9 +497,10 @@ object JavaConversions { case class MutableMapWrapper[A, B](underlying : mutable.Map[A, B])(m : ClassManifest[A]) extends MutableMapWrapperLike[A, B](underlying)(m) - abstract class JMapWrapperLike[A, B, +Repr <: mutable.MapLike[A, B, Repr] with mutable.Map[A, B]] - (underlying: ju.Map[A, B]) + trait JMapWrapperLike[A, B, +Repr <: mutable.MapLike[A, B, Repr] with mutable.Map[A, B]] extends mutable.Map[A, B] with mutable.MapLike[A, B, Repr] { + def underlying: ju.Map[A, B] + override def size = underlying.size def get(k : A) = { @@ -538,8 +539,8 @@ object JavaConversions { override def empty: Repr = null.asInstanceOf[Repr] } - case class JMapWrapper[A, B](underlying : ju.Map[A, B]) - extends JMapWrapperLike[A, B, JMapWrapper[A, B]](underlying) { + case class JMapWrapper[A, B](val underlying : ju.Map[A, B]) + extends JMapWrapperLike[A, B, JMapWrapper[A, B]] { override def empty = JMapWrapper(new ju.HashMap[A, B]) } @@ -584,8 +585,8 @@ object JavaConversions { } - case class JConcurrentMapWrapper[A, B](underlying: juc.ConcurrentMap[A, B]) - extends JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]](underlying) with mutable.ConcurrentMap[A, B] { + case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) + extends JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with mutable.ConcurrentMap[A, B] { override def get(k: A) = { val v = underlying.get(k) if (v != null) Some(v) diff --git a/src/library/scala/collection/LinearSeq.scala b/src/library/scala/collection/LinearSeq.scala index 5862741530..1afb2fdb7f 100644 --- a/src/library/scala/collection/LinearSeq.scala +++ b/src/library/scala/collection/LinearSeq.scala @@ -14,18 +14,10 @@ package scala.collection import generic._ import mutable.Builder -/** <p> - * Class <code>Linear[A]</code> represents linear sequences of elements. - * For such sequences <code>isEmpty</code>, <code>head</code> and - * <code>tail</code> are guaranteed to be efficient constant time (or near so) - * operations.<br/> - * It does not add any methods to <code>Seq</code> but overrides several - * methods with optimized implementations. - * </p> +/** A base trait for linear sequences. + * $linearSeqInfo * * @author Martin Odersky - * @author Matthias Zenger - * @version 1.0, 16/07/2003 * @since 2.8 */ trait LinearSeq[+A] extends Seq[A] diff --git a/src/library/scala/collection/LinearSeqLike.scala b/src/library/scala/collection/LinearSeqLike.scala index 9bed88967c..1c99d4a3d9 100644 --- a/src/library/scala/collection/LinearSeqLike.scala +++ b/src/library/scala/collection/LinearSeqLike.scala @@ -19,12 +19,16 @@ import scala.util.control.Breaks._ /** A template trait for linear sequences of type `LinearSeq[A]`. * * $linearSeqInfo + * + * This trait just implements `iterator` + * in terms of `isEmpty, ``head`, and `tail`. + * However, see `LinearSeqOptimized` for an implementation trait that overrides operations + * to make them run faster under the assumption of fast linear access with `head` and `tail`. + * * @author Martin Odersky - * @author Matthias Zenger - * @version 1.0, 16/07/2003 + * @version 2.8 * @since 2.8 * - * @define Coll LinearSeq * @define linearSeqInfo * Linear sequences are defined in terms of three abstract methods, which are assumed * to have efficient implementations. These are: @@ -35,9 +39,8 @@ import scala.util.control.Breaks._ * }}} * Here, `A` is the type of the sequence elements and `Repr` is the type of the sequence itself. * - * Linear sequences do not define any new methods wrt `Seq`. However, abstract `Seq` methods - * are defined in terms of `isEmpty`, `head`, and `tail`, and several other methods are overridden - * with optimized implementations. + * Linear sequences do not add any new methods to `Seq`, but promise efficient implementations + * of linear access patterns. * * @tparam A the element type of the $coll * @tparam Repr the type of the actual $coll containing the elements. @@ -47,38 +50,6 @@ trait LinearSeqLike[+A, +Repr <: LinearSeqLike[A, Repr]] extends SeqLike[A, Repr override protected[this] def thisCollection: LinearSeq[A] = this.asInstanceOf[LinearSeq[A]] override protected[this] def toCollection(repr: Repr): LinearSeq[A] = repr.asInstanceOf[LinearSeq[A]] - def isEmpty: Boolean - - def head: A - - def tail: Repr - - /** The length of the $coll. - * - * $willNotTerminateInf - * - * Note: the execution of `length` may take time proportial to the length of the sequence. - */ - def length: Int = { - var these = self - var len = 0 - while (!these.isEmpty) { - len += 1 - these = these.tail - } - len - } - - /** Selects an element by its index in the $coll. - * Note: the execution of `apply` may take time proportial to the index value. - * @throws `IndexOutOfBoundsEsxception` if `idx` does not satisfy `0 <= idx < length`. - */ - def apply(n: Int): A = { - val rest = drop(n) - if (n < 0 || rest.isEmpty) throw new IndexOutOfBoundsException - rest.head - } - override /*IterableLike*/ def iterator: Iterator[A] = new Iterator[A] { var these = self @@ -89,239 +60,4 @@ trait LinearSeqLike[+A, +Repr <: LinearSeqLike[A, Repr]] extends SeqLike[A, Repr } else Iterator.empty.next override def toList: List[A] = these.toList } - - override /*IterableLike*/ - def foreach[B](f: A => B) { - var these = this - while (!these.isEmpty) { - f(these.head) - these = these.tail - } - } - - - override /*IterableLike*/ - def forall(p: A => Boolean): Boolean = { - var these = this - while (!these.isEmpty) { - if (!p(these.head)) return false - these = these.tail - } - true - } - - override /*IterableLike*/ - def exists(p: A => Boolean): Boolean = { - var these = this - while (!these.isEmpty) { - if (p(these.head)) return true - these = these.tail - } - false - } - - override /*TraversableLike*/ - def count(p: A => Boolean): Int = { - var these = this - var cnt = 0 - while (!these.isEmpty) { - if (p(these.head)) cnt += 1 - these = these.tail - } - cnt - } - - override /*IterableLike*/ - def find(p: A => Boolean): Option[A] = { - var these = this - while (!these.isEmpty) { - if (p(these.head)) return Some(these.head) - these = these.tail - } - None - } -/* - override def mapFind[B](f: A => Option[B]): Option[B] = { - var res: Option[B] = None - var these = this - while (res.isEmpty && !these.isEmpty) { - res = f(these.head) - these = these.tail - } - res - } -*/ - override /*TraversableLike*/ - def foldLeft[B](z: B)(f: (B, A) => B): B = { - var acc = z - var these = this - while (!these.isEmpty) { - acc = f(acc, these.head) - these = these.tail - } - acc - } - - override /*IterableLike*/ - def foldRight[B](z: B)(f: (A, B) => B): B = - if (this.isEmpty) z - else f(head, tail.foldRight(z)(f)) - - override /*TraversableLike*/ - def reduceLeft[B >: A](f: (B, A) => B): B = - if (isEmpty) throw new UnsupportedOperationException("empty.reduceLeft") - else tail.foldLeft[B](head)(f) - - override /*IterableLike*/ - def reduceRight[B >: A](op: (A, B) => B): B = - if (isEmpty) throw new UnsupportedOperationException("Nil.reduceRight") - else if (tail.isEmpty) head - else op(head, tail.reduceRight(op)) - - override /*TraversableLike*/ - def last: A = { - if (isEmpty) throw new NoSuchElementException - var these = this - var nx = these.tail - while (!nx.isEmpty) { - these = nx - nx = nx.tail - } - these.head - } - - override /*IterableLike*/ - def take(n: Int): Repr = { - val b = newBuilder - var i = 0 - var these = repr - while (!these.isEmpty && i < n) { - i += 1 - b += these.head - these = these.tail - } - b.result - } - - override /*TraversableLike*/ - def drop(n: Int): Repr = { - var these: Repr = repr - var count = n - while (!these.isEmpty && count > 0) { - these = these.tail - count -= 1 - } - these - } - - override /*IterableLike*/ - def dropRight(n: Int): Repr = { - val b = newBuilder - var these = this - var lead = this drop n - while (!lead.isEmpty) { - b += these.head - these = these.tail - lead = lead.tail - } - b.result - } - - override /*IterableLike*/ - def slice(from: Int, until: Int): Repr = { - val b = newBuilder - var i = from - var these = this drop from - while (i < until && !these.isEmpty) { - b += these.head - these = these.tail - i += 1 - } - b.result - } - - override /*IterableLike*/ - def takeWhile(p: A => Boolean): Repr = { - val b = newBuilder - var these = this - while (!these.isEmpty && p(these.head)) { - b += these.head - these = these.tail - } - b.result - } - - override /*TraversableLike*/ - def span(p: A => Boolean): (Repr, Repr) = { - var these: Repr = repr - val b = newBuilder - while (!these.isEmpty && p(these.head)) { - b += these.head - these = these.tail - } - (b.result, these) - } - - override /*IterableLike*/ - def sameElements[B >: A](that: Iterable[B]): Boolean = that match { - case that1: LinearSeq[_] => - var these = this - var those = that1 - while (!these.isEmpty && !those.isEmpty && these.head == those.head) { - these = these.tail - those = those.tail - } - these.isEmpty && those.isEmpty - case _ => - super.sameElements(that) - } - - override /*SeqLike*/ - def lengthCompare(len: Int): Int = { - var i = 0 - var these = self - while (!these.isEmpty && i <= len) { - i += 1 - these = these.tail - } - i - len - } - - override /*SeqLike*/ - def isDefinedAt(x: Int): Boolean = x >= 0 && lengthCompare(x) > 0 - - override /*SeqLike*/ - def segmentLength(p: A => Boolean, from: Int): Int = { - var i = 0 - var these = this drop from - while (!these.isEmpty && p(these.head)) { - i += 1 - these = these.tail - } - i - } - - override /*SeqLike*/ - def indexWhere(p: A => Boolean, from: Int): Int = { - var i = from - var these = this drop from - while (!these.isEmpty && !p(these.head)) { - i += 1 - these = these.tail - } - if (these.isEmpty) -1 else i - } - - override /*SeqLike*/ - def lastIndexWhere(p: A => Boolean, end: Int): Int = { - var i = 0 - var these = this - var last = -1 - while (!these.isEmpty && i <= end) { - if (p(these.head)) last = i - these = these.tail - i += 1 - } - last - } } diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala new file mode 100755 index 0000000000..7d3c58ad85 --- /dev/null +++ b/src/library/scala/collection/LinearSeqOptimized.scala @@ -0,0 +1,301 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: LinearSeqOptimized.scala 20608 2010-01-20 00:28:09Z extempore $ + + +package scala.collection +import generic._ + +import mutable.ListBuffer +import immutable.List +import scala.util.control.Breaks._ + +/** A template trait for linear sequences of type `LinearSeq[A]` which optimizes + * the implementation of several methods under the assumption of fast linear access. + * + * $linearSeqInfo + * @author Martin Odersky + * @version 2.8 + * @since 2.8 + * + * @tparam A the element type of the $coll + * @tparam Repr the type of the actual $coll containing the elements. + */ +trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends LinearSeqLike[A, Repr] { self: Repr => + + def isEmpty: Boolean + + def head: A + + def tail: Repr + + /** The length of the $coll. + * + * $willNotTerminateInf + * + * Note: the execution of `length` may take time proportial to the length of the sequence. + */ + def length: Int = { + var these = self + var len = 0 + while (!these.isEmpty) { + len += 1 + these = these.tail + } + len + } + + /** Selects an element by its index in the $coll. + * Note: the execution of `apply` may take time proportial to the index value. + * @throws `IndexOutOfBoundsException` if `idx` does not satisfy `0 <= idx < length`. + */ + def apply(n: Int): A = { + val rest = drop(n) + if (n < 0 || rest.isEmpty) throw new IndexOutOfBoundsException + rest.head + } + + override /*IterableLike*/ + def foreach[B](f: A => B) { + var these = this + while (!these.isEmpty) { + f(these.head) + these = these.tail + } + } + + + override /*IterableLike*/ + def forall(p: A => Boolean): Boolean = { + var these = this + while (!these.isEmpty) { + if (!p(these.head)) return false + these = these.tail + } + true + } + + override /*IterableLike*/ + def exists(p: A => Boolean): Boolean = { + var these = this + while (!these.isEmpty) { + if (p(these.head)) return true + these = these.tail + } + false + } + + override /*TraversableLike*/ + def count(p: A => Boolean): Int = { + var these = this + var cnt = 0 + while (!these.isEmpty) { + if (p(these.head)) cnt += 1 + these = these.tail + } + cnt + } + + override /*IterableLike*/ + def find(p: A => Boolean): Option[A] = { + var these = this + while (!these.isEmpty) { + if (p(these.head)) return Some(these.head) + these = these.tail + } + None + } +/* + override def mapFind[B](f: A => Option[B]): Option[B] = { + var res: Option[B] = None + var these = this + while (res.isEmpty && !these.isEmpty) { + res = f(these.head) + these = these.tail + } + res + } +*/ + override /*TraversableLike*/ + def foldLeft[B](z: B)(f: (B, A) => B): B = { + var acc = z + var these = this + while (!these.isEmpty) { + acc = f(acc, these.head) + these = these.tail + } + acc + } + + override /*IterableLike*/ + def foldRight[B](z: B)(f: (A, B) => B): B = + if (this.isEmpty) z + else f(head, tail.foldRight(z)(f)) + + override /*TraversableLike*/ + def reduceLeft[B >: A](f: (B, A) => B): B = + if (isEmpty) throw new UnsupportedOperationException("empty.reduceLeft") + else tail.foldLeft[B](head)(f) + + override /*IterableLike*/ + def reduceRight[B >: A](op: (A, B) => B): B = + if (isEmpty) throw new UnsupportedOperationException("Nil.reduceRight") + else if (tail.isEmpty) head + else op(head, tail.reduceRight(op)) + + override /*TraversableLike*/ + def last: A = { + if (isEmpty) throw new NoSuchElementException + var these = this + var nx = these.tail + while (!nx.isEmpty) { + these = nx + nx = nx.tail + } + these.head + } + + override /*IterableLike*/ + def take(n: Int): Repr = { + val b = newBuilder + var i = 0 + var these = repr + while (!these.isEmpty && i < n) { + i += 1 + b += these.head + these = these.tail + } + b.result + } + + override /*TraversableLike*/ + def drop(n: Int): Repr = { + var these: Repr = repr + var count = n + while (!these.isEmpty && count > 0) { + these = these.tail + count -= 1 + } + these + } + + override /*IterableLike*/ + def dropRight(n: Int): Repr = { + val b = newBuilder + var these = this + var lead = this drop n + while (!lead.isEmpty) { + b += these.head + these = these.tail + lead = lead.tail + } + b.result + } + + override /*IterableLike*/ + def slice(from: Int, until: Int): Repr = { + val b = newBuilder + var i = from + var these = this drop from + while (i < until && !these.isEmpty) { + b += these.head + these = these.tail + i += 1 + } + b.result + } + + override /*IterableLike*/ + def takeWhile(p: A => Boolean): Repr = { + val b = newBuilder + var these = this + while (!these.isEmpty && p(these.head)) { + b += these.head + these = these.tail + } + b.result + } + + override /*TraversableLike*/ + def span(p: A => Boolean): (Repr, Repr) = { + var these: Repr = repr + val b = newBuilder + while (!these.isEmpty && p(these.head)) { + b += these.head + these = these.tail + } + (b.result, these) + } + + override /*IterableLike*/ + def sameElements[B >: A](that: Iterable[B]): Boolean = that match { + case that1: LinearSeq[_] => + var these = this + var those = that1 + while (!these.isEmpty && !those.isEmpty && these.head == those.head) { + these = these.tail + those = those.tail + } + these.isEmpty && those.isEmpty + case _ => + super.sameElements(that) + } + + override /*SeqLike*/ + def lengthCompare(len: Int): Int = { + var i = 0 + var these = self + while (!these.isEmpty && i <= len) { + i += 1 + these = these.tail + } + i - len + } + + override /*SeqLike*/ + def isDefinedAt(x: Int): Boolean = x >= 0 && lengthCompare(x) > 0 + + override /*SeqLike*/ + def segmentLength(p: A => Boolean, from: Int): Int = { + var i = 0 + var these = this drop from + while (!these.isEmpty && p(these.head)) { + i += 1 + these = these.tail + } + i + } + + override /*SeqLike*/ + def indexWhere(p: A => Boolean, from: Int): Int = { + var i = from + var these = this drop from + while (these.nonEmpty) { + if (p(these.head)) + return i + + i += 1 + these = these.tail + } + -1 + } + + override /*SeqLike*/ + def lastIndexWhere(p: A => Boolean, end: Int): Int = { + var i = 0 + var these = this + var last = -1 + while (!these.isEmpty && i <= end) { + if (p(these.head)) last = i + these = these.tail + i += 1 + } + last + } +} diff --git a/src/library/scala/collection/MapLike.scala b/src/library/scala/collection/MapLike.scala index 55cea1a678..5e1af7a2d7 100644 --- a/src/library/scala/collection/MapLike.scala +++ b/src/library/scala/collection/MapLike.scala @@ -12,6 +12,7 @@ package scala.collection import generic._ import mutable.{Builder, StringBuilder, MapBuilder} +import annotation.migration import PartialFunction._ /** A template trait for maps of type `Map[A, B]` which associate keys of type `A` @@ -71,7 +72,7 @@ self => /** Optionally returns the value associated with a key. * - * @key the key value + * @param key the key value * @return an option value containing the value associated with `key` in this map, * or `None` if none exists. */ @@ -109,7 +110,7 @@ self => * @param default a computation that yields a default value in case no binding for `key` is * found in the map. * @tparam B1 the result type of the default computation. - * @return the value assocuated with `key` if it exists, + * @return the value associated with `key` if it exists, * otherwise the result of the `default` computation. * @usecase def getOrElse(key: A, default: => B): B */ @@ -181,15 +182,16 @@ self => * * @return an iterator over all keys. */ - @deprecated("use `keysIterator' instead") - def keys: Iterator[A] = keysIterator + @migration(2, 8, "As of 2.8, keys returns Iterable[A] rather than Iterator[A].") + def keys: Iterable[A] = keySet /** Collects all values of this map in an iterable collection. * @return the values of this map as an iterable. */ - def valuesIterable: Iterable[B] = new DefaultValuesIterable + @migration(2, 8, "As of 2.8, values returns Iterable[B] rather than Iterator[B].") + def values: Iterable[B] = new DefaultValuesIterable - /** The implementation class of the iterable returned by `valuesIterable`. + /** The implementation class of the iterable returned by `values`. */ protected class DefaultValuesIterable extends Iterable[B] { def iterator = valuesIterator @@ -207,13 +209,6 @@ self => def next = iter.next._2 } - /** Creates an iterator for all contained values. - * - * @return an iterator over all values. - */ - @deprecated("use `valuesIterator' instead") - def values: Iterator[B] = valuesIterator - /** Defines the default value computation for the map, * returned when a key is not found * The method implemented here throws an exception, @@ -230,7 +225,7 @@ self => * @return an immutable map consisting only of those key value pairs of this map where the key satisfies * the predicate `p`. The resulting map wraps the original map without copying any elements. */ - def filterKeys(p: A => Boolean) = new DefaultMap[A, B] { + def filterKeys(p: A => Boolean): Map[A, B] = new DefaultMap[A, B] { override def foreach[C](f: ((A, B)) => C): Unit = for (kv <- self) if (p(kv._1)) f(kv) def iterator = self.iterator.filter(kv => p(kv._1)) override def contains(key: A) = self.contains(key) && p(key) @@ -245,7 +240,7 @@ self => /** A map view resulting from applying a given function `f` to each value * associated with a key in this map. */ - def mapValues[C](f: B => C) = new DefaultMap[A, C] { + def mapValues[C](f: B => C): Map[A, C] = new DefaultMap[A, C] { override def foreach[D](g: ((A, C)) => D): Unit = for ((k, v) <- self) g((k, f(v))) def iterator = for ((k, v) <- self.iterator) yield (k, f(v)) override def size = self.size @@ -291,18 +286,25 @@ self => * @return a new map with the given bindings added to this map * @usecase def + (kvs: Traversable[(A, B)]): Map[A, B] */ - def ++[B1 >: B](kvs: Traversable[(A, B1)]): Map[A, B1] = - ((repr: Map[A, B1]) /: kvs) (_ + _) + def ++[B1 >: B](xs: TraversableOnce[(A, B1)]): Map[A, B1] = + ((repr: Map[A, B1]) /: xs) (_ + _) - /** Adds all key/value pairs produced by an iterator to this map, returning a new map. + /** Returns a new map with all key/value pairs for which the predicate + * <code>p</code> returns <code>true</code>. * - * @param iter the iterator producing key/value pairs - * @tparam B1 the type of the added values - * @return a new map with the given bindings added to this map - * @usecase def + (iter: Iterator[(A, B)]): Map[A, B] + * @param p A predicate over key-value pairs + * @note This method works by successively removing elements fro which the + * predicate is false from this set. + * If removal is slow, or you expect that most elements of the set$ + * will be removed, you might consider using <code>filter</code> + * with a negated predicate instead. */ - def ++[B1 >: B] (iter: Iterator[(A, B1)]): Map[A, B1] = - ((repr: Map[A, B1]) /: iter) (_ + _) + override def filterNot(p: ((A, B)) => Boolean): This = { + var res: This = repr + for (kv <- this) + if (p(kv)) res = (res - kv._1).asInstanceOf[This] // !!! concrete overrides abstract problem + res + } /** Appends all bindings of this map to a string builder using start, end, and separator strings. * The written text begins with the string `start` and ends with the string @@ -320,7 +322,7 @@ self => /** Defines the prefix of this object's `toString` representation. * @return a string representation which starts the result of `toString` applied to this $coll. - * Unless overridden in subclasse, the string prefix of every map is `"Map"`. + * Unless overridden in subclasses, the string prefix of every map is `"Map"`. */ override def stringPrefix: String = "Map" @@ -351,7 +353,7 @@ self => } } catch { case ex: ClassCastException => - println("calss cast "); false + println("class cast "); false }} case _ => false diff --git a/src/library/scala/collection/MapProxyLike.scala b/src/library/scala/collection/MapProxyLike.scala index 427eaa6e2c..f269a368dd 100644 --- a/src/library/scala/collection/MapProxyLike.scala +++ b/src/library/scala/collection/MapProxyLike.scala @@ -36,10 +36,9 @@ trait MapProxyLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] override def isDefinedAt(key: A) = self.isDefinedAt(key) override def keySet: Set[A] = self.keySet override def keysIterator: Iterator[A] = self.keysIterator - override def keys: Iterator[A] = self.keysIterator - override def valuesIterable: Iterable[B] = self.valuesIterable + override def keys: Iterable[A] = self.keys + override def values: Iterable[B] = self.values override def valuesIterator: Iterator[B] = self.valuesIterator - override def values: Iterator[B] = self.valuesIterator override def default(key: A): B = self.default(key) override def filterKeys(p: A => Boolean) = self.filterKeys(p) override def mapValues[C](f: B => C) = self.mapValues(f) diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index 32aae28851..0db64926a6 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -11,7 +11,7 @@ package scala.collection -import mutable.{ListBuffer, HashMap, GenericArray} +import mutable.{ListBuffer, HashMap, ArraySeq} import immutable.{List, Range} import generic._ @@ -169,7 +169,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * * @param idx The index to select. * @return the element of this $coll at index `idx`, where `0` indicates the first element. - * @throws `IndexOutOfBoundsEsxception` if `idx` does not satisfy `0 <= idx < length`. + * @throws `IndexOutOfBoundsException` if `idx` does not satisfy `0 <= idx < length`. */ def apply(idx: Int): A @@ -212,7 +212,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => */ def isDefinedAt(idx: Int): Boolean = (idx >= 0) && (idx < length) - /** Computes length of longest segment whose elements all satisfy some preficate. + /** Computes length of longest segment whose elements all satisfy some predicate. * * $mayNotTerminateInf * @@ -229,7 +229,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => i } - /** Returns the length of the longest prefix whose elements all satisfy some preficate. + /** Returns the length of the longest prefix whose elements all satisfy some predicate. * * $mayNotTerminateInf * @@ -261,12 +261,15 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => def indexWhere(p: A => Boolean, from: Int): Int = { var i = from var it = iterator.drop(from) - while (it.hasNext && !p(it.next())) - i += 1 - if (it.hasNext) i else -1 + while (it.hasNext) { + if (p(it.next())) return i + else i += 1 + } + + -1 } - /** Returns index of the first element satisying a predicate, or `-1`. + /** Returns index of the first element satisfying a predicate, or `-1`. */ def findIndexOf(p: A => Boolean): Int = indexWhere(p) @@ -491,7 +494,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => /** Finds last index before or at a given end index where this $coll contains a given sequence as a slice. * @param that the sequence to test - * @param end the end idnex + * @param end the end index * @return the last index `<= end` such that the elements of this $coll starting at this index * match the elements of sequence `that`, or `-1` of no such subsequence exists. */ @@ -557,7 +560,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form * part of the result, but any following occurrences will. */ - def diff[B >: A, That](that: Seq[B]): Repr = { + def diff[B >: A](that: Seq[B]): Repr = { val occ = occCounts(that) val b = newBuilder for (x <- this) @@ -585,7 +588,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained * in the result, but any following occurrences will be omitted. */ - def intersect[B >: A, That](that: Seq[B]): Repr = { + def intersect[B >: A](that: Seq[B]): Repr = { val occ = occCounts(that) val b = newBuilder for (x <- this) @@ -607,7 +610,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * * @return A new $coll which contains the first occurrence of every element of this $coll. */ - def removeDuplicates: Repr = { + def distinct: Repr = { val b = newBuilder var seen = Set[A]() //TR: should use mutable.HashSet? for (x <- this) { @@ -627,7 +630,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * @tparam B the element type of the returned $coll. * @tparam That $thatinfo * @param bf $bfinfo - * @return a new collection of type `That` consisting of all elements of this $coll + * @return a new $coll consisting of all elements of this $coll * except that `replaced` elements starting from `from` are replaced * by `patch`. * @usecase def patch(from: Int, that: Seq[A], replaced: Int): $Coll[A] @@ -650,7 +653,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * @tparam B the element type of the returned $coll. * @tparam That $thatinfo * @param bf $bfinfo - * @return a new collection of type `That` which is a copy of this $coll with the element at position `index` replaced by `elem`. + * @return a new $coll` which is a copy of this $coll with the element at position `index` replaced by `elem`. * @usecase def updated(index: Int, elem: A): $Coll[A] * @return a copy of this $coll with the element at position `index` replaced by `elem`. */ @@ -721,7 +724,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => b ++= thisCollection while (diff > 0) { b += elem - diff -=1 + diff -= 1 } b.result } @@ -757,12 +760,34 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * the desired ordering. * @return a $coll consisting of the elements of this $coll * sorted according to the comparison function `lt`. - * @ex {{{ + * @example {{{ * List("Steve", "Tom", "John", "Bob").sortWith(_.compareTo(_) < 0) = * List("Bob", "John", "Steve", "Tom") * }}} */ - def sortWith(lt: (A, A) => Boolean): Repr = sortWith(Ordering fromLessThan lt) + def sortWith(lt: (A, A) => Boolean): Repr = sorted(Ordering fromLessThan lt) + + /** Sorts this $Coll according to the Ordering which results from transforming + * an implicitly given Ordering with a transformation function. + * @see scala.math.Ordering + * $willNotTerminateInf + * @param f the transformation function mapping elements + * to some other domain `B`. + * @param ord the ordering assumed on domain `B`. + * @tparam B the target type of the transformation `f`, and the type where + * the ordering `ord` is defined. + * @return a $coll consisting of the elements of this $coll + * sorted according to the ordering where `x < y` if + * `ord.lt(f(x), f(y))`. + * + * @example {{{ + * val words = "The quick brown fox jumped over the lazy dog".split(' ') + * // this works because scala.Ordering will implicitly provide an Ordering[Tuple2[Int, Char]] + * words.sortBy(x => (x.length, x.head)) + * res0: Array[String] = Array(The, dog, fox, the, lazy, over, brown, quick, jumped) + * }}} + */ + def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Repr = sorted(ord on f) /** Sorts this $coll according to an Ordering. * @@ -775,42 +800,19 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * @return a $coll consisting of the elements of this $coll * sorted according to the ordering `ord`. */ - def sortWith[B >: A](ord: Ordering[B]): Repr = { - val arr = new GenericArray[A](this.length) + def sorted[B >: A](implicit ord: Ordering[B]): Repr = { + val arr = new ArraySeq[A](this.length) var i = 0 for (x <- this) { arr(i) = x i += 1 } - java.util.Arrays.sort( - arr.array, ord.asInstanceOf[Ordering[Object]]) + java.util.Arrays.sort(arr.array, ord.asInstanceOf[Ordering[Object]]) val b = newBuilder for (x <- arr) b += x b.result } - /** Sorts this $Coll according to the Ordering which results from transforming - * an implicitly given Ordering with a transformation function. - * @see scala.math.Ordering - * $willNotTerminateInf - * @param f the transformation function mapping elements - * to some other domain `B`. - * @param ord the ordering assumed on domain `B`. - * @tparam B the target type of the transformation `f`, and the type where - * the ordering `ord` is defined. - * @return a $coll consisting of the elements of this $coll - * sorted according to the ordering where `x < y` if - * `ord.lt(f(x), f(y))`. - * - * @ex {{{ - * val words = "The quick brown fox jumped over the lazy dog".split(' ') - * // this works because scala.Ordering will implicitly provide an Ordering[Tuple2[Int, Char]] - * words.sortBy(x => (x.length, x.head)) - * res0: Array[String] = Array(The, dog, fox, the, lazy, over, brown, quick, jumped) - * }}} - */ - def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Repr = sortWith(ord on f) - /** Converts this $coll to a sequence. * $willNotTerminateInf * @@ -820,7 +822,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => /** Produces the range of all indices of this sequence. * - * @range a `Range` value from `0` to one less than the length of this $coll. + * @return a `Range` value from `0` to one less than the length of this $coll. */ def indices: Range = 0 until length @@ -839,16 +841,17 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => override def hashCode() = (Seq.hashSeed /: this)(_ * 41 + _.hashCode) override def equals(that: Any): Boolean = that match { - case that: Seq[_] => (that canEqual this) && (this sameElements that) - case _ => false + case that: Seq[_] => (that canEqual this) && (this sameElements that) + case _ => false } /* Need to override string, so that it's not the Function1's string that gets mixed in. */ override def toString = super[IterableLike].toString - /** Returns index of the last element satisying a predicate, or -1. + /** Returns index of the last element satisfying a predicate, or -1. */ + @deprecated("use `lastIndexWhere` instead") def findLastIndexOf(p: A => Boolean): Int = lastIndexWhere(p) /** Tests whether every element of this $coll relates to the @@ -862,15 +865,7 @@ trait SeqLike[+A, +Repr] extends IterableLike[A, Repr] { self => * and `y` of `that`, otherwise `false`. */ @deprecated("use `corresponds` instead") - def equalsWith[B](that: Seq[B])(f: (A,B) => Boolean): Boolean = { - val i = this.iterator - val j = that.iterator - while (i.hasNext && j.hasNext) - if (!f(i.next, j.next)) - return false - - !i.hasNext && !j.hasNext - } + def equalsWith[B](that: Seq[B])(f: (A,B) => Boolean): Boolean = corresponds(that)(f) /** * returns a projection that can be used to call non-strict <code>filter</code>, diff --git a/src/library/scala/collection/SeqProxyLike.scala b/src/library/scala/collection/SeqProxyLike.scala index 3dfac63dde..24ee0b430a 100644 --- a/src/library/scala/collection/SeqProxyLike.scala +++ b/src/library/scala/collection/SeqProxyLike.scala @@ -23,11 +23,10 @@ import generic._ * @version 2.8 * @since 2.8 */ -trait SeqProxyLike[+A, +This <: SeqLike[A, This] with Seq[A]] extends SeqLike[A, This] with IterableProxyLike[A, This] { +trait SeqProxyLike[+A, +Repr <: SeqLike[A, Repr] with Seq[A]] extends SeqLike[A, Repr] with IterableProxyLike[A, Repr] { override def length: Int = self.length override def apply(idx: Int): A = self.apply(idx) override def lengthCompare(len: Int): Int = self.lengthCompare(len) - override def size = self.size override def isDefinedAt(x: Int): Boolean = self.isDefinedAt(x) override def segmentLength(p: A => Boolean, from: Int): Int = self.segmentLength(p, from) override def prefixLength(p: A => Boolean) = self.prefixLength(p) @@ -40,22 +39,34 @@ trait SeqProxyLike[+A, +This <: SeqLike[A, This] with Seq[A]] extends SeqLike[A, override def lastIndexOf[B >: A](elem: B, end: Int): Int = self.lastIndexWhere(elem ==, end) override def lastIndexWhere(p: A => Boolean): Int = self.lastIndexWhere(p, length - 1) override def lastIndexWhere(p: A => Boolean, end: Int): Int = self.lastIndexWhere(p) - override def reverse: This = self.reverse + override def reverse: Repr = self.reverse + override def reverseMap[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.reverseMap(f)(bf) override def reverseIterator: Iterator[A] = self.reverseIterator override def startsWith[B](that: Seq[B], offset: Int): Boolean = self.startsWith(that, offset) override def startsWith[B](that: Seq[B]): Boolean = self.startsWith(that) override def endsWith[B](that: Seq[B]): Boolean = self.endsWith(that) override def indexOfSlice[B >: A](that: Seq[B]): Int = self.indexOfSlice(that) + override def indexOfSlice[B >: A](that: Seq[B], from: Int): Int = self.indexOfSlice(that) + override def lastIndexOfSlice[B >: A](that: Seq[B]): Int = self.lastIndexOfSlice(that) + override def lastIndexOfSlice[B >: A](that: Seq[B], end: Int): Int = self.lastIndexOfSlice(that, end) + override def containsSlice[B](that: Seq[B]): Boolean = self.indexOfSlice(that) != -1 override def contains(elem: Any): Boolean = self.contains(elem) - override def union[B >: A, That](that: Seq[B])(implicit bf: CanBuildFrom[This, B, That]): That = self.union(that)(bf) - override def diff[B >: A, That](that: Seq[B]): This = self.diff(that) - override def intersect[B >: A, That](that: Seq[B]): This = self.intersect(that) - override def removeDuplicates: This = self.removeDuplicates - override def patch[B >: A, That](from: Int, patch: Seq[B], replaced: Int)(implicit bf: CanBuildFrom[This, B, That]): That = self.patch(from, patch, replaced)(bf) - override def padTo[B >: A, That](len: Int, elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = self.padTo(len, elem)(bf) + override def union[B >: A, That](that: Seq[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = self.union(that)(bf) + override def diff[B >: A](that: Seq[B]): Repr = self.diff(that) + override def intersect[B >: A](that: Seq[B]): Repr = self.intersect(that) + override def distinct: Repr = self.distinct + override def patch[B >: A, That](from: Int, patch: Seq[B], replaced: Int)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.patch(from, patch, replaced)(bf) + override def updated[B >: A, That](index: Int, elem: B)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.updated(index, elem)(bf) + override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.+:(elem)(bf) + override def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.:+(elem)(bf) + override def padTo[B >: A, That](len: Int, elem: B)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.padTo(len, elem)(bf) + override def corresponds[B](that: Seq[B])(p: (A,B) => Boolean): Boolean = self.corresponds(that)(p) + override def sortWith(lt: (A, A) => Boolean): Repr = self.sortWith(lt) + override def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Repr = self.sortBy(f)(ord) + override def sorted[B >: A](implicit ord: Ordering[B]): Repr = self.sorted(ord) override def indices: Range = self.indices override def view = self.view override def view(from: Int, until: Int) = self.view(from, until) - override def equalsWith[B](that: Seq[B])(f: (A,B) => Boolean): Boolean = (self zip that) forall { case (x,y) => f(x,y) } - override def containsSlice[B](that: Seq[B]): Boolean = self.indexOfSlice(that) != -1 } + + diff --git a/src/library/scala/collection/SeqView.scala b/src/library/scala/collection/SeqView.scala index 61443b3b90..79d50f1de6 100644 --- a/src/library/scala/collection/SeqView.scala +++ b/src/library/scala/collection/SeqView.scala @@ -21,6 +21,8 @@ import TraversableView.NoBuilder */ trait SeqView[+A, +Coll] extends SeqViewLike[A, Coll, SeqView[A, Coll]] +/** $factoryInfo + */ object SeqView { type Coll = TraversableView[_, C] forSome {type C <: Traversable[_]} implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, SeqView[A, Seq[_]]] = diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala index 1a8cd20013..7014833a46 100644 --- a/src/library/scala/collection/SeqViewLike.scala +++ b/src/library/scala/collection/SeqViewLike.scala @@ -21,8 +21,8 @@ import TraversableView.NoBuilder * @version 2.8 */ trait SeqViewLike[+A, - +Coll, - +This <: SeqView[A, Coll] with SeqViewLike[A, Coll, This]] + +Coll, + +This <: SeqView[A, Coll] with SeqViewLike[A, Coll, This]] extends Seq[A] with SeqLike[A, This] with IterableView[A, Coll] with IterableViewLike[A, Coll, This] { self => @@ -31,6 +31,11 @@ trait SeqViewLike[+A, override def apply(idx: Int): B } + trait Forced[B] extends Transformed[B] with super.Forced[B] { + override def length = forced.length + override def apply(idx: Int) = forced.apply(idx) + } + trait Sliced extends Transformed[A] with super.Sliced { override def length = ((until min self.length) - from) max 0 override def apply(idx: Int): A = @@ -104,7 +109,8 @@ trait SeqViewLike[+A, trait Zipped[B] extends Transformed[(A, B)] with super.Zipped[B] { protected[this] lazy val thatSeq = other.toSeq - override def length: Int = self.length min thatSeq.length + /* Have to be careful here - other may be an infinite sequence. */ + override def length = if ((thatSeq lengthCompare self.length) <= 0) thatSeq.length else self.length override def apply(idx: Int) = (self.apply(idx), thatSeq.apply(idx)) } @@ -143,9 +149,20 @@ trait SeqViewLike[+A, override def stringPrefix = self.stringPrefix+"P" } + trait Prepended[B >: A] extends Transformed[B] { + protected[this] val fst: B + override def iterator: Iterator[B] = Iterator.single(fst) ++ self.iterator + override def length: Int = 1 + self.length + override def apply(idx: Int): B = + if (idx == 0) fst + else self.apply(idx - 1) + override def stringPrefix = self.stringPrefix+"A" + } + /** Boilerplate method, to override in each subclass * This method could be eliminated if Scala had virtual classes */ + protected override def newForced[B](xs: => Seq[B]): Transformed[B] = new Forced[B] { val forced = xs } protected override def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } protected override def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } protected override def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } @@ -157,6 +174,7 @@ trait SeqViewLike[+A, protected override def newZippedAll[A1 >: A, B](that: Iterable[B], _thisElem: A1, _thatElem: B): Transformed[(A1, B)] = new ZippedAll[A1, B] { val other = that; val thisElem = _thisElem; val thatElem = _thatElem } protected def newReversed: Transformed[A] = new Reversed { } protected def newPatched[B >: A](_from: Int, _patch: Seq[B], _replaced: Int): Transformed[B] = new Patched[B] { val from = _from; val patch = _patch; val replaced = _replaced } + protected def newPrepended[B >: A](elem: B): Transformed[B] = new Prepended[B] { protected[this] val fst = elem } override def reverse: This = newReversed.asInstanceOf[This] @@ -167,14 +185,35 @@ trait SeqViewLike[+A, // else super.patch[B, That](from, patch, replaced)(bf) } - //TR TODO: updated, +: ed :+ ed - override def padTo[B >: A, That](len: Int, elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = patch(length, fill(len - length)(elem), 0) override def reverseMap[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = reverse.map(f) + override def updated[B >: A, That](index: Int, elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = { + require(0 <= index && index < length) + patch(index, List(elem), 1)(bf) + } + + override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = + newPrepended(elem).asInstanceOf[That] + + override def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = + ++(Iterator.single(elem))(bf) + + override def union[B >: A, That](that: Seq[B])(implicit bf: CanBuildFrom[This, B, That]): That = + newForced(thisSeq union that).asInstanceOf[That] + + override def diff[B >: A](that: Seq[B]): This = + newForced(thisSeq diff that).asInstanceOf[This] + + override def intersect[B >: A](that: Seq[B]): This = + newForced(thisSeq intersect that).asInstanceOf[This] + + override def sorted[B >: A](implicit ord: Ordering[B]): This = + newForced(thisSeq sorted ord).asInstanceOf[This] + override def stringPrefix = "SeqView" } diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala index 156d0d8b2b..48b5358afc 100644 --- a/src/library/scala/collection/SetLike.scala +++ b/src/library/scala/collection/SetLike.scala @@ -187,7 +187,7 @@ self => * @note This operation contains an unchecked cast: if `that` * is a set, it will assume with an unchecked cast * that it has the same element type as this set. - * Any subsequuent ClassCastException is treated as a `false` result. + * Any subsequent ClassCastException is treated as a `false` result. */ override def equals(that: Any): Boolean = that match { case that: Set[_] => diff --git a/src/library/scala/collection/SortedMap.scala b/src/library/scala/collection/SortedMap.scala index 24f363243f..7b0d35220e 100644 --- a/src/library/scala/collection/SortedMap.scala +++ b/src/library/scala/collection/SortedMap.scala @@ -21,9 +21,9 @@ import mutable.Builder */ trait SortedMap[A, +B] extends Map[A, B] with SortedMapLike[A, B, SortedMap[A, B]] { /** Needs to be overridden in subclasses. */ - override def empty = SortedMap.empty[A, B] + override def empty: SortedMap[A, B] = SortedMap.empty[A, B] - override protected[this] def newBuilder : Builder[(A, B), SortedMap[A, B]] = + override protected[this] def newBuilder: Builder[(A, B), SortedMap[A, B]] = immutable.SortedMap.newBuilder[A, B] } diff --git a/src/library/scala/collection/Traversable.scala b/src/library/scala/collection/Traversable.scala index c3d7fa8bc7..1cecec5227 100644 --- a/src/library/scala/collection/Traversable.scala +++ b/src/library/scala/collection/Traversable.scala @@ -29,8 +29,7 @@ trait Traversable[+A] extends TraversableLike[A, Traversable[A]] override def isEmpty: Boolean override def size: Int override def hasDefiniteSize - override def ++[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[Traversable[A], B, That]): That - override def ++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[Traversable[A], B, That]): That + override def ++[B >: A, That](xs: TraversableOnce[B])(implicit bf: CanBuildFrom[Traversable[A], B, That]): That override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Traversable[A], B, That]): That override def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[Traversable[A], B, That]): That override def filter(p: A => Boolean): Traversable[A] diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index fc666ddb92..7008d3b5fd 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -88,8 +88,8 @@ import immutable.{List, Stream, Nil, ::} * * Note: will not terminate for infinite-sized collections. */ -trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] { -self => +trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr] with TraversableOnce[A] { + self => import Traversable.breaks._ @@ -148,23 +148,10 @@ self => result } - /** Tests whether the $coll is not empty. - * - * @return `true` if the $coll contains at least one element, `false` otherwise. + /** Tests whether this $coll can be repeatedly traversed. + * @return `true` */ - def nonEmpty: Boolean = !isEmpty - - /** The size of this $coll. - * - * $willNotTerminateInf - * - * @return the number of elements in this $coll. - */ - def size: Int = { - var result = 0 - for (x <- this) result += 1 - result - } + final def isTraversableAgain = true /** Tests whether this $coll is known to have a finite size. * All strict collections are known to have finite size. For a non-strict collection @@ -186,36 +173,15 @@ self => * @return a new collection of type `That` which contains all elements of this $coll * followed by all elements of `that`. * - * @usecase def ++(that: Traversable[A]): $Coll[A] - * - * @return a new $coll which contains all elements of this $coll - * followed by all elements of `that`. - */ - def ++[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { - val b = bf(repr) - b ++= thisCollection - b ++= that - b.result - } - - /** Concatenates this $coll with the elements of an iterator. - * - * @param that the iterator to append. - * @tparam B the element type of the returned collection. - * @tparam That $thatinfo - * @param bf $bfinfo - * @return a new collection of type `That` which contains all elements of this $coll - * followed by all elements of `that`. - * - * @usecase def ++(that: Iterator[A]): $Coll[A] + * @usecase def ++(that: TraversableOnce[A]): $Coll[A] * * @return a new $coll which contains all elements of this $coll * followed by all elements of `that`. */ - def ++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { + def ++[B >: A, That](xs: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) b ++= thisCollection - b ++= that + b ++= xs b.result } @@ -292,13 +258,13 @@ self => * `pf` to each element on which it is defined and collecting the results. * The order of the elements is preserved. * - * @usecase def partialMap[B](pf: PartialFunction[A, B]): $Coll[B] + * @usecase def collect[B](pf: PartialFunction[A, B]): $Coll[B] * * @return a new $coll resulting from applying the given partial function * `pf` to each element on which it is defined and collecting the results. * The order of the elements is preserved. */ - def partialMap[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { + def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) for (x <- this) if (pf.isDefinedAt(x)) b += pf(x) b.result @@ -409,21 +375,6 @@ self => result } - /** Counts the number of elements in the $coll which satisfy a predicate. - * - * @param p the predicate used to test elements. - * @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 - } - /** Finds the first element of the $coll satisfying a predicate, if any. * * $mayNotTerminateInf @@ -464,227 +415,44 @@ self => } */ - /** Applies a binary operator to a start value and all elements of this $coll, going left to right. - * - * $willNotTerminateInf - * $orderDependentFold - * - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll$, - * going left to right with the start value `z` on the left: - * {{{ - * op(...op(z, x,,1,,), x,,2,,, ..., x,,n,,) - * }}} - * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. - */ - def foldLeft[B](z: B)(op: (B, A) => B): B = { - var result = z - for (x <- this) - result = op(result, x) - result - } - - /** Applies a binary operator to a start value and all elements of this $coll, going left to right. - * - * Note: `/:` is alternate syntax for `foldLeft`; `z /: xs` is the same as `xs foldLeft z`. - * $willNotTerminateInf - * $orderDependentFold - * - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll$, - * going left to right with the start value `z` on the left: - * {{{ - * op(...op(op(z, x,,1,,), x,,2,,), ..., x,,n,,) - * }}} - * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. - */ - def /: [B](z: B)(op: (B, A) => B): B = foldLeft(z)(op) - - /** Applies a binary operator to all elements of this $coll and a start value, going right to left. - * - * $willNotTerminateInf - * $orderDependentFold - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll$, - * going right to left with the start value `z` on the right: - * {{{ - * op(x,,1,,, op(x,,2,,, ... op(x,,n,,, z)...)) - * }}} - * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. - */ - def foldRight[B](z: B)(op: (A, B) => B): B = { - var elems: List[A] = Nil - for (x <- this) elems = x :: elems - elems.foldLeft(z)((x, y) => op(y, x)) - } - - /** Applies a binary operator to all elements of this $coll and a start value, going right to left. - * - * Note: `:\` is alternate syntax for `foldRight`; `xs :\ z` is the same as `xs foldRight z`. - * $willNotTerminateInf - * $orderDependentFold - * - * @param z the start value - * @param op the binary operator - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll$, - * going right to left with the start value `z` on the right: - * {{{ - * op(x,,1,,, op(x,,2,,, ... op(x,,n,,, z)...)) - * }}} - * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. - */ - def :\ [B](z: B)(op: (A, B) => B): B = foldRight(z)(op) - - /** Applies a binary operator to all elements of this $coll, going left to right. - * $willNotTerminateInf - * $orderDependentFold - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll$, - * going left to right: - * {{{ - * op(...(op(x,,1,,, x,,2,,), ... ) , x,,n,,) - * }}} - * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. - * @throws `UnsupportedOperationException` if this $coll is empty. - */ - def reduceLeft[B >: A](op: (B, A) => B): B = { - if (isEmpty) throw new UnsupportedOperationException("empty.reduceLeft") - var result: B = head - var first = true - for (x <- this) - if (first) first = false - else result = op(result, x) - result - } - - /** Optionally applies a binary operator to all elements of this $coll, going left to right. - * $willNotTerminateInf - * $orderDependentFold - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return an option value containing the result of `reduceLeft(op)` is this $coll is nonempty, - * `None` otherwise. - */ - def reduceLeftOption[B >: A](op: (B, A) => B): Option[B] = { - if (isEmpty) None else Some(reduceLeft(op)) - } - - /** Applies a binary operator to all elements of this $coll, going right to left. - * $willNotTerminateInf - * $orderDependentFold - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll$, - * going right to left: - * {{{ - * op(x,,1,,, op(x,,2,,, ..., op(x,,n-1,,, x,,n,,)...)) - * }}} - * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. - * @throws `UnsupportedOperationException` if this $coll is empty. - */ - def reduceRight[B >: A](op: (A, B) => B): B = { - if (isEmpty) throw new UnsupportedOperationException("empty.reduceRight") - var elems: List[A] = Nil - for (x <- this) elems = x :: elems - elems.reduceLeft[B]((x, y) => op(y, x)) - } - - /** Optionally applies a binary operator to all elements of this $coll, going right to left. - * $willNotTerminateInf - * $orderDependentFold - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return an option value containing the result of `reduceRight(op)` is this $coll is nonempty, - * `None` otherwise. - */ - def reduceRightOption[B >: A](op: (A, B) => B): Option[B] = - if (isEmpty) None else Some(reduceRight(op)) - - /** Sums up the elements of this collection. - * - * @param num an implicit parameter defining a set of numeric operations - * which includes the `+` operator to be used in forming the sum. - * @tparam B the result type of the `+` operator. - * @return the sum of all elements of this $coll with respect to the `+` operator in `num`. - * - * @usecase def sum: Int - * - * @return the sum of all elements in this $coll of numbers of type `Int`. - * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation - * can be used as element type of the $coll and as result type of `sum`. - * Examples of such types are: `Long`, `Float`, `Double`, `BigInt`. - * - */ - def sum[B >: A](implicit num: Numeric[B]): B = { - var acc = num.zero - for (x <- self) acc = num.plus(acc, x) - acc - } - - /** Multiplies up the elements of this collection. - * - * @param num an implicit parameter defining a set of numeric operations - * which includes the `*` operator to be used in forming the product. - * @tparam B the result type of the `*` operator. - * @return the product of all elements of this $coll with respect to the `*` operator in `num`. - * - * @usecase def product: Int - * - * @return the product of all elements in this $coll of numbers of type `Int`. - * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation - * can be used as element type of the $coll and as result type of `product`. - * Examples of such types are: `Long`, `Float`, `Double`, `BigInt`. - */ - def product[B >: A](implicit num: Numeric[B]): B = { - var acc = num.one - for (x <- self) acc = num.times(acc, x) - acc - } - - /** Finds the smallest element. - * - * @param cmp An ordering to be used for comparing elements. - * @tparam B The type over which the ordering is defined. - * @return the smallest element of this $coll with respect to the ordering `cmp`. + /** + * Produces a collection containing cummulative results of applying the operator going left to right. + * $willNotTerminateInf + * $orderDependent * - * @usecase def min: A - * @return the smallest element of this $coll + * @tparam B the type of the elements in the resulting collection + * @tparam That the actual type of the resulting collection + * @param z the initial value + * @param op the binary operator applied to the intermediate result and the element + * @param bf $bfinfo + * @return collection with intermediate results */ - def min[B >: A](implicit cmp: Ordering[B]): A = { - if (isEmpty) throw new UnsupportedOperationException("empty.min") - var acc = self.head - for (x <- self) - if (cmp.lt(x, acc)) acc = x - acc + def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = { + val b = bf(repr) + var acc = z + b += acc + for (x <- this) { acc = op(acc, x); b += acc } + b.result } - /** Finds the largest element. - * - * @param cmp An ordering to be used for comparing elements. - * @tparam B The type over which the ordering is defined. - * @return the largest element of this $coll with respect to the ordering `cmp`. + /** + * Produces a collection containing cummulative results of applying the operator going right to left. + * $willNotTerminateInf + * $orderDependent * - * @usecase def min: A - * @return the largest element of this $coll. + * @tparam B the type of the elements in the resulting collection + * @tparam That the actual type of the resulting collection + * @param z the initial value + * @param op the binary operator applied to the intermediate result and the element + * @param bf $bfinfo + * @return collection with intermediate results */ - def max[B >: A](implicit cmp: Ordering[B]): A = { - if (isEmpty) throw new UnsupportedOperationException("empty.max") - var acc = self.head - for (x <- self) - if (cmp.gt(x, acc)) acc = x - acc + def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = { + val b = bf(repr) + var acc = z + b += acc + for (x <- reversed) { acc = op(x, acc); b += acc } + b.result } /** Selects the first element of this $coll. @@ -849,7 +617,7 @@ self => b.result } - /** Spits this $coll into a prefix/suffix pair according to a predicate. + /** Splits this $coll into a prefix/suffix pair according to a predicate. * * Note: `c span p` is equivalent to (but possibly more efficient than) * `(c takeWhile p, c dropWhile p)`, provided the evaluation of the predicate `p` @@ -889,14 +657,6 @@ self => (l.result, r.result) } - /** Copies all elements of this $coll to a buffer. - * $willNotTerminateInf - * @param dest The buffer to which elements are copied. - */ - def copyToBuffer[B >: A](dest: Buffer[B]) { - for (x <- this) dest += x - } - /** Copies elements of this $coll to an array. * Fills the given array `xs` with at most `len` elements of * this $coll, starting at position `start`. @@ -925,188 +685,11 @@ self => } } - /** Copies elements of this $coll to an array. - * Fills the given array `xs` with all elements of - * this $coll, starting at position `start`. - * Copying will stop once either the end of the current $coll is reached, - * or the end of the array is reached. - * - * $willNotTerminateInf - * - * @param xs the array to fill. - * @param start the starting index. - * @tparam B the type of the elements of the array. - * - * @usecase def copyToArray(xs: Array[A], start: Int): Unit - */ - def copyToArray[B >: A](xs: Array[B], start: Int) { - copyToArray(xs, start, xs.length - start) - } - - /** Copies elements of this $coll to an array. - * Fills the given array `xs` with all elements of - * this $coll, starting at position `0`. - * Copying will stop once either the end of the current $coll is reached, - * or the end of the array is reached. - * - * $willNotTerminateInf - * - * @param xs the array to fill. - * @tparam B the type of the elements of the array. - * - * @usecase def copyToArray(xs: Array[A], start: Int): Unit - */ - def copyToArray[B >: A](xs: Array[B]) { - copyToArray(xs, 0) - } - - /** Converts this $coll to an array. - * $willNotTerminateInf - * - * @tparam B the type of the elements of the array. A `ClassManifest` for this type must - * be available. - * @return an array containing all elements of this $coll. - * - * @usecase def toArray: Array[A] - * @return an array containing all elements of this $coll. - * A `ClassManifest` must be available for the element type of this $coll. - */ - def toArray[B >: A : ClassManifest]: Array[B] = { - val result = new Array[B](size) - copyToArray(result, 0) - result - } - - /** Converts this $coll to a list. - * $willNotTerminateInf - * @return a list containing all elements of this $coll. - */ - def toList: List[A] = (new ListBuffer[A] ++= thisCollection).toList - - /** Converts this $coll to an iterable collection. - * $willNotTerminateInf - * @return an `Iterable` containing all elements of this $coll. - */ - def toIterable: Iterable[A] = toStream - - /** Converts this $coll to a sequence. - * $willNotTerminateInf - * @return a sequence containing all elements of this $coll. - */ - def toSeq: Seq[A] = toList - - /** Converts this $coll to an indexed sequence. - * $willNotTerminateInf - * @return an indexed sequence containing all elements of this $coll. - */ - def toIndexedSeq[B >: A]: mutable.IndexedSeq[B] = (new ArrayBuffer[B] ++= thisCollection) - - /** Converts this $coll to a stream. - * $willNotTerminateInf - * @return a stream containing all elements of this $coll. - */ - def toStream: Stream[A] = toList.toStream - - /** Converts this $coll to a set. - * $willNotTerminateInf - * @return a set containing all elements of this $coll. - */ - def toSet[B >: A]: immutable.Set[B] = immutable.Set() ++ thisCollection - - /** Converts this $coll to a map. This method is unavailable unless - * the elements are members of Tuple2, each ((K, V)) becoming a key-value - * pair in the map. Duplicate keys will be overwritten by later keys: - * if this is an unordered collection, which key is in the resulting map - * is undefined. - * $willNotTerminateInf - * @return a map containing all elements of this $coll. - */ - def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = { - val b = immutable.Map.newBuilder[T, U] - for (x <- this) - b += x - - b.result - } - - /** Displays all elements of this $coll in a string using start, end, and separator strings. - * - * @param start the starting string. - * @param sep the separator string. - * @param end the ending string. - * @return a string representation of this $coll. The resulting string - * begins with the string `start` and ends with the string - * `end`. Inside, the string representations (w.r.t. the method `toString`) - * of all elements of this $coll are separated by the string `sep`. - * - * @ex `List(1, 2, 3).mkString("(", "; ", ")") = "(1; 2; 3)"` - */ - def mkString(start: String, sep: String, end: String): String = - addString(new StringBuilder(), start, sep, end).toString - - /** Displays all elements of this $coll in a string using a separator string. - * - * @param sep the separator string. - * @return a string representation of this $coll. In the resulting string - * the string representations (w.r.t. the method `toString`) - * of all elements of this $coll are separated by the string `sep`. - * - * @ex `List(1, 2, 3).mkString("|") = "1|2|3"` - */ - def mkString(sep: String): String = - addString(new StringBuilder(), sep).toString - - /** Displays all elements of this $coll in a string. - * @return a string representation of this $coll. In the resulting string - * the string representations (w.r.t. the method `toString`) - * of all elements of this $coll follow each other without any separator string. - */ - def mkString: String = - addString(new StringBuilder()).toString - - /** Appends all elements of this $coll to a string builder using start, end, and separator strings. - * The written text begins with the string `start` and ends with the string - * `end`. Inside, the string representations (w.r.t. the method `toString`) - * of all elements of this $coll are separated by the string `sep`. - * - * @param b the string builder to which elements are appended. - * @param start the starting string. - * @param sep the separator string. - * @param end the ending string. - * @return the string builder `b` to which elements were appended. - */ - 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 - } - - /** Appends all elements of this $coll to a string builder using a separator string. - * The written text consists of the string representations (w.r.t. the method `toString`) - * of all elements of this $coll, separated by the string `sep`. - * - * @param b the string builder to which elements are appended. - * @param sep the separator string. - * @return the string builder `b` to which elements were appended. - */ - def addString(b: StringBuilder, sep: String): StringBuilder = addString(b, "", sep, "") - - /** Appends all elements of this $coll to a string builder. - * The written text consists of the string representations (w.r.t. the method `toString`) - * of all elements of this $coll without any separator string. - * - * @param b the string builder to which elements are appended. - * @return the string builder `b` to which elements were appended. - */ - def addString(b: StringBuilder): StringBuilder = addString(b, "") + def toTraversable: Traversable[A] = thisCollection + def toIterator: Iterator[A] = toIterable.iterator /** Converts this $coll to a string - * @returns a string representation of this collection. By default this + * @return a string representation of this collection. By default this * string consists of the `stringPrefix` of this $coll, * followed by all elements separated by commas and enclosed in parentheses. */ @@ -1131,7 +714,7 @@ self => */ def view = new TraversableView[A, Repr] { protected lazy val underlying = self.repr - override def foreach[B](f: A => B) = self foreach f + override def foreach[U](f: A => U) = self foreach f } /** Creates a non-strict view of a slice of this $coll. diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala new file mode 100644 index 0000000000..6e4917b77e --- /dev/null +++ b/src/library/scala/collection/TraversableOnce.scala @@ -0,0 +1,522 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection + +import mutable.{ Buffer, ListBuffer, ArrayBuffer } + +/** A template trait for collections which can be traversed one + * or more times. + * $traversableonceinfo + * + * @tparam A the element type of the collection + * + * @define traversableonceinfo + * This trait is composed of those methods which can be implemented + * solely in terms of foreach and which do not need access to a Builder. + * It represents the implementations common to Iterators and + * Traversables, such as folds, conversions, and other operations which + * traverse some or all of the elements and return a derived value. + * + * @author Martin Odersky + * @author Paul Phillips + * @version 2.8 + * @since 2.8 + * + * @define coll traversable or iterator + * @define orderDependentFold + * + * Note: might return different results for different runs, unless the underlying collection type is ordered. + * or the operator is associative and commutative. + * @define willNotTerminateInf + * + * Note: will not terminate for infinite-sized collections. + */ +trait TraversableOnce[+A] { + self => + + /** Self-documenting abstract methods. */ + def foreach[U](f: A => U): Unit + def isEmpty: Boolean + def hasDefiniteSize: Boolean + + /** Tests whether this $coll can be repeatedly traversed. Always + * true for Traversables and false for Iterators unless overridden. + * + * @return `true` if it is repeatedly traversable, `false` otherwise. + */ + def isTraversableAgain: Boolean + + /** Returns an Iterator over the elements in this $coll. Will return + * the same Iterator if this instance is already an Iterator. + * $willNotTerminateInf + * @return an Iterator containing all elements of this $coll. + */ + def toIterator: Iterator[A] + + /** Converts this $coll to an unspecified Traversable. Will return + * the same collection if this instance is already Traversable. + * $willNotTerminateInf + * @return a Traversable containing all elements of this $coll. + */ + def toTraversable: Traversable[A] + + /** Presently these are abstract because the Traversable versions use + * breakable/break, and I wasn't sure enough of how that's supposed to + * function to consolidate them with the Iterator versions. + */ + def forall(p: A => Boolean): Boolean + def exists(p: A => Boolean): Boolean + def find(p: A => Boolean): Option[A] + def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit + // def mapFind[B](f: A => Option[B]): Option[B] + + // for internal use + protected[this] def reversed = { + var elems: List[A] = Nil + self foreach (elems ::= _) + elems + } + + /** The size of this $coll. + * + * $willNotTerminateInf + * + * @return the number of elements in this $coll. + */ + def size: Int = { + var result = 0 + for (x <- self) result += 1 + result + } + + /** Tests whether the $coll is not empty. + * + * @return `true` if the $coll contains at least one element, `false` otherwise. + */ + def nonEmpty: Boolean = !isEmpty + + /** Counts the number of elements in the $coll which satisfy a predicate. + * + * @param p the predicate used to test elements. + * @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 + } + + /** Applies a binary operator to a start value and all elements of this $coll, going left to right. + * + * Note: `/:` is alternate syntax for `foldLeft`; `z /: xs` is the same as `xs foldLeft z`. + * $willNotTerminateInf + * $orderDependentFold + * + * @param z the start value. + * @param op the binary operator. + * @tparam B the result type of the binary operator. + * @return the result of inserting `op` between consecutive elements of this $coll$, + * going left to right with the start value `z` on the left: + * {{{ + * op(...op(op(z, x,,1,,), x,,2,,), ..., x,,n,,) + * }}} + * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. + */ + def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op) + + /** Applies a binary operator to all elements of this $coll and a start value, going right to left. + * + * Note: `:\` is alternate syntax for `foldRight`; `xs :\ z` is the same as `xs foldRight z`. + * $willNotTerminateInf + * $orderDependentFold + * + * @param z the start value + * @param op the binary operator + * @tparam B the result type of the binary operator. + * @return the result of inserting `op` between consecutive elements of this $coll$, + * going right to left with the start value `z` on the right: + * {{{ + * op(x,,1,,, op(x,,2,,, ... op(x,,n,,, z)...)) + * }}} + * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. + */ + def :\[B](z: B)(op: (A, B) => B): B = foldRight(z)(op) + + /** Applies a binary operator to a start value and all elements of this $coll, going left to right. + * + * $willNotTerminateInf + * $orderDependentFold + * + * @param z the start value. + * @param op the binary operator. + * @tparam B the result type of the binary operator. + * @return the result of inserting `op` between consecutive elements of this $coll$, + * going left to right with the start value `z` on the left: + * {{{ + * op(...op(z, x,,1,,), x,,2,,, ..., x,,n,,) + * }}} + * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. + */ + def foldLeft[B](z: B)(op: (B, A) => B): B = { + var result = z + this foreach (x => result = op(result, x)) + result + } + + /** Applies a binary operator to all elements of this $coll and a start value, going right to left. + * + * $willNotTerminateInf + * $orderDependentFold + * @param z the start value. + * @param op the binary operator. + * @tparam B the result type of the binary operator. + * @return the result of inserting `op` between consecutive elements of this $coll$, + * going right to left with the start value `z` on the right: + * {{{ + * op(x,,1,,, op(x,,2,,, ... op(x,,n,,, z)...)) + * }}} + * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. + */ + def foldRight[B](z: B)(op: (A, B) => B): B = + reversed.foldLeft(z)((x, y) => op(y, x)) + + /** Applies a binary operator to all elements of this $coll, going left to right. + * $willNotTerminateInf + * $orderDependentFold + * + * @param op the binary operator. + * @tparam B the result type of the binary operator. + * @return the result of inserting `op` between consecutive elements of this $coll$, + * going left to right: + * {{{ + * op(...(op(x,,1,,, x,,2,,), ... ) , x,,n,,) + * }}} + * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. + * @throws `UnsupportedOperationException` if this $coll is empty. + */ + def reduceLeft[B >: A](op: (B, A) => B): B = { + if (isEmpty) + throw new UnsupportedOperationException("empty.reduceLeft") + + var first = true + var acc: B = 0.asInstanceOf[B] + + for (x <- self) { + if (first) { + acc = x + first = false + } + else acc = op(acc, x) + } + acc + } + + /** Applies a binary operator to all elements of this $coll, going right to left. + * $willNotTerminateInf + * $orderDependentFold + * + * @param op the binary operator. + * @tparam B the result type of the binary operator. + * @return the result of inserting `op` between consecutive elements of this $coll$, + * going right to left: + * {{{ + * op(x,,1,,, op(x,,2,,, ..., op(x,,n-1,,, x,,n,,)...)) + * }}} + * where `x,,1,,, ..., x,,n,,` are the elements of this $coll. + * @throws `UnsupportedOperationException` if this $coll is empty. + */ + def reduceRight[B >: A](op: (A, B) => B): B = { + if (isEmpty) + throw new UnsupportedOperationException("empty.reduceRight") + + reversed.reduceLeft[B]((x, y) => op(y, x)) + } + + /** Optionally applies a binary operator to all elements of this $coll, going left to right. + * $willNotTerminateInf + * $orderDependentFold + * + * @param op the binary operator. + * @tparam B the result type of the binary operator. + * @return an option value containing the result of `reduceLeft(op)` is this $coll is nonempty, + * `None` otherwise. + */ + def reduceLeftOption[B >: A](op: (B, A) => B): Option[B] = + if (isEmpty) None else Some(reduceLeft(op)) + + /** Optionally applies a binary operator to all elements of this $coll, going right to left. + * $willNotTerminateInf + * $orderDependentFold + * + * @param op the binary operator. + * @tparam B the result type of the binary operator. + * @return an option value containing the result of `reduceRight(op)` is this $coll is nonempty, + * `None` otherwise. + */ + def reduceRightOption[B >: A](op: (A, B) => B): Option[B] = + if (isEmpty) None else Some(reduceRight(op)) + + /** Sums up the elements of this collection. + * + * @param num an implicit parameter defining a set of numeric operations + * which includes the `+` operator to be used in forming the sum. + * @tparam B the result type of the `+` operator. + * @return the sum of all elements of this $coll with respect to the `+` operator in `num`. + * + * @usecase def sum: Int + * + * @return the sum of all elements in this $coll of numbers of type `Int`. + * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation + * can be used as element type of the $coll and as result type of `sum`. + * Examples of such types are: `Long`, `Float`, `Double`, `BigInt`. + * + */ + def sum[B >: A](implicit num: Numeric[B]): B = foldLeft(num.zero)(num.plus) + + /** Multiplies up the elements of this collection. + * + * @param num an implicit parameter defining a set of numeric operations + * which includes the `*` operator to be used in forming the product. + * @tparam B the result type of the `*` operator. + * @return the product of all elements of this $coll with respect to the `*` operator in `num`. + * + * @usecase def product: Int + * + * @return the product of all elements in this $coll of numbers of type `Int`. + * Instead of `Int`, any other type `T` with an implicit `Numeric[T]` implementation + * can be used as element type of the $coll and as result type of `product`. + * Examples of such types are: `Long`, `Float`, `Double`, `BigInt`. + */ + def product[B >: A](implicit num: Numeric[B]): B = foldLeft(num.one)(num.times) + + /** Finds the smallest element. + * + * @param cmp An ordering to be used for comparing elements. + * @tparam B The type over which the ordering is defined. + * @return the smallest element of this $coll with respect to the ordering `cmp`. + * + * @usecase def min: A + * @return the smallest element of this $coll + */ + def min[B >: A](implicit cmp: Ordering[B]): A = { + if (isEmpty) + throw new UnsupportedOperationException("empty.min") + + reduceLeft((x, y) => if (cmp.lteq(x, y)) x else y) + } + + /** Finds the largest element. + * + * @param cmp An ordering to be used for comparing elements. + * @tparam B The type over which the ordering is defined. + * @return the largest element of this $coll with respect to the ordering `cmp`. + * + * @usecase def max: A + * @return the largest element of this $coll. + */ + def max[B >: A](implicit cmp: Ordering[B]): A = { + if (isEmpty) + throw new UnsupportedOperationException("empty.max") + + reduceLeft((x, y) => if (cmp.gteq(x, y)) x else y) + } + + /** Copies all elements of this $coll to a buffer. + * $willNotTerminateInf + * @param dest The buffer to which elements are copied. + */ + def copyToBuffer[B >: A](dest: Buffer[B]): Unit = dest ++= self + + /** Copies values produced by this iterator to an array. + * Fills the given array `xs` with values produced by this iterator, after skipping `start` values. + * Copying will stop once either the end of the current iterator is reached, + * or the end of the array is reached. + * + * $willNotTerminateInf + * + * @param xs the array to fill. + * @param start the starting index. + * @tparam B the type of the elements of the array. + * + * @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit + */ + def copyToArray[B >: A](xs: Array[B], start: Int): Unit = + copyToArray(xs, start, xs.length - start) + + /** Copies values produced by this iterator to an array. + * Fills the given array `xs` with values produced by this iterator. + * Copying will stop once either the end of the current iterator is reached, + * or the end of the array is reached. + * + * $willNotTerminateInf + * + * @param xs the array to fill. + * @tparam B the type of the elements of the array. + * + * @usecase def copyToArray(xs: Array[A], start: Int, len: Int): Unit + */ + def copyToArray[B >: A](xs: Array[B]): Unit = + copyToArray(xs, 0, xs.length) + + /** Converts this $coll to an array. + * $willNotTerminateInf + * + * @tparam B the type of the elements of the array. A `ClassManifest` for this type must + * be available. + * @return an array containing all elements of this $coll. + * + * @usecase def toArray: Array[A] + * @return an array containing all elements of this $coll. + * A `ClassManifest` must be available for the element type of this $coll. + */ + def toArray[B >: A : ClassManifest]: Array[B] = { + if (isTraversableAgain) { + val result = new Array[B](size) + copyToArray(result, 0) + result + } + else toStream.toArray + } + + /** Converts this $coll to a list. + * $willNotTerminateInf + * @return a list containing all elements of this $coll. + */ + def toList: List[A] = new ListBuffer[A] ++= self toList + + /** Converts this $coll to an iterable collection. + * $willNotTerminateInf + * @return an `Iterable` containing all elements of this $coll. + */ + def toIterable: Iterable[A] = toStream + + /** Converts this $coll to a sequence. + * $willNotTerminateInf + * @return a sequence containing all elements of this $coll. + */ + def toSeq: Seq[A] = toList + + /** Converts this $coll to an indexed sequence. + * $willNotTerminateInf + * @return an indexed sequence containing all elements of this $coll. + */ + def toIndexedSeq[B >: A]: mutable.IndexedSeq[B] = new ArrayBuffer[B] ++= self + + /** Converts this $coll to a stream. + * $willNotTerminateInf + * @return a stream containing all elements of this $coll. + */ + def toStream: Stream[A] = toList.toStream + + /** Converts this $coll to a set. + * $willNotTerminateInf + * @return a set containing all elements of this $coll. + */ + def toSet[B >: A]: immutable.Set[B] = immutable.Set() ++ self + + /** Converts this $coll to a map. This method is unavailable unless + * the elements are members of Tuple2, each ((K, V)) becoming a key-value + * pair in the map. Duplicate keys will be overwritten by later keys: + * if this is an unordered collection, which key is in the resulting map + * is undefined. + * $willNotTerminateInf + * @return a map containing all elements of this $coll. + */ + def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = { + val b = immutable.Map.newBuilder[T, U] + for (x <- self) + b += x + + b.result + } + + /** Displays all elements of this $coll in a string using start, end, and separator strings. + * + * @param start the starting string. + * @param sep the separator string. + * @param end the ending string. + * @return a string representation of this $coll. The resulting string + * begins with the string `start` and ends with the string + * `end`. Inside, the string representations (w.r.t. the method `toString`) + * of all elements of this $coll are separated by the string `sep`. + * + * @example `List(1, 2, 3).mkString("(", "; ", ")") = "(1; 2; 3)"` + */ + def mkString(start: String, sep: String, end: String): String = + addString(new StringBuilder(), start, sep, end).toString + + /** Displays all elements of this $coll in a string using a separator string. + * + * @param sep the separator string. + * @return a string representation of this $coll. In the resulting string + * the string representations (w.r.t. the method `toString`) + * of all elements of this $coll are separated by the string `sep`. + * + * @example `List(1, 2, 3).mkString("|") = "1|2|3"` + */ + def mkString(sep: String): String = mkString("", sep, "") + + /** Displays all elements of this $coll in a string. + * @return a string representation of this $coll. In the resulting string + * the string representations (w.r.t. the method `toString`) + * of all elements of this $coll follow each other without any separator string. + */ + def mkString: String = mkString("") + + /** Appends all elements of this $coll to a string builder using start, end, and separator strings. + * The written text begins with the string `start` and ends with the string + * `end`. Inside, the string representations (w.r.t. the method `toString`) + * of all elements of this $coll are separated by the string `sep`. + * + * @param b the string builder to which elements are appended. + * @param start the starting string. + * @param sep the separator string. + * @param end the ending string. + * @return the string builder `b` to which elements were appended. + */ + def addString(b: StringBuilder, start: String, sep: String, end: String): StringBuilder = { + var first = true + + b append start + for (x <- self) { + if (first) { + b append x + first = false + } + else { + b append sep + b append x + } + } + b append end + + b + } + + /** Appends all elements of this $coll to a string builder using a separator string. + * The written text consists of the string representations (w.r.t. the method `toString`) + * of all elements of this $coll, separated by the string `sep`. + * + * @param b the string builder to which elements are appended. + * @param sep the separator string. + * @return the string builder `b` to which elements were appended. + */ + def addString(b: StringBuilder, sep: String): StringBuilder = addString(b, "", sep, "") + + /** Appends all elements of this $coll to a string builder. + * The written text consists of the string representations (w.r.t. the method `toString`) + * of all elements of this $coll without any separator string. + * + * @param b the string builder to which elements are appended. + * @return the string builder `b` to which elements were appended. + */ + def addString(b: StringBuilder): StringBuilder = addString(b, "") +} diff --git a/src/library/scala/collection/TraversableProxy.scala b/src/library/scala/collection/TraversableProxy.scala index 4a14937781..dd450dccac 100644 --- a/src/library/scala/collection/TraversableProxy.scala +++ b/src/library/scala/collection/TraversableProxy.scala @@ -11,7 +11,7 @@ package scala.collection -// Methods could be printed by cat TraversibeLike.scala | egrep '^ (override )?def' +// Methods could be printed by cat TraverableLike.scala | egrep '^ (override )?def' /** This trait implements a proxy for traversable objects. It forwards diff --git a/src/library/scala/collection/TraversableProxyLike.scala b/src/library/scala/collection/TraversableProxyLike.scala index 24d6c7048d..fb8da98a6b 100644 --- a/src/library/scala/collection/TraversableProxyLike.scala +++ b/src/library/scala/collection/TraversableProxyLike.scala @@ -24,23 +24,22 @@ import mutable.{Buffer, StringBuilder} * @version 2.8 * @since 2.8 */ -trait TraversableProxyLike[+A, +This <: TraversableLike[A, This] with Traversable[A]] extends TraversableLike[A, This] with Proxy { - def self: This +trait TraversableProxyLike[+A, +Repr <: TraversableLike[A, Repr] with Traversable[A]] extends TraversableLike[A, Repr] with Proxy { + def self: Repr override def foreach[B](f: A => B): Unit = self.foreach(f) override def isEmpty: Boolean = self.isEmpty override def nonEmpty: Boolean = self.nonEmpty override def size: Int = self.size override def hasDefiniteSize = self.hasDefiniteSize - override def ++[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = self.++(that)(bf) - override def ++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[This, B, That]): That = self.++(that)(bf) - override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = self.map(f)(bf) - override def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = self.flatMap(f)(bf) - override def partialMap[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[This, B, That]): That = self.partialMap(pf)(bf) - override def filter(p: A => Boolean): This = self.filter(p) - override def filterNot(p: A => Boolean): This = self.filterNot(p) - override def partition(p: A => Boolean): (This, This) = self.partition(p) - override def groupBy[K](f: A => K): Map[K, This] = self.groupBy(f) + override def ++[B >: A, That](xs: TraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = self.++(xs)(bf) + override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.map(f)(bf) + override def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = self.flatMap(f)(bf) + override def filter(p: A => Boolean): Repr = self.filter(p) + override def filterNot(p: A => Boolean): Repr = self.filterNot(p) + override def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[Repr, B, That]): That = self.collect(pf)(bf) + override def partition(p: A => Boolean): (Repr, Repr) = self.partition(p) + override def groupBy[K](f: A => K): Map[K, Repr] = self.groupBy(f) override def forall(p: A => Boolean): Boolean = self.forall(p) override def exists(p: A => Boolean): Boolean = self.exists(p) override def count(p: A => Boolean): Int = self.count(p) @@ -53,28 +52,37 @@ trait TraversableProxyLike[+A, +This <: TraversableLike[A, This] with Traversabl override def reduceLeftOption[B >: A](op: (B, A) => B): Option[B] = self.reduceLeftOption(op) override def reduceRight[B >: A](op: (A, B) => B): B = self.reduceRight(op) override def reduceRightOption[B >: A](op: (A, B) => B): Option[B] = self.reduceRightOption(op) + override def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.scanLeft(z)(op)(bf) + override def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = self.scanRight(z)(op)(bf) + override def sum[B >: A](implicit num: Numeric[B]): B = self.sum(num) + override def product[B >: A](implicit num: Numeric[B]): B = self.product(num) + override def min[B >: A](implicit cmp: Ordering[B]): A = self.min(cmp) + override def max[B >: A](implicit cmp: Ordering[B]): A = self.max(cmp) override def head: A = self.head override def headOption: Option[A] = self.headOption - override def tail: This = self.tail + override def tail: Repr = self.tail override def last: A = self.last override def lastOption: Option[A] = self.lastOption - override def init: This = self.init - override def take(n: Int): This = self.take(n) - override def drop(n: Int): This = self.drop(n) - override def slice(from: Int, until: Int): This = self.slice(from, until) - override def takeWhile(p: A => Boolean): This = self.takeWhile(p) - override def dropWhile(p: A => Boolean): This = self.dropWhile(p) - override def span(p: A => Boolean): (This, This) = self.span(p) - override def splitAt(n: Int): (This, This) = self.splitAt(n) + override def init: Repr = self.init + override def take(n: Int): Repr = self.take(n) + override def drop(n: Int): Repr = self.drop(n) + override def slice(from: Int, until: Int): Repr = self.slice(from, until) + override def takeWhile(p: A => Boolean): Repr = self.takeWhile(p) + override def dropWhile(p: A => Boolean): Repr = self.dropWhile(p) + override def span(p: A => Boolean): (Repr, Repr) = self.span(p) + override def splitAt(n: Int): (Repr, Repr) = self.splitAt(n) override def copyToBuffer[B >: A](dest: Buffer[B]) = self.copyToBuffer(dest) override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) = self.copyToArray(xs, start, len) override def copyToArray[B >: A](xs: Array[B], start: Int) = self.copyToArray(xs, start) + override def copyToArray[B >: A](xs: Array[B]) = self.copyToArray(xs) override def toArray[B >: A: ClassManifest]: Array[B] = self.toArray override def toList: List[A] = self.toList override def toIterable: Iterable[A] = self.toIterable override def toSeq: Seq[A] = self.toSeq + override def toIndexedSeq[B >: A]: mutable.IndexedSeq[B] = self.toIndexedSeq override def toStream: Stream[A] = self.toStream override def toSet[B >: A]: immutable.Set[B] = self.toSet + override def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = self.toMap(ev) override def mkString(start: String, sep: String, end: String): String = self.mkString(start, sep, end) override def mkString(sep: String): String = self.mkString(sep) override def mkString: String = self.mkString @@ -83,14 +91,18 @@ trait TraversableProxyLike[+A, +This <: TraversableLike[A, This] with Traversabl override def addString(b: StringBuilder): StringBuilder = self.addString(b) override def stringPrefix : String = self.stringPrefix override def view = self.view - override def view(from: Int, until: Int): TraversableView[A, This] = self.view(from, until) + override def view(from: Int, until: Int): TraversableView[A, Repr] = self.view(from, until) } -private class TraversableProxyLikeConfirmation[+A, +This <: TraversableLike[A, This] with Traversable[A]] +/** Martin to Paul: I'm not sure what the purpose of this class is? I assume it was to make + * sure that TraversableProxyLike has all Traversable methods, but it fails at that + * +private class TraversableProxyLikeConfirmation[+A, +Repr <: TraversableLike[A, Repr] with Traversable[A]] extends TraversableProxyLike[A, Traversable[A]] with interfaces.TraversableMethods[A, Traversable[A]] { - def self: This = repr.asInstanceOf[This] + def self: Repr = repr.asInstanceOf[Repr] protected[this] def newBuilder = scala.collection.Traversable.newBuilder[A] - // : Builder[A, This] + // : Builder[A, Repr] } +*/ diff --git a/src/library/scala/collection/TraversableView.scala b/src/library/scala/collection/TraversableView.scala index 8a67b8d10f..e9332097e7 100644 --- a/src/library/scala/collection/TraversableView.scala +++ b/src/library/scala/collection/TraversableView.scala @@ -18,7 +18,7 @@ import TraversableView.NoBuilder /** <p> * A base class for views of <a href="../Traversable.html" * target="ContentFrame"><code>Traversable<code></a>.<br/> - * Every subclass has to implenment the <code>foreach</code> method. + * Every subclass has to implement the <code>foreach</code> method. * </p> * * @author Martin Odersky diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala index 84c33296db..09e6a65158 100644 --- a/src/library/scala/collection/TraversableViewLike.scala +++ b/src/library/scala/collection/TraversableViewLike.scala @@ -12,7 +12,7 @@ package scala.collection import generic._ -import mutable.Builder +import mutable.{Builder, ArrayBuffer} import TraversableView.NoBuilder /** <p> @@ -47,8 +47,23 @@ self => b.result() } + /** The implementation base trait of this view. + * This trait and all its subtraits has to be re-implemented for each + * ViewLike class. + */ trait Transformed[+B] extends TraversableView[B, Coll] { lazy val underlying = self.underlying + override def toString = stringPrefix+"(...)" + } + + /** A fall back which forces everything into a vector and then applies an operation + * on it. Used for those operations which do not naturally lend themselves to a view + */ + trait Forced[B] extends Transformed[B] { + protected[this] def forced: Seq[B] + private[this] lazy val forcedCache = forced + override def foreach[U](f: B => U) = forcedCache.foreach(f) + override def stringPrefix = self.stringPrefix+"C" } /** pre: from >= 0 @@ -56,7 +71,7 @@ self => trait Sliced extends Transformed[A] { protected[this] val from: Int protected[this] val until: Int - override def foreach[C](f: A => C) { + override def foreach[U](f: A => U) { var index = 0 for (x <- self) { if (from <= index) { @@ -73,7 +88,7 @@ self => trait Mapped[B] extends Transformed[B] { protected[this] val mapping: A => B - override def foreach[C](f: B => C) { + override def foreach[U](f: B => U) { for (x <- self) f(mapping(x)) } @@ -82,7 +97,7 @@ self => trait FlatMapped[B] extends Transformed[B] { protected[this] val mapping: A => Traversable[B] - override def foreach[C](f: B => C) { + override def foreach[U](f: B => U) { for (x <- self) for (y <- mapping(x)) f(y) @@ -92,7 +107,7 @@ self => trait Appended[B >: A] extends Transformed[B] { protected[this] val rest: Traversable[B] - override def foreach[C](f: B => C) { + override def foreach[U](f: B => U) { for (x <- self) f(x) for (x <- rest) f(x) } @@ -101,7 +116,7 @@ self => trait Filtered extends Transformed[A] { protected[this] val pred: A => Boolean - override def foreach[C](f: A => C) { + override def foreach[U](f: A => U) { for (x <- self) if (pred(x)) f(x) } @@ -110,7 +125,7 @@ self => trait TakenWhile extends Transformed[A] { protected[this] val pred: A => Boolean - override def foreach[C](f: A => C) { + override def foreach[U](f: A => U) { for (x <- self) { if (!pred(x)) return f(x) @@ -121,7 +136,7 @@ self => trait DroppedWhile extends Transformed[A] { protected[this] val pred: A => Boolean - override def foreach[C](f: A => C) { + override def foreach[U](f: A => U) { var go = false for (x <- self) { if (!go && !pred(x)) go = true @@ -134,6 +149,7 @@ self => /** Boilerplate method, to override in each subclass * This method could be eliminated if Scala had virtual classes */ + protected def newForced[B](xs: => Seq[B]): Transformed[B] = new Forced[B] { val forced = xs } protected def newAppended[B >: A](that: Traversable[B]): Transformed[B] = new Appended[B] { val rest = that } protected def newMapped[B](f: A => B): Transformed[B] = new Mapped[B] { val mapping = f } protected def newFlatMapped[B](f: A => Traversable[B]): Transformed[B] = new FlatMapped[B] { val mapping = f } @@ -142,14 +158,12 @@ self => protected def newDroppedWhile(p: A => Boolean): Transformed[A] = new DroppedWhile { val pred = p } protected def newTakenWhile(p: A => Boolean): Transformed[A] = new TakenWhile { val pred = p } - override def ++[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = { - newAppended(that).asInstanceOf[That] + override def ++[B >: A, That](xs: TraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = { + newAppended(xs.toTraversable).asInstanceOf[That] // was: if (bf.isInstanceOf[ByPassCanBuildFrom]) newAppended(that).asInstanceOf[That] // else super.++[B, That](that)(bf) } - override def ++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[This, B, That]): That = ++[B, That](that.toStream) - override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = { newMapped(f).asInstanceOf[That] // val b = bf(repr) @@ -157,6 +171,9 @@ self => // else super.map[B, That](f)(bf) } + override def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[This, B, That]): That = + filter(pf.isDefinedAt).map(pf)(bf) + override def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = { newFlatMapped(f).asInstanceOf[That] // was: val b = bf(repr) @@ -164,7 +181,14 @@ self => // else super.flatMap[B, That](f)(bf) } + protected[this] def thisSeq: Seq[A] = { + val buf = new ArrayBuffer[A] + self foreach (buf +=) + buf.result + } + override def filter(p: A => Boolean): This = newFiltered(p).asInstanceOf[This] + override def partition(p: A => Boolean): (This, This) = (filter(p), filter(!p(_))) override def init: This = newSliced(0, size - 1).asInstanceOf[This] override def drop(n: Int): This = newSliced(n max 0, Int.MaxValue).asInstanceOf[This] override def take(n: Int): This = newSliced(0, n).asInstanceOf[This] @@ -173,5 +197,17 @@ self => override def takeWhile(p: A => Boolean): This = newTakenWhile(p).asInstanceOf[This] override def span(p: A => Boolean): (This, This) = (takeWhile(p), dropWhile(p)) override def splitAt(n: Int): (This, This) = (take(n), drop(n)) + + override def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[This, B, That]): That = + newForced(thisSeq.scanLeft(z)(op)).asInstanceOf[That] + + override def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[This, B, That]): That = + newForced(thisSeq.scanRight(z)(op)).asInstanceOf[That] + + override def groupBy[K](f: A => K): Map[K, This] = + thisSeq.groupBy(f).mapValues(xs => newForced(xs).asInstanceOf[This]) + override def stringPrefix = "TraversableView" } + + diff --git a/src/library/scala/collection/generic/Addable.scala b/src/library/scala/collection/generic/Addable.scala index 9686e96c09..ecbd8301b6 100644 --- a/src/library/scala/collection/generic/Addable.scala +++ b/src/library/scala/collection/generic/Addable.scala @@ -52,16 +52,5 @@ trait Addable[A, +Repr <: Addable[A, Repr]] { self => * @param elems the collection containing the added elements. * @return a new $coll with the given elements added. */ - def ++ (elems: Traversable[A]): Repr = (repr /: elems) (_ + _) - - /** Creates a new $coll by adding all elements produced by an iterator to this $coll. - * - * @param iter the iterator producing the added elements. - * @return a new $coll with the given elements added. - */ - def ++ (iter: Iterator[A]): Repr = (repr /: iter) (_ + _) + def ++ (xs: TraversableOnce[A]): Repr = (repr /: xs) (_ + _) } - - - - diff --git a/src/library/scala/collection/generic/GenericTraversableTemplate.scala b/src/library/scala/collection/generic/GenericTraversableTemplate.scala index 0e3c3c203b..683f609686 100644 --- a/src/library/scala/collection/generic/GenericTraversableTemplate.scala +++ b/src/library/scala/collection/generic/GenericTraversableTemplate.scala @@ -100,8 +100,8 @@ trait GenericTraversableTemplate[+A, +CC[X] <: Traversable[X]] extends HasNewBui } /** Transposes this $coll of traversable collections into - * @B the type of the elements of each traversable collection. - * @asTraversable an implicit conversion which asserts that the element type of this + * @tparam B the type of the elements of each traversable collection. + * @param asTraversable an implicit conversion which asserts that the element type of this * $coll is a `Traversable`. * @return a two-dimensional $coll of ${coll}s which has as ''n''th row * the ''n''th column of this $coll. diff --git a/src/library/scala/collection/generic/Growable.scala b/src/library/scala/collection/generic/Growable.scala index 7950dee9de..80f933a901 100644 --- a/src/library/scala/collection/generic/Growable.scala +++ b/src/library/scala/collection/generic/Growable.scala @@ -16,7 +16,6 @@ package generic * a `clear` method. * * @author Martin Odersky - * @owner Martin Odersky * @version 2.8 * @since 2.8 * @define coll growable collection @@ -42,26 +41,15 @@ trait Growable[-A] { */ def +=(elem1: A, elem2: A, elems: A*): this.type = this += elem1 += elem2 ++= elems - /** ${Add}s all elements produced by an iterator to this $coll. + /** ${Add}s all elements produced by a TraversableOnce to this $coll. * - * @param iter the iterator producing the elements to $add. + * @param iter the TraversableOnce producing the elements to $add. * @return the $coll itself. */ - def ++=(iter: Iterator[A]): this.type = { iter foreach += ; this } - - /** ${Add}s all elements contained in a traversable collection to this $coll. - * - * @param elems the collection containing the elements to $add. - * @return the $coll itself. - */ - def ++=(elems: Traversable[A]): this.type = { elems foreach +=; this } + def ++=(xs: TraversableOnce[A]): this.type = { xs foreach += ; this } /** Clears the $coll's contents. After this operation, the * $coll is empty. */ def clear() } - - - - diff --git a/src/library/scala/collection/generic/IterableForwarder.scala b/src/library/scala/collection/generic/IterableForwarder.scala index 9cd1ccd843..f4aef2fcbb 100644 --- a/src/library/scala/collection/generic/IterableForwarder.scala +++ b/src/library/scala/collection/generic/IterableForwarder.scala @@ -22,7 +22,7 @@ import collection.mutable.Buffer * <li><code>toString</code>, <code>hashCode</code>, <code>equals</code>, * <code>stringPrefix</code></li> * <li><code>newBuilder</code>, <code>view</code></li> - * <li>all calls creating a new iterable objetc of the same kind</li> + * <li>all calls creating a new iterable object of the same kind</li> * </ul> * <p> * The above methods are forwarded by subclass <a href="../IterableProxy.html" @@ -41,6 +41,6 @@ trait IterableForwarder[+A] extends Iterable[A] with TraversableForwarder[A] { // Iterable delegates // Iterable methods could be printed by cat IterableLike.scala | sed -n '/trait Iterable/,$ p' | egrep '^ (override )?def' - override def iterator = underlying.iterator + override def iterator: Iterator[A] = underlying.iterator override def sameElements[B >: A](that: Iterable[B]): Boolean = underlying.sameElements(that) } diff --git a/src/library/scala/collection/generic/SeqForwarder.scala b/src/library/scala/collection/generic/SeqForwarder.scala index 0ecdaf4566..e5dbe4b79d 100644 --- a/src/library/scala/collection/generic/SeqForwarder.scala +++ b/src/library/scala/collection/generic/SeqForwarder.scala @@ -30,24 +30,31 @@ trait SeqForwarder[+A] extends Seq[A] with IterableForwarder[A] { protected override def underlying: Seq[A] - // PartialFunction delegates - - override def apply(i: Int): A = underlying.apply(i) - override def isDefinedAt(x: Int): Boolean = underlying.isDefinedAt(x) - - // Seq delegates - // Seq methods could be printed by cat SeqLike.scala | sed -n '/trait Seq/,$ p' | egrep '^ (override )?def' - override def length: Int = underlying.length - override def lengthCompare(l: Int) = underlying lengthCompare l + override def apply(idx: Int): A = underlying.apply(idx) + override def lengthCompare(len: Int): Int = underlying.lengthCompare(len) + override def isDefinedAt(x: Int): Boolean = underlying.isDefinedAt(x) override def segmentLength(p: A => Boolean, from: Int): Int = underlying.segmentLength(p, from) override def prefixLength(p: A => Boolean) = underlying.prefixLength(p) + override def indexWhere(p: A => Boolean): Int = underlying.indexWhere(p) override def indexWhere(p: A => Boolean, from: Int): Int = underlying.indexWhere(p, from) + override def findIndexOf(p: A => Boolean): Int = underlying.indexWhere(p) + override def indexOf[B >: A](elem: B): Int = underlying.indexOf(elem) override def indexOf[B >: A](elem: B, from: Int): Int = underlying.indexOf(elem, from) + override def lastIndexOf[B >: A](elem: B): Int = underlying.lastIndexOf(elem) + override def lastIndexOf[B >: A](elem: B, end: Int): Int = underlying.lastIndexOf(elem, end) + override def lastIndexWhere(p: A => Boolean): Int = underlying.lastIndexWhere(p) + override def lastIndexWhere(p: A => Boolean, end: Int): Int = underlying.lastIndexWhere(p, end) override def reverseIterator: Iterator[A] = underlying.reverseIterator override def startsWith[B](that: Seq[B], offset: Int): Boolean = underlying.startsWith(that, offset) + override def startsWith[B](that: Seq[B]): Boolean = underlying.startsWith(that) override def endsWith[B](that: Seq[B]): Boolean = underlying.endsWith(that) override def indexOfSlice[B >: A](that: Seq[B]): Int = underlying.indexOfSlice(that) + override def indexOfSlice[B >: A](that: Seq[B], from: Int): Int = underlying.indexOfSlice(that, from) + override def lastIndexOfSlice[B >: A](that: Seq[B]): Int = underlying.lastIndexOfSlice(that) + override def lastIndexOfSlice[B >: A](that: Seq[B], end: Int): Int = underlying.lastIndexOfSlice(that, end) + override def containsSlice[B](that: Seq[B]): Boolean = underlying.containsSlice(that) override def contains(elem: Any): Boolean = underlying.contains(elem) + override def corresponds[B](that: Seq[B])(p: (A,B) => Boolean): Boolean = underlying.corresponds(that)(p) override def indices: Range = underlying.indices } diff --git a/src/library/scala/collection/generic/Shrinkable.scala b/src/library/scala/collection/generic/Shrinkable.scala index bd773a97f9..cf970e1232 100644 --- a/src/library/scala/collection/generic/Shrinkable.scala +++ b/src/library/scala/collection/generic/Shrinkable.scala @@ -15,7 +15,6 @@ package generic * using a `-=` operator. * * @author Martin Odersky - * @owner Martin Odersky * @version 2.8 * @since 2.8 * @define coll shrinkable collection @@ -48,14 +47,7 @@ trait Shrinkable[-A] { * @param iter the iterator producing the elements to remove. * @return the $coll itself */ - def --=(iter: Iterator[A]): this.type = { iter foreach -=; this } - - /** Removes all elements contained in a traversable collection from this $coll. - * - * @param iter the collection containing the elements to remove. - * @return the $coll itself - */ - def --=(iter: Traversable[A]): this.type = { iter foreach -=; this } + def --=(xs: TraversableOnce[A]): this.type = { xs foreach -= ; this } } diff --git a/src/library/scala/collection/generic/Sorted.scala b/src/library/scala/collection/generic/Sorted.scala index 73bc1b6553..aa95c76a88 100644 --- a/src/library/scala/collection/generic/Sorted.scala +++ b/src/library/scala/collection/generic/Sorted.scala @@ -16,8 +16,8 @@ package generic * @author Sean McDirmid * @since 2.8 */ -trait Sorted[K, +This <: Sorted[K, This]]{ - def ordering : Ordering[K]; +trait Sorted[K, +This <: Sorted[K, This]] { + def ordering : Ordering[K] /** The current collection */ protected def repr: This @@ -25,7 +25,6 @@ trait Sorted[K, +This <: Sorted[K, This]]{ /** return as a projection the set of keys in this collection */ def keySet: SortedSet[K] - /** Returns the first key of the collection. */ def firstKey: K @@ -68,24 +67,25 @@ trait Sorted[K, +This <: Sorted[K, This]]{ */ def range(from: K, until: K): This = rangeImpl(Some(from), Some(until)) - /** Create a range projection of this collection with no lower-bound. * @param to The upper-bound (inclusive) of the ranged projection. */ def to(to: K): This = { // tough! - val i = keySet.from(to).iterator; - if (!i.hasNext) return repr - val next = i.next; - if (next == to) { - if (!i.hasNext) return repr - else return until(i.next) - } else return until(next) + val i = keySet.from(to).iterator + if (i.isEmpty) return repr + val next = i.next + if (next == to) + if (i.isEmpty) repr + else until(i.next) + else + until(next) } protected def hasAll(j: Iterator[K]): Boolean = { - val i = keySet.iterator; - if (!i.hasNext) return !j.hasNext; + val i = keySet.iterator + if (i.isEmpty) return j.isEmpty + var in = i.next; while (j.hasNext) { val jn = j.next; @@ -99,5 +99,4 @@ trait Sorted[K, +This <: Sorted[K, This]]{ } true } - } diff --git a/src/library/scala/collection/generic/Subtractable.scala b/src/library/scala/collection/generic/Subtractable.scala index 8ded9c22d1..b2051d2773 100644 --- a/src/library/scala/collection/generic/Subtractable.scala +++ b/src/library/scala/collection/generic/Subtractable.scala @@ -56,14 +56,5 @@ trait Subtractable[A, +Repr <: Subtractable[A, Repr]] { self => * @return a new $coll that contains all elements of the current $coll * except one less occurrence of each of the elements of `elems`. */ - def --(elems: Traversable[A]): Repr = (repr /: elems) (_ - _) - - /** Creates a new $coll from this $coll by removing all elements produced - * by an iterator. - * - * @param iter the iterator producing the removed elements. - * @return a new $coll that contains all elements of the current $coll - * except one less occurrence of each of the elements produced by `iter`. - */ - def --(iter: Iterator[A]): Repr = (repr /: iter) (_ - _) + def --(xs: TraversableOnce[A]): Repr = (repr /: xs) (_ - _) } diff --git a/src/library/scala/collection/generic/TraversableFactory.scala b/src/library/scala/collection/generic/TraversableFactory.scala index 4f2eb40a64..c2668b48a2 100644 --- a/src/library/scala/collection/generic/TraversableFactory.scala +++ b/src/library/scala/collection/generic/TraversableFactory.scala @@ -38,7 +38,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl extends GenericCompanion[CC] { /** A generic implementation of the `CanBuildFrom` trait, which forwards - * all calls to `apply(from)` to the `genericBuilder` methof of + * all calls to `apply(from)` to the `genericBuilder` method of * $coll `from`, and which forwards all calls of `apply()` to the * `newBuilder` method of this factory. */ diff --git a/src/library/scala/collection/generic/TraversableForwarder.scala b/src/library/scala/collection/generic/TraversableForwarder.scala index bd7f751288..dcba86f3d7 100644 --- a/src/library/scala/collection/generic/TraversableForwarder.scala +++ b/src/library/scala/collection/generic/TraversableForwarder.scala @@ -42,33 +42,47 @@ trait TraversableForwarder[+A] extends Traversable[A] { /** The iterable object to which calls are forwarded */ protected def underlying: Traversable[A] - // Iterable delegates - // Iterable methods could be printed by cat TarversableLike.scala | sed -n '/trait Iterable/,$ p' | egrep '^ (override )?def' - - override def isEmpty = underlying.isEmpty - override def nonEmpty = underlying.nonEmpty + override def foreach[B](f: A => B): Unit = underlying.foreach(f) + override def isEmpty: Boolean = underlying.isEmpty + override def nonEmpty: Boolean = underlying.nonEmpty + override def size: Int = underlying.size override def hasDefiniteSize = underlying.hasDefiniteSize - override def foreach[B](f: A => B) = underlying.foreach(f) override def forall(p: A => Boolean): Boolean = underlying.forall(p) override def exists(p: A => Boolean): Boolean = underlying.exists(p) override def count(p: A => Boolean): Int = underlying.count(p) override def find(p: A => Boolean): Option[A] = underlying.find(p) override def foldLeft[B](z: B)(op: (B, A) => B): B = underlying.foldLeft(z)(op) + override def /: [B](z: B)(op: (B, A) => B): B = underlying./:(z)(op) override def foldRight[B](z: B)(op: (A, B) => B): B = underlying.foldRight(z)(op) + override def :\ [B](z: B)(op: (A, B) => B): B = underlying.:\(z)(op) override def reduceLeft[B >: A](op: (B, A) => B): B = underlying.reduceLeft(op) - override def reduceRight[B >: A](op: (A, B) => B): B = underlying.reduceRight(op) override def reduceLeftOption[B >: A](op: (B, A) => B): Option[B] = underlying.reduceLeftOption(op) + override def reduceRight[B >: A](op: (A, B) => B): B = underlying.reduceRight(op) override def reduceRightOption[B >: A](op: (A, B) => B): Option[B] = underlying.reduceRightOption(op) + override def sum[B >: A](implicit num: Numeric[B]): B = underlying.sum(num) + override def product[B >: A](implicit num: Numeric[B]): B = underlying.product(num) + override def min[B >: A](implicit cmp: Ordering[B]): A = underlying.min(cmp) + override def max[B >: A](implicit cmp: Ordering[B]): A = underlying.max(cmp) + override def head: A = underlying.head + override def headOption: Option[A] = underlying.headOption + override def last: A = underlying.last + override def lastOption: Option[A] = underlying.lastOption override def copyToBuffer[B >: A](dest: Buffer[B]) = underlying.copyToBuffer(dest) override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) = underlying.copyToArray(xs, start, len) - override def toArray[B >: A : ClassManifest]: Array[B] = underlying.toArray + override def copyToArray[B >: A](xs: Array[B], start: Int) = underlying.copyToArray(xs, start) + override def copyToArray[B >: A](xs: Array[B]) = underlying.copyToArray(xs) + override def toArray[B >: A: ClassManifest]: Array[B] = underlying.toArray override def toList: List[A] = underlying.toList + override def toIterable: Iterable[A] = underlying.toIterable override def toSeq: Seq[A] = underlying.toSeq + override def toIndexedSeq[B >: A]: mutable.IndexedSeq[B] = underlying.toIndexedSeq override def toStream: Stream[A] = underlying.toStream + override def toSet[B >: A]: immutable.Set[B] = underlying.toSet + override def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] = underlying.toMap(ev) override def mkString(start: String, sep: String, end: String): String = underlying.mkString(start, sep, end) + override def mkString(sep: String): String = underlying.mkString(sep) + override def mkString: String = underlying.mkString 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 lastOption: Option[A] = underlying.lastOption + override def addString(b: StringBuilder, sep: String): StringBuilder = underlying.addString(b, sep) + override def addString(b: StringBuilder): StringBuilder = underlying.addString(b) } diff --git a/src/library/scala/collection/generic/TraversableView.scala.1 b/src/library/scala/collection/generic/TraversableView.scala.1 deleted file mode 100644 index 3608de42be..0000000000 --- a/src/library/scala/collection/generic/TraversableView.scala.1 +++ /dev/null @@ -1,152 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ -package scalay.collection.generic - -import Math.MAX_INT -import TraversableView.NoBuilder - -/** <p> - * A base class for views of <code>Traversable</code>. - * </p> - * <p> - * Every subclass has to implement the <code>foreach</code> method. - * </p> - * - * @since 2.8 - */ -abstract class TraversableView[+A, +Coll <: Traversable[_]] extends Traversable[A] { -self => - - type This >: this.type <: TraversableView[A, Coll] { type This = self.This } - protected val thisCollection: This = this - - protected[this] def newBuilder: Builder[A, This, This] = - throw new UnsupportedOperationException(this+".newBuilder") - - def force[B >: A, That](implicit b: Builder[B, That, Coll]) = { - b ++= this - b.result() - } - - trait Transformed[+B] extends TraversableView[B, Coll] - - /** pre: from >= 0 - */ - trait Sliced extends Transformed[A] { - protected[this] val from: Int - protected[this] val until: Int - override def foreach(f: A => Unit) { - var index = 0 - for (x <- self) { - if (from <= index) { - if (until <= index) return - f(x) - } - index += 1 - } - } - override def stringPrefix = self.stringPrefix+"S" - override def slice(from1: Int, until1: Int) = - newSliced(from + (from1 max 0), from + (until1 max 0)).asInstanceOf[This] - } - - trait Mapped[B] extends Transformed[B] { - protected[this] val mapping: A => B - override def foreach(f: B => Unit) { - for (x <- self) - f(mapping(x)) - } - override def stringPrefix = self.stringPrefix+"M" - } - - trait FlatMapped[B] extends Transformed[B] { - protected[this] val mapping: A => Traversable[B] - override def foreach(f: B => Unit) { - for (x <- self) - for (y <- mapping(x)) - f(y) - } - override def stringPrefix = self.stringPrefix+"N" - } - - trait Appended[B >: A] extends Transformed[B] { - protected[this] val rest: Traversable[B] - override def foreach(f: B => Unit) { - for (x <- self) f(x) - for (x <- rest) f(x) - } - override def stringPrefix = self.stringPrefix+"A" - } - - trait Filtered extends Transformed[A] { - protected[this] val pred: A => Boolean - override def foreach(f: A => Unit) { - for (x <- self) - if (pred(x)) f(x) - } - override def stringPrefix = self.stringPrefix+"F" - } - - trait TakenWhile extends Transformed[A] { - protected[this] val pred: A => Boolean - override def foreach(f: A => Unit) { - for (x <- self) { - if (!pred(x)) return - f(x) - } - } - override def stringPrefix = self.stringPrefix+"T" - } - - trait DroppedWhile extends Transformed[A] { - protected[this] val pred: A => Boolean - override def foreach(f: A => Unit) { - var go = false - for (x <- self) { - if (!go && !pred(x)) go = true - if (go) f(x) - } - } - override def stringPrefix = self.stringPrefix+"D" - } - - override def ++[B >: A, That](that: Traversable[B])(implicit b: Builder[B, That, This]): That = - if (b.isInstanceOf[NoBuilder[_]]) newAppended(that).asInstanceOf[That] - else super.++[B, That](that)(b) - - override def ++[B >: A, That](that: Iterator[B])(implicit b: Builder[B, That, This]): That = ++[B, That](that.toStream) - - override def map[B, That](f: A => B)(implicit b: Builder[B, That, This]): That = - if (b.isInstanceOf[NoBuilder[_]]) newMapped(f).asInstanceOf[That] - else super.map[B, That](f)(b) - - override def flatMap[B, That](f: A => Traversable[B])(implicit b: Builder[B, That, This]): That = - if (b.isInstanceOf[NoBuilder[_]]) newFlatMapped(f).asInstanceOf[That] - else super.flatMap[B, That](f)(b) - - override def filter(p: A => Boolean): This = newFiltered(p).asInstanceOf[This] - override def init: This = newSliced(0, size - 1).asInstanceOf[This] - override def drop(n: Int): This = newSliced(n max 0, MAX_INT).asInstanceOf[This] - override def take(n: Int): This = newSliced(0, n).asInstanceOf[This] - override def slice(from: Int, until: Int): This = newSliced(from max 0, until).asInstanceOf[This] - override def dropWhile(p: A => Boolean): This = newDroppedWhile(p).asInstanceOf[This] - override def takeWhile(p: A => Boolean): This = newTakenWhile(p).asInstanceOf[This] - override def span(p: A => Boolean): (This, This) = (takeWhile(p), dropWhile(p)) - override def splitAt(n: Int): (This, This) = (take(n), drop(n)) -} - -object TraversableView { - class NoBuilder[A] extends Builder[A, Nothing, TraversableView[_, _]] { - def +=(elem: A) {} - def iterator: Iterator[A] = Iterator.empty - @deprecated("use `iterator' instead") def elements = iterator - def result() = throw new UnsupportedOperationException("TraversableView.Builder.result") - def clear() {} - } - implicit def implicitBuilder[A]: Builder[A, TraversableView[A, Traversable[_]], TraversableView[_, _]] = new NoBuilder -} diff --git a/src/library/scala/collection/immutable/DefaultMap.scala b/src/library/scala/collection/immutable/DefaultMap.scala new file mode 100755 index 0000000000..7ee8197150 --- /dev/null +++ b/src/library/scala/collection/immutable/DefaultMap.scala @@ -0,0 +1,53 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: DefaultMap.scala 20028 2009-12-07 11:49:19Z cunei $ + + +package scala.collection +package immutable + +import generic._ + +/** <p> + * A default map which implements the <code>updated</code> and <code>-</code> + * methods of maps.<br/> + * Instances that inherit from <code>DefaultMap[A, B]</code> still have to + * define: + * </p><pre> + * <b>def</b> get(key: A): Option[B] + * <b>def</b> iterator: Iterator[(A, B)]</pre> + * <p> + * It refers back to the original map. + * </p> + * <p> + * It might also be advisable to override <code>foreach</code> or + * <code>size</code> if efficient implementations can be found. + * </p> + * + * @since 2.8 + */ +trait DefaultMap[A, +B] extends Map[A, B] { self => + + /** A default implementation which creates a new immutable map. + */ + override def +[B1 >: B](kv: (A, B1)): Map[A, B1] = { + val b = Map.newBuilder[A, B1] + b ++= this + b += ((kv._1, kv._2)) + b.result + } + + /** A default implementation which creates a new immutable map. + */ + override def - (key: A): Map[A, B] = { + val b = newBuilder + b ++= this filter (key !=) + b.result + } +} diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 2215e22f71..e0f801546c 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -16,184 +16,383 @@ import generic._ import annotation.unchecked.uncheckedVariance /** <p> - * This class implements immutable maps using a hash table. - * </p> - * <p> - * It is optimized for sequential accesses where the last updated table is - * accessed most often. It supports with reasonable efficiency accesses to - * previous versions of the table by keeping a change log that's regularly - * compacted. It needs to synchronize most methods, so it is less suitable - * for highly concurrent accesses. + * This class implements immutable maps using a hash trie. * </p> * * @note the builder of a hash map returns specialized representations EmptyMap,Map1,..., Map4 * for maps of size <= 4. * * @author Martin Odersky - * @version 2.0, 19/01/2007 + * @author Tiark Rompf + * @version 2.8 * @since 2.3 */ -@serializable @SerialVersionUID(1L) -class HashMap[A, +B] extends Map[A,B] with MapLike[A, B, HashMap[A, B]] with mutable.HashTable[A] { +@serializable @SerialVersionUID(2L) +class HashMap[A, +B] extends Map[A,B] with MapLike[A, B, HashMap[A, B]] { - type Entry = scala.collection.mutable.DefaultEntry[A, Any] - - @transient protected var later: HashMap[A, B @uncheckedVariance] = null - @transient protected var oldKey: A = _ - @transient protected var oldValue: Option[B @uncheckedVariance] = _ - @transient protected var deltaSize: Int = _ + override def size: Int = 0 override def empty = HashMap.empty[A, B] - def get(key: A): Option[B] = synchronized { - var m: HashMap[A, _ >: B] = this - var cnt = 0 - while (m.later != null) { - if (key == m.oldKey) return m.oldValue.asInstanceOf[Option[B]] - cnt += 1 - m = m.later - } - if (cnt > logLimit) makeCopy(m) - val e = m.findEntry(key) - if (e == null) None - else Some(getValue(e)) - } + def iterator: Iterator[(A,B)] = Iterator.empty - override def updated [B1 >: B] (key: A, value: B1): HashMap[A, B1] = synchronized { - makeCopyIfUpdated() - val e = findEntry(key) - if (e == null) { - markUpdated(key, None, 1) - later.addEntry(new Entry(key, value)) - } else { - markUpdated(key, Some(getValue(e)), 0) - e.value = value - } - later.asInstanceOf[HashMap[A, B1]] - } + override def foreach[U](f: ((A, B)) => U): Unit = { } + + def get(key: A): Option[B] = + get0(key, computeHash(key), 0) + + override def updated [B1 >: B] (key: A, value: B1): HashMap[A, B1] = + updated0(key, computeHash(key), 0, value, null) + + override def + [B1 >: B] (kv: (A, B1)): HashMap[A, B1] = + updated0(kv._1, computeHash(kv._1), 0, kv._2, kv) - /** 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 - */ - override def + [B1 >: B] (kv: (A, B1)): HashMap[A, B1] = updated(kv._1, kv._2) - - /** 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. - */ override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): HashMap[A, B1] = this + elem1 + elem2 ++ elems + // TODO: optimize (might be able to use mutable updates) - def - (key: A): HashMap[A, B] = synchronized { - makeCopyIfUpdated() - val e = findEntry(key) - if (e == null) this - else { - markUpdated(key, Some(getValue(e)), -1) - later removeEntry key - later.asInstanceOf[HashMap[A, B]] - } - } + def - (key: A): HashMap[A, B] = + removed0(key, computeHash(key), 0) - override def size: Int = synchronized { - var m: HashMap[A, _ >: B] = this - var cnt = 0 - var s = 0 - while (m.later != null) { - s -= m.deltaSize - cnt += 1 - m = m.later - } - s += m.tableSize - if (cnt > logLimit) makeCopy(m) - s - } + protected def elemHashCode(key: A) = if (key == null) 0 else key.hashCode() - def iterator = synchronized { - makeCopyIfUpdated() - entriesIterator map {e => (e.key, getValue(e))} + protected final def improve(hcode: Int) = { + var h: Int = hcode + ~(hcode << 9) + h = h ^ (h >>> 14) + h = h + (h << 4) + h ^ (h >>> 10) } - private def getValue(e: Entry) = - e.value.asInstanceOf[B] - - private def logLimit: Int = math.sqrt(table.length).toInt - - private[this] def markUpdated(key: A, ov: Option[B], delta: Int) { - val lf = loadFactor - later = new HashMap[A, B] { - override def initialSize = 0 - /* We need to do this to avoid a reference to the outer HashMap */ - def _newLoadFactor = lf - override def loadFactor = _newLoadFactor - table = HashMap.this.table - tableSize = HashMap.this.tableSize - threshold = HashMap.this.threshold - } - oldKey = key - oldValue = ov - deltaSize = delta - } + protected def computeHash(key: A) = improve(elemHashCode(key)) - private def makeCopy(last: HashMap[A, _ >: B]) { - def undo(m: HashMap[A, _ >: B]) { - if (m ne last) { - undo(m.later) - if (m.deltaSize == 1) removeEntry(m.oldKey) - else if (m.deltaSize == 0) findEntry(m.oldKey).value = m.oldValue.get - else if (m.deltaSize == -1) addEntry(new Entry(m.oldKey, m.oldValue.get)) - } - } - def copy(e: Entry): Entry = - if (e == null) null - else { - val rest = copy(e.next) - val result = new Entry(e.key, e.value) - result.next = rest - result - } - val ltable = last.table - val s = ltable.length - table = new scala.Array[collection.mutable.HashEntry[A, Entry]](s) - var i = 0 - while (i < s) { - table(i) = copy(ltable(i).asInstanceOf[Entry]) - i += 1 - } - tableSize = last.tableSize - threshold = last.threshold - undo(this) - later = null - } + protected def get0(key: A, hash: Int, level: Int): Option[B] = None - private def makeCopyIfUpdated() { - var m: HashMap[A, _ >: B] = this - while (m.later != null) m = m.later - if (m ne this) makeCopy(m) - } + protected def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1)): HashMap[A, B1] = + new HashMap.HashMap1(key, hash, value, kv) - private def writeObject(out: java.io.ObjectOutputStream) { - serializeTo(out, _.value) - } - private def readObject(in: java.io.ObjectInputStream) { - init[B](in, new Entry(_, _)) - } + + protected def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = this + } /** A factory object for immutable HashMaps. * * @author Martin Odersky + * @author Tiark Rompf * @version 2.8 * @since 2.3 */ object HashMap extends ImmutableMapFactory[HashMap] { implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), HashMap[A, B]] = new MapCanBuildFrom[A, B] - def empty[A, B]: HashMap[A, B] = new HashMap + def empty[A, B]: HashMap[A, B] = EmptyHashMap.asInstanceOf[HashMap[A, B]] + + private object EmptyHashMap extends HashMap[Any,Nothing] { + + } + + // TODO: add HashMap2, HashMap3, ... + + class HashMap1[A,+B](private var key: A, private[HashMap] var hash: Int, private var value: (B @uncheckedVariance), private var kv: (A,B @uncheckedVariance)) extends HashMap[A,B] { + override def size = 1 + + override def get0(key: A, hash: Int, level: Int): Option[B] = + if (hash == this.hash && key == this.key) Some(value) else None + + override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1)): HashMap[A, B1] = + if (hash == this.hash && key == this.key) new HashMap1(key, hash, value, kv) + else { + if (hash != this.hash) { + //new HashTrieMap[A,B1](level+5, this, new HashMap1(key, hash, value, kv)) + val m = new HashTrieMap[A,B1](0,new Array[HashMap[A,B1]](0),0) // TODO: could save array alloc + m.updated0(this.key, this.hash, level, this.value, this.kv).updated0(key, hash, level, value, kv) + } else { + // 32-bit hash collision (rare, but not impossible) + // wrap this in a HashTrieMap if called with level == 0 (otherwise serialization won't work) + if (level == 0) { + val elems = new Array[HashMap[A,B1]](1) + elems(0) = new HashMapCollision1(hash, ListMap.empty.updated(this.key,this.value).updated(key,value)) + new HashTrieMap[A,B1](1 << ((hash >>> level) & 0x1f), elems, 2) + } else { + new HashMapCollision1(hash, ListMap.empty.updated(this.key,this.value).updated(key,value)) + } + } + } + + override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = + if (hash == this.hash && key == this.key) HashMap.empty[A,B] else this + + override def iterator: Iterator[(A,B)] = Iterator(ensurePair) + override def foreach[U](f: ((A, B)) => U): Unit = f(ensurePair) + private[HashMap] def ensurePair: (A,B) = if (kv ne null) kv else { kv = (key, value); kv } + + private def writeObject(out: java.io.ObjectOutputStream) { + out.writeObject(key) + out.writeObject(value) + } + + private def readObject(in: java.io.ObjectInputStream) { + key = in.readObject().asInstanceOf[A] + value = in.readObject().asInstanceOf[B] + hash = computeHash(key) + } + + } + + private class HashMapCollision1[A,+B](private[HashMap] var hash: Int, var kvs: ListMap[A,B @uncheckedVariance]) extends HashMap[A,B] { + override def size = kvs.size + + override def get0(key: A, hash: Int, level: Int): Option[B] = + if (hash == this.hash) kvs.get(key) else None + + override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1)): HashMap[A, B1] = + if (hash == this.hash) new HashMapCollision1(hash, kvs.updated(key, value)) + else { + var m: HashMap[A,B1] = new HashTrieMap[A,B1](0,new Array[HashMap[A,B1]](0),0) + // might be able to save some ops here, but it doesn't seem to be worth it + for ((k,v) <- kvs) + m = m.updated0(k, this.hash, level, v, null) + m.updated0(key, hash, level, value, kv) + } + + override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = + if (hash == this.hash) { + val kvs1 = kvs - key + if (!kvs1.isEmpty) + new HashMapCollision1(hash, kvs1) + else + HashMap.empty[A,B] + } else this + + override def iterator: Iterator[(A,B)] = kvs.iterator + override def foreach[U](f: ((A, B)) => U): Unit = kvs.foreach(f) + + private def writeObject(out: java.io.ObjectOutputStream) { + // this cannot work - reading things in might produce different + // hash codes and remove the collision. however this is never called + // because no references to this class are ever handed out to client code + // and HashTrieMap serialization takes care of the situation + error("cannot serialize an immutable.HashMap where all items have the same 32-bit hash code") + //out.writeObject(kvs) + } + + private def readObject(in: java.io.ObjectInputStream) { + error("cannot deserialize an immutable.HashMap where all items have the same 32-bit hash code") + //kvs = in.readObject().asInstanceOf[ListMap[A,B]] + //hash = computeHash(kvs.) + } + + } + + + class HashTrieMap[A,+B](private var bitmap: Int, private var elems: Array[HashMap[A,B @uncheckedVariance]], + private var size0: Int) extends HashMap[A,B] { +/* + def this (level: Int, m1: HashMap1[A,B], m2: HashMap1[A,B]) = { + this(((m1.hash >>> level) & 0x1f) | ((m2.hash >>> level) & 0x1f), { + val idx1 = (m1.hash >>> level) & 0x1f + val idx2 = (m2.hash >>> level) & 0x1f + assert(idx1 != idx2, m1.hash + "==" + m2.hash + " at level " + level) // TODO + val elems = new Array[HashMap[A,B]](2) + if (idx1 < idx2) { + elems(0) = m1 + elems(1) = m2 + } else { + elems(0) = m2 + elems(1) = m1 + } + elems + }, 2) + } +*/ + override def size = size0 + + override def get0(key: A, hash: Int, level: Int): Option[B] = { + val index = (hash >>> level) & 0x1f + val mask = (1 << index) + if (bitmap == - 1) { + elems(index & 0x1f).get0(key, hash, level + 5) + } else if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask-1)) + // TODO: might be worth checking if sub is HashTrieMap (-> monomorphic call site) + elems(offset).get0(key, hash, level + 5) + } else + None + } + + override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1)): HashMap[A, B1] = { + val index = (hash >>> level) & 0x1f + val mask = (1 << index) + val offset = Integer.bitCount(bitmap & (mask-1)) + if ((bitmap & mask) != 0) { + val elemsNew = new Array[HashMap[A,B1]](elems.length) + Array.copy(elems, 0, elemsNew, 0, elems.length) + val sub = elems(offset) + // TODO: might be worth checking if sub is HashTrieMap (-> monomorphic call site) + val subNew = sub.updated0(key, hash, level + 5, value, kv) + elemsNew(offset) = subNew + new HashTrieMap(bitmap, elemsNew, size + (subNew.size - sub.size)) + } else { + val elemsNew = new Array[HashMap[A,B1]](elems.length + 1) + Array.copy(elems, 0, elemsNew, 0, offset) + elemsNew(offset) = new HashMap1(key, hash, value, kv) + Array.copy(elems, offset, elemsNew, offset + 1, elems.length - offset) + val bitmapNew = bitmap | mask + new HashTrieMap(bitmapNew, elemsNew, size + 1) + } + } + + override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = { + val index = (hash >>> level) & 0x1f + val mask = (1 << index) + val offset = Integer.bitCount(bitmap & (mask-1)) + if (((bitmap >>> index) & 1) == 1) { + val elemsNew = new Array[HashMap[A,B]](elems.length) + Array.copy(elems, 0, elemsNew, 0, elems.length) + val sub = elems(offset) + // TODO: might be worth checking if sub is HashTrieMap (-> monomorphic call site) + val subNew = sub.removed0(key, hash, level + 5) + elemsNew(offset) = subNew + // TODO: handle shrinking + val sizeNew = size + (subNew.size - sub.size) + if (sizeNew > 0) + new HashTrieMap(bitmap, elemsNew, size + (subNew.size - sub.size)) + else + HashMap.empty[A,B] + } else { + this + } + } + +/* + override def iterator = { // TODO: optimize (use a stack to keep track of pos) + + def iter(m: HashTrieMap[A,B], k: => Stream[(A,B)]): Stream[(A,B)] = { + def horiz(elems: Array[HashMap[A,B]], i: Int, k: => Stream[(A,B)]): Stream[(A,B)] = { + if (i < elems.length) { + elems(i) match { + case m: HashTrieMap[A,B] => iter(m, horiz(elems, i+1, k)) + case m: HashMap1[A,B] => new Stream.Cons(m.ensurePair, horiz(elems, i+1, k)) + } + } else k + } + horiz(m.elems, 0, k) + } + iter(this, Stream.empty).iterator + } +*/ + + + override def iterator = new Iterator[(A,B)] { + private[this] var depth = 0 + private[this] var arrayStack = new Array[Array[HashMap[A,B]]](6) + private[this] var posStack = new Array[Int](6) + + private[this] var arrayD = elems + private[this] var posD = 0 + + private[this] var subIter: Iterator[(A,B)] = null // to traverse collision nodes + + def hasNext = (subIter ne null) || depth >= 0 + + def next: (A,B) = { + if (subIter ne null) { + val el = subIter.next + if (!subIter.hasNext) + subIter = null + el + } else + next0(arrayD, posD) + } + + @scala.annotation.tailrec private[this] def next0(elems: Array[HashMap[A,B]], i: Int): (A,B) = { + if (i == elems.length-1) { // reached end of level, pop stack + depth -= 1 + if (depth >= 0) { + arrayD = arrayStack(depth) + posD = posStack(depth) + arrayStack(depth) = null + } else { + arrayD = null + posD = 0 + } + } else + posD += 1 + + elems(i) match { + case m: HashTrieMap[A,B] => // push current pos onto stack and descend + if (depth >= 0) { + arrayStack(depth) = arrayD + posStack(depth) = posD + } + depth += 1 + arrayD = m.elems + posD = 0 + next0(m.elems, 0) + case m: HashMap1[A,B] => m.ensurePair + case m => + subIter = m.iterator + subIter.next + } + } + } + +/* + +import collection.immutable._ +def time(block: =>Unit) = { val t0 = System.nanoTime; block; println("elapsed: " + (System.nanoTime - t0)/1000000.0) } +var mOld = OldHashMap.empty[Int,Int] +var mNew = HashMap.empty[Int,Int] +time { for (i <- 0 until 100000) mOld = mOld.updated(i,i) } +time { for (i <- 0 until 100000) mOld = mOld.updated(i,i) } +time { for (i <- 0 until 100000) mOld = mOld.updated(i,i) } +time { for (i <- 0 until 100000) mNew = mNew.updated(i,i) } +time { for (i <- 0 until 100000) mNew = mNew.updated(i,i) } +time { for (i <- 0 until 100000) mNew = mNew.updated(i,i) } +time { mOld.iterator.foreach( p => ()) } +time { mOld.iterator.foreach( p => ()) } +time { mOld.iterator.foreach( p => ()) } +time { mNew.iterator.foreach( p => ()) } +time { mNew.iterator.foreach( p => ()) } +time { mNew.iterator.foreach( p => ()) } + +*/ + + + override def foreach[U](f: ((A, B)) => U): Unit = { + var i = 0; + while (i < elems.length) { + elems(i).foreach(f) + i += 1 + } + } + + + private def writeObject(out: java.io.ObjectOutputStream) { + // no out.defaultWriteObject() + out.writeInt(size) + foreach { p => + out.writeObject(p._1) + out.writeObject(p._2) + } + } + + private def readObject(in: java.io.ObjectInputStream) { + val size = in.readInt + var index = 0 + var m = HashMap.empty[A,B] + while (index < size) { + // TODO: optimize (use unsafe mutable update) + m = m + ((in.readObject.asInstanceOf[A], in.readObject.asInstanceOf[B])) + index += 1 + } + var tm = m.asInstanceOf[HashTrieMap[A,B]] + bitmap = tm.bitmap + elems = tm.elems + size0 = tm.size0 + } + + } + } diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index 2320187be9..16d4473de1 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -13,148 +13,353 @@ package scala.collection package immutable import generic._ +import annotation.unchecked.uncheckedVariance /** <p> - * This class implements immutable sets using a hash table. - * </p> - * <p> - * It is optimized for sequential accesses where the last updated table is - * accessed most often. It supports with reasonable efficiency accesses to - * previous versions of the table by keeping a change log that's regularly - * compacted. It needs to synchronize most methods, so it is less suitable - * for highly concurrent accesses. + * This class implements immutable sets using a hash trie. * </p> * * @note the builder of a hash set returns specialized representations EmptySet,Set1,..., Set4 * for sets of size <= 4. * * @author Martin Odersky + * @author Tiark Rompf * @version 2.8 * @since 2.3 */ -@serializable @SerialVersionUID(1L) +@serializable @SerialVersionUID(2L) class HashSet[A] extends Set[A] with GenericSetTemplate[A, HashSet] - with SetLike[A, HashSet[A]] - with mutable.FlatHashTable[A] { + with SetLike[A, HashSet[A]] { override def companion: GenericCompanion[HashSet] = HashSet - @transient protected var later: HashSet[A] = null - @transient protected var changedElem: A = _ - @transient protected var deleted: Boolean = _ - - def contains(elem: A): Boolean = synchronized { - var m = this - var cnt = 0 - while (m.later != null) { - if (elem == m.changedElem) return m.deleted - cnt += 1 - m = m.later - } - if (cnt > logLimit) makeCopy(m) - m.containsEntry(elem) - } + //class HashSet[A] extends Set[A] with SetLike[A, HashSet[A]] { - def + (elem: A): HashSet[A] = synchronized { - makeCopyIfUpdated() - if (containsEntry(elem)) this - else { - markUpdated(elem, false) - later addEntry elem - later - } - } + override def size: Int = 0 - def - (elem: A): HashSet[A] = synchronized { - makeCopyIfUpdated() - if (!containsEntry(elem)) this - else { - markUpdated(elem, true) - later removeEntry elem - later - } - } + override def empty = HashSet.empty[A] - override def size: Int = synchronized { - var m = this - var cnt = 0 - var s = 0 - while (m.later != null) { - if (m.deleted) s += 1 else s -= 1 - cnt += 1 - m = m.later - } - s += m.tableSize - if (cnt > logLimit) makeCopy(m) - s - } + def iterator: Iterator[A] = Iterator.empty - override def iterator = synchronized { - makeCopyIfUpdated() - // note need to cache because (later versions of) set might be mutated while elements are traversed. - val cached = new mutable.ArrayBuffer() ++= super.iterator - cached.iterator - } + override def foreach[U](f: A => U): Unit = { } - private def logLimit: Int = math.sqrt(table.length).toInt - - private def markUpdated(elem: A, del: Boolean) { - val lf = loadFactor - later = new HashSet[A] { - override def initialSize = 0 - /* We need to do this to avoid a reference to the outer HashMap */ - def _newLoadFactor = lf - override def loadFactor = _newLoadFactor - table = HashSet.this.table - tableSize = HashSet.this.tableSize - threshold = HashSet.this.threshold - } - changedElem = elem - deleted = del - } + def contains(e: A): Boolean = get0(e, computeHash(e), 0) - private def makeCopy(last: HashSet[A]) { - def undo(m: HashSet[A]) { - if (m.deleted) addEntry(m.changedElem) - else removeEntry(m.changedElem) - } - table = new scala.Array[AnyRef](last.table.length) - scala.Array.copy(last.table, 0, table, 0, table.length) - tableSize = last.tableSize - threshold = last.threshold - - // we need to work from the end of the list but non-tail-recursion - // potentially blows the stack, so instead we create a stack on the heap. - // See ticket #408. - val toUndo = new mutable.Stack[HashSet[A]] - toUndo pushAll ((Iterator iterate this)(_.later) takeWhile (_ ne last)) - toUndo foreach undo - later = null - } + override def + (e: A): HashSet[A] = updated0(e, computeHash(e), 0) - private def makeCopyIfUpdated() { - var m = this - while (m.later != null) m = m.later - if (m ne this) makeCopy(m) - } + override def + (elem1: A, elem2: A, elems: A*): HashSet[A] = + this + elem1 + elem2 ++ elems + // TODO: optimize (might be able to use mutable updates) - private def writeObject(s: java.io.ObjectOutputStream) { - serializeTo(s) - } + def - (e: A): HashSet[A] = + removed0(e, computeHash(e), 0) + + protected def elemHashCode(key: A) = if (key == null) 0 else key.hashCode() - private def readObject(in: java.io.ObjectInputStream) { - init(in, x => x) + protected final def improve(hcode: Int) = { + var h: Int = hcode + ~(hcode << 9) + h = h ^ (h >>> 14) + h = h + (h << 4) + h ^ (h >>> 10) } + + protected def computeHash(key: A) = improve(elemHashCode(key)) + + protected def get0(key: A, hash: Int, level: Int): Boolean = false + + protected def updated0(key: A, hash: Int, level: Int): HashSet[A] = + new HashSet.HashSet1(key, hash) + + + + protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = this + } +/* +object HashSet extends SetFactory[HashSet] { + implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A] + override def empty[A]: HashSet[A] = new HashSet +} +*/ + + /** A factory object for immutable HashSets. * * @author Martin Odersky + * @author Tiark Rompf * @version 2.8 * @since 2.3 */ object HashSet extends SetFactory[HashSet] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A] - override def empty[A]: HashSet[A] = new HashSet + override def empty[A]: HashSet[A] = EmptyHashSet.asInstanceOf[HashSet[A]] + + private object EmptyHashSet extends HashSet[Any] { + } + + // TODO: add HashSet2, HashSet3, ... + + class HashSet1[A](private[HashSet] var key: A, private[HashSet] var hash: Int) extends HashSet[A] { + override def size = 1 + + override def get0(key: A, hash: Int, level: Int): Boolean = + (hash == this.hash && key == this.key) + + override def updated0(key: A, hash: Int, level: Int): HashSet[A] = + if (hash == this.hash && key == this.key) this + else { + if (hash != this.hash) { + //new HashTrieSet[A](level+5, this, new HashSet1(key, hash)) + val m = new HashTrieSet[A](0,new Array[HashSet[A]](0),0) // TODO: could save array alloc + m.updated0(this.key, this.hash, level).updated0(key, hash, level) + } else { + // 32-bit hash collision (rare, but not impossible) + // wrap this in a HashTrieSet if called with level == 0 (otherwise serialization won't work) + if (level == 0) { + val elems = new Array[HashSet[A]](1) + elems(0) = new HashSetCollision1(hash, ListSet.empty + this.key + key) + new HashTrieSet[A](1 << ((hash >>> level) & 0x1f), elems, 2) + } else { + new HashSetCollision1(hash, ListSet.empty + this.key + key) + } + } + } + + override def removed0(key: A, hash: Int, level: Int): HashSet[A] = + if (hash == this.hash && key == this.key) HashSet.empty[A] else this + + override def iterator: Iterator[A] = Iterator(key) + override def foreach[U](f: A => U): Unit = f(key) + + private def writeObject(out: java.io.ObjectOutputStream) { + out.writeObject(key) + } + + private def readObject(in: java.io.ObjectInputStream) { + key = in.readObject().asInstanceOf[A] + hash = computeHash(key) + } + + } + + private class HashSetCollision1[A](private[HashSet] var hash: Int, var ks: ListSet[A]) extends HashSet[A] { + override def size = ks.size + + override def get0(key: A, hash: Int, level: Int): Boolean = + if (hash == this.hash) ks.contains(key) else false + + override def updated0(key: A, hash: Int, level: Int): HashSet[A] = + if (hash == this.hash) new HashSetCollision1(hash, ks + key) + else { + var m: HashSet[A] = new HashTrieSet[A](0,new Array[HashSet[A]](0),0) + // might be able to save some ops here, but it doesn't seem to be worth it + for (k <- ks) + m = m.updated0(k, this.hash, level) + m.updated0(key, hash, level) + } + + override def removed0(key: A, hash: Int, level: Int): HashSet[A] = + if (hash == this.hash) { + val ks1 = ks - key + if (!ks1.isEmpty) + new HashSetCollision1(hash, ks1) + else + HashSet.empty[A] + } else this + + override def iterator: Iterator[A] = ks.iterator + override def foreach[U](f: A => U): Unit = ks.foreach(f) + + private def writeObject(out: java.io.ObjectOutputStream) { + // this cannot work - reading things in might produce different + // hash codes and remove the collision. however this is never called + // because no references to this class are ever handed out to client code + // and HashTrieSet serialization takes care of the situation + error("cannot serialize an immutable.HashSet where all items have the same 32-bit hash code") + //out.writeObject(kvs) + } + + private def readObject(in: java.io.ObjectInputStream) { + error("cannot deserialize an immutable.HashSet where all items have the same 32-bit hash code") + //kvs = in.readObject().asInstanceOf[ListSet[A]] + //hash = computeHash(kvs.) + } + + } + + + class HashTrieSet[A](private var bitmap: Int, private var elems: Array[HashSet[A]], + private var size0: Int) extends HashSet[A] { + + override def size = size0 + + override def get0(key: A, hash: Int, level: Int): Boolean = { + val index = (hash >>> level) & 0x1f + val mask = (1 << index) + if (bitmap == - 1) { + elems(index & 0x1f).get0(key, hash, level + 5) + } else if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask-1)) + // TODO: might be worth checking if sub is HashTrieSet (-> monomorphic call site) + elems(offset).get0(key, hash, level + 5) + } else + false + } + + override def updated0(key: A, hash: Int, level: Int): HashSet[A] = { + val index = (hash >>> level) & 0x1f + val mask = (1 << index) + val offset = Integer.bitCount(bitmap & (mask-1)) + if ((bitmap & mask) != 0) { + val elemsNew = new Array[HashSet[A]](elems.length) + Array.copy(elems, 0, elemsNew, 0, elems.length) + val sub = elems(offset) + // TODO: might be worth checking if sub is HashTrieSet (-> monomorphic call site) + val subNew = sub.updated0(key, hash, level + 5) + elemsNew(offset) = subNew + new HashTrieSet(bitmap, elemsNew, size + (subNew.size - sub.size)) + } else { + val elemsNew = new Array[HashSet[A]](elems.length + 1) + Array.copy(elems, 0, elemsNew, 0, offset) + elemsNew(offset) = new HashSet1(key, hash) + Array.copy(elems, offset, elemsNew, offset + 1, elems.length - offset) + val bitmapNew = bitmap | mask + new HashTrieSet(bitmapNew, elemsNew, size + 1) + } + } + + override def removed0(key: A, hash: Int, level: Int): HashSet[A] = { + val index = (hash >>> level) & 0x1f + val mask = (1 << index) + val offset = Integer.bitCount(bitmap & (mask-1)) + if (((bitmap >>> index) & 1) == 1) { + val elemsNew = new Array[HashSet[A]](elems.length) + Array.copy(elems, 0, elemsNew, 0, elems.length) + val sub = elems(offset) + // TODO: might be worth checking if sub is HashTrieSet (-> monomorphic call site) + val subNew = sub.removed0(key, hash, level + 5) + elemsNew(offset) = subNew + // TODO: handle shrinking + val sizeNew = size + (subNew.size - sub.size) + if (sizeNew > 0) + new HashTrieSet(bitmap, elemsNew, size + (subNew.size - sub.size)) + else + HashSet.empty[A] + } else { + this + } + } + + override def iterator = new Iterator[A] { + private[this] var depth = 0 + private[this] var arrayStack = new Array[Array[HashSet[A]]](6) + private[this] var posStack = new Array[Int](6) + + private[this] var arrayD = elems + private[this] var posD = 0 + + private[this] var subIter: Iterator[A] = null // to traverse collision nodes + + def hasNext = (subIter ne null) || depth >= 0 + + def next: A = { + if (subIter ne null) { + val el = subIter.next + if (!subIter.hasNext) + subIter = null + el + } else + next0(arrayD, posD) + } + + @scala.annotation.tailrec private[this] def next0(elems: Array[HashSet[A]], i: Int): A = { + if (i == elems.length-1) { // reached end of level, pop stack + depth -= 1 + if (depth >= 0) { + arrayD = arrayStack(depth) + posD = posStack(depth) + arrayStack(depth) = null + } else { + arrayD = null + posD = 0 + } + } else + posD += 1 + + elems(i) match { + case m: HashTrieSet[A] => // push current pos onto stack and descend + if (depth >= 0) { + arrayStack(depth) = arrayD + posStack(depth) = posD + } + depth += 1 + arrayD = m.elems + posD = 0 + next0(m.elems, 0) + case m: HashSet1[A] => m.key + case m => + subIter = m.iterator + subIter.next + } + } + } + +/* + +import collection.immutable._ +def time(block: =>Unit) = { val t0 = System.nanoTime; block; println("elapsed: " + (System.nanoTime - t0)/1000000.0) } +var mOld = OldHashSet.empty[Int] +var mNew = HashSet.empty[Int] +time { for (i <- 0 until 100000) mOld = mOld + i } +time { for (i <- 0 until 100000) mOld = mOld + i } +time { for (i <- 0 until 100000) mOld = mOld + i } +time { for (i <- 0 until 100000) mNew = mNew + i } +time { for (i <- 0 until 100000) mNew = mNew + i } +time { for (i <- 0 until 100000) mNew = mNew + i } +time { mOld.iterator.foreach( p => ()) } +time { mOld.iterator.foreach( p => ()) } +time { mOld.iterator.foreach( p => ()) } +time { mNew.iterator.foreach( p => ()) } +time { mNew.iterator.foreach( p => ()) } +time { mNew.iterator.foreach( p => ()) } + +*/ + + + override def foreach[U](f: A => U): Unit = { + var i = 0; + while (i < elems.length) { + elems(i).foreach(f) + i += 1 + } + } + + + private def writeObject(out: java.io.ObjectOutputStream) { + // no out.defaultWriteObject() + out.writeInt(size) + foreach { e => + out.writeObject(e) + } + } + + private def readObject(in: java.io.ObjectInputStream) { + val size = in.readInt + var index = 0 + var m = HashSet.empty[A] + while (index < size) { + // TODO: optimize (use unsafe mutable update) + m = m + in.readObject.asInstanceOf[A] + index += 1 + } + var tm = m.asInstanceOf[HashTrieSet[A]] + bitmap = tm.bitmap + elems = tm.elems + size0 = tm.size0 + } + + } + } diff --git a/src/library/scala/collection/immutable/IndexedSeq.scala b/src/library/scala/collection/immutable/IndexedSeq.scala index 0d7b1b0d23..3f29052808 100644 --- a/src/library/scala/collection/immutable/IndexedSeq.scala +++ b/src/library/scala/collection/immutable/IndexedSeq.scala @@ -14,8 +14,9 @@ package immutable import generic._ import mutable.{ArrayBuffer, Builder} -/** A subtrait of <code>collection.IndexedSeq</code> which represents sequences +/** A subtrait of <code>collection.IndexedSeq</code> which represents indexed sequences * that cannot be mutated. + * $indexedSeqInfo * * @since 2.8 */ @@ -36,5 +37,5 @@ object IndexedSeq extends SeqFactory[IndexedSeq] { def apply(idx: Int) = buf.apply(idx) } implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, IndexedSeq[A]] = new GenericCanBuildFrom[A] - def newBuilder[A]: Builder[A, IndexedSeq[A]] = new ArrayBuffer[A] mapResult (buf => new Impl(buf)) -}
\ No newline at end of file + def newBuilder[A]: Builder[A, IndexedSeq[A]] = Vector.newBuilder[A] +} diff --git a/src/library/scala/collection/immutable/IntMap.scala b/src/library/scala/collection/immutable/IntMap.scala index 52451e6012..62309a9f48 100644 --- a/src/library/scala/collection/immutable/IntMap.scala +++ b/src/library/scala/collection/immutable/IntMap.scala @@ -151,7 +151,10 @@ import IntMap._ * <a href="http://citeseer.ist.psu.edu/okasaki98fast.html">Fast Mergeable Integer Maps</a> * by Okasaki and Gill. Essentially a trie based on binary digits of the the integers. * + * Note: This class is as of 2.8 largely superseded by HashMap. + * * @since 2.7 + * */ sealed abstract class IntMap[+T] extends Map[Int, T] with MapLike[Int, T, IntMap[T]] { override def empty: IntMap[T] = IntMap.Nil; @@ -357,7 +360,7 @@ sealed abstract class IntMap[+T] extends Map[Int, T] with MapLike[Int, T, IntMap } /** - * Forms the intersection of these two maps with a combinining function. The resulting map is + * Forms the intersection of these two maps with a combining function. The resulting map is * a map that has only keys present in both maps and has values produced from the original mappings * by combining them with f. * diff --git a/src/library/scala/collection/immutable/LinearSeq.scala b/src/library/scala/collection/immutable/LinearSeq.scala index c1efea037c..016afd4508 100644 --- a/src/library/scala/collection/immutable/LinearSeq.scala +++ b/src/library/scala/collection/immutable/LinearSeq.scala @@ -17,7 +17,7 @@ import mutable.Builder /** A subtrait of <code>collection.LinearSeq</code> which represents sequences * that cannot be mutated. - * + * $linearSeqInfo * @since 2.8 */ trait LinearSeq[+A] extends Seq[A] diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 2088f3ac78..2b91ab8852 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -46,7 +46,7 @@ import annotation.tailrec sealed abstract class List[+A] extends LinearSeq[A] with Product with GenericTraversableTemplate[A, List] - with LinearSeqLike[A, List[A]] { + with LinearSeqOptimized[A, List[A]] { override def companion: GenericCompanion[List] = List import scala.collection.{Iterable, Traversable, Seq, IndexedSeq} @@ -61,7 +61,7 @@ sealed abstract class List[+A] extends LinearSeq[A] * @param x the element to prepend. * @return a list which contains `x` as first element and * which continues with this list. - * @ex `1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)` + * @example `1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)` * @usecase def ::(x: A): List[A] */ def ::[B >: A] (x: B): List[B] = @@ -71,7 +71,7 @@ sealed abstract class List[+A] extends LinearSeq[A] * @param prefix The list elements to prepend. * @return a list resulting from the concatenation of the given * list `prefix` and this list. - * @ex `List(1, 2) ::: List(3, 4) = List(3, 4).:::(List(1, 2)) = List(1, 2, 3, 4)` + * @example `List(1, 2) ::: List(3, 4) = List(3, 4).:::(List(1, 2)) = List(1, 2, 3, 4)` * @usecase def :::(prefix: List[A]): List[A] */ def :::[B >: A](prefix: List[B]): List[B] = @@ -133,16 +133,18 @@ sealed abstract class List[+A] extends LinearSeq[A] loop(this) } - // Overridden methods from IterableLike or overloaded variants of such methods + // Overridden methods from IterableLike and SeqLike or overloaded variants of such methods - override def ++[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = { + override def ++[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = { val b = bf(this) if (b.isInstanceOf[ListBuffer[_]]) (this ::: that.toList).asInstanceOf[That] else super.++(that) } - override def ++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = - this ++ that.toList + override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[List[A], B, That]): That = bf match { + case _: List.GenericCanBuildFrom[_] => (elem :: this).asInstanceOf[That] + case _ => super.+:(elem)(bf) + } override def toList: List[A] = this @@ -288,6 +290,9 @@ sealed abstract class List[+A] extends LinearSeq[A] b.toList } + @deprecated("use `distinct' instead") + def removeDuplicates: List[A] = distinct + /** <p> * Sort the list according to the comparison function * `lt(e1: a, e2: a) => Boolean`, @@ -299,7 +304,7 @@ sealed abstract class List[+A] extends LinearSeq[A] * @param lt the comparison function * @return a list sorted according to the comparison function * `lt(e1: a, e2: a) => Boolean`. - * @ex <pre> + * @example <pre> * List("Steve", "Tom", "John", "Bob") * .sort((e1, e2) => (e1 compareTo e2) < 0) = * List("Bob", "John", "Steve", "Tom")</pre> @@ -383,7 +388,7 @@ case object Nil extends List[Nothing] { throw new NoSuchElementException("head of empty list") override def tail: List[Nothing] = throw new UnsupportedOperationException("tail of empty list") - // Removal of equals method here might lead to an infinite recusion similar to IntMap.equals. + // Removal of equals method here might lead to an infinite recursion similar to IntMap.equals. override def equals(that: Any) = that match { case that1: Seq[_] => that1.isEmpty case _ => false @@ -539,7 +544,7 @@ object List extends SeqFactory[List] { * Returns the `Left` values in the given `Iterable` * of `Either`s. */ - @deprecated("use `xs partialMap { case Left(x: A) => x }' instead of `List.lefts(xs)'") + @deprecated("use `xs collect { case Left(x: A) => x }' instead of `List.lefts(xs)'") def lefts[A, B](es: Iterable[Either[A, B]]) = es.foldRight[List[A]](Nil)((e, as) => e match { case Left(a) => a :: as @@ -549,7 +554,7 @@ object List extends SeqFactory[List] { /** * Returns the `Right` values in the given`Iterable` of `Either`s. */ - @deprecated("use `xs partialMap { case Right(x: B) => x }' instead of `List.rights(xs)'") + @deprecated("use `xs collect { case Right(x: B) => x }' instead of `List.rights(xs)'") def rights[A, B](es: Iterable[Either[A, B]]) = es.foldRight[List[B]](Nil)((e, bs) => e match { case Left(_) => bs @@ -561,9 +566,9 @@ object List extends SeqFactory[List] { * @param xs the iterable of Eithers to separate * @return a pair of lists. */ - @deprecated("use `Either.separate' instead") + @deprecated("use `(for (Left(x) <- es) yield x, for (Right(x) <- es) yield x)` instead") def separate[A,B](es: Iterable[Either[A, B]]): (List[A], List[B]) = - es.foldRight[(List[A], List[B])]((Nil, Nil)) { + es.foldRight[(List[A], List[B])]((Nil, Nil)) { case (Left(a), (lefts, rights)) => (a :: lefts, rights) case (Right(b), (lefts, rights)) => (lefts, b :: rights) } @@ -590,7 +595,7 @@ object List extends SeqFactory[List] { * * @param arr the array to convert * @param start the first index to consider - * @param len the lenght of the range to convert + * @param len the length of the range to convert * @return a list that contains the same elements than `arr` * in the same order */ diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala index 0f66a1f452..d8e3e0856b 100644 --- a/src/library/scala/collection/immutable/ListMap.scala +++ b/src/library/scala/collection/immutable/ListMap.scala @@ -30,7 +30,7 @@ object ListMap extends ImmutableMapFactory[ListMap] { * directly, or by applying the function <code>ListMap.empty</code>. * * @author Matthias Zenger - * @author Martin Oderskty + * @author Martin Odersky * @version 2.0, 01/01/2007 * @since 1 */ diff --git a/src/library/scala/collection/immutable/LongMap.scala b/src/library/scala/collection/immutable/LongMap.scala index e527712475..0d74e41cec 100644 --- a/src/library/scala/collection/immutable/LongMap.scala +++ b/src/library/scala/collection/immutable/LongMap.scala @@ -138,6 +138,8 @@ import LongMap._; * <a href="http://citeseer.ist.psu.edu/okasaki98fast.html">Fast Mergeable Long Maps</a> * by Okasaki and Gill. Essentially a trie based on binary digits of the the integers. * + * Note: This class is as of 2.8 largely superseded by HashMap. + * * @since 2.7 */ sealed abstract class LongMap[+T] extends Map[Long, T] with MapLike[Long, T, LongMap[T]] { @@ -344,7 +346,7 @@ sealed abstract class LongMap[+T] extends Map[Long, T] with MapLike[Long, T, Lon } /** - * Forms the intersection of these two maps with a combinining function. The resulting map is + * Forms the intersection of these two maps with a combining function. The resulting map is * a map that has only keys present in both maps and has values produced from the original mappings * by combining them with f. * diff --git a/src/library/scala/collection/immutable/Map.scala b/src/library/scala/collection/immutable/Map.scala index f42794d09e..b5a852683a 100644 --- a/src/library/scala/collection/immutable/Map.scala +++ b/src/library/scala/collection/immutable/Map.scala @@ -44,7 +44,7 @@ trait Map[A, +B] extends Iterable[(A, B)] object Map extends ImmutableMapFactory[Map] { implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B] - def empty[A, B]: Map[A, B] = new EmptyMap[A, B] + def empty[A, B]: Map[A, B] = EmptyMap.asInstanceOf[Map[A, B]] class WithDefault[A, +B](underlying: Map[A, B], d: A => B) extends Map[A, B] { override def size = underlying.size @@ -58,12 +58,22 @@ object Map extends ImmutableMapFactory[Map] { } @serializable - class EmptyMap[A, +B] extends Map[A, B] { + private object EmptyMap extends Map[Any, Nothing] { + override def size: Int = 0 + def get(key: Any): Option[Nothing] = None + def iterator: Iterator[(Any, Nothing)] = Iterator.empty + override def updated [B1] (key: Any, value: B1): Map[Any, B1] = new Map1(key, value) + def + [B1](kv: (Any, B1)): Map[Any, B1] = updated(kv._1, kv._2) + def - (key: Any): Map[Any, Nothing] = this + } + + @serializable @deprecated("use `Map.empty' instead") + class EmptyMap[A,B] extends Map[A,B] { override def size: Int = 0 def get(key: A): Option[B] = None def iterator: Iterator[(A, B)] = Iterator.empty - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = new Map1(key, value) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) + override def updated [B1] (key: A, value: B1): Map[A, B1] = new Map1(key, value) + def + [B1](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) def - (key: A): Map[A, B] = this } @@ -78,7 +88,7 @@ object Map extends ImmutableMapFactory[Map] { else new Map2(key1, value1, key, value) def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) def - (key: A): Map[A, B] = - if (key == key1) empty else this + if (key == key1) Map.empty else this override def foreach[U](f: ((A, B)) => U): Unit = { f((key1, value1)) } diff --git a/src/library/scala/collection/immutable/MapLike.scala b/src/library/scala/collection/immutable/MapLike.scala index a06bce1038..662321bb0c 100644 --- a/src/library/scala/collection/immutable/MapLike.scala +++ b/src/library/scala/collection/immutable/MapLike.scala @@ -41,8 +41,9 @@ import generic._ * @version 2.8 * @since 2.8 */ -trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] extends scala.collection.MapLike[A, B, This] { -self => +trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] + extends scala.collection.MapLike[A, B, This] +{ self => import scala.collection.Traversable @@ -74,16 +75,36 @@ self => * * @param elems the traversable object. */ - override def ++[B1 >: B](elems: Traversable[(A, B1)]): immutable.Map[A, B1] = - ((repr: immutable.Map[A, B1]) /: elems) (_ + _) + override def ++[B1 >: B](xs: TraversableOnce[(A, B1)]): immutable.Map[A, B1] = + ((repr: immutable.Map[A, B1]) /: xs) (_ + _) - /** Adds a number of elements provided by an iterator - * and returns a new collection with the added elements. - * - * @param iter the iterator + /** Filters this map by retaining only keys satisfying a predicate. + * @param p the predicate used to test keys + * @return an immutable map consisting only of those key value pairs of this map where the key satisfies + * the predicate `p`. The resulting map wraps the original map without copying any elements. */ - override def ++[B1 >: B] (iter: Iterator[(A, B1)]): immutable.Map[A, B1] = - ((repr: immutable.Map[A, B1]) /: iter) (_ + _) + override def filterKeys(p: A => Boolean): Map[A, B] = new DefaultMap[A, B] { + override def foreach[C](f: ((A, B)) => C): Unit = for (kv <- self) if (p(kv._1)) f(kv) + def iterator = self.iterator.filter(kv => p(kv._1)) + override def contains(key: A) = self.contains(key) && p(key) + def get(key: A) = if (!p(key)) None else self.get(key) + } + + /** Transforms this map by applying a function to every retrieved value. + * @param d the function used to transform values of this map. + * @return an immutable map which maps every key of this map + * to `f(this(key))`. The resulting map wraps the original map without copying any elements. + */ + /** A map view resulting from applying a given function `f` to each value + * associated with a key in this map. + */ + override def mapValues[C](f: B => C): Map[A, C] = new DefaultMap[A, C] { + override def foreach[D](g: ((A, C)) => D): Unit = for ((k, v) <- self) g((k, f(v))) + def iterator = for ((k, v) <- self.iterator) yield (k, f(v)) + override def size = self.size + override def contains(key: A) = self.contains(key) + def get(key: A) = self.get(key).map(f) + } /** This function transforms all the values of mappings contained * in this map with function <code>f</code>. @@ -97,23 +118,6 @@ self => b.result } - /** Returns a new map with all key/value pairs for which the predicate - * <code>p</code> returns <code>true</code>. - * - * @param p A predicate over key-value pairs - * @note This method works by successively removing elements fro which the - * predicate is false from this set. - * If removal is slow, or you expect that most elements of the set$ - * will be removed, you might consider using <code>filter</code> - * with a negated predicate instead. - */ - override def filterNot(p: ((A, B)) => Boolean): This = { - var res: This = repr - for (kv <- this) - if (p(kv)) res = (res - kv._1).asInstanceOf[This] // !!! concrete overrides abstract problem - res - } - @deprecated("use `updated' instead") def update[B1 >: B](key: A, value: B1): immutable.Map[A, B1] = updated(key, value).asInstanceOf[immutable.Map[A, B1]] } diff --git a/src/library/scala/collection/immutable/MapProxy.scala b/src/library/scala/collection/immutable/MapProxy.scala index 0ef7aa620a..371af042e7 100644 --- a/src/library/scala/collection/immutable/MapProxy.scala +++ b/src/library/scala/collection/immutable/MapProxy.scala @@ -37,5 +37,9 @@ trait MapProxy[A, +B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]] override def + [B1 >: B](kv: (A, B1)): Map[A, B1] = newProxy(self + kv) override def + [B1 >: B](elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *) = newProxy(self.+(elem1, elem2, elems: _*)) + override def -(key: A) = newProxy(self - key) + + override def filterKeys(p: A => Boolean) = self.filterKeys(p) + override def mapValues[C](f: B => C) = self.mapValues(f) } diff --git a/src/library/scala/collection/immutable/NumericRange.scala b/src/library/scala/collection/immutable/NumericRange.scala index 5514f7a24d..d3e4558884 100644 --- a/src/library/scala/collection/immutable/NumericRange.scala +++ b/src/library/scala/collection/immutable/NumericRange.scala @@ -34,11 +34,18 @@ import generic._ * @version 2.8 */ @serializable -abstract class NumericRange[+T] +abstract class NumericRange[T] (val start: T, val end: T, val step: T, val isInclusive: Boolean) (implicit num: Integral[T]) extends IndexedSeq[T] { + /** Note that NumericRange must be invariant so that constructs + * such as + * + * 1L to 10 by 5 + * + * do not infer the range type as AnyVal. + */ import num._ private def fail(msg: String) = throw new IllegalArgumentException(msg) @@ -56,20 +63,18 @@ extends IndexedSeq[T] // inclusive/exclusiveness captured this way because we do not have any // concept of a "unit", we can't just add an epsilon to an exclusive // endpoint to make it inclusive (as can be done with the int-based Range.) - protected def limitTest[U >: T](x: U)(implicit unum: Integral[U]) = - !isEmpty && isInclusive && unum.equiv(x, end) + protected def limitTest(x: T) = !isEmpty && isInclusive && equiv(x, end) protected def underlying = collection.immutable.IndexedSeq.empty[T] /** Create a new range with the start and end values of this range and * a new <code>step</code>. */ - def by[U >: T](newStep: U)(implicit unum: Integral[U]): NumericRange[U] = - copy(start, end, newStep) + def by(newStep: T): NumericRange[T] = copy(start, end, newStep) /** Create a copy of this range. */ - def copy[U >: T](start: U, end: U, step: U)(implicit unum: Integral[U]): NumericRange[U] + def copy(start: T, end: T, step: T): NumericRange[T] override def foreach[U](f: T => U) { var i = start @@ -115,9 +120,8 @@ extends IndexedSeq[T] } // a well-typed contains method. - def containsTyped[U >: T](x: U)(implicit unum: Integral[U]): Boolean = { - import unum._ - def divides(d: U, by: U) = equiv(d % by, zero) + def containsTyped(x: T): Boolean = { + def divides(d: T, by: T) = equiv(d % by, zero) limitTest(x) || ( if (step > zero) @@ -154,7 +158,7 @@ extends IndexedSeq[T] // XXX This may be incomplete. new NumericRange[A](fm(start), fm(end), fm(step), isInclusive) { - def copy[A1 >: A](start: A1, end: A1, step: A1)(implicit unum: Integral[A1]): NumericRange[A1] = + def copy(start: A, end: A, step: A): NumericRange[A] = if (isInclusive) NumericRange.inclusive(start, end, step) else NumericRange(start, end, step) @@ -162,8 +166,7 @@ extends IndexedSeq[T] override def foreach[U](f: A => U) { underlyingRange foreach (x => f(fm(x))) } override def isEmpty = underlyingRange.isEmpty override def apply(idx: Int): A = fm(underlyingRange(idx)) - override def containsTyped[A1 >: A](el: A1)(implicit unum: Integral[A1]) = - underlyingRange exists (x => fm(x) == el) + override def containsTyped(el: A) = underlyingRange exists (x => fm(x) == el) } } @@ -200,7 +203,7 @@ extends IndexedSeq[T] object NumericRange { class Inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T]) extends NumericRange(start, end, step, true) { - def copy[U >: T](start: U, end: U, step: U)(implicit unum: Integral[U]): Inclusive[U] = + def copy(start: T, end: T, step: T): Inclusive[T] = NumericRange.inclusive(start, end, step) def exclusive: Exclusive[T] = NumericRange(start, end, step) @@ -208,7 +211,7 @@ object NumericRange { class Exclusive[T](start: T, end: T, step: T)(implicit num: Integral[T]) extends NumericRange(start, end, step, false) { - def copy[U >: T](start: U, end: U, step: U)(implicit unum: Integral[U]): Exclusive[U] = + def copy(start: T, end: T, step: T): Exclusive[T] = NumericRange(start, end, step) def inclusive: Inclusive[T] = NumericRange.inclusive(start, end, step) diff --git a/src/library/scala/collection/immutable/PagedSeq.scala b/src/library/scala/collection/immutable/PagedSeq.scala index bde8d67ffe..bd12502520 100644 --- a/src/library/scala/collection/immutable/PagedSeq.scala +++ b/src/library/scala/collection/immutable/PagedSeq.scala @@ -202,7 +202,7 @@ private class Page[T: ClassManifest](val num: Int) { /** The next page in the sequence */ var next : Page[T] = null - /** A later page in the sequence, serves a cachae for pointing to last page */ + /** A later page in the sequence, serves a cache for pointing to last page */ var later : Page[T] = this /** The number of characters read into this page */ @@ -218,11 +218,11 @@ private class Page[T: ClassManifest](val num: Int) { /** The index of the first character in this page relative to the whole sequence */ final def start = num * PageSize - /** The index of the character following the last charcater in this page relative + /** The index of the character following the last character in this page relative * to the whole sequence */ final def end = start + filled - /** The currently last page in the sequence; might change as more charcaters are appended */ + /** The currently last page in the sequence; might change as more characters are appended */ final def latest: Page[T] = { if (later.next != null) later = later.next.latest later diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala index 9957f90ab3..02d344ceea 100644 --- a/src/library/scala/collection/immutable/Queue.scala +++ b/src/library/scala/collection/immutable/Queue.scala @@ -12,12 +12,8 @@ package scala.collection package immutable -import scala.annotation.tailrec - -object Queue { - val Empty: Queue[Nothing] = new Queue(Nil, Nil) - def apply[A](elems: A*) = new Queue(Nil, elems.toList) -} +import generic._ +import mutable.{ Builder, ListBuffer } /** <code>Queue</code> objects implement data structures that allow to * insert and retrieve elements in a first-in-first-out (FIFO) manner. @@ -28,10 +24,13 @@ object Queue { */ @serializable @SerialVersionUID(-7622936493364270175L) -class Queue[+A] protected( - protected val in: List[A], - protected val out: List[A]) extends Seq[A] -{ +class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) + extends Seq[A] + with GenericTraversableTemplate[A, Queue] + with SeqLike[A, Queue[A]] { + + override def companion: GenericCompanion[Queue] = Queue + /** Returns the <code>n</code>-th element of this queue. * The first element is at position 0. * @@ -127,3 +126,13 @@ class Queue[+A] protected( */ override def toString() = mkString("Queue(", ", ", ")") } + +object Queue extends SeqFactory[Queue] { + implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Queue[A]] = new GenericCanBuildFrom[A] + def newBuilder[A]: Builder[A, Queue[A]] = new ListBuffer[A] mapResult (x => new Queue[A](Nil, x.toList)) + override def empty[A]: Queue[A] = new Queue[A](Nil, Nil) + override def apply[A](xs: A*): Queue[A] = new Queue[A](Nil, xs.toList) + + @deprecated("Use Queue.empty instead") + val Empty: Queue[Nothing] = Queue() +} diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 47a97664de..43b11b67be 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -39,25 +39,34 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int] def isInclusive = false - protected def limit = end - override def foreach[U](f: Int => U) { - var i = start - while (if (step > 0) i < limit else i > limit) { + if (fullLength > 0) { + val last = this.last + var i = start + while (i != last) { + f(i) + i += step + } f(i) - i += step } } - lazy val length: Int = { - def plen(start: Int, limit: Int, step: Int) = - if (limit <= start) 0 else (limit - start - 1) / step + 1 - if (step > 0) plen(start, limit, step) - else plen(limit, start, -step) + override def last: Int = if (step == 1 || step == -1) { + end - step + } else { + val size = end.toLong - start.toLong + val inclusiveLast = (size / step.toLong * step.toLong + start.toLong).toInt + if (size % step == 0) inclusiveLast - step else inclusiveLast } - final override def isEmpty = - if (step > 0) start >= limit else start <= limit + def length: Int = fullLength.toInt + + protected def fullLength: Long = if (end > start == step > 0 && start != end) + ((last.toLong - start.toLong) / step.toLong + 1) + else + 0 + + final override def isEmpty = length == 0 @inline final def apply(idx: Int): Int = { @@ -66,12 +75,19 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int] } // take and drop have to be tolerant of large values without overflowing - private def locationAfterN(n: Int) = start + step * (0 max n min length) + private def locationAfterN(n: Int) = if (n > 0) { + if (step > 0) + ((start.toLong + step.toLong * n.toLong) min last.toLong).toInt + else + ((start.toLong + step.toLong * n.toLong) max last.toLong).toInt + } else { + start + } - final override def take(n: Int): Range = { - val limit1 = locationAfterN(n) - if (step > 0) Range(start, limit1 min limit, step) - else Range(start, limit1 max limit, step) + final override def take(n: Int): Range = if (n > 0 && length > 0) { + Range(start, locationAfterN(n - 1), step).inclusive + } else { + Range(start, start, step) } final override def drop(n: Int): Range = @@ -85,7 +101,11 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int] private def skip(p: Int => Boolean): Int = { var s = start - while ((if (step > 0) s < limit else s > limit) && p(s)) s += step + if (length > 0) { + val last = this.last + while ((if (step > 0) s <= last else s >= last) && p(s)) + s += step + } s } @@ -103,16 +123,18 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int] final override def dropRight(n: Int): Range = take(length - n) - final override def reverse: Range = new Range.Inclusive(last, start, -step) + final override def reverse: Range = if (length > 0) new Range.Inclusive(last, start, -step) else this /** Make range inclusive. - * @pre if (step > 0) end != MaxInt else end != MinInt */ def inclusive = new Range.Inclusive(start, end, step) - def contains(x: Int): Boolean = - if (step > 0) start <= x && x < limit && (x - start) % step == 0 - else start >= x && x > limit && (start - x) % step == 0 + final def contains(x: Int): Boolean = if (length > 0) { + if (step > 0) start <= x && x <= last && (x - start) % step == 0 + else start >= x && x >= last && (start - x) % step == 0 + } else { + false + } override def equals(other: Any) = other match { case x: Range => @@ -139,37 +161,45 @@ object Range { class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) { override def isInclusive = true - override protected val limit = end + math.signum(step) override protected def copy(start: Int, end: Int, step: Int): Range = new Inclusive(start, end, step) + override def last: Int = if (step == 1 || step == -1) + end + else + ((end.toLong - start.toLong) / step.toLong * step.toLong + start.toLong).toInt + protected override def fullLength: Long = if (end > start == step > 0 || start == end) + ((last.toLong - start.toLong) / step.toLong + 1) + else + 0 } - /** Make a range from `start` until `end` (exclusive) with step value 1. + /** Make a range from `start` until `end` (exclusive) with given step value. + * @note step != 0 */ def apply(start: Int, end: Int, step: Int): Range = new Range(start, end, step) /** Make an range from `start` to `end` inclusive with step value 1. - * @pre end != MaxInt */ def apply(start: Int, end: Int): Range with ByOne = new Range(start, end, 1) with ByOne /** Make an inclusive range from start to end with given step value. - * @pre step != 0 - * @pre if (step > 0) end != MaxInt else end != MinInt + * @note step != 0 */ def inclusive(start: Int, end: Int, step: Int): Range.Inclusive = new Inclusive(start, end, step) /** Make an inclusive range from start to end with step value 1. - * @pre end != MaxInt */ def inclusive(start: Int, end: Int): Range.Inclusive with ByOne = new Inclusive(start, end, 1) with ByOne trait ByOne extends Range { override final def foreach[U](f: Int => U) { - var i = start - val l = limit - while (i < l) { + if (length > 0) { + val last = this.last + var i = start + while (i != last) { + f(i) + i += 1 + } f(i) - i += 1 } } } diff --git a/src/library/scala/collection/immutable/RedBlack.scala b/src/library/scala/collection/immutable/RedBlack.scala index dfb34552cd..e7b4f3c978 100644 --- a/src/library/scala/collection/immutable/RedBlack.scala +++ b/src/library/scala/collection/immutable/RedBlack.scala @@ -12,7 +12,8 @@ package scala.collection package immutable -/** +/** An base class containing the implementations for TreeMaps and TreeSets + * * @since 2.3 */ @serializable @SerialVersionUID(8691885935445612921L) diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala index be1e86bcdd..1bec1b9a48 100644 --- a/src/library/scala/collection/immutable/Set.scala +++ b/src/library/scala/collection/immutable/Set.scala @@ -41,12 +41,22 @@ trait Set[A] extends Iterable[A] object Set extends SetFactory[Set] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A] - override def empty[A]: Set[A] = new EmptySet[A] + override def empty[A]: Set[A] = EmptySet.asInstanceOf[Set[A]] private val hashSeed = "Set".hashCode /** An optimized representation for immutable empty sets */ @serializable + private object EmptySet extends Set[Any] { + override def size: Int = 0 + def contains(elem: Any): Boolean = false + def + (elem: Any): Set[Any] = new Set1(elem) + def - (elem: Any): Set[Any] = this + def iterator: Iterator[Any] = Iterator.empty + override def foreach[U](f: Any => U): Unit = {} + } + + @serializable @deprecated("use `Set.empty' instead") class EmptySet[A] extends Set[A] { override def size: Int = 0 def contains(elem: A): Boolean = false @@ -66,7 +76,7 @@ object Set extends SetFactory[Set] { if (contains(elem)) this else new Set2(elem1, elem) def - (elem: A): Set[A] = - if (elem == elem1) new EmptySet[A] + if (elem == elem1) Set.empty else this def iterator: Iterator[A] = Iterator(elem1) diff --git a/src/library/scala/collection/immutable/SortedMap.scala b/src/library/scala/collection/immutable/SortedMap.scala index 316cab9b50..919b529a49 100644 --- a/src/library/scala/collection/immutable/SortedMap.scala +++ b/src/library/scala/collection/immutable/SortedMap.scala @@ -31,6 +31,8 @@ trait SortedMap[A, +B] extends Map[A, B] override protected[this] def newBuilder : Builder[(A, B), SortedMap[A, B]] = SortedMap.newBuilder[A, B] + override def empty: SortedMap[A, B] = SortedMap.empty + override def updated [B1 >: B](key: A, value: B1): SortedMap[A, B1] = this + ((key, value)) /** Add a key/value pair to this map. @@ -56,16 +58,8 @@ trait SortedMap[A, +B] extends Map[A, B] * * @param elems the traversable object. */ - override def ++[B1 >: B](elems: scala.collection.Traversable[(A, B1)]): SortedMap[A, B1] = - ((repr: SortedMap[A, B1]) /: elems) (_ + _) - - /** Adds a number of elements provided by an iterator - * and returns a new collection with the added elements. - * - * @param iter the iterator - */ - override def ++[B1 >: B] (iter: Iterator[(A, B1)]): SortedMap[A, B1] = - ((repr: SortedMap[A, B1]) /: iter) (_ + _) + override def ++[B1 >: B](xs: TraversableOnce[(A, B1)]): SortedMap[A, B1] = + ((repr: SortedMap[A, B1]) /: xs) (_ + _) } /** diff --git a/src/library/scala/collection/immutable/Stack.scala b/src/library/scala/collection/immutable/Stack.scala index a5d7e9515a..640fb39af5 100644 --- a/src/library/scala/collection/immutable/Stack.scala +++ b/src/library/scala/collection/immutable/Stack.scala @@ -37,7 +37,7 @@ object Stack extends SeqFactory[Stack] { @serializable @SerialVersionUID(1976480595012942526L) class Stack[+A] protected (protected val elems: List[A]) extends LinearSeq[A] with GenericTraversableTemplate[A, Stack] - with LinearSeqLike[A, Stack[A]] { + with LinearSeqOptimized[A, Stack[A]] { override def companion: GenericCompanion[Stack] = Stack def this() = this(Nil) @@ -74,18 +74,8 @@ class Stack[+A] protected (protected val elems: List[A]) extends LinearSeq[A] * @param elems the iterator object. * @return the stack with the new elements on top. */ - def pushAll[B >: A](elems: Iterator[B]): Stack[B] = - ((this: Stack[B]) /: elems)(_ push _) - - /** Push all elements provided by the given traversable object onto - * the stack. The last element returned by the iterable object - * will be on top of the new stack. - * - * @param elems the iterable object. - * @return the stack with the new elements on top. - */ - def pushAll[B >: A](elems: scala.collection.Traversable[B]): Stack[B] = - ((this: Stack[B]) /: elems)(_ push _) + def pushAll[B >: A](xs: TraversableOnce[B]): Stack[B] = + ((this: Stack[B]) /: xs.toIterator)(_ push _) /** Returns the top element of the stack. An error is signaled if * there is no element on the stack. diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 1377fbe59d..3b10963ddb 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -40,7 +40,7 @@ import scala.annotation.tailrec */ abstract class Stream[+A] extends LinearSeq[A] with GenericTraversableTemplate[A, Stream] - with LinearSeqLike[A, Stream[A]] { + with LinearSeqOptimized[A, Stream[A]] { self => override def companion: GenericCompanion[Stream] = Stream @@ -113,17 +113,21 @@ self => * then StreamBuilder will be chosen for the implicit. * we recognize that fact and optimize to get more laziness. */ - override def ++[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { + override def ++[B >: A, That](that: TraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { // we assume there is no other builder factory on streams and therefore know that That = Stream[A] (if (isEmpty) that.toStream else new Stream.Cons(head, (tail ++ that).asInstanceOf[Stream[A]])).asInstanceOf[That] } - /** Create a new stream which contains all elements of this stream - * followed by all elements of Iterator `that' + /** + * Create a new stream which contains all intermediate results of applying the operator + * to subsequent elements left to right. + * @note This works because the target type of the Builder That is a Stream. */ - override def++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = - this ++ that.toStream + override final def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { + (if (this.isEmpty) Stream(z) + else new Stream.Cons(z, tail.scanLeft(op(z, head))(op).asInstanceOf[Stream[B]])).asInstanceOf[That] + } /** Returns the stream resulting from applying the given function * <code>f</code> to each element of this stream. @@ -344,9 +348,9 @@ self => /** Builds a new stream from this stream in which any duplicates (wrt to ==) removed. * Among duplicate elements, only the first one is retained in the result stream */ - override def removeDuplicates: Stream[A] = + override def distinct: Stream[A] = if (isEmpty) this - else new Stream.Cons(head, tail.filter(head !=).removeDuplicates) + else new Stream.Cons(head, tail.filter(head !=).distinct) /** Returns a new sequence of given length containing the elements of this sequence followed by zero * or more occurrences of given elements. @@ -420,12 +424,12 @@ object Stream extends SeqFactory[Stream] { import scala.collection.{Iterable, Seq, IndexedSeq} /** A builder for streams - * @note: This builder is lazy only in the sense that it does not go downs the spine - * of traversables that are added as a whole. If more laziness can be achieved, - * this builder should be bypassed. + * @note This builder is lazy only in the sense that it does not go downs the spine + * of traversables that are added as a whole. If more laziness can be achieved, + * this builder should be bypassed. */ class StreamBuilder[A] extends scala.collection.mutable.LazyBuilder[A, Stream[A]] { - def result: Stream[A] = (for (xs <- parts.iterator; x <- xs.toIterable.iterator) yield x).toStream + def result: Stream[A] = parts.toStream flatMap (_.toStream) } object Empty extends Stream[Nothing] { diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala index 500de352f6..5b5a627cfe 100644 --- a/src/library/scala/collection/immutable/StringLike.scala +++ b/src/library/scala/collection/immutable/StringLike.scala @@ -34,7 +34,7 @@ import StringLike._ /** * @since 2.8 */ -trait StringLike[+Repr] extends IndexedSeqLike[Char, Repr] with Ordered[String] { +trait StringLike[+Repr] extends IndexedSeqOptimized[Char, Repr] with Ordered[String] { self => /** Creates a string builder buffer as builder for this class */ @@ -263,7 +263,7 @@ self => * @param args the arguments used to instantiating the pattern. * @throws java.lang.IllegalArgumentException */ - def format(l: java.util.Locale, args: Any*): String = + def formatLocal(l: java.util.Locale, args: Any*): String = java.lang.String.format(l, toString, args map unwrapArg: _*) } diff --git a/src/library/scala/collection/immutable/TreeSet.scala b/src/library/scala/collection/immutable/TreeSet.scala index 1a3ed38e1c..79e1a6b00b 100644 --- a/src/library/scala/collection/immutable/TreeSet.scala +++ b/src/library/scala/collection/immutable/TreeSet.scala @@ -19,8 +19,7 @@ import mutable.{Builder, AddingBuilder} * * @since 1 */ -object TreeSet extends SortedSetFactory[TreeSet]{ - +object TreeSet extends SortedSetFactory[TreeSet] { implicit def implicitBuilder[A](implicit ordering: Ordering[A]): Builder[A, TreeSet[A]] = newBuilder[A](ordering) override def newBuilder[A](implicit ordering: Ordering[A]): Builder[A, TreeSet[A]] = new AddingBuilder(empty[A](ordering)) @@ -28,7 +27,6 @@ object TreeSet extends SortedSetFactory[TreeSet]{ /** The empty set of this type */ def empty[A](implicit ordering: Ordering[A]) = new TreeSet[A] - } /** This class implements immutable sets using a tree. diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala index 1326768090..6defe66d6f 100644 --- a/src/library/scala/collection/immutable/Vector.scala +++ b/src/library/scala/collection/immutable/Vector.scala @@ -19,24 +19,25 @@ import scala.collection.mutable.Builder object Vector extends SeqFactory[Vector] { - /*private[immutable]*/ val BF = new GenericCanBuildFrom[Nothing] { + private[immutable] val BF = new GenericCanBuildFrom[Nothing] { override def apply() = newBuilder[Nothing] } @inline implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Vector[A]] = BF.asInstanceOf[CanBuildFrom[Coll, A, Vector[A]]] def newBuilder[A]: Builder[A, Vector[A]] = new VectorBuilder[A] - /*private[immutable]*/ val NIL = new Vector[Nothing](0, 0, 0) + private[immutable] val NIL = new Vector[Nothing](0, 0, 0) @inline override def empty[A]: Vector[A] = NIL } -// TODO: most members are still public -> restrict access (caveat: private prevents inlining) +// in principle, most members should be private. however, access privileges must +// be carefully chosen to not prevent method inlining @serializable -final class Vector[+A](startIndex: Int, endIndex: Int, focus: Int) extends Seq[A] +final class Vector[+A](startIndex: Int, endIndex: Int, focus: Int) extends IndexedSeq[A] with GenericTraversableTemplate[A, Vector] - with SeqLike[A, Vector[A]] - with VectorPointer[A @uncheckedVariance] { + with IndexedSeqLike[A, Vector[A]] + with VectorPointer[A @uncheckedVariance] { self => override def companion: GenericCompanion[Vector] = Vector @@ -45,7 +46,7 @@ override def companion: GenericCompanion[Vector] = Vector //assert(focus >= 0, focus+"<0") //assert(focus <= endIndex, focus+">"+endIndex) - /*private*/ var dirty = false + private[immutable] var dirty = false def length = endIndex - startIndex @@ -60,20 +61,35 @@ override def companion: GenericCompanion[Vector] = Vector s } + + // can still be improved + override /*SeqLike*/ + def reverseIterator: Iterator[A] = new Iterator[A] { + private var i = self.length + def hasNext: Boolean = 0 < i + def next: A = + if (0 < i) { + i -= 1 + self(i) + } else Iterator.empty.next + } + + // TODO: reverse + // TODO: check performance of foreach/map etc. should override or not? // Ideally, clients will inline calls to map all the way down, including the iterator/builder methods. // In principle, escape analysis could even remove the iterator/builder allocations and do it // with local variables exclusively. But we're not quite there yet ... - @inline def foreach0[U](f: A => U): Unit = iterator.foreach0(f) - @inline def map0[B, That](f: A => B)(implicit bf: CanBuildFrom[Vector[A], B, That]): That = { + @deprecated("this method is experimental and will be removed in a future release") + @inline def foreachFast[U](f: A => U): Unit = iterator.foreachFast(f) + @deprecated("this method is experimental and will be removed in a future release") + @inline def mapFast[B, That](f: A => B)(implicit bf: CanBuildFrom[Vector[A], B, That]): That = { val b = bf(repr) - foreach0(x => b += f(x)) + foreachFast(x => b += f(x)) b.result } - // TODO: reverse - // TODO: reverseIterator def apply(index: Int): A = { val idx = checkRangeConvert(index) @@ -108,41 +124,71 @@ override def companion: GenericCompanion[Vector] = Vector } override def take(n: Int): Vector[A] = { - if (n < 0) throw new IllegalArgumentException(n.toString) - if (startIndex + n < endIndex) { + if (n <= 0) + Vector.empty + else if (startIndex + n < endIndex) dropBack0(startIndex + n) - } else + else this } override def drop(n: Int): Vector[A] = { - if (n < 0) throw new IllegalArgumentException(n.toString) - if (startIndex + n < endIndex) { + if (n <= 0) + this + else if (startIndex + n < endIndex) dropFront0(startIndex + n) - } else + else Vector.empty } override def takeRight(n: Int): Vector[A] = { - if (n < 0) throw new IllegalArgumentException(n.toString) - if (endIndex - n > startIndex) { + if (n <= 0) + Vector.empty + else if (endIndex - n > startIndex) dropFront0(endIndex - n) - } else + else this } override def dropRight(n: Int): Vector[A] = { - if (n < 0) throw new IllegalArgumentException(n.toString) - if (endIndex - n > startIndex) { + if (n <= 0) + this + else if (endIndex - n > startIndex) dropBack0(endIndex - n) - } else + else Vector.empty } + override /*IterableLike*/ def head: A = { + if (isEmpty) throw new UnsupportedOperationException("empty.head") + apply(0) + } + + override /*TraversableLike*/ def tail: Vector[A] = { + if (isEmpty) throw new UnsupportedOperationException("empty.tail") + drop(1) + } + + override /*TraversableLike*/ def last: A = { + if (isEmpty) throw new UnsupportedOperationException("empty.last") + apply(length-1) + } + + override /*TraversableLike*/ def init: Vector[A] = { + if (isEmpty) throw new UnsupportedOperationException("empty.init") + dropRight(1) + } + + override /*IterableLike*/ def slice(from: Int, until: Int): Vector[A] = + take(until).drop(from) + + override /*IterableLike*/ def splitAt(n: Int): (Vector[A], Vector[A]) = (take(n), drop(n)) + + // semi-private api - def updateAt[B >: A](index: Int, elem: B): Vector[B] = { + private[immutable] def updateAt[B >: A](index: Int, elem: B): Vector[B] = { val idx = checkRangeConvert(index) val s = new Vector[B](startIndex, endIndex, idx) s.initFrom(this) @@ -153,7 +199,6 @@ override def companion: GenericCompanion[Vector] = Vector } - private def gotoPosWritable(oldIndex: Int, newIndex: Int, xor: Int) = if (dirty) { gotoPosWritable1(oldIndex, newIndex, xor) } else { @@ -168,7 +213,7 @@ override def companion: GenericCompanion[Vector] = Vector dirty = true } - def appendFront[B>:A](value: B): Vector[B] = { + private[immutable] def appendFront[B>:A](value: B): Vector[B] = { if (endIndex != startIndex) { var blockIndex = (startIndex - 1) & ~31 var lo = (startIndex - 1) & 31 @@ -263,7 +308,7 @@ override def companion: GenericCompanion[Vector] = Vector } } - def appendBack[B>:A](value: B): Vector[B] = { + private[immutable] def appendBack[B>:A](value: B): Vector[B] = { // //println("------- append " + value) // debug() if (endIndex != startIndex) { @@ -361,22 +406,22 @@ override def companion: GenericCompanion[Vector] = Vector display5 = copyRange(display5, oldLeft, newLeft) } - def zeroLeft(array: Array[AnyRef], index: Int): Unit = { + private def zeroLeft(array: Array[AnyRef], index: Int): Unit = { var i = 0; while (i < index) { array(i) = null; i+=1 } } - def zeroRight(array: Array[AnyRef], index: Int): Unit = { + private def zeroRight(array: Array[AnyRef], index: Int): Unit = { var i = index; while (i < array.length) { array(i) = null; i+=1 } } - def copyLeft(array: Array[AnyRef], right: Int): Array[AnyRef] = { + private def copyLeft(array: Array[AnyRef], right: Int): Array[AnyRef] = { // if (array eq null) // println("OUCH!!! " + right + "/" + depth + "/"+startIndex + "/" + endIndex + "/" + focus) val a2 = new Array[AnyRef](array.length) Platform.arraycopy(array, 0, a2, 0, right) a2 } - def copyRight(array: Array[AnyRef], left: Int): Array[AnyRef] = { + private def copyRight(array: Array[AnyRef], left: Int): Array[AnyRef] = { val a2 = new Array[AnyRef](array.length) Platform.arraycopy(array, left, a2, left, a2.length - left) a2 @@ -592,18 +637,17 @@ final class VectorIterator[+A](_startIndex: Int, _endIndex: Int) extends Iterato res } - // TODO: take - // TODO: drop + // TODO: drop (important?) - // TODO: remove! - @inline def foreach0[U](f: A => U) { while (hasNext) f(next()) } + @deprecated("this method is experimental and will be removed in a future release") + @inline def foreachFast[U](f: A => U) { while (hasNext) f(next()) } } final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A @uncheckedVariance] { - // TODO: possible alternative: start with display0 = null, blockIndex = -32, lo = 32 - // to avoid allocation initial array if the result will be empty anyways + // possible alternative: start with display0 = null, blockIndex = -32, lo = 32 + // to avoid allocating initial array if the result will be empty anyways display0 = new Array[AnyRef](32) depth = 1 @@ -612,7 +656,7 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A private var lo = 0 def += (elem: A): this.type = { - if (lo == 32) { + if (lo >= display0.length) { val newBlockIndex = blockIndex+32 gotoNextBlockStartWritable(newBlockIndex, blockIndex ^ newBlockIndex) blockIndex = newBlockIndex @@ -624,11 +668,12 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A } def result: Vector[A] = { - if (blockIndex + lo == 0) + val size = blockIndex + lo + if (size == 0) return Vector.empty - val s = new Vector[A](0, blockIndex + lo, 0) // TODO: should focus front or back? + val s = new Vector[A](0, size, 0) // should focus front or back? s.initFrom(this) - if (depth > 1) s.gotoPos(0, blockIndex + lo) + if (depth > 1) s.gotoPos(0, size - 1) // we're currently focused to size - 1, not size! s } @@ -643,18 +688,18 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A private[immutable] trait VectorPointer[T] { - var depth: Int = _ - var display0: Array[AnyRef] = _ - var display1: Array[AnyRef] = _ - var display2: Array[AnyRef] = _ - var display3: Array[AnyRef] = _ - var display4: Array[AnyRef] = _ - var display5: Array[AnyRef] = _ + private[immutable] var depth: Int = _ + private[immutable] var display0: Array[AnyRef] = _ + private[immutable] var display1: Array[AnyRef] = _ + private[immutable] var display2: Array[AnyRef] = _ + private[immutable] var display3: Array[AnyRef] = _ + private[immutable] var display4: Array[AnyRef] = _ + private[immutable] var display5: Array[AnyRef] = _ // used - final def initFrom[U](that: VectorPointer[U]): Unit = initFrom(that, that.depth) + private[immutable] final def initFrom[U](that: VectorPointer[U]): Unit = initFrom(that, that.depth) - final def initFrom[U](that: VectorPointer[U], depth: Int) = { + private[immutable] final def initFrom[U](that: VectorPointer[U], depth: Int) = { this.depth = depth (depth - 1) match { case -1 => @@ -690,7 +735,7 @@ private[immutable] trait VectorPointer[T] { // requires structure is at pos oldIndex = xor ^ index - final def getElem(index: Int, xor: Int): T = { + private[immutable] final def getElem(index: Int, xor: Int): T = { if (xor < (1 << 5)) { // level = 0 display0(index & 31).asInstanceOf[T] } else @@ -717,7 +762,7 @@ private[immutable] trait VectorPointer[T] { // go to specific position // requires structure is at pos oldIndex = xor ^ index, // ensures structure is at pos index - final def gotoPos(index: Int, xor: Int): Unit = { + private[immutable] final def gotoPos(index: Int, xor: Int): Unit = { if (xor < (1 << 5)) { // level = 0 (could maybe removed) } else if (xor < (1 << 10)) { // level = 1 @@ -754,7 +799,7 @@ private[immutable] trait VectorPointer[T] { // USED BY ITERATOR // xor: oldIndex ^ index - final def gotoNextBlockStart(index: Int, xor: Int): Unit = { // goto block start pos + private[immutable] final def gotoNextBlockStart(index: Int, xor: Int): Unit = { // goto block start pos if (xor < (1 << 10)) { // level = 1 display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] } else @@ -787,7 +832,7 @@ private[immutable] trait VectorPointer[T] { // USED BY BUILDER // xor: oldIndex ^ index - final def gotoNextBlockStartWritable(index: Int, xor: Int): Unit = { // goto block start pos + private[immutable] final def gotoNextBlockStartWritable(index: Int, xor: Int): Unit = { // goto block start pos if (xor < (1 << 10)) { // level = 1 if (depth == 1) { display1 = new Array(32); display1(0) = display0; depth+=1} display0 = new Array(32) @@ -841,14 +886,15 @@ private[immutable] trait VectorPointer[T] { // STUFF BELOW USED BY APPEND / UPDATE - final def copyOf(a: Array[AnyRef]) = { + private[immutable] final def copyOf(a: Array[AnyRef]) = { //println("copy") + if (a eq null) println ("NULL") val b = new Array[AnyRef](a.length) Platform.arraycopy(a, 0, b, 0, a.length) b } - final def nullSlotAndCopy(array: Array[AnyRef], index: Int) = { + private[immutable] final def nullSlotAndCopy(array: Array[AnyRef], index: Int) = { //println("copy and null") val x = array(index) array(index) = null @@ -860,7 +906,7 @@ private[immutable] trait VectorPointer[T] { // requires structure is at pos index // ensures structure is clean and at pos index and writable at all levels except 0 - final def stabilize(index: Int) = (depth - 1) match { + private[immutable] final def stabilize(index: Int) = (depth - 1) match { case 5 => display5 = copyOf(display5) display4 = copyOf(display4) @@ -901,16 +947,13 @@ private[immutable] trait VectorPointer[T] { - - - /// USED IN UPDATE AND APPEND BACK // prepare for writing at an existing position // requires structure is clean and at pos oldIndex = xor ^ newIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 - final def gotoPosWritable0(newIndex: Int, xor: Int): Unit = (depth - 1) match { + private[immutable] final def gotoPosWritable0(newIndex: Int, xor: Int): Unit = (depth - 1) match { case 5 => display5 = copyOf(display5) display4 = nullSlotAndCopy(display5, (newIndex >> 25) & 31).asInstanceOf[Array[AnyRef]] @@ -943,7 +986,7 @@ private[immutable] trait VectorPointer[T] { // requires structure is dirty and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 - final def gotoPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = { + private[immutable] final def gotoPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = { if (xor < (1 << 5)) { // level = 0 display0 = copyOf(display0) } else @@ -1009,7 +1052,7 @@ private[immutable] trait VectorPointer[T] { // USED IN DROP - final def copyRange(array: Array[AnyRef], oldLeft: Int, newLeft: Int) = { + private[immutable] final def copyRange(array: Array[AnyRef], oldLeft: Int, newLeft: Int) = { val elems = new Array[AnyRef](32) Platform.arraycopy(array, oldLeft, elems, newLeft, 32 - math.max(newLeft,oldLeft)) elems @@ -1023,7 +1066,7 @@ private[immutable] trait VectorPointer[T] { // requires structure is clean and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 - final def gotoFreshPosWritable0(oldIndex: Int, newIndex: Int, xor: Int): Unit = { // goto block start pos + private[immutable] final def gotoFreshPosWritable0(oldIndex: Int, newIndex: Int, xor: Int): Unit = { // goto block start pos if (xor < (1 << 5)) { // level = 0 //println("XXX clean with low xor") } else @@ -1103,7 +1146,7 @@ private[immutable] trait VectorPointer[T] { // requires structure is dirty and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 - final def gotoFreshPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = { + private[immutable] final def gotoFreshPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = { stabilize(oldIndex) gotoFreshPosWritable0(oldIndex, newIndex, xor) } @@ -1113,7 +1156,7 @@ private[immutable] trait VectorPointer[T] { // DEBUG STUFF - def debug(): Unit = { + private[immutable] def debug(): Unit = { return /* //println("DISPLAY 5: " + display5 + " ---> " + (if (display5 ne null) display5.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) diff --git a/src/library/scala/collection/interfaces/MapMethods.scala b/src/library/scala/collection/interfaces/MapMethods.scala index dbe05906b1..fd6e7ad2a7 100644 --- a/src/library/scala/collection/interfaces/MapMethods.scala +++ b/src/library/scala/collection/interfaces/MapMethods.scala @@ -30,15 +30,15 @@ with SubtractableMethods[A, This] def apply(key: A): B def contains(key: A): Boolean def isDefinedAt(key: A): Boolean - def keySet: Set[A] + def keys: Iterable[A] def keysIterator: Iterator[A] - def valuesIterable: Iterable[B] + def keySet: Set[A] + def values: Iterable[B] def valuesIterator: Iterator[B] def default(key: A): B def filterKeys(p: A => Boolean): DefaultMap[A, B] def mapValues[C](f: B => C): DefaultMap[A, C] def updated [B1 >: B](key: A, value: B1): Map[A, B1] def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): Map[A, B1] - def ++[B1 >: B](elems: Traversable[(A, B1)]): Map[A, B1] - def ++[B1 >: B] (iter: Iterator[(A, B1)]): Map[A, B1] + def ++[B1 >: B](xs: TraversableOnce[(A, B1)]): Map[A, B1] } diff --git a/src/library/scala/collection/interfaces/SeqMethods.scala b/src/library/scala/collection/interfaces/SeqMethods.scala index df0307174d..401c5e6c55 100644 --- a/src/library/scala/collection/interfaces/SeqMethods.scala +++ b/src/library/scala/collection/interfaces/SeqMethods.scala @@ -44,7 +44,7 @@ trait SeqMethods[+A, +This <: SeqLike[A, This] with Seq[A]] extends IterableMeth def padTo[B >: A, That](len: Int, elem: B)(implicit bf: CanBuildFrom[This, B, That]): That def patch[B >: A, That](from: Int, patch: Seq[B], replaced: Int)(implicit bf: CanBuildFrom[This, B, That]): That def prefixLength(p: A => Boolean): Int - def removeDuplicates: This + def distinct: This def reverse: This def reverseIterator: Iterator[A] def segmentLength(p: A => Boolean, from: Int): Int diff --git a/src/library/scala/collection/interfaces/SetMethods.scala b/src/library/scala/collection/interfaces/SetMethods.scala index 8a3142b44a..453143b790 100644 --- a/src/library/scala/collection/interfaces/SetMethods.scala +++ b/src/library/scala/collection/interfaces/SetMethods.scala @@ -21,8 +21,7 @@ trait AddableMethods[A, +This <: Addable[A, This]] { protected def repr: This def +(elem: A): This def + (elem1: A, elem2: A, elems: A*): This - def ++ (elems: Traversable[A]): This - def ++ (iter: Iterator[A]): This + def ++ (xs: TraversableOnce[A]): This } /** @@ -32,8 +31,7 @@ trait SubtractableMethods[A, +This <: Subtractable[A, This]] { protected def repr: This def -(elem: A): This def -(elem1: A, elem2: A, elems: A*): This - def --(elems: Traversable[A]): This - def --(iter: Iterator[A]): This + def --(xs: TraversableOnce[A]): This } /** diff --git a/src/library/scala/collection/interfaces/TraversableMethods.scala b/src/library/scala/collection/interfaces/TraversableMethods.scala index 08ade7586d..1fc2451ec0 100644 --- a/src/library/scala/collection/interfaces/TraversableMethods.scala +++ b/src/library/scala/collection/interfaces/TraversableMethods.scala @@ -24,11 +24,10 @@ trait TraversableMethods[+A, +This <: TraversableLike[A, This] with Traversable[ // maps/iteration def flatMap[B, That](f: A => Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That - def partialMap[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[This, B, That]): That + def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[This, B, That]): That // new collections - def ++[B >: A, That](that: Iterator[B])(implicit bf: CanBuildFrom[This, B, That]): That - def ++[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That + def ++[B >: A, That](xs: TraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That def copyToArray[B >: A](xs: Array[B], start: Int): Unit def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit def copyToBuffer[B >: A](dest: Buffer[B]): Unit diff --git a/src/library/scala/collection/interfaces/TraversableOnceMethods.scala b/src/library/scala/collection/interfaces/TraversableOnceMethods.scala new file mode 100644 index 0000000000..1e71215efd --- /dev/null +++ b/src/library/scala/collection/interfaces/TraversableOnceMethods.scala @@ -0,0 +1,69 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection +package interfaces + +import mutable.Buffer + +trait TraversableOnceMethods[+A] { + self: TraversableOnce[A] => + + def foreach[U](f: A => U): Unit + protected[this] def reversed: TraversableOnce[A] + + // tests + def isEmpty: Boolean + def nonEmpty: Boolean + def hasDefiniteSize: Boolean + def isTraversableAgain: Boolean + + // applying a predicate + def forall(p: A => Boolean): Boolean + def exists(p: A => Boolean): Boolean + def find(p: A => Boolean): Option[A] + def count(p: A => Boolean): Int + + // folds + def /:[B](z: B)(op: (B, A) => B): B + def :\[B](z: B)(op: (A, B) => B): B + def foldLeft[B](z: B)(op: (B, A) => B): B + def foldRight[B](z: B)(op: (A, B) => B): B + def reduceLeft[B >: A](op: (B, A) => B): B + def reduceRight[B >: A](op: (A, B) => B): B + def reduceLeftOption[B >: A](op: (B, A) => B): Option[B] + def reduceRightOption[B >: A](op: (A, B) => B): Option[B] + + def sum[B >: A](implicit num: Numeric[B]): B + def product[B >: A](implicit num: Numeric[B]): B + def min[B >: A](implicit cmp: Ordering[B]): A + def max[B >: A](implicit cmp: Ordering[B]): A + + // copies and conversions + def copyToBuffer[B >: A](dest: Buffer[B]): Unit + def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit + def copyToArray[B >: A](xs: Array[B], start: Int): Unit + def copyToArray[B >: A](xs: Array[B]): Unit + + def toArray[B >: A : ClassManifest]: Array[B] + def toIterable: Iterable[A] + def toIterator: Iterator[A] + def toList: List[A] + def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] + def toSet[B >: A]: immutable.Set[B] + def toStream: Stream[A] + def toTraversable: Traversable[A] + + def mkString(start: String, sep: String, end: String): String + def mkString(sep: String): String + def mkString: String + + def addString(buf: StringBuilder, start: String, sep: String, end: String): StringBuilder + def addString(buf: StringBuilder, sep: String): StringBuilder + def addString(buf: StringBuilder): StringBuilder +} diff --git a/src/library/scala/collection/mutable/AddingBuilder.scala b/src/library/scala/collection/mutable/AddingBuilder.scala index 06822e859b..d16a4a71f3 100644 --- a/src/library/scala/collection/mutable/AddingBuilder.scala +++ b/src/library/scala/collection/mutable/AddingBuilder.scala @@ -24,7 +24,7 @@ import generic._ * @version 2.8 * @since 2.8 */ -class AddingBuilder[Elem, To <: Addable[Elem, To] with scala.collection.Iterable[Elem] with scala.collection.IterableLike[Elem, To]](empty: To) +class AddingBuilder[Elem, To <: Addable[Elem, To] with collection.Iterable[Elem] with collection.IterableLike[Elem, To]](empty: To) extends Builder[Elem, To] { protected var elems: To = empty def +=(x: Elem): this.type = { elems = elems + x; this } diff --git a/src/library/scala/collection/mutable/ArrayBuffer.scala b/src/library/scala/collection/mutable/ArrayBuffer.scala index c88b9d3374..0c6aa9ce0c 100644 --- a/src/library/scala/collection/mutable/ArrayBuffer.scala +++ b/src/library/scala/collection/mutable/ArrayBuffer.scala @@ -29,7 +29,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) extends Buffer[A] with GenericTraversableTemplate[A, ArrayBuffer] with BufferLike[A, ArrayBuffer[A]] - with IndexedSeqLike[A, ArrayBuffer[A]] + with IndexedSeqOptimized[A, ArrayBuffer[A]] with Builder[A, ArrayBuffer[A]] with ResizableArray[A] { @@ -43,7 +43,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) override def sizeHint(len: Int) { if (len > size && len >= 1) { - val newarray = new Array[AnyRef](len min 1) + val newarray = new Array[AnyRef](len) Array.copy(array, 0, newarray, 0, size0) array = newarray } @@ -65,10 +65,10 @@ class ArrayBuffer[A](override protected val initialSize: Int) * via its <code>iterator</code> method. The identity of the * buffer is returned. * - * @param iter the iterfable object. + * @param iter the iterable object. * @return the updated buffer. */ - override def ++=(iter: Traversable[A]): this.type = iter match { + override def ++=(xs: TraversableOnce[A]): this.type = xs match { case v: IndexedSeq[_] => val n = v.length ensureSize(size0 + n) @@ -76,7 +76,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) size0 += n this case _ => - super.++=(iter) + super.++=(xs) } /** Prepends a single element to this buffer and return @@ -101,7 +101,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) * @param iter the iterable object. * @return the updated buffer. */ - override def ++=:(iter: Traversable[A]): this.type = { insertAll(0, iter); this } + override def ++=:(xs: TraversableOnce[A]): this.type = { insertAll(0, xs.toTraversable); this } /** Inserts new elements at the index <code>n</code>. Opposed to method * <code>update</code>, this method will not replace an element with a @@ -125,7 +125,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) * the buffer size. * * @param n the index which refers to the first element to delete. - * @param count the number of elemenets to delete + * @param count the number of elements to delete * @throws Predef.IndexOutOfBoundsException if <code>n</code> is out of bounds. */ override def remove(n: Int, count: Int) { diff --git a/src/library/scala/collection/mutable/ArrayBuilder.scala b/src/library/scala/collection/mutable/ArrayBuilder.scala index c824cc15f5..7e4bab353b 100644 --- a/src/library/scala/collection/mutable/ArrayBuilder.scala +++ b/src/library/scala/collection/mutable/ArrayBuilder.scala @@ -67,7 +67,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[T]): this.type = (xs: AnyRef) match { + override def ++=(xs: TraversableOnce[T]): this.type = (xs: AnyRef) match { case xs: WrappedArray.ofRef[_] => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -131,7 +131,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Byte]): this.type = xs match { + override def ++=(xs: TraversableOnce[Byte]): this.type = xs match { case xs: WrappedArray.ofByte => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -195,7 +195,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Short]): this.type = xs match { + override def ++=(xs: TraversableOnce[Short]): this.type = xs match { case xs: WrappedArray.ofShort => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -259,7 +259,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Char]): this.type = xs match { + override def ++=(xs: TraversableOnce[Char]): this.type = xs match { case xs: WrappedArray.ofChar => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -323,7 +323,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Int]): this.type = xs match { + override def ++=(xs: TraversableOnce[Int]): this.type = xs match { case xs: WrappedArray.ofInt => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -387,7 +387,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Long]): this.type = xs match { + override def ++=(xs: TraversableOnce[Long]): this.type = xs match { case xs: WrappedArray.ofLong => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -451,7 +451,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Float]): this.type = xs match { + override def ++=(xs: TraversableOnce[Float]): this.type = xs match { case xs: WrappedArray.ofFloat => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -515,7 +515,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Double]): this.type = xs match { + override def ++=(xs: TraversableOnce[Double]): this.type = xs match { case xs: WrappedArray.ofDouble => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -579,7 +579,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Boolean]): this.type = xs match { + override def ++=(xs: TraversableOnce[Boolean]): this.type = xs match { case xs: WrappedArray.ofBoolean => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) @@ -643,7 +643,7 @@ object ArrayBuilder { this } - override def ++=(xs: scala.collection.Traversable[Unit]): this.type = xs match { + override def ++=(xs: TraversableOnce[Unit]): this.type = xs match { case xs: WrappedArray.ofUnit => ensureSize(this.size + xs.length) Array.copy(xs.array, 0, elems, this.size, xs.length) diff --git a/src/library/scala/collection/mutable/ArrayLike.scala b/src/library/scala/collection/mutable/ArrayLike.scala index c26f333afb..0b64f1255e 100644 --- a/src/library/scala/collection/mutable/ArrayLike.scala +++ b/src/library/scala/collection/mutable/ArrayLike.scala @@ -18,7 +18,7 @@ import generic._ * * @since 2.8 */ -trait ArrayLike[A, +Repr] extends IndexedSeqLike[A, Repr] { self => +trait ArrayLike[A, +Repr] extends IndexedSeqOptimized[A, Repr] { self => /** Creates a possible nested IndexedSeq which consists of all the elements * of this array. If the elements are arrays themselves, the `deep' transformation diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala index 61fcc77e14..553461c805 100644 --- a/src/library/scala/collection/mutable/ArrayOps.scala +++ b/src/library/scala/collection/mutable/ArrayOps.scala @@ -24,6 +24,12 @@ abstract class ArrayOps[T] extends ArrayLike[T, Array[T]] { ClassManifest.fromClass( repr.getClass.getComponentType.getComponentType.asInstanceOf[Predef.Class[U]])) + override def toArray[U >: T : ClassManifest]: Array[U] = + if (implicitly[ClassManifest[U]].erasure eq repr.getClass.getComponentType) + repr.asInstanceOf[Array[U]] + else + super.toArray[U] + /** Flattens a two-dimensional array by concatenating all its rows * into a single array */ diff --git a/src/library/scala/collection/mutable/GenericArray.scala b/src/library/scala/collection/mutable/ArraySeq.scala index 4aecf48585..f6f958601d 100644 --- a/src/library/scala/collection/mutable/GenericArray.scala +++ b/src/library/scala/collection/mutable/ArraySeq.scala @@ -22,12 +22,12 @@ import generic._ * @version 2.8 * @since 2.8 */ -class GenericArray[A](override val length: Int) +class ArraySeq[A](override val length: Int) extends IndexedSeq[A] - with GenericTraversableTemplate[A, GenericArray] - with IndexedSeqLike[A, GenericArray[A]] { + with GenericTraversableTemplate[A, ArraySeq] + with IndexedSeqOptimized[A, ArraySeq[A]] { - override def companion: GenericCompanion[GenericArray] = GenericArray + override def companion: GenericCompanion[ArraySeq] = ArraySeq val array: Array[AnyRef] = new Array[AnyRef](length) @@ -64,11 +64,11 @@ extends IndexedSeq[A] } } -object GenericArray extends SeqFactory[GenericArray] { - implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, GenericArray[A]] = new GenericCanBuildFrom[A] - def newBuilder[A]: Builder[A, GenericArray[A]] = +object ArraySeq extends SeqFactory[ArraySeq] { + implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ArraySeq[A]] = new GenericCanBuildFrom[A] + def newBuilder[A]: Builder[A, ArraySeq[A]] = new ArrayBuffer[A] mapResult { buf => - val result = new GenericArray[A](buf.length) + val result = new ArraySeq[A](buf.length) buf.copyToArray(result.array.asInstanceOf[Array[Any]], 0) result } diff --git a/src/library/scala/collection/mutable/ArrayStack.scala b/src/library/scala/collection/mutable/ArrayStack.scala index 1c3bdacaa5..8f9d1bfc88 100644 --- a/src/library/scala/collection/mutable/ArrayStack.scala +++ b/src/library/scala/collection/mutable/ArrayStack.scala @@ -104,15 +104,7 @@ class ArrayStack[T] private(private var table : Array[AnyRef], * * @param x The source of elements to push */ - def ++=(x: scala.collection.Iterable[T]): this.type = { x.foreach(this +=(_)); this } - - - /** - * Pushes all the provided elements onto the stack. - * - * @param x The source of elements to push - */ - def ++=(x: Iterator[T]): this.type = { x.foreach(this +=(_)); this } + def ++=(xs: TraversableOnce[T]): this.type = { xs foreach += ; this } /** * Alias for push. diff --git a/src/library/scala/collection/mutable/BufferLike.scala b/src/library/scala/collection/mutable/BufferLike.scala index 3516a60233..0fb34cc8e0 100644 --- a/src/library/scala/collection/mutable/BufferLike.scala +++ b/src/library/scala/collection/mutable/BufferLike.scala @@ -14,6 +14,7 @@ package mutable import generic._ import script._ +import annotation.migration /** A template trait for buffers of type `Buffer[A]`. * @@ -30,10 +31,6 @@ import script._ * @author Martin Odersky * @author Matthias Zenger * @version 2.8 - * @since 2.8 - * @author Matthias Zenger - * @author Martin Odersky - * @version 2.8 * @since 2.8 * @define buffernote @note * This trait provides most of the operations of a `Buffer` independently of its representation. @@ -63,12 +60,14 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] extends Growable[A] with Shrinkable[A] with Scriptable[A] - with Addable[A, This] with Subtractable[A, This] with Cloneable[This] with SeqLike[A, This] { self : This => + // Note this does not extend Addable because `+` is being phased out of + // all Seq-derived classes. + import scala.collection.{Iterable, Traversable} // Abstract methods from IndexedSeq: @@ -132,50 +131,33 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] this } - /** Prepends the elements contained in a traversable collection - * to this buffer. - * @param elems the collection containing the elements to prepend. - * @return the buffer itself. - */ - def ++=:(elems: Traversable[A]): this.type = { insertAll(0, elems); this } - - /** Prepends the elements produced by an iterator to this buffer. + /** Prepends elements to this buffer. * - * @param iter the iterator producing the elements to prepend. - * @return the buffer itself. + * @param xs the TraversableOnce containing the elements to prepend. + * @return the buffer itself. */ - def ++=:(iter: Iterator[A]): this.type = { insertAll(0, iter.toSeq); this } + def ++=:(xs: TraversableOnce[A]): this.type = { insertAll(0, xs.toTraversable); this } /** Appends the given elements to this buffer. * * @param elems the elements to append. */ - def append(elems: A*) { this ++= elems } + def append(elems: A*) { appendAll(elems) } /** Appends the elements contained in a traversable collection to this buffer. * @param elems the collection containing the elements to append. */ - def appendAll(elems: Traversable[A]) { this ++= elems } - - /** Appends the elements produced by an iterator to this buffer. - * @param elems the iterator producing the elements to append. - */ - def appendAll(iter: Iterator[A]) { this ++= iter } + def appendAll(xs: TraversableOnce[A]) { this ++= xs } /** Prepends given elements to this buffer. * @param elems the elements to prepend. */ - def prepend(elems: A*) { elems ++=: this } + def prepend(elems: A*) { prependAll(elems) } /** Prepends the elements contained in a traversable collection to this buffer. * @param elems the collection containing the elements to prepend. */ - def prependAll(iter: Traversable[A]) { iter ++=: this } - - /** Prepends a number of elements produced by an iterator to this buffer. - * @param iter the iterator producing the elements to prepend. - */ - def prependAll(iter: Iterator[A]) { iter ++=: this } + def prependAll(xs: TraversableOnce[A]) { xs ++=: this } /** Inserts new elements at a given index into this buffer. * @@ -230,7 +212,7 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] */ override def stringPrefix: String = "Buffer" - /** Provide a read-only view of this byffer as a sequence + /** Provide a read-only view of this buffer as a sequence * @return A sequence which refers to this buffer for all its operations. */ def readOnly: scala.collection.Seq[A] = toSeq @@ -254,25 +236,35 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] @deprecated("use ++=: instead") final def ++:(iter: Traversable[A]): This = ++=:(iter) + @deprecated("use `+=:' instead") + final def +:(elem: A): This = +=:(elem) + /** Adds a single element to this collection and returns - * the collection itself. + * the collection itself. Note that for backward compatibility + * reasons, this method mutates the collection in place, unlike + * similar but undeprecated methods throughout the collections + * hierarchy. You are strongly recommended to use '+=' instead. * * @param elem the element to add. */ @deprecated("Use += instead if you intend to add by side effect to an existing collection.\n"+ - "Use `clone() ++=' if you intend to create a new collection.") - override def + (elem: A): This = { +=(elem); repr } + "Use `clone() +=' if you intend to create a new collection.") + def + (elem: A): This = { +=(elem); repr } /** Adds two or more elements to this collection and returns - * the collection itself. + * the collection itself. Note that for backward compatibility + * reasons, this method mutates the collection in place, unlike + * all similar methods throughout the collections hierarchy. + * similar but undeprecated methods throughout the collections + * hierarchy. You are strongly recommended to use '++=' instead. * * @param elem1 the first element to add. * @param elem2 the second element to add. * @param elems the remaining elements to add. */ - @deprecated("Use += instead if you intend to add by side effect to an existing collection.\n"+ + @deprecated("Use ++= instead if you intend to add by side effect to an existing collection.\n"+ "Use `clone() ++=' if you intend to create a new collection.") - override def + (elem1: A, elem2: A, elems: A*): This = { + def + (elem1: A, elem2: A, elems: A*): This = { this += elem1 += elem2 ++= elems repr } @@ -282,33 +274,22 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] * * @param iter the iterable object. */ - @deprecated("Use ++= instead if you intend to add by side effect to an existing collection.\n"+ - "Use `clone() ++=` if you intend to create a new collection.") - override def ++(iter: Traversable[A]): This = { - for (elem <- iter) +=(elem) - repr - } - - /** Adds a number of elements provided by an iterator and returns - * the collection itself. - * - * @param iter the iterator - */ - @deprecated("Use ++= instead if you intend to add by side effect to an existing collection.\n"+ - "Use `clone() ++=` if you intend to create a new collection.") - override def ++ (iter: Iterator[A]): This = { - for (elem <- iter) +=(elem) - repr - } + @migration(2, 8, + "As of 2.8, ++ always creates a new collection, even on Buffers.\n"+ + "Use ++= instead if you intend to add by side effect to an existing collection.\n" + ) + def ++(xs: TraversableOnce[A]): This = clone() ++= xs /** Removes a single element from this collection and returns * the collection itself. * * @param elem the element to remove. */ - @deprecated("Use -= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() -=` if you intend to create a new collection.") - override def -(elem: A): This = { -=(elem); repr } + @migration(2, 8, + "As of 2.8, - always creates a new collection, even on Buffers.\n"+ + "Use -= instead if you intend to remove by side effect from an existing collection.\n" + ) + override def -(elem: A): This = clone() -= elem /** Removes two or more elements from this collection and returns * the collection itself. @@ -317,40 +298,20 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] * @param elem2 the second element to remove. * @param elems the remaining elements to remove. */ - @deprecated("Use -= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() -=` if you intend to create a new collection.") - override def -(elem1: A, elem2: A, elems: A*): This = { - this -= elem1 -= elem2 --= elems - repr - } + @migration(2, 8, + "As of 2.8, - always creates a new collection, even on Buffers.\n"+ + "Use -= instead if you intend to remove by side effect from an existing collection.\n" + ) + override def -(elem1: A, elem2: A, elems: A*): This = clone() -= elem1 -= elem2 --= elems /** Removes a number of elements provided by a Traversable object and returns * the collection itself. * * @param iter the Traversable object. */ - @deprecated("Use --= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() --=` if you intend to create a new collection.") - override def --(iter: Traversable[A]): This = { - for (elem <- iter) -=(elem) - repr - } - - @deprecated("use `+=:' instead") - final def +:(elem: A): This = +=:(elem) - - /** Removes a number of elements provided by an iterator and returns - * the collection itself. - * - * @param iter the iterator - */ - @deprecated("Use --= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() --=` if you intend to create a new collection.") - override def --(iter: Iterator[A]): This = { - for (elem <- iter) -=(elem) - repr - } + @migration(2, 8, + "As of 2.8, -- always creates a new collection, even on Buffers.\n"+ + "Use --= instead if you intend to remove by side effect from an existing collection.\n" + ) + override def --(xs: TraversableOnce[A]): This = clone() --= xs } - - - diff --git a/src/library/scala/collection/mutable/BufferProxy.scala b/src/library/scala/collection/mutable/BufferProxy.scala index cc8aba79ab..d4444dab67 100644 --- a/src/library/scala/collection/mutable/BufferProxy.scala +++ b/src/library/scala/collection/mutable/BufferProxy.scala @@ -61,14 +61,14 @@ trait BufferProxy[A] extends Buffer[A] with Proxy { */ @deprecated("Use ++= instead if you intend to add by side effect to an existing collection.\n"+ "Use `clone() ++=` if you intend to create a new collection.") - def ++(iter: scala.collection.Iterable[A]): Buffer[A] = self.++(iter) + override def ++(xs: TraversableOnce[A]): Buffer[A] = self.++(xs) /** Appends a number of elements provided by an iterable object * via its <code>iterator</code> method. * * @param iter the iterable object. */ - def ++=(iter: scala.collection.Iterable[A]): this.type = { self.++=(iter); this } + override def ++=(xs: TraversableOnce[A]): this.type = { self.++=(xs); this } /** Appends a sequence of elements to this buffer. * @@ -81,7 +81,7 @@ trait BufferProxy[A] extends Buffer[A] with Proxy { * * @param iter the iterable object. */ - def appendAll(iter: scala.collection.Iterable[A]) { self.appendAll(iter) } + override def appendAll(xs: TraversableOnce[A]) { self.appendAll(xs) } /** Prepend a single element to this buffer and return * the identity of the buffer. @@ -90,8 +90,7 @@ trait BufferProxy[A] extends Buffer[A] with Proxy { */ def +=:(elem: A): this.type = { self.+=:(elem); this } - override def ++=:(iter: scala.collection.Traversable[A]): this.type = { self.++=:(iter); this } - override def ++=:(iter: scala.collection.Iterator[A]): this.type = { self.++=:(iter); this } + override def ++=:(xs: TraversableOnce[A]): this.type = { self.++=:(xs); this } /** Prepend an element to this list. * @@ -105,7 +104,7 @@ trait BufferProxy[A] extends Buffer[A] with Proxy { * * @param iter the iterable object. */ - def prependAll(elems: scala.collection.Iterable[A]) { self.prependAll(elems) } + override def prependAll(xs: TraversableOnce[A]) { self.prependAll(xs) } /** Inserts new elements at the index <code>n</code>. Opposed to method * <code>update</code>, this method will not replace an element with a diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala index c7932ae344..2e6a9149bc 100644 --- a/src/library/scala/collection/mutable/Builder.scala +++ b/src/library/scala/collection/mutable/Builder.scala @@ -48,7 +48,7 @@ trait Builder[-Elem, +To] extends Growable[Elem] { * builder implementations are still required to work correctly even if the hint is * wrong, i.e. a different number of elements is added. * - * @size the hint how many elements will be added. + * @param size the hint how many elements will be added. */ def sizeHint(size: Int) {} @@ -64,8 +64,7 @@ trait Builder[-Elem, +To] extends Growable[Elem] { val self = Builder.this def +=(x: Elem): this.type = { self += x; this } def clear() = self.clear() - override def ++=(xs: Iterator[Elem]): this.type = { self ++= xs; this } - override def ++=(xs:scala.collection.Traversable[Elem]): this.type = { self ++= xs; this } + override def ++=(xs: TraversableOnce[Elem]): this.type = { self ++= xs; this } def result: NewTo = f(self.result) } } diff --git a/src/library/scala/collection/mutable/ConcurrentMap.scala b/src/library/scala/collection/mutable/ConcurrentMap.scala index d09bf57e1b..2cfa4f8ae2 100644 --- a/src/library/scala/collection/mutable/ConcurrentMap.scala +++ b/src/library/scala/collection/mutable/ConcurrentMap.scala @@ -1,9 +1,5 @@ -package scala.collection.mutable - - - - - +package scala.collection +package mutable /** * A template trait for mutable maps that allow concurrent access. @@ -66,14 +62,4 @@ trait ConcurrentMap[A, B] extends Map[A, B] { * @return `Some(v)` if the given key was previously mapped to some value `v`, or `None` otherwise */ def replace(k: A, v: B): Option[B] - } - - - - - - - - - diff --git a/src/library/scala/collection/mutable/DoubleLinkedList.scala b/src/library/scala/collection/mutable/DoubleLinkedList.scala index 8c50f739e1..718d6aa35d 100644 --- a/src/library/scala/collection/mutable/DoubleLinkedList.scala +++ b/src/library/scala/collection/mutable/DoubleLinkedList.scala @@ -40,7 +40,7 @@ class DoubleLinkedList[A]() extends LinearSeq[A] } object DoubleLinkedList extends SeqFactory[DoubleLinkedList] { - implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, DoubleLinkedList[A]] = new GenericCanBuildFrom[A] //new CanBuildFrom[Coll, A, DoubleLinkedList[A]] { : Coll) = from.traversableBuilder[A] } + implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, DoubleLinkedList[A]] = new GenericCanBuildFrom[A] def newBuilder[A]: Builder[A, DoubleLinkedList[A]] = new Builder[A, DoubleLinkedList[A]] { var current: DoubleLinkedList[A] = _ diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index 0e73bf7fad..ea4033d405 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -11,7 +11,7 @@ package scala.collection package mutable -/** +/** An implementation class backing a HashSet. * @since 2.3 */ trait FlatHashTable[A] { @@ -46,7 +46,7 @@ trait FlatHashTable[A] { private def initialCapacity = capacity(initialSize) /** - * Initialises the collection from the input stream. `f` will be called for each element + * Initializes the collection from the input stream. `f` will be called for each element * read from the input stream in the order determined by the stream. This is useful for * structures where iteration order is important (e.g. LinkedHashSet). * diff --git a/src/library/scala/collection/mutable/GrowingBuilder.scala b/src/library/scala/collection/mutable/GrowingBuilder.scala new file mode 100644 index 0000000000..445e9d4f3e --- /dev/null +++ b/src/library/scala/collection/mutable/GrowingBuilder.scala @@ -0,0 +1,30 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection +package mutable + +import generic._ + +/** The canonical builder for collections that are growable, i.e. that support an + * efficient `+=` method which adds an element to the collection. It is + * almost identical to AddingBuilder, but necessitated by the existence of + * classes which are Growable but not Addable, which is a result of covariance + * interacting surprisingly with any2stringadd thus driving '+' out of the Seq + * hierarchy. The tendrils of original sin should never be underestimated. + * + * @author Paul Phillips + * @version 2.8 + * @since 2.8 + */ +class GrowingBuilder[Elem, To <: Growable[Elem]](empty: To) extends Builder[Elem, To] { + protected var elems: To = empty + def +=(x: Elem): this.type = { elems += x; this } + def clear() { elems = empty } + def result: To = elems +} diff --git a/src/library/scala/collection/mutable/HashMap.scala b/src/library/scala/collection/mutable/HashMap.scala index 658c574087..2b5cad37d8 100644 --- a/src/library/scala/collection/mutable/HashMap.scala +++ b/src/library/scala/collection/mutable/HashMap.scala @@ -67,7 +67,7 @@ class HashMap[A, B] extends Map[A, B] } /* Override to avoid tuple allocation in foreach */ - override def valuesIterable: collection.Iterable[B] = new DefaultValuesIterable { + override def values: collection.Iterable[B] = new DefaultValuesIterable { override def foreach[C](f: B => C) = foreachEntry(e => f(e.value)) } diff --git a/src/library/scala/collection/mutable/HashSet.scala b/src/library/scala/collection/mutable/HashSet.scala index f1f2ed3274..e985e717b0 100644 --- a/src/library/scala/collection/mutable/HashSet.scala +++ b/src/library/scala/collection/mutable/HashSet.scala @@ -50,7 +50,7 @@ class HashSet[A] extends Set[A] } } - override def clone(): Set[A] = new HashSet[A] ++= this + override def clone() = new HashSet[A] ++= this private def writeObject(s: java.io.ObjectOutputStream) { serializeTo(s) diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index aa7993ed14..14f1720a4c 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -65,7 +65,7 @@ trait HashTable[A] { private def initialCapacity = capacity(initialSize) /** - * Initialises the collection from the input stream. `f` will be called for each key/value pair + * Initializes the collection from the input stream. `f` will be called for each key/value pair * read from the input stream in the order determined by the stream. This is useful for * structures where iteration order is important (e.g. LinkedHashMap). */ diff --git a/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala b/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala index d6b3115b81..fba28e7c2a 100644 --- a/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala +++ b/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala @@ -12,6 +12,7 @@ package scala.collection package mutable +import annotation.migration /** This class can be used as an adaptor to create mutable maps from * immutable map implementations. Only method <code>empty</code> has @@ -41,19 +42,17 @@ extends Map[A, B] override def isDefinedAt(key: A) = imap.isDefinedAt(key) - override def keySet: scala.collection.Set[A] = imap.keySet + override def keySet: collection.Set[A] = imap.keySet override def keysIterator: Iterator[A] = imap.keysIterator - @deprecated("use `keysIterator' instead") - override def keys: Iterator[A] = imap.keysIterator - - override def valuesIterable: scala.collection.Iterable[B] = imap.valuesIterable + @migration(2, 8, "As of 2.8, keys returns Iterable[A] rather than Iterator[A].") + override def keys: collection.Iterable[A] = imap.keys override def valuesIterator: Iterator[B] = imap.valuesIterator - @deprecated("use `valuesIterator' instead") - override def values: Iterator[B] = imap.valuesIterator + @migration(2, 8, "As of 2.8, values returns Iterable[B] rather than Iterator[B].") + override def values: collection.Iterable[B] = imap.values def iterator: Iterator[(A, B)] = imap.iterator diff --git a/src/library/scala/collection/mutable/IndexedSeq.scala b/src/library/scala/collection/mutable/IndexedSeq.scala index b11131e917..0a173395e0 100644 --- a/src/library/scala/collection/mutable/IndexedSeq.scala +++ b/src/library/scala/collection/mutable/IndexedSeq.scala @@ -16,6 +16,9 @@ import generic._ /** A subtrait of <code>collection.IndexedSeq</code> which represents sequences * that can be mutated. + * $indexedSeqInfo + * + * @since 2.8 */ trait IndexedSeq[A] extends Seq[A] with scala.collection.IndexedSeq[A] diff --git a/src/library/scala/collection/mutable/IndexedSeqOptimized.scala b/src/library/scala/collection/mutable/IndexedSeqOptimized.scala new file mode 100755 index 0000000000..134cc2a8ea --- /dev/null +++ b/src/library/scala/collection/mutable/IndexedSeqOptimized.scala @@ -0,0 +1,21 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id: IndexedSeqLike.scala 20129 2009-12-14 17:12:17Z odersky $ + + +package scala.collection +package mutable +import generic._ + +/** A subtrait of scala.collection.IndexedSeq which represents sequences + * that can be mutated. + * + * @since 2.8 + */ +trait IndexedSeqOptimized[A, +Repr] extends IndexedSeqLike[A, Repr] with scala.collection.IndexedSeqOptimized[A, Repr] diff --git a/src/library/scala/collection/mutable/IndexedSeqView.scala b/src/library/scala/collection/mutable/IndexedSeqView.scala index e864845455..d870b762d3 100644 --- a/src/library/scala/collection/mutable/IndexedSeqView.scala +++ b/src/library/scala/collection/mutable/IndexedSeqView.scala @@ -25,7 +25,10 @@ import TraversableView.NoBuilder * @version 2.8 * @since 2.8 */ -trait IndexedSeqView[A, +Coll] extends scala.collection.IndexedSeqView[A, Coll] { +trait IndexedSeqView[A, +Coll] extends IndexedSeq[A] + with IndexedSeqOptimized[A, IndexedSeqView[A, Coll]] + with scala.collection.SeqView[A, Coll] + with scala.collection.SeqViewLike[A, Coll, IndexedSeqView[A, Coll]] { self => def update(idx: Int, elem: A) @@ -88,9 +91,22 @@ self => override def reverse: IndexedSeqView[A, Coll] = newReversed.asInstanceOf[IndexedSeqView[A, Coll]] } -/* - * object IndexedSeqView { - type Coll = TraversableView[_, C] forSome { type C <: scala.collection.Traversable[_] } - implicit def canBuildFrom[A]: CanBuildFrom[IndexedSeq[_], A, IndexedSeqView[A], Coll] = new CanBuildFrom[mutable.IndexedSeq[_], A, IndexedSeqView[A], Coll] { : Coll) = new NoBuilder } +/** $factoryInfo + * Note that the canBuildFrom factories yield SeqViews, not IndexedSewqViews. + * This is intentional, because not all operations yield again a mutable.IndexedSeqView. + * For instance, map just gives a SeqView, which reflects the fact that + * map cannot do its work and maintain a pointer into the original indexed sequence. + */ +object IndexedSeqView { + type Coll = TraversableView[_, C] forSome {type C <: Traversable[_]} + implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, SeqView[A, Seq[_]]] = + new CanBuildFrom[Coll, A, SeqView[A, Seq[_]]] { + def apply(from: Coll) = new NoBuilder + def apply() = new NoBuilder + } + implicit def arrCanBuildFrom[A]: CanBuildFrom[TraversableView[_, Array[_]], A, SeqView[A, Array[A]]] = + new CanBuildFrom[TraversableView[_, Array[_]], A, SeqView[A, Array[A]]] { + def apply(from: TraversableView[_, Array[_]]) = new NoBuilder + def apply() = new NoBuilder + } } -*/ diff --git a/src/library/scala/collection/mutable/LazyBuilder.scala b/src/library/scala/collection/mutable/LazyBuilder.scala index 2ce1fa9827..7714d29f08 100644 --- a/src/library/scala/collection/mutable/LazyBuilder.scala +++ b/src/library/scala/collection/mutable/LazyBuilder.scala @@ -20,10 +20,9 @@ import immutable.{List, Nil} */ abstract class LazyBuilder[Elem, +To] extends Builder[Elem, To] { /** The different segments of elements to be added to the builder, represented as iterators */ - protected var parts = new ListBuffer[scala.collection.Traversable[Elem]] + protected var parts = new ListBuffer[TraversableOnce[Elem]] def +=(x: Elem): this.type = { parts += List(x); this } - override def ++=(xs: Iterator[Elem]): this.type = { parts += xs.toStream; this } - override def ++=(xs: scala.collection.Traversable[Elem]): this.type = { parts += xs; this } + override def ++=(xs: TraversableOnce[Elem]): this.type = { parts += xs ; this } def result(): To def clear() { parts.clear() } } diff --git a/src/library/scala/collection/mutable/LinearSeq.scala b/src/library/scala/collection/mutable/LinearSeq.scala index 25d7ef6be8..9abaef5aff 100644 --- a/src/library/scala/collection/mutable/LinearSeq.scala +++ b/src/library/scala/collection/mutable/LinearSeq.scala @@ -14,8 +14,9 @@ package mutable import generic._ -/** A subtrait of <code>collection.Seq</code> which represents sequences - * that cannot be mutated. +/** A subtrait of <code>collection.LinearSeq</code> which represents sequences + * that can be mutated. + * $linearSeqInfo * * @since 2.8 */ diff --git a/src/library/scala/collection/mutable/LinkedListLike.scala b/src/library/scala/collection/mutable/LinkedListLike.scala index c363609762..2523ece370 100644 --- a/src/library/scala/collection/mutable/LinkedListLike.scala +++ b/src/library/scala/collection/mutable/LinkedListLike.scala @@ -55,7 +55,7 @@ trait LinkedListLike[A, This <: Seq[A] with LinkedListLike[A, This]] extends Seq } /** Insert linked list `that` at current position of this linked list - * @pre this linked list is not empty + * @note this linked list must not be empty */ def insert(that: This): Unit = { require(nonEmpty, "insert into empty list") diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala index 686b1acf8d..b8e5aeb262 100644 --- a/src/library/scala/collection/mutable/ListBuffer.scala +++ b/src/library/scala/collection/mutable/ListBuffer.scala @@ -231,7 +231,7 @@ final class ListBuffer[A] * * @param n the index which refers to the element to delete. * @return n the element that was formerly at position <code>n</code>. - * @pre an element exists at position <code>n</code> + * @note an element must exists at position <code>n</code> * @throws Predef.IndexOutOfBoundsException if <code>n</code> is out of bounds. */ def remove(n: Int): A = { @@ -335,5 +335,5 @@ final class ListBuffer[A] */ object ListBuffer extends SeqFactory[ListBuffer] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListBuffer[A]] = new GenericCanBuildFrom[A] - def newBuilder[A]: Builder[A, ListBuffer[A]] = new AddingBuilder(new ListBuffer[A]) + def newBuilder[A]: Builder[A, ListBuffer[A]] = new GrowingBuilder(new ListBuffer[A]) } diff --git a/src/library/scala/collection/mutable/ListMap.scala b/src/library/scala/collection/mutable/ListMap.scala index 82cc6340c0..c96873c81d 100644 --- a/src/library/scala/collection/mutable/ListMap.scala +++ b/src/library/scala/collection/mutable/ListMap.scala @@ -14,7 +14,7 @@ package mutable import generic._ -/** +/** A simple map backed by a list. * @since 2.8 */ @serializable diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala index a1bb25910a..9c3c1c0e5f 100644 --- a/src/library/scala/collection/mutable/MapLike.scala +++ b/src/library/scala/collection/mutable/MapLike.scala @@ -13,6 +13,7 @@ package scala.collection package mutable import generic._ +import annotation.migration /** A template trait for mutable maps of type `mutable.Map[A, B]` which * associate keys of type `A` with values of type `B`. @@ -41,7 +42,7 @@ import generic._ * {{{ * def> empty: This * }}} - * If you wish to avoid the unncessary construction of an `Option` + * If you wish to avoid the unnecessary construction of an `Option` * object, you could also override `apply`, `update`, * and `delete`. @@ -51,7 +52,7 @@ import generic._ * @define Coll mutable.Map */ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] - extends MapLikeBase[A, B, This] + extends scala.collection.MapLike[A, B, This] with Builder[(A, B), This] with Growable[(A, B)] with Shrinkable[A] @@ -101,23 +102,24 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] def += (kv: (A, B)): this.type /** Creates a new map consisting of all key/value pairs of the current map - * plus a new pair of a guven key and value. + * plus a new pair of a given key and value. * * @param key The key to add * @param value The new value * @return A fresh immutable map with the binding from `key` to * `value` added to this map. */ - override def updated[B1 >: B](key: A, value: B1): mutable.Map[A, B1] = this + ((key, value)) + override def updated[B1 >: B](key: A, value: B1): Map[A, B1] = this + ((key, value)) /** Add a new key/value mapping and return the map itself. * * @param kv the key/value mapping to be added */ - @deprecated("This operation will create a new map in the future. To add an element as a side\n"+ - "effect to an existing map and return that map itself, use +=. If you do want\n"+ - "to create a fresh map, you can use `clone() +=' to avoid a @deprecated warning.") - def + (kv: (A, B)): this.type = { update(kv._1, kv._2); this } + @migration(2, 8, + "As of 2.8, this operation creates a new map. To add an element as a\n"+ + "side effect to an existing map and return that map itself, use +=." + ) + def + [B1 >: B] (kv: (A, B1)): Map[A, B1] = clone().asInstanceOf[Map[A, B1]] += kv /** Adds two or more key/value mappings and return the map itself. * with the added elements. @@ -126,11 +128,12 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param elem2 the second element to add. * @param elems the remaining elements to add. */ - @deprecated("This operation will create a new map in the future. To add an element as a side\n"+ - "effect to an existing map and return that map itself, use +=. If you do want to\n"+ - "create a fresh map, you can use `clone() +=` to avoid a @deprecated warning.") - def +(elem1: (A, B), elem2: (A, B), elems: (A, B)*): this.type = - this += elem1 += elem2 ++= elems + @migration(2, 8, + "As of 2.8, this operation creates a new map. To add an element as a\n"+ + "side effect to an existing map and return that map itself, use +=." + ) + override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): Map[A, B1] = + clone().asInstanceOf[Map[A, B1]] += elem1 += elem2 ++= elems /** Adds a number of elements provided by a traversable object * via its `iterator` method and returns @@ -139,21 +142,12 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * * @param iter the traversable object. */ - @deprecated("This operation will create a new map in the future. To add elements as a side\n"+ - "effect to an existing map and return that map itself, use ++=. If you do want\n"+ - "to create a fresh map, you can use `clone() ++=` to avoid a @deprecated warning.") - def ++(iter: Traversable[(A, B)]): this.type = { for (elem <- iter) +=(elem); this } - - /** Adds a number of elements provided by an iterator - * via its `iterator` method and returns - * the collection itself. - * - * @param iter the iterator - */ - @deprecated("This operation will create a new map in the future. To add elements as a side\n"+ - "effect to an existing map and return that map itself, use ++=. If you do want\n"+ - "to create a fresh map, you can use `clone() +=` to avoid a @deprecated warning.") - def ++(iter: Iterator[(A, B)]): this.type = { for (elem <- iter) +=(elem); this } + @migration(2, 8, + "As of 2.8, this operation creates a new map. To add the elements as a\n"+ + "side effect to an existing map and return that map itself, use ++=." + ) + override def ++[B1 >: B](xs: TraversableOnce[(A, B1)]): Map[A, B1] = + clone().asInstanceOf[Map[A, B1]] ++= xs /** Removes a key from this map, returning the value associated previously * with that key as an option. @@ -176,30 +170,31 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] /** Delete a key from this map if it is present and return the map itself. * @param key the key to be removed */ - @deprecated("This operation will create a new map in the future. To add elements as a side\n"+ - "effect to an existing map and return that map itself, use -=. If you do want\n"+ - "to create a fresh map, you can use `clone() -=` to avoid a @deprecated warning.") - override def -(key: A): This = { -=(key); repr } + @migration(2, 8, + "As of 2.8, this operation creates a new map. To remove an element as a\n"+ + "side effect to an existing map and return that map itself, use -=." + ) + override def -(key: A): This = clone() -= key /** If given key is defined in this map, remove it and return associated value as an Option. * If key is not present return None. * @param key the key to be removed */ - @deprecated("Use `remove' instead") def removeKey(key: A): Option[B] = remove(key) + @deprecated("Use `remove' instead") def removeKey(key: A): Option[B] = remove(key) /** Removes all bindings from the map. After this operation has completed, * the map will be empty. */ - def clear() { for ((k, v) <- this.iterator) -=(k) } + def clear() { keysIterator foreach -= } /** If given key is already in this map, returns associated value * Otherwise, computes value from given expression `op`, stores with key * in map and returns that value. - * @param the key to test - * @param the computation yielding the value to associate with `key`, if - * `key` is previosuly unbound. - * @return the value associated with key (either previously or as a result - * of executing the method). + * @param key the key to test + * @param op the computation yielding the value to associate with `key`, if + * `key` is previously unbound. + * @return the value associated with key (either previously or as a result + * of executing the method). */ def getOrElseUpdate(key: A, op: => B): B = get(key) match { @@ -209,7 +204,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] /** Applies a transformation function to all values contained in this map. * The transformation function produces new values from existing keys - * asssociated values. + * associated values. * * @param f the transformation to apply * @return the map itself. @@ -232,8 +227,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] this } - override def clone(): This = - empty ++= repr + override def clone(): This = empty ++= repr /** The result when this map is used as a builder * @return the map representation itself. @@ -247,35 +241,21 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param elem2 the second element to remove. * @param elems the remaining elements to remove. */ - @deprecated("Use -= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() -=' if you intend to create a new collection.") - override def -(elem1: A, elem2: A, elems: A*): This = { - this -= elem1 -= elem2 --= elems - repr - } + @migration(2, 8, + "As of 2.8, this operation creates a new map. To remove an element as a\n"+ + "side effect to an existing map and return that map itself, use -=." + ) + override def -(elem1: A, elem2: A, elems: A*): This = + clone() -= elem1 -= elem2 --= elems /** Removes a number of elements provided by a Traversable object and returns * the collection itself. * * @param iter the Traversable object. */ - @deprecated("Use --= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() --=' if you intend to create a new collection.") - override def --(iter: Traversable[A]): This = { - for (elem <- iter) -=(elem) - repr - } - - - /** Removes a number of elements provided by an iterator and returns - * the collection itself. - * - * @param iter the iterator - */ - @deprecated("Use --= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() --=' if you intend to create a new collection.") - override def --(iter: Iterator[A]): This = { - for (elem <- iter) -=(elem) - repr - } + @migration(2, 8, + "As of 2.8, this operation creates a new map. To remove the elements as a\n"+ + "side effect to an existing map and return that map itself, use --=." + ) + override def --(xs: TraversableOnce[A]): This = clone() --= xs } diff --git a/src/library/scala/collection/mutable/MapLikeBase.scala b/src/library/scala/collection/mutable/MapLikeBase.scala deleted file mode 100644 index 402df79d84..0000000000 --- a/src/library/scala/collection/mutable/MapLikeBase.scala +++ /dev/null @@ -1,37 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - -// $Id$ - - -package scala.collection -package mutable - -/** The reason for this class is so that we can - * have both a generic immutable `+` with signature - * - * def + [B1 >: B](kv: (A, B1)): Map[A, B1] - * - * and a (deprecated) mutable `+` of signature - * - * def + (kv: (A, B)): this.type = this += kv - * - * The former is required to fulfill the Map contract. - * The latter is required for backwards compatibility. - * We can't have both methods in the same class, as that would give a double definition. - * They are OK in different classes though, and narrowly escape a `same erasure' problem. - * Once the deprecated + goes away we can do without class MapLikeBase. - * - * @author Martin Odersky - * @version 2.8 - * @since 2.8 - */ -trait MapLikeBase[A, B, +This <: MapLikeBase[A, B, This] with Map[A, B]] - extends scala.collection.MapLike[A, B, This] with Cloneable[This] { - def + [B1 >: B] (kv: (A, B1)): mutable.Map[A, B1] = clone().asInstanceOf[mutable.Map[A, B1]] += kv -} diff --git a/src/library/scala/collection/mutable/MapProxy.scala b/src/library/scala/collection/mutable/MapProxy.scala index 55e6eba1e3..cb768f6778 100644 --- a/src/library/scala/collection/mutable/MapProxy.scala +++ b/src/library/scala/collection/mutable/MapProxy.scala @@ -28,14 +28,16 @@ package mutable trait MapProxy[A, B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]] { + private def newProxy[B1 >: B](newSelf: Map[A, B1]): MapProxy[A, B1] = + new MapProxy[A, B1] { val self = newSelf } + override def repr = this override def empty: MapProxy[A, B] = new MapProxy[A, B] { val self = MapProxy.this.self.empty } - override def +(kv: (A, B)) = { self.update(kv._1, kv._2) ; this } - override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *) = - { self.+(elem1, elem2, elems: _*) ; this } + override def + [B1 >: B] (kv: (A, B1)): Map[A, B1] = newProxy(self + kv) + override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *) = newProxy(self.+(elem1, elem2, elems: _*)) - override def -(key: A) = { self.remove(key); this } + override def -(key: A) = newProxy(self - key) override def += (kv: (A, B)) = { self += kv ; this } override def -= (key: A) = { self -= key ; this } diff --git a/src/library/scala/collection/mutable/MultiMap.scala b/src/library/scala/collection/mutable/MultiMap.scala index e335500349..01ddea070c 100644 --- a/src/library/scala/collection/mutable/MultiMap.scala +++ b/src/library/scala/collection/mutable/MultiMap.scala @@ -25,6 +25,9 @@ package mutable trait MultiMap[A, B] extends Map[A, Set[B]] { protected def makeSet: Set[B] = new HashSet[B] + @deprecated("use addBinding instead") + def add(key: A, value: B): this.type = addBinding(key, value) + def addBinding(key: A, value: B): this.type = { get(key) match { case None => diff --git a/src/library/scala/collection/mutable/MutableList.scala b/src/library/scala/collection/mutable/MutableList.scala index e6423aa677..7784927c87 100644 --- a/src/library/scala/collection/mutable/MutableList.scala +++ b/src/library/scala/collection/mutable/MutableList.scala @@ -29,7 +29,7 @@ import immutable.{List, Nil} */ @serializable @SerialVersionUID(5938451523372603072L) class MutableList[A] extends LinearSeq[A] - with LinearSeqLike[A, MutableList[A]] + with LinearSeqOptimized[A, MutableList[A]] with Builder[A, MutableList[A]] { override protected[this] def newBuilder = new MutableList[A] diff --git a/src/library/scala/collection/mutable/OpenHashMap.scala b/src/library/scala/collection/mutable/OpenHashMap.scala index 9f0d9d2c25..79bb96a0bf 100644 --- a/src/library/scala/collection/mutable/OpenHashMap.scala +++ b/src/library/scala/collection/mutable/OpenHashMap.scala @@ -15,7 +15,7 @@ package mutable /** * @since 2.7 */ -object OpenHashMap{ +object OpenHashMap { def apply[K, V](elems : (K, V)*) = { val dict = new OpenHashMap[K, V]; elems.foreach({case (x, y) => dict(x) = y}); diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala index c4dac9effb..4d74a2ee74 100644 --- a/src/library/scala/collection/mutable/PriorityQueue.scala +++ b/src/library/scala/collection/mutable/PriorityQueue.scala @@ -13,7 +13,7 @@ package scala.collection package mutable import generic._ - +import annotation.migration /** This class implements priority queues using a heap. * To prioritize elements of type T there must be an implicit @@ -28,7 +28,6 @@ import generic._ class PriorityQueue[A](implicit ord: Ordering[A]) extends Seq[A] with SeqLike[A, PriorityQueue[A]] - with Addable[A, PriorityQueue[A]] with Growable[A] with Cloneable[PriorityQueue[A]] with Builder[A, PriorityQueue[A]] @@ -47,8 +46,8 @@ class PriorityQueue[A](implicit ord: Ordering[A]) private val resarr = new ResizableArrayAccess[A] - resarr.p_size0 += 1 // we do not use array(0) - override def length: Int = resarr.length - 1 // adjust length accordingly + resarr.p_size0 += 1 // we do not use array(0) + override def length: Int = resarr.length - 1 // adjust length accordingly override def size: Int = length override def isEmpty: Boolean = resarr.p_size0 < 2 override def repr = this @@ -116,6 +115,23 @@ class PriorityQueue[A](implicit ord: Ordering[A]) } } + @deprecated( + "Use += instead if you intend to add by side effect to an existing collection.\n"+ + "Use `clone() +=' if you intend to create a new collection." + ) + def +(elem: A): PriorityQueue[A] = { this.clone() += elem } + + /** Add two or more elements to this set. + * @param elem1 the first element. + * @param kv2 the second element. + * @param kvs the remaining elements. + */ + @deprecated( + "Use ++= instead if you intend to add by side effect to an existing collection.\n"+ + "Use `clone() ++=' if you intend to create a new collection." + ) + def +(elem1: A, elem2: A, elems: A*) = { this.clone().+=(elem1, elem2, elems : _*) } + /** Inserts a single element into the priority queue. * * @param elem the element to insert @@ -128,27 +144,12 @@ class PriorityQueue[A](implicit ord: Ordering[A]) this } - def +(elem: A): PriorityQueue[A] = { this.clone() += elem } - - /** Add two or more elements to this set. - * @param elem1 the first element. - * @param kv2 the second element. - * @param kvs the remaining elements. - */ - override def +(elem1: A, elem2: A, elems: A*) = { this.clone().+=(elem1, elem2, elems : _*) } - /** Adds all elements provided by an <code>Iterable</code> object * into the priority queue. * * @param iter an iterable object */ - override def ++(elems: scala.collection.Traversable[A]) = { this.clone() ++= elems } - - /** Adds all elements provided by an iterator into the priority queue. - * - * @param it an iterator - */ - override def ++(iter: Iterator[A]) = { this.clone() ++= iter } // ...whereas this doesn't? + def ++(xs: TraversableOnce[A]) = { this.clone() ++= xs } /** Adds all elements to the queue. * @@ -223,7 +224,7 @@ class PriorityQueue[A](implicit ord: Ordering[A]) } override def reverseIterator = new Iterator[A] { - val arr = new Array[Any](size) + val arr = new Array[Any](PriorityQueue.this.size) iterator.copyToArray(arr) var i = arr.size - 1 def hasNext: Boolean = i >= 0 @@ -267,9 +268,9 @@ class PriorityQueue[A](implicit ord: Ordering[A]) // } } - - - - - - +// !!! TODO - but no SortedSeqFactory (yet?) +// object PriorityQueue extends SeqFactory[PriorityQueue] { +// def empty[A](implicit ord: Ordering[A]): PriorityQueue[A] = new PriorityQueue[A](ord) +// implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, PriorityQueue] = +// } +//
\ No newline at end of file diff --git a/src/library/scala/collection/mutable/PriorityQueueProxy.scala b/src/library/scala/collection/mutable/PriorityQueueProxy.scala index 0771ce6b60..427ffe478a 100644 --- a/src/library/scala/collection/mutable/PriorityQueueProxy.scala +++ b/src/library/scala/collection/mutable/PriorityQueueProxy.scala @@ -48,21 +48,11 @@ abstract class PriorityQueueProxy[A](implicit ord: Ordering[A]) extends Priority */ override def +=(elem: A): this.type = { self += elem; this } - /** Adds all elements provided by an <code>Iterable</code> object - * into the priority queue. - * - * @param iter an iterable object - */ - def ++=(iter: scala.collection.Iterable[A]): this.type = { - self ++= iter - this - } - /** Adds all elements provided by an iterator into the priority queue. * * @param it an iterator */ - override def ++=(it: Iterator[A]): this.type = { + override def ++=(it: TraversableOnce[A]): this.type = { self ++= it this } diff --git a/src/library/scala/collection/mutable/Publisher.scala b/src/library/scala/collection/mutable/Publisher.scala index 4f675eff9f..58e4394ef7 100644 --- a/src/library/scala/collection/mutable/Publisher.scala +++ b/src/library/scala/collection/mutable/Publisher.scala @@ -47,7 +47,7 @@ trait Publisher[Evt] { def removeSubscriptions() { filters.clear } protected def publish(event: Evt) { - filters.keysIterator.foreach(sub => + filters.keys.foreach(sub => if (!suspended.contains(sub) && filters.entryExists(sub, p => p(event))) sub.notify(self, event) diff --git a/src/library/scala/collection/mutable/Queue.scala b/src/library/scala/collection/mutable/Queue.scala index 3b09ceba91..3754dbc3f2 100644 --- a/src/library/scala/collection/mutable/Queue.scala +++ b/src/library/scala/collection/mutable/Queue.scala @@ -24,7 +24,6 @@ import generic._ */ @serializable @cloneable class Queue[A] extends MutableList[A] with Cloneable[Queue[A]] { - /** Adds all elements to the queue. * * @param elems the elements to add. @@ -144,3 +143,8 @@ class Queue[A] extends MutableList[A] with Cloneable[Queue[A]] { */ def front: A = first0.elem } + +// !!! TODO - integrate +object Queue { + def apply[A](xs: A*): Queue[A] = new Queue[A] ++= xs +} diff --git a/src/library/scala/collection/mutable/QueueProxy.scala b/src/library/scala/collection/mutable/QueueProxy.scala index a322934f63..b2548b26cc 100644 --- a/src/library/scala/collection/mutable/QueueProxy.scala +++ b/src/library/scala/collection/mutable/QueueProxy.scala @@ -45,24 +45,13 @@ trait QueueProxy[A] extends Queue[A] with Proxy { */ override def +=(elem: A): this.type = { self += elem; this } - /** Adds all elements provided by an <code>Iterable</code> object - * at the end of the queue. The elements are prepended in the order they - * are given out by the iterator. - * - * @param iter an iterable object - */ - def ++=(iter: scala.collection.Iterable[A]): this.type = { - self ++= iter - this - } - /** Adds all elements provided by an iterator * at the end of the queue. The elements are prepended in the order they * are given out by the iterator. * * @param iter an iterator */ - override def ++=(it: Iterator[A]): this.type = { + override def ++=(it: TraversableOnce[A]): this.type = { self ++= it this } diff --git a/src/library/scala/collection/mutable/ResizableArray.scala b/src/library/scala/collection/mutable/ResizableArray.scala index 435eb3ee0f..80ab1cd559 100644 --- a/src/library/scala/collection/mutable/ResizableArray.scala +++ b/src/library/scala/collection/mutable/ResizableArray.scala @@ -24,7 +24,7 @@ import generic._ */ trait ResizableArray[A] extends IndexedSeq[A] with GenericTraversableTemplate[A, ResizableArray] - with IndexedSeqLike[A, ResizableArray[A]] { + with IndexedSeqOptimized[A, ResizableArray[A]] { override def companion: GenericCompanion[ResizableArray] = ResizableArray diff --git a/src/library/scala/collection/mutable/SetBuilder.scala b/src/library/scala/collection/mutable/SetBuilder.scala index 6286c46ac4..450d76463c 100644 --- a/src/library/scala/collection/mutable/SetBuilder.scala +++ b/src/library/scala/collection/mutable/SetBuilder.scala @@ -13,17 +13,10 @@ package mutable import generic._ -/** The canonical builder for collections that are addable, i.e. that support - * an efficient + method which adds an element to the collection. - * Collections are built from their empty element using this + method. - * @param empty The empty element of the collection. +/** The canonical builder for mutable Sets. * + * @param empty The empty element of the collection. * @since 2.8 */ -class SetBuilder[A, Coll <: Addable[A, Coll] with scala.collection.Iterable[A] with scala.collection.IterableLike[A, Coll]](empty: Coll) -extends Builder[A, Coll] { - protected var elems: Coll = empty - def +=(x: A): this.type = { elems = elems + x; this } - def clear() { elems = empty } - def result: Coll = elems -} +class SetBuilder[A, Coll <: Addable[A, Coll] with collection.Iterable[A] with collection.IterableLike[A, Coll]](empty: Coll) +extends AddingBuilder[A, Coll](empty) { } diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala index cb6eb293c1..7004e52b8e 100644 --- a/src/library/scala/collection/mutable/SetLike.scala +++ b/src/library/scala/collection/mutable/SetLike.scala @@ -14,6 +14,7 @@ package mutable import generic._ import script._ +import scala.annotation.migration /** A template trait for mutable sets of type `mutable.Set[A]`. * @tparam A the type of the elements of the set @@ -63,6 +64,9 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] */ override protected[this] def newBuilder: Builder[A, This] = empty + @migration(2, 8, "Set.map now returns a Set, so it will discard duplicate values.") + override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = super.map(f)(bf) + /** Adds an element to this $coll. * * @param elem the element to be added @@ -119,7 +123,7 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] */ def clear() { foreach(-=) } - override def clone(): mutable.Set[A] = empty ++= repr + override def clone(): This = empty ++= repr /** The result when this set is used as a builder * @return the set representation itself. @@ -131,9 +135,11 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] * * @param elem the element to add. */ - @deprecated("Use += instead if you intend to add by side effect to an existing collection.\n"+ - "Use `clone() +=' if you intend to create a new collection.") - override def + (elem: A): This = { +=(elem); repr } + @migration(2, 8, + "As of 2.8, this operation creates a new set. To add an element as a\n"+ + "side effect to an existing set and return that set itself, use +=." + ) + override def + (elem: A): This = clone() += elem /** Adds two or more elements to this collection and returns * the collection itself. @@ -142,45 +148,34 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] * @param elem2 the second element to add. * @param elems the remaining elements to add. */ - @deprecated("Use += instead if you intend to add by side effect to an existing collection.\n"+ - "Use `clone() +=' if you intend to create a new collection.") - override def + (elem1: A, elem2: A, elems: A*): This = { - this += elem1 += elem2 ++= elems - repr - } + @migration(2, 8, + "As of 2.8, this operation creates a new set. To add the elements as a\n"+ + "side effect to an existing set and return that set itself, use +=." + ) + override def + (elem1: A, elem2: A, elems: A*): This = + clone() += elem1 += elem2 ++= elems /** Adds a number of elements provided by a traversable object and returns * either the collection itself. * * @param iter the iterable object. */ - @deprecated("Use ++= instead if you intend to add by side effect to an existing collection.\n"+ - "Use `clone() ++=' if you intend to create a new collection.") - override def ++(iter: scala.collection.Traversable[A]): This = { - for (elem <- iter) +=(elem) - repr - } - - /** Adds a number of elements provided by an iterator and returns - * the collection itself. - * - * @param iter the iterator - */ - @deprecated("Use ++= instead if you intend to add by side effect to an existing collection.\n"+ - "Use `clone() ++=' if you intend to create a new collection.") - override def ++ (iter: Iterator[A]): This = { - for (elem <- iter) +=(elem) - repr - } + @migration(2, 8, + "As of 2.8, this operation creates a new set. To add the elements as a\n"+ + "side effect to an existing set and return that set itself, use ++=." + ) + override def ++(xs: TraversableOnce[A]): This = clone() ++= xs /** Removes a single element from this collection and returns * the collection itself. * * @param elem the element to remove. */ - @deprecated("Use -= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() -=' if you intend to create a new collection.") - override def -(elem: A): This = { -=(elem); repr } + @migration(2, 8, + "As of 2.8, this operation creates a new set. To remove the element as a\n"+ + "side effect to an existing set and return that set itself, use -=." + ) + override def -(elem: A): This = clone() -= elem /** Removes two or more elements from this collection and returns * the collection itself. @@ -189,36 +184,23 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] * @param elem2 the second element to remove. * @param elems the remaining elements to remove. */ - @deprecated("Use -= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() -=' if you intend to create a new collection.") - override def -(elem1: A, elem2: A, elems: A*): This = { - this -= elem1 -= elem2 --= elems - repr - } + @migration(2, 8, + "As of 2.8, this operation creates a new set. To remove the elements as a\n"+ + "side effect to an existing set and return that set itself, use -=." + ) + override def -(elem1: A, elem2: A, elems: A*): This = + clone() -= elem1 -= elem2 --= elems /** Removes a number of elements provided by a Traversable object and returns * the collection itself. * * @param iter the Traversable object. */ - @deprecated("Use --= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() --=' if you intend to create a new collection.") - override def --(iter: scala.collection.Traversable[A]): This = { - for (elem <- iter) -=(elem) - repr - } - - /** Removes a number of elements provided by an iterator and returns - * the collection itself. - * - * @param iter the iterator - */ - @deprecated("Use --= instead if you intend to remove by side effect from an existing collection.\n"+ - "Use `clone() --=' if you intend to create a new collection.") - override def --(iter: Iterator[A]): This = { - for (elem <- iter) -=(elem) - repr - } + @migration(2, 8, + "As of 2.8, this operation creates a new set. To remove the elements as a\n"+ + "side effect to an existing set and return that set itself, use --=." + ) + override def --(xs: TraversableOnce[A]): This = clone() --= xs /** Send a message to this scriptable object. * diff --git a/src/library/scala/collection/mutable/Stack.scala b/src/library/scala/collection/mutable/Stack.scala index bbb4189dc3..45e9fa24b2 100644 --- a/src/library/scala/collection/mutable/Stack.scala +++ b/src/library/scala/collection/mutable/Stack.scala @@ -15,6 +15,7 @@ package mutable import generic._ import collection.immutable.{List, Nil} import collection.Iterator +import annotation.migration /** A stack implements a data structure which allows to store and retrieve * objects in a last-in-first-out (LIFO) fashion. @@ -63,19 +64,11 @@ class Stack[A] private (var elems: List[A]) extends scala.collection.Seq[A] with * @param elems the iterator object. * @return the stack with the new elements on top. */ - def pushAll(elems: Iterator[A]): this.type = { for (elem <- elems) { push(elem); () }; this } + def pushAll(xs: TraversableOnce[A]): this.type = { xs foreach push ; this } - /** Push all elements provided by the given iterable object onto - * the stack. The last element returned by the traversable object - * will be on top of the new stack. - * - * @param elems the iterable object. - * @return the stack with the new elements on top. - */ - def pushAll(elems: scala.collection.Traversable[A]): this.type = { for (elem <- elems) { push(elem); () }; this } - - @deprecated("use pushAll") def ++=(it: Iterator[A]): this.type = pushAll(it) - @deprecated("use pushAll") def ++=(it: scala.collection.Iterable[A]): this.type = pushAll(it) + @deprecated("use pushAll") + @migration(2, 8, "Stack ++= now pushes arguments on the stack from left to right.") + def ++=(xs: TraversableOnce[A]): this.type = pushAll(xs) /** Returns the top element of the stack. This method will not remove * the element from the stack. An error is signaled if there is no @@ -112,17 +105,27 @@ class Stack[A] private (var elems: List[A]) extends scala.collection.Seq[A] with * * @return an iterator over all stack elements. */ + @migration(2, 8, "Stack iterator and foreach now traverse in FIFO order.") override def iterator: Iterator[A] = elems.iterator /** Creates a list of all stack elements in LIFO order. * * @return the created list. */ + @migration(2, 8, "Stack iterator and foreach now traverse in FIFO order.") override def toList: List[A] = elems + @migration(2, 8, "Stack iterator and foreach now traverse in FIFO order.") + override def foreach[U](f: A => U): Unit = super.foreach(f) + /** This method clones the stack. * * @return a stack with the same elements. */ override def clone(): Stack[A] = new Stack[A](elems) } + +// !!! TODO - integrate +object Stack { + def apply[A](xs: A*): Stack[A] = new Stack[A] ++= xs +} diff --git a/src/library/scala/collection/mutable/StackProxy.scala b/src/library/scala/collection/mutable/StackProxy.scala index 99f556112a..d3810dd158 100644 --- a/src/library/scala/collection/mutable/StackProxy.scala +++ b/src/library/scala/collection/mutable/StackProxy.scala @@ -48,15 +48,7 @@ trait StackProxy[A] extends Stack[A] with Proxy { this } - override def pushAll(elems: Iterator[A]): this.type = { - self pushAll elems - this - } - - override def pushAll(elems: scala.collection.Traversable[A]): this.type = { - self pushAll elems - this - } + override def pushAll(xs: TraversableOnce[A]): this.type = { self pushAll xs; this } /** Pushes all elements provided by an <code>Iterable</code> object * on top of the stack. The elements are pushed in the order they @@ -64,21 +56,8 @@ trait StackProxy[A] extends Stack[A] with Proxy { * * @param iter an iterable object */ - @deprecated("use pushAll") override def ++=(iter: scala.collection.Iterable[A]): this.type = { - self ++= iter - this - } + @deprecated("use pushAll") override def ++=(xs: TraversableOnce[A]): this.type = { self ++= xs ; this } - /** Pushes all elements provided by an iterator - * on top of the stack. The elements are pushed in the order they - * are given out by the iterator. - * - * @param iter an iterator - */ - @deprecated("use pushAll") override def ++=(it: Iterator[A]): this.type = { - self ++= it - this - } override def push(elem1: A, elem2: A, elems: A*): this.type = { self.push(elem1).push(elem2).pushAll(elems) diff --git a/src/library/scala/collection/mutable/SynchronizedBuffer.scala b/src/library/scala/collection/mutable/SynchronizedBuffer.scala index f6caa57729..1c9a77c46a 100644 --- a/src/library/scala/collection/mutable/SynchronizedBuffer.scala +++ b/src/library/scala/collection/mutable/SynchronizedBuffer.scala @@ -60,8 +60,8 @@ trait SynchronizedBuffer[A] extends Buffer[A] { * * @param iter the iterable object. */ - override def ++(iter: Traversable[A]): Self = synchronized { - super.++(iter) + override def ++(xs: TraversableOnce[A]): Self = synchronized { + super.++(xs) } /** Appends a number of elements provided by an iterable object @@ -69,8 +69,8 @@ trait SynchronizedBuffer[A] extends Buffer[A] { * * @param iter the iterable object. */ - override def ++=(iter: Traversable[A]): this.type = synchronized[this.type] { - super.++=(iter) + override def ++=(xs: TraversableOnce[A]): this.type = synchronized[this.type] { + super.++=(xs) } /** Appends a sequence of elements to this buffer. @@ -86,8 +86,8 @@ trait SynchronizedBuffer[A] extends Buffer[A] { * * @param iter the iterable object. */ - override def appendAll(iter: Traversable[A]): Unit = synchronized { - super.appendAll(iter) + override def appendAll(xs: TraversableOnce[A]): Unit = synchronized { + super.appendAll(xs) } /** Prepend a single element to this buffer and return @@ -105,17 +105,13 @@ trait SynchronizedBuffer[A] extends Buffer[A] { * * @param iter the iterable object. */ - override def ++=:(iter: Traversable[A]): this.type = synchronized[this.type] { - super.++=:(iter) - } + override def ++=:(xs: TraversableOnce[A]): this.type = synchronized[this.type] { super.++=:(xs) } /** Prepend an element to this list. * * @param elem the element to prepend. */ - override def prepend(elems: A*): Unit = synchronized { - super.prependAll(elems) - } + override def prepend(elems: A*): Unit = prependAll(elems) /** Prepends a number of elements provided by an iterable object * via its <code>iterator</code> method. The identity of the @@ -123,8 +119,8 @@ trait SynchronizedBuffer[A] extends Buffer[A] { * * @param iter the iterable object. */ - override def prependAll(elems: Traversable[A]): Unit = synchronized { - super.prependAll(elems) + override def prependAll(xs: TraversableOnce[A]): Unit = synchronized { + super.prependAll(xs) } /** Inserts new elements at the index <code>n</code>. Opposed to method diff --git a/src/library/scala/collection/mutable/SynchronizedMap.scala b/src/library/scala/collection/mutable/SynchronizedMap.scala index ca29fa20b8..dabcaa7e1c 100644 --- a/src/library/scala/collection/mutable/SynchronizedMap.scala +++ b/src/library/scala/collection/mutable/SynchronizedMap.scala @@ -12,6 +12,7 @@ package scala.collection package mutable +import annotation.migration /** This class should be used as a mixin. It synchronizes the <code>Map</code> * functions of the class into which it is mixed in. @@ -35,20 +36,21 @@ trait SynchronizedMap[A, B] extends Map[A, B] { override def getOrElseUpdate(key: A, default: => B): B = synchronized { super.getOrElseUpdate(key, default) } override def transform(f: (A, B) => B): this.type = synchronized[this.type] { super.transform(f) } override def retain(p: (A, B) => Boolean): this.type = synchronized[this.type] { super.retain(p) } - override def valuesIterable: scala.collection.Iterable[B] = synchronized { super.valuesIterable } - @deprecated("Use `valuesIterator' instead") override def values: Iterator[B] = synchronized { super.valuesIterator } + @migration(2, 8, "As of 2.8, values returns Iterable[B] rather than Iterator[B].") + override def values: collection.Iterable[B] = synchronized { super.values } override def valuesIterator: Iterator[B] = synchronized { super.valuesIterator } override def clone(): Self = synchronized { super.clone() } override def foreach[U](f: ((A, B)) => U) = synchronized { super.foreach(f) } override def apply(key: A): B = synchronized { super.apply(key) } - override def keySet: scala.collection.Set[A] = synchronized { super.keySet } - @deprecated("Use `keysIterator' instead") override def keys: Iterator[A] = synchronized { super.keysIterator } + override def keySet: collection.Set[A] = synchronized { super.keySet } + @migration(2, 8, "As of 2.8, keys returns Iterable[A] rather than Iterator[A].") + override def keys: collection.Iterable[A] = synchronized { super.keys } override def keysIterator: Iterator[A] = synchronized { super.keysIterator } override def isEmpty: Boolean = synchronized { super.isEmpty } override def contains(key: A): Boolean = synchronized {super.contains(key) } override def isDefinedAt(key: A) = synchronized { super.isDefinedAt(key) } - @deprecated("See Map.+ for explanation") override def +(kv: (A, B)): this.type = synchronized[this.type] { super.+(kv) } + // @deprecated("See Map.+ for explanation") override def +(kv: (A, B)): this.type = synchronized[this.type] { super.+(kv) } // can't override -, -- same type! // @deprecated override def -(key: A): Self = synchronized { super.-(key) } diff --git a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala b/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala index 066c96a651..9d18846252 100644 --- a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala +++ b/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala @@ -39,23 +39,11 @@ class SynchronizedPriorityQueue[A](implicit ord: Ordering[A]) extends PriorityQu this } - /** Adds all elements provided by an <code>Iterable</code> object - * into the priority queue. - * - * @param iter an iterable object - */ - def ++=(iter: scala.collection.Iterable[A]): this.type = { - synchronized { - super.++=(iter) - } - this - } - /** Adds all elements provided by an iterator into the priority queue. * * @param it an iterator */ - override def ++=(it: Iterator[A]): this.type = { + override def ++=(it: TraversableOnce[A]): this.type = { synchronized { super.++=(it) } @@ -87,7 +75,7 @@ class SynchronizedPriorityQueue[A](implicit ord: Ordering[A]) extends PriorityQu */ override def clear(): Unit = synchronized { super.clear } - /** Returns an iterator which yiels all the elements of the priority + /** Returns an iterator which yield all the elements of the priority * queue in descending priority order. * * @return an iterator over all elements sorted in descending order. diff --git a/src/library/scala/collection/mutable/SynchronizedQueue.scala b/src/library/scala/collection/mutable/SynchronizedQueue.scala index 3a1bc2e383..e7630cee06 100644 --- a/src/library/scala/collection/mutable/SynchronizedQueue.scala +++ b/src/library/scala/collection/mutable/SynchronizedQueue.scala @@ -42,15 +42,7 @@ class SynchronizedQueue[A] extends Queue[A] { * * @param iter an iterable object */ - override def ++=(iter: Traversable[A]): this.type = synchronized[this.type] { super.++=(iter) } - - /** Adds all elements provided by an iterator - * at the end of the queue. The elements are prepended in the order they - * are given out by the iterator. - * - * @param it an iterator - */ - override def ++=(it: Iterator[A]): this.type = synchronized[this.type] { super.++=(it) } + override def ++=(xs: TraversableOnce[A]): this.type = synchronized[this.type] { super.++=(xs) } /** Adds all elements to the queue. * diff --git a/src/library/scala/collection/mutable/SynchronizedSet.scala b/src/library/scala/collection/mutable/SynchronizedSet.scala index a4832ba9f4..d3023b9136 100644 --- a/src/library/scala/collection/mutable/SynchronizedSet.scala +++ b/src/library/scala/collection/mutable/SynchronizedSet.scala @@ -39,24 +39,16 @@ trait SynchronizedSet[A] extends Set[A] { super.+=(elem) } - override def ++=(that: Traversable[A]): this.type = synchronized[this.type] { - super.++=(that) - } - - override def ++=(it: Iterator[A]): this.type = synchronized[this.type] { - super.++=(it) + override def ++=(xs: TraversableOnce[A]): this.type = synchronized[this.type] { + super.++=(xs) } abstract override def -=(elem: A): this.type = synchronized[this.type] { super.-=(elem) } - override def --=(that: Traversable[A]): this.type = synchronized[this.type] { - super.--=(that) - } - - override def --=(it: Iterator[A]): this.type = synchronized[this.type] { - super.--=(it) + override def --=(xs: TraversableOnce[A]): this.type = synchronized[this.type] { + super.--=(xs) } override def update(elem: A, included: Boolean): Unit = synchronized { @@ -103,7 +95,7 @@ trait SynchronizedSet[A] extends Set[A] { super.<<(cmd) } - override def clone(): Set[A] = synchronized { + override def clone(): Self = synchronized { super.clone() } } diff --git a/src/library/scala/collection/mutable/SynchronizedStack.scala b/src/library/scala/collection/mutable/SynchronizedStack.scala index ff2f986244..4394d307eb 100644 --- a/src/library/scala/collection/mutable/SynchronizedStack.scala +++ b/src/library/scala/collection/mutable/SynchronizedStack.scala @@ -44,21 +44,13 @@ class SynchronizedStack[A] extends Stack[A] { */ override def push(elem1: A, elem2: A, elems: A*): this.type = synchronized[this.type] { super.push(elem1, elem2, elems: _*) } - /** Pushes all elements provided by an <code>Traversable</code> object - * on top of the stack. The elements are pushed in the order they - * are given out by the iterator. - * - * @param iter an iterable object - */ - override def pushAll(elems: scala.collection.Traversable[A]): this.type = synchronized[this.type] { super.pushAll(elems) } - /** Pushes all elements provided by an iterator * on top of the stack. The elements are pushed in the order they * are given out by the iterator. * * @param elems an iterator */ - override def pushAll(elems: Iterator[A]): this.type = synchronized[this.type] { super.pushAll(elems) } + override def pushAll(xs: TraversableOnce[A]): this.type = synchronized[this.type] { super.pushAll(elems) } /** Returns the top element of the stack. This method will not remove * the element from the stack. An error is signaled if there is no diff --git a/src/library/scala/collection/mutable/WeakHashMap.scala b/src/library/scala/collection/mutable/WeakHashMap.scala index 81c91dec3d..cad4dc2e43 100644 --- a/src/library/scala/collection/mutable/WeakHashMap.scala +++ b/src/library/scala/collection/mutable/WeakHashMap.scala @@ -13,10 +13,19 @@ package scala.collection package mutable import JavaConversions._ +import generic._ + /** * @since 2.8 */ -class WeakHashMap[A, B] extends JMapWrapper[A, B](new java.util.WeakHashMap) { +class WeakHashMap[A, B] extends JMapWrapper[A, B](new java.util.WeakHashMap) + with JMapWrapperLike[A, B, WeakHashMap[A, B]] { override def empty = new WeakHashMap[A, B] } + +object WeakHashMap extends MutableMapFactory[WeakHashMap] { + implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), WeakHashMap[A, B]] = new MapCanBuildFrom[A, B] + def empty[A, B]: WeakHashMap[A, B] = new WeakHashMap[A, B] +} + diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala index 6652f5e40a..10117a1086 100644 --- a/src/library/scala/collection/mutable/WrappedArray.scala +++ b/src/library/scala/collection/mutable/WrappedArray.scala @@ -41,6 +41,13 @@ abstract class WrappedArray[T] extends IndexedSeq[T] with ArrayLike[T, WrappedAr /** The underlying array */ def array: Array[T] + + override def toArray[U >: T : ClassManifest]: Array[U] = + if (implicitly[ClassManifest[U]].erasure eq array.getClass.getComponentType) + array.asInstanceOf[Array[U]] + else + super.toArray[U] + override def stringPrefix = "WrappedArray" /** Clones this object, including the underlying Array. */ diff --git a/src/library/scala/collection/readme-if-you-want-to-add-something.txt b/src/library/scala/collection/readme-if-you-want-to-add-something.txt new file mode 100755 index 0000000000..6700cb7b68 --- /dev/null +++ b/src/library/scala/collection/readme-if-you-want-to-add-something.txt @@ -0,0 +1,50 @@ +Conventions for Collection Implementors + +Martin Odersky +19 Mar 2010 + +This note describes some conventions which must be followed to keep +the collection libraries consistent. + +We distinguish in the following between two kinds of methods + + - ``Accessors'' access some of the elements of a collection, but return a result which + is unrelated to the collection. + Example of accessors are: head, foldLeft, indexWhere, toSeq. + + - ``Transformers'' access elements of a collection and produce a new collection of related + type as a result. The relation might either be direct (same type as receiver) + or indirect, linked by a CanBuildFrom implicit. + Example of transformers are: filter, map, groupBy, zip. + +1. Proxies + +Every collection type has a Proxy class that forwards all operations to +an underlying collection. Proxy methods are all implemented in classes +with names ending in `ProxyLike'. If you add a new method to a collection +class you need to add the same method to the corresponding ProxyLike class. + +2. Forwarders + +Classes Traversable, Iterable, and Seq also have forwarders, which +forward all collection-specific accessor operations to an underlying +collection. These are defined as classes with names ending +in `Forwarder' in package collection.generic. If you add a new +accessor method to a Seq or one of its collection superclasses, you +need to add the same method to the corresponding forwarder class. + +3. Views + +Classes Traversable, Iterable, Seq, IndexedSeq, and mutable.IndexedSeq +support views. Their operations are all defined in classes with names +ending in `ViewLike'. If you add a new transformer method to one of +the above collection classes, you need to add the same method to the +corresponding view class. Failure to do so will cause the +corresponding method to fail at runtime with an exception like +UnsupportedOperationException("coll.newBuilder"). If there is no good +way to implement the operation in question lazily, there's a fallback +using the newForced method. See the definition of sorted in trait +SeqViewLike as an example. + + + diff --git a/src/library/scala/compat/Platform.scala b/src/library/scala/compat/Platform.scala index f7f5070699..7580d2cc0e 100644 --- a/src/library/scala/compat/Platform.scala +++ b/src/library/scala/compat/Platform.scala @@ -47,7 +47,7 @@ object Platform { @inline def getClassForName(name: String): Class[_] = java.lang.Class.forName(name) - val EOL = System.getProperty("line.separator", "\n") + val EOL = util.Properties.lineSeparator @inline def currentTime: Long = System.currentTimeMillis() diff --git a/src/library/scala/concurrent/DelayedLazyVal.scala b/src/library/scala/concurrent/DelayedLazyVal.scala index 092800cb10..7c5d43e70c 100644 --- a/src/library/scala/concurrent/DelayedLazyVal.scala +++ b/src/library/scala/concurrent/DelayedLazyVal.scala @@ -27,9 +27,15 @@ import ops.future * @version 2.8 */ class DelayedLazyVal[T](f: () => T, body: => Unit) { - @volatile private[this] var isDone = false + @volatile private[this] var _isDone = false private[this] lazy val complete = f() + /** Whether the computation is complete. + * + * @return true if the computation is complete. + */ + def isDone = _isDone + /** The current result of f(), or the final result if complete. * * @return the current value @@ -38,6 +44,6 @@ class DelayedLazyVal[T](f: () => T, body: => Unit) { future { body - isDone = true + _isDone = true } } diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index 6bd6b33484..bb6965fcdc 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -29,6 +29,8 @@ object BigDecimal private val minCached = -512 private val maxCached = 512 + + /** Cache ony for defaultMathContext using BigDecimals in a small range. */ private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1) val defaultMathContext = MathContext.UNLIMITED @@ -50,12 +52,13 @@ object BigDecimal */ def apply(i: Int): BigDecimal = apply(i, defaultMathContext) def apply(i: Int, mc: MathContext): BigDecimal = - if (minCached <= i && i <= maxCached) { + if (mc == defaultMathContext && minCached <= i && i <= maxCached) { val offset = i - minCached var n = cache(offset) if (n eq null) { n = new BigDecimal(BigDec.valueOf(i), mc); cache(offset) = n } n - } else new BigDecimal(BigDec.valueOf(i), mc) + } + else new BigDecimal(BigDec.valueOf(i), mc) /** Constructs a <code>BigDecimal</code> whose value is equal to that of the * specified long value. diff --git a/src/library/scala/math/BigInt.scala b/src/library/scala/math/BigInt.scala index 4c9f970cb4..5267ad8b95 100644 --- a/src/library/scala/math/BigInt.scala +++ b/src/library/scala/math/BigInt.scala @@ -102,7 +102,7 @@ object BigInt { */ implicit def int2bigInt(i: Int): BigInt = apply(i) - /** Implicit copnversion from long to BigInt + /** Implicit conversion from long to BigInt */ implicit def long2bigInt(l: Long): BigInt = apply(l) } diff --git a/src/library/scala/math/Numeric.scala b/src/library/scala/math/Numeric.scala index fc8e7c307d..65f213a08e 100644 --- a/src/library/scala/math/Numeric.scala +++ b/src/library/scala/math/Numeric.scala @@ -75,6 +75,21 @@ object Numeric { } implicit object ByteIsIntegral extends ByteIsIntegral with Ordering.ByteOrdering + trait CharIsIntegral extends Integral[Char] { + def plus(x: Char, y: Char): Char = (x + y).toChar + def minus(x: Char, y: Char): Char = (x - y).toChar + def times(x: Char, y: Char): Char = (x * y).toChar + def quot(x: Char, y: Char): Char = (x / y).toChar + def rem(x: Char, y: Char): Char = (x % y).toChar + def negate(x: Char): Char = (-x).toChar + def fromInt(x: Int): Char = x.toChar + def toInt(x: Char): Int = x.toInt + def toLong(x: Char): Long = x.toLong + def toFloat(x: Char): Float = x.toFloat + def toDouble(x: Char): Double = x.toDouble + } + implicit object CharIsIntegral extends CharIsIntegral with Ordering.CharOrdering + trait LongIsIntegral extends Integral[Long] { def plus(x: Long, y: Long): Long = x + y def minus(x: Long, y: Long): Long = x - y diff --git a/src/library/scala/math/Ordering.scala b/src/library/scala/math/Ordering.scala index 1660cdb99e..04c2d96aba 100644 --- a/src/library/scala/math/Ordering.scala +++ b/src/library/scala/math/Ordering.scala @@ -133,6 +133,8 @@ object Ordering extends LowPriorityOrderingImplicits { override def lteq(x: T, y: T): Boolean = !cmp(y, x) } + def by[T, S: Ordering](f: T => S): Ordering[T] = fromLessThan((x, y) => implicitly[Ordering[S]].lt(f(x), f(y))) + trait UnitOrdering extends Ordering[Unit] { def compare(x: Unit, y: Unit) = 0 } diff --git a/src/library/scala/package.scala b/src/library/scala/package.scala index 9fa09e3b72..9f31623bdf 100644 --- a/src/library/scala/package.scala +++ b/src/library/scala/package.scala @@ -26,6 +26,8 @@ package object scala { type NumberFormatException = java.lang.NumberFormatException type AbstractMethodError = java.lang.AbstractMethodError + type TraversableOnce[+A] = scala.collection.TraversableOnce[A] + type Traversable[+A] = scala.collection.Traversable[A] val Traversable = scala.collection.Traversable diff --git a/src/library/scala/reflect/ClassManifest.scala b/src/library/scala/reflect/ClassManifest.scala index 58f3c89499..ded013a4b5 100644 --- a/src/library/scala/reflect/ClassManifest.scala +++ b/src/library/scala/reflect/ClassManifest.scala @@ -27,7 +27,7 @@ import scala.collection.mutable.{WrappedArray, ArrayBuilder} * </p> */ @serializable -trait ClassManifest[T] extends OptManifest[T] { +trait ClassManifest[T] extends OptManifest[T] with Equals { /** A class representing the type U to which T would be erased. Note * that there is no subtyping relationship between T and U. */ @@ -73,15 +73,20 @@ trait ClassManifest[T] extends OptManifest[T] { def >:>(that: ClassManifest[_]): Boolean = that <:< this + def canEqual(other: Any) = other match { + case _: ClassManifest[_] => true + case _ => false + } + /** Tests whether the type represented by this manifest is equal to the * type represented by `that' manifest. BE AWARE: the current * implementation is an approximation, as the test is done on the * erasure of the type. */ override def equals(that: Any): Boolean = that match { - case _: AnyValManifest[_] => false - case m: ClassManifest[_] => this.erasure == m.erasure + case m: ClassManifest[_] if m canEqual this => this.erasure == m.erasure case _ => false } + override def hashCode = this.erasure.hashCode protected def arrayClass[T](tp: Predef.Class[_]): Predef.Class[Array[T]] = java.lang.reflect.Array.newInstance(tp, 0).getClass.asInstanceOf[Predef.Class[Array[T]]] @@ -225,11 +230,4 @@ object ClassManifest { override val typeArguments = args.toList override def toString = prefix.toString+"#"+name+argString } - - /** ClassManifest for the intersection type `parents_0 with ... with parents_n'. */ - def intersectionType[T](parents: ClassManifest[_]*): ClassManifest[T] = - new (ClassManifest[T] @serializable) { - def erasure = parents.head.erasure - override def toString = parents.mkString(" with ") - } } diff --git a/src/library/scala/reflect/Code.scala b/src/library/scala/reflect/Code.scala index 71e148db81..61138f2495 100644 --- a/src/library/scala/reflect/Code.scala +++ b/src/library/scala/reflect/Code.scala @@ -12,7 +12,7 @@ package scala.reflect /** This type is required by the compiler and <b>should not be used in client code</b>. */ -class Code[Type](val tree: Tree) +class Code[T](val tree: Tree) /** This type is required by the compiler and <b>should not be used in client code</b>. */ object Code { diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index 69842e1193..b7cb86e1bd 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -27,18 +27,33 @@ import scala.collection.immutable.{List, Nil} * </p> */ @serializable -trait Manifest[T] extends ClassManifest[T] { +trait Manifest[T] extends ClassManifest[T] with Equals { override def typeArguments: List[Manifest[_]] = List() override def arrayManifest: Manifest[Array[T]] = Manifest.classType[Array[T]](arrayClass[T](erasure)) + + override def canEqual(that: Any): Boolean = that match { + case _: Manifest[_] => true + case _ => false + } + override def equals(that: Any): Boolean = that match { + case m: Manifest[_] if m canEqual this => (this <:< m) && (m <:< this) + case _ => false + } + override def hashCode = this.erasure.hashCode } @serializable -trait AnyValManifest[T] extends Manifest[T] { +trait AnyValManifest[T] extends Manifest[T] with Equals { import Manifest.{ Any, AnyVal } override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) || (that eq AnyVal) + override def canEqual(other: Any) = other match { + case _: AnyValManifest[_] => true + case _ => false + } override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override def hashCode = System.identityHashCode(this) } /** <ps> @@ -137,6 +152,7 @@ object Manifest { override def toString = "Any" override def <:<(that: ClassManifest[_]): Boolean = (that eq this) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.Any } @@ -144,6 +160,7 @@ object Manifest { override def toString = "Object" override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.Object } @@ -151,6 +168,7 @@ object Manifest { override def toString = "AnyVal" override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.AnyVal } @@ -159,6 +177,7 @@ object Manifest { override def <:<(that: ClassManifest[_]): Boolean = (that ne null) && (that ne Nothing) && !(that <:< AnyVal) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.Null } @@ -166,6 +185,7 @@ object Manifest { override def toString = "Nothing" override def <:<(that: ClassManifest[_]): Boolean = (that ne null) override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef] + override def hashCode = System.identityHashCode(this) private def readResolve(): Any = Manifest.Nothing } diff --git a/src/library/scala/util/NameTransformer.scala b/src/library/scala/reflect/NameTransformer.scala index 83451240d5..0629c3a2f8 100644..100755 --- a/src/library/scala/util/NameTransformer.scala +++ b/src/library/scala/reflect/NameTransformer.scala @@ -6,10 +6,10 @@ ** |/ ** \* */ -// $Id$ +// $Id: NameTransformer.scala 20028 2009-12-07 11:49:19Z cunei $ -package scala.util +package scala.reflect /** * @author Martin Odersky diff --git a/src/library/scala/reflect/ScalaSignature.java b/src/library/scala/reflect/ScalaSignature.java new file mode 100644 index 0000000000..d1cdbc0589 --- /dev/null +++ b/src/library/scala/reflect/ScalaSignature.java @@ -0,0 +1,13 @@ +package scala.reflect; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface ScalaSignature { + public String bytes(); +} diff --git a/src/library/scala/reflect/generic/AnnotationInfos.scala b/src/library/scala/reflect/generic/AnnotationInfos.scala new file mode 100755 index 0000000000..cc6c909a45 --- /dev/null +++ b/src/library/scala/reflect/generic/AnnotationInfos.scala @@ -0,0 +1,50 @@ +package scala.reflect +package generic + +trait AnnotationInfos { self: Universe => + + type AnnotationInfo <: AnyRef + val AnnotationInfo: AnnotationInfoExtractor + + abstract class AnnotationInfoExtractor { + def apply(atp: Type, args: List[Tree], assocs: List[(Name, ClassfileAnnotArg)]): AnnotationInfo + def unapply(info: AnnotationInfo): Option[(Type, List[Tree], List[(Name, ClassfileAnnotArg)])] + } + + type ClassfileAnnotArg <: AnyRef + implicit def classfileAnnotArgManifest: ClassManifest[ClassfileAnnotArg] // need a precise manifest to pass to UnPickle's toArray call + + type LiteralAnnotArg <: ClassfileAnnotArg + val LiteralAnnotArg: LiteralAnnotArgExtractor + + type ArrayAnnotArg <: ClassfileAnnotArg + val ArrayAnnotArg: ArrayAnnotArgExtractor + + type ScalaSigBytes <: ClassfileAnnotArg + val ScalaSigBytes: ScalaSigBytesExtractor + + type NestedAnnotArg <: ClassfileAnnotArg + val NestedAnnotArg: NestedAnnotArgExtractor + + abstract class LiteralAnnotArgExtractor { + def apply(const: Constant): LiteralAnnotArg + def unapply(arg: LiteralAnnotArg): Option[Constant] + } + + abstract class ArrayAnnotArgExtractor { + def apply(const: Array[ClassfileAnnotArg]): ArrayAnnotArg + def unapply(arg: ArrayAnnotArg): Option[Array[ClassfileAnnotArg]] + } + + abstract class ScalaSigBytesExtractor { + def apply(bytes: Array[Byte]): ScalaSigBytes + def unapply(arg: ScalaSigBytes): Option[Array[Byte]] + } + + abstract class NestedAnnotArgExtractor { + def apply(anninfo: AnnotationInfo): NestedAnnotArg + def unapply(arg: NestedAnnotArg): Option[AnnotationInfo] + } +} + + diff --git a/src/library/scala/reflect/generic/ByteCodecs.scala b/src/library/scala/reflect/generic/ByteCodecs.scala new file mode 100644 index 0000000000..fd2e326e19 --- /dev/null +++ b/src/library/scala/reflect/generic/ByteCodecs.scala @@ -0,0 +1,209 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2007-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ +package scala.reflect.generic + +object ByteCodecs { + + def avoidZero(src: Array[Byte]): Array[Byte] = { + var i = 0 + val srclen = src.length + var count = 0 + while (i < srclen) { + if (src(i) == 0x7f) count += 1 + i += 1 + } + val dst = new Array[Byte](srclen + count) + i = 0 + var j = 0 + while (i < srclen) { + val in = src(i) + if (in == 0x7f) { + dst(j) = (0xc0).toByte + dst(j + 1) = (0x80).toByte + j += 2 + } else { + dst(j) = (in + 1).toByte + j += 1 + } + i += 1 + } + dst + } + + def regenerateZero(src: Array[Byte]): Int = { + var i = 0 + val srclen = src.length + var j = 0 + while (i < srclen) { + val in: Int = src(i) & 0xff + if (in == 0xc0 && (src(i + 1) & 0xff) == 0x80) { + src(j) = 0x7f + i += 2 + } else { + src(j) = (in - 1).toByte + i += 1 + } + j += 1 + } + j + } + + def encode8to7(src: Array[Byte]): Array[Byte] = { + val srclen = src.length + val dstlen = (srclen * 8 + 6) / 7 + val dst = new Array[Byte](dstlen) + var i = 0 + var j = 0 + while (i + 6 < srclen) { + var in: Int = src(i) & 0xff + dst(j) = (in & 0x7f).toByte + var out: Int = in >>> 7 + in = src(i + 1) & 0xff + dst(j + 1) = (out | (in << 1) & 0x7f).toByte + out = in >>> 6 + in = src(i + 2) & 0xff + dst(j + 2) = (out | (in << 2) & 0x7f).toByte + out = in >>> 5 + in = src(i + 3) & 0xff + dst(j + 3) = (out | (in << 3) & 0x7f).toByte + out = in >>> 4 + in = src(i + 4) & 0xff + dst(j + 4) = (out | (in << 4) & 0x7f).toByte + out = in >>> 3 + in = src(i + 5) & 0xff + dst(j + 5) = (out | (in << 5) & 0x7f).toByte + out = in >>> 2 + in = src(i + 6) & 0xff + dst(j + 6) = (out | (in << 6) & 0x7f).toByte + out = in >>> 1 + dst(j + 7) = out.toByte + i += 7 + j += 8 + } + if (i < srclen) { + var in: Int = src(i) & 0xff + dst(j) = (in & 0x7f).toByte; j += 1 + var out: Int = in >>> 7 + if (i + 1 < srclen) { + in = src(i + 1) & 0xff + dst(j) = (out | (in << 1) & 0x7f).toByte; j += 1 + out = in >>> 6 + if (i + 2 < srclen) { + in = src(i + 2) & 0xff + dst(j) = (out | (in << 2) & 0x7f).toByte; j += 1 + out = in >>> 5 + if (i + 3 < srclen) { + in = src(i + 3) & 0xff + dst(j) = (out | (in << 3) & 0x7f).toByte; j += 1 + out = in >>> 4 + if (i + 4 < srclen) { + in = src(i + 4) & 0xff + dst(j) = (out | (in << 4) & 0x7f).toByte; j += 1 + out = in >>> 3 + if (i + 5 < srclen) { + in = src(i + 5) & 0xff + dst(j) = (out | (in << 5) & 0x7f).toByte; j += 1 + out = in >>> 2 + } + } + } + } + } + if (j < dstlen) dst(j) = out.toByte + } + dst + } + + @deprecated("use 2-argument version instead") + def decode7to8(src: Array[Byte], srclen: Int, dstlen: Int) { decode7to8(src, srclen) } + + def decode7to8(src: Array[Byte], srclen: Int): Int = { + var i = 0 + var j = 0 + val dstlen = (srclen * 7 + 7) / 8 + while (i + 7 < srclen) { + var out: Int = src(i) + var in: Byte = src(i + 1) + src(j) = (out | (in & 0x01) << 7).toByte + out = in >>> 1 + in = src(i + 2) + src(j + 1) = (out | (in & 0x03) << 6).toByte + out = in >>> 2 + in = src(i + 3) + src(j + 2) = (out | (in & 0x07) << 5).toByte + out = in >>> 3 + in = src(i + 4) + src(j + 3) = (out | (in & 0x0f) << 4).toByte + out = in >>> 4 + in = src(i + 5) + src(j + 4) = (out | (in & 0x1f) << 3).toByte + out = in >>> 5 + in = src(i + 6) + src(j + 5) = (out | (in & 0x3f) << 2).toByte + out = in >>> 6 + in = src(i + 7) + src(j + 6) = (out | in << 1).toByte + i += 8 + j += 7 + } + if (i < srclen) { + var out: Int = src(i) + if (i + 1 < srclen) { + var in: Byte = src(i + 1) + src(j) = (out | (in & 0x01) << 7).toByte; j += 1 + out = in >>> 1 + if (i + 2 < srclen) { + in = src(i + 2) + src(j) = (out | (in & 0x03) << 6).toByte; j += 1 + out = in >>> 2 + if (i + 3 < srclen) { + in = src(i + 3) + src(j) = (out | (in & 0x07) << 5).toByte; j += 1 + out = in >>> 3 + if (i + 4 < srclen) { + in = src(i + 4) + src(j) = (out | (in & 0x0f) << 4).toByte; j += 1 + out = in >>> 4 + if (i + 5 < srclen) { + in = src(i + 5) + src(j) = (out | (in & 0x1f) << 3).toByte; j += 1 + out = in >>> 5 + if (i + 6 < srclen) { + in = src(i + 6) + src(j) = (out | (in & 0x3f) << 2).toByte; j += 1 + out = in >>> 6 + } + } + } + } + } + } + if (j < dstlen) src(j) = out.toByte + } + dstlen + } + + def encode(xs: Array[Byte]): Array[Byte] = avoidZero(encode8to7(xs)) + + @deprecated("use 1-argument version instead") + def decode(xs: Array[Byte], dstlen: Int) { decode(xs) } + + /** Destructively decode array xs and returns the length of the decoded array */ + def decode(xs: Array[Byte]): Int = { + val len = regenerateZero(xs) + decode7to8(xs, len) + } +} + + + + + + + + diff --git a/src/library/scala/reflect/generic/Constants.scala b/src/library/scala/reflect/generic/Constants.scala new file mode 100755 index 0000000000..2fe9d24980 --- /dev/null +++ b/src/library/scala/reflect/generic/Constants.scala @@ -0,0 +1,236 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: Constants.scala 20028 2009-12-07 11:49:19Z cunei $ + +package scala.reflect +package generic + +import java.lang.Integer.toOctalString +import PickleFormat._ + +trait Constants { self: Universe => + + import definitions._ + + final val NoTag = LITERAL - LITERAL + final val UnitTag = LITERALunit - LITERAL + final val BooleanTag = LITERALboolean - LITERAL + final val ByteTag = LITERALbyte - LITERAL + final val ShortTag = LITERALshort - LITERAL + final val CharTag = LITERALchar - LITERAL + final val IntTag = LITERALint - LITERAL + final val LongTag = LITERALlong - LITERAL + final val FloatTag = LITERALfloat - LITERAL + final val DoubleTag = LITERALdouble - LITERAL + final val StringTag = LITERALstring - LITERAL + final val NullTag = LITERALnull - LITERAL + final val ClassTag = LITERALclass - LITERAL + // For supporting java enumerations inside java annotations (see ClassfileParser) + final val EnumTag = LITERALenum - LITERAL + + case class Constant(value: Any) { + + val tag: Int = + if (value.isInstanceOf[Unit]) UnitTag + else if (value.isInstanceOf[Boolean]) BooleanTag + else if (value.isInstanceOf[Byte]) ByteTag + else if (value.isInstanceOf[Short]) ShortTag + else if (value.isInstanceOf[Char]) CharTag + else if (value.isInstanceOf[Int]) IntTag + else if (value.isInstanceOf[Long]) LongTag + else if (value.isInstanceOf[Float]) FloatTag + else if (value.isInstanceOf[Double]) DoubleTag + else if (value.isInstanceOf[String]) StringTag + else if (value.isInstanceOf[AbsType]) ClassTag + else if (value.isInstanceOf[AbsSymbol]) EnumTag + else if (value == null) NullTag + else throw new Error("bad constant value: " + value) + + def isNumeric: Boolean = ByteTag <= tag && tag <= DoubleTag + + def tpe: Type = tag match { + case UnitTag => UnitClass.tpe + case BooleanTag => BooleanClass.tpe + case ByteTag => ByteClass.tpe + case ShortTag => ShortClass.tpe + case CharTag => CharClass.tpe + case IntTag => IntClass.tpe + case LongTag => LongClass.tpe + case FloatTag => FloatClass.tpe + case DoubleTag => DoubleClass.tpe + case StringTag => StringClass.tpe + case NullTag => NullClass.tpe + case ClassTag => ClassType(value.asInstanceOf[Type]) + case EnumTag => + // given (in java): "class A { enum E { VAL1 } }" + // - symbolValue: the symbol of the actual enumeration value (VAL1) + // - .owner: the ModuleClasSymbol of the enumeration (object E) + // - .linkedClassOfClass: the ClassSymbol of the enumeration (class E) + symbolValue.owner.linkedClassOfClass.tpe + } + + /** We need the equals method to take account of tags as well as values. + * + * @param other ... + * @return ... + */ + override def equals(other: Any): Boolean = other match { + case that: Constant => + this.tag == that.tag && + (this.value == that.value || this.isNaN && that.isNaN) + case _ => false + } + + def isNaN = value match { + case f: Float => f.isNaN + case d: Double => d.isNaN + case _ => false + } + + def booleanValue: Boolean = + if (tag == BooleanTag) value.asInstanceOf[Boolean] + else throw new Error("value " + value + " is not a boolean"); + + def byteValue: Byte = tag match { + case ByteTag => value.asInstanceOf[Byte] + case ShortTag => value.asInstanceOf[Short].toByte + case CharTag => value.asInstanceOf[Char].toByte + case IntTag => value.asInstanceOf[Int].toByte + case LongTag => value.asInstanceOf[Long].toByte + case FloatTag => value.asInstanceOf[Float].toByte + case DoubleTag => value.asInstanceOf[Double].toByte + case _ => throw new Error("value " + value + " is not a Byte") + } + + def shortValue: Short = tag match { + case ByteTag => value.asInstanceOf[Byte].toShort + case ShortTag => value.asInstanceOf[Short] + case CharTag => value.asInstanceOf[Char].toShort + case IntTag => value.asInstanceOf[Int].toShort + case LongTag => value.asInstanceOf[Long].toShort + case FloatTag => value.asInstanceOf[Float].toShort + case DoubleTag => value.asInstanceOf[Double].toShort + case _ => throw new Error("value " + value + " is not a Short") + } + + def charValue: Char = tag match { + case ByteTag => value.asInstanceOf[Byte].toChar + case ShortTag => value.asInstanceOf[Short].toChar + case CharTag => value.asInstanceOf[Char] + case IntTag => value.asInstanceOf[Int].toChar + case LongTag => value.asInstanceOf[Long].toChar + case FloatTag => value.asInstanceOf[Float].toChar + case DoubleTag => value.asInstanceOf[Double].toChar + case _ => throw new Error("value " + value + " is not a Char") + } + + def intValue: Int = tag match { + case ByteTag => value.asInstanceOf[Byte].toInt + case ShortTag => value.asInstanceOf[Short].toInt + case CharTag => value.asInstanceOf[Char].toInt + case IntTag => value.asInstanceOf[Int] + case LongTag => value.asInstanceOf[Long].toInt + case FloatTag => value.asInstanceOf[Float].toInt + case DoubleTag => value.asInstanceOf[Double].toInt + case _ => throw new Error("value " + value + " is not an Int") + } + + def longValue: Long = tag match { + case ByteTag => value.asInstanceOf[Byte].toLong + case ShortTag => value.asInstanceOf[Short].toLong + case CharTag => value.asInstanceOf[Char].toLong + case IntTag => value.asInstanceOf[Int].toLong + case LongTag => value.asInstanceOf[Long] + case FloatTag => value.asInstanceOf[Float].toLong + case DoubleTag => value.asInstanceOf[Double].toLong + case _ => throw new Error("value " + value + " is not a Long") + } + + def floatValue: Float = tag match { + case ByteTag => value.asInstanceOf[Byte].toFloat + case ShortTag => value.asInstanceOf[Short].toFloat + case CharTag => value.asInstanceOf[Char].toFloat + case IntTag => value.asInstanceOf[Int].toFloat + case LongTag => value.asInstanceOf[Long].toFloat + case FloatTag => value.asInstanceOf[Float] + case DoubleTag => value.asInstanceOf[Double].toFloat + case _ => throw new Error("value " + value + " is not a Float") + } + + def doubleValue: Double = tag match { + case ByteTag => value.asInstanceOf[Byte].toDouble + case ShortTag => value.asInstanceOf[Short].toDouble + case CharTag => value.asInstanceOf[Char].toDouble + case IntTag => value.asInstanceOf[Int].toDouble + case LongTag => value.asInstanceOf[Long].toDouble + case FloatTag => value.asInstanceOf[Float].toDouble + case DoubleTag => value.asInstanceOf[Double] + case _ => throw new Error("value " + value + " is not a Double") + } + + /** Convert constant value to conform to given type. + * + * @param pt ... + * @return ... + */ + def convertTo(pt: Type): Constant = { + val target = pt.typeSymbol + if (target == tpe.typeSymbol) + this + else if (target == ByteClass && ByteTag <= tag && tag <= IntTag && + -128 <= intValue && intValue <= 127) + Constant(byteValue) + else if (target == ShortClass && ByteTag <= tag && tag <= IntTag && + -32768 <= intValue && intValue <= 32767) + Constant(shortValue) + else if (target == CharClass && ByteTag <= tag && tag <= IntTag && + 0 <= intValue && intValue <= 65635) + Constant(charValue) + else if (target == IntClass && ByteTag <= tag && tag <= IntTag) + Constant(intValue) + else if (target == LongClass && ByteTag <= tag && tag <= LongTag) + Constant(longValue) + else if (target == FloatClass && ByteTag <= tag && tag <= FloatTag) + Constant(floatValue) + else if (target == DoubleClass && ByteTag <= tag && tag <= DoubleTag) + Constant(doubleValue) + else { + null + } + } + + def stringValue: String = + if (value == null) "null" + else if (tag == ClassTag) signature(typeValue) + else value.toString() + + def escapedStringValue: String = { + def escape(text: String): String = { + val buf = new StringBuilder + for (c <- text.iterator) + if (c.isControl) + buf.append("\\0" + toOctalString(c.asInstanceOf[Int])) + else + buf.append(c) + buf.toString + } + tag match { + case NullTag => "null" + case StringTag => "\"" + escape(stringValue) + "\"" + case ClassTag => "classOf[" + signature(typeValue) + "]" + case CharTag => escape("\'" + charValue + "\'") + case LongTag => longValue.toString() + "L" + case _ => value.toString() + } + } + + def typeValue: Type = value.asInstanceOf[Type] + + def symbolValue: Symbol = value.asInstanceOf[Symbol] + + override def hashCode: Int = + if (value == null) 0 else value.hashCode() * 41 + 17 + } +} diff --git a/src/library/scala/reflect/generic/Flags.scala b/src/library/scala/reflect/generic/Flags.scala new file mode 100755 index 0000000000..f0f1f14ade --- /dev/null +++ b/src/library/scala/reflect/generic/Flags.scala @@ -0,0 +1,198 @@ +package scala.reflect +package generic + +object Flags extends Flags + +class Flags { + + // modifiers + final val IMPLICIT = 0x00000200 + final val FINAL = 0x00000020 + final val PRIVATE = 0x00000004 + final val PROTECTED = 0x00000001 + + final val SEALED = 0x00000400 + final val OVERRIDE = 0x00000002 + final val CASE = 0x00000800 + final val ABSTRACT = 0x00000008 // abstract class, or used in conjunction + // with abstract override. + // Note difference to DEFERRED! + + final val DEFERRED = 0x00000010 // was `abstract' for members | trait is virtual + final val METHOD = 0x00000040 // a method + final val MODULE = 0x00000100 // symbol is module or class implementing a module + final val INTERFACE = 0x00000080 // symbol is an interface (i.e. a trait which defines only abstract methods) + + final val MUTABLE = 0x00001000 // symbol is a mutable variable. + final val PARAM = 0x00002000 // symbol is a (value or type) parameter to a method + final val PACKAGE = 0x00004000 // symbol is a java package + // available: 0x00008000 + + final val COVARIANT = 0x00010000 // symbol is a covariant type variable + final val CAPTURED = 0x00010000 // variable is accessed from nested function. + // Set by LambdaLift + final val BYNAMEPARAM = 0x00010000 // parameter is by name + final val CONTRAVARIANT = 0x00020000 // symbol is a contravariant type variable + final val LABEL = 0x00020000 // method symbol is a label. Set by TailCall + final val INCONSTRUCTOR = 0x00020000 // class symbol is defined in this/superclass + // constructor. + final val ABSOVERRIDE = 0x00040000 // combination of abstract & override + final val LOCAL = 0x00080000 // symbol is local to current class (i.e. private[this] or protected[this] + // pre: PRIVATE or PROTECTED are also set + final val JAVA = 0x00100000 // symbol was defined by a Java class + final val SYNTHETIC = 0x00200000 // symbol is compiler-generated + final val STABLE = 0x00400000 // functions that are assumed to be stable + // (typically, access methods for valdefs) + // or classes that do not contain abstract types. + final val STATIC = 0x00800000 // static field, method or class + + final val CASEACCESSOR = 0x01000000 // symbol is a case parameter (or its accessor) + final val TRAIT = 0x02000000 // symbol is a trait + final val DEFAULTPARAM = 0x02000000 // the parameter has a default value + final val BRIDGE = 0x04000000 // function is a bridge method. Set by Erasure + final val ACCESSOR = 0x08000000 // a value or variable accessor (getter or setter) + + final val SUPERACCESSOR = 0x10000000 // a super accessor + final val PARAMACCESSOR = 0x20000000 // for value definitions: is an access method + // for a final val parameter + // for parameters: is a val parameter + final val MODULEVAR = 0x40000000 // for variables: is the variable caching a module value + final val SYNTHETICMETH = 0x40000000 // for methods: synthetic method, but without SYNTHETIC flag + final val MONOMORPHIC = 0x40000000 // for type symbols: does not have type parameters + final val LAZY = 0x80000000L // symbol is a lazy val. can't have MUTABLE unless transformed by typer + + final val IS_ERROR = 0x100000000L // symbol is an error symbol + final val OVERLOADED = 0x200000000L // symbol is overloaded + final val LIFTED = 0x400000000L // class has been lifted out to package level + // local value has been lifted out to class level + // todo: make LIFTED = latePRIVATE? + final val MIXEDIN = 0x800000000L // term member has been mixed in + final val EXISTENTIAL = 0x800000000L // type is an existential parameter or skolem + + final val EXPANDEDNAME = 0x1000000000L // name has been expanded with class suffix + final val IMPLCLASS = 0x2000000000L // symbol is an implementation class + final val PRESUPER = 0x2000000000L // value is evaluated before super call + final val TRANS_FLAG = 0x4000000000L // transient flag guaranteed to be reset + // after each phase. + + final val LOCKED = 0x8000000000L // temporary flag to catch cyclic dependencies + final val SPECIALIZED = 0x10000000000L// symbol is a generated specialized member + final val DEFAULTINIT = 0x20000000000L// symbol is a generated specialized member + final val VBRIDGE = 0x40000000000L// symbol is a varargs bridge + + // pickling and unpickling of flags + + // The flags from 0x001 to 0x800 are different in the raw flags + // and in the pickled format. + + private final val IMPLICIT_PKL = 0x00000001 + private final val FINAL_PKL = 0x00000002 + private final val PRIVATE_PKL = 0x00000004 + private final val PROTECTED_PKL = 0x00000008 + + private final val SEALED_PKL = 0x00000010 + private final val OVERRIDE_PKL = 0x00000020 + private final val CASE_PKL = 0x00000040 + private final val ABSTRACT_PKL = 0x00000080 + + private final val DEFERRED_PKL = 0x00000100 + private final val METHOD_PKL = 0x00000200 + private final val MODULE_PKL = 0x00000400 + private final val INTERFACE_PKL = 0x00000800 + + private final val PKL_MASK = 0x00000FFF + + final val PickledFlags: Long = 0xFFFFFFFFL + + private val r2p = { + def rawFlagsToPickledAux(flags:Int) = { + var pflags=0 + if ((flags & IMPLICIT )!=0) pflags|=IMPLICIT_PKL + if ((flags & FINAL )!=0) pflags|=FINAL_PKL + if ((flags & PRIVATE )!=0) pflags|=PRIVATE_PKL + if ((flags & PROTECTED)!=0) pflags|=PROTECTED_PKL + if ((flags & SEALED )!=0) pflags|=SEALED_PKL + if ((flags & OVERRIDE )!=0) pflags|=OVERRIDE_PKL + if ((flags & CASE )!=0) pflags|=CASE_PKL + if ((flags & ABSTRACT )!=0) pflags|=ABSTRACT_PKL + if ((flags & DEFERRED )!=0) pflags|=DEFERRED_PKL + if ((flags & METHOD )!=0) pflags|=METHOD_PKL + if ((flags & MODULE )!=0) pflags|=MODULE_PKL + if ((flags & INTERFACE)!=0) pflags|=INTERFACE_PKL + pflags + } + val v=new Array[Int](PKL_MASK+1) + var i=0 + while (i<=PKL_MASK) { + v(i)=rawFlagsToPickledAux(i) + i+=1 + } + v + } + + private val p2r = { + def pickledToRawFlagsAux(pflags:Int) = { + var flags=0 + if ((pflags & IMPLICIT_PKL )!=0) flags|=IMPLICIT + if ((pflags & FINAL_PKL )!=0) flags|=FINAL + if ((pflags & PRIVATE_PKL )!=0) flags|=PRIVATE + if ((pflags & PROTECTED_PKL)!=0) flags|=PROTECTED + if ((pflags & SEALED_PKL )!=0) flags|=SEALED + if ((pflags & OVERRIDE_PKL )!=0) flags|=OVERRIDE + if ((pflags & CASE_PKL )!=0) flags|=CASE + if ((pflags & ABSTRACT_PKL )!=0) flags|=ABSTRACT + if ((pflags & DEFERRED_PKL )!=0) flags|=DEFERRED + if ((pflags & METHOD_PKL )!=0) flags|=METHOD + if ((pflags & MODULE_PKL )!=0) flags|=MODULE + if ((pflags & INTERFACE_PKL)!=0) flags|=INTERFACE + flags + } + val v=new Array[Int](PKL_MASK+1) + var i=0 + while (i<=PKL_MASK) { + v(i)=pickledToRawFlagsAux(i) + i+=1 + } + v + } + + def rawFlagsToPickled(flags:Long):Long = + (flags & ~PKL_MASK) | r2p(flags.toInt & PKL_MASK) + + def pickledToRawFlags(pflags:Long):Long = + (pflags & ~PKL_MASK) | p2r(pflags.toInt & PKL_MASK) + + // List of the raw flags, in pickled order + protected val pickledListOrder = { + def findBit(m:Long):Int = { + var mask=m + var i=0 + while (i <= 62) { + if ((mask&1) == 1L) return i + mask >>= 1 + i += 1 + } + throw new AssertionError() + } + val v=new Array[Long](63) + v(findBit(IMPLICIT_PKL ))=IMPLICIT + v(findBit(FINAL_PKL ))=FINAL + v(findBit(PRIVATE_PKL ))=PRIVATE + v(findBit(PROTECTED_PKL))=PROTECTED + v(findBit(SEALED_PKL ))=SEALED + v(findBit(OVERRIDE_PKL ))=OVERRIDE + v(findBit(CASE_PKL ))=CASE + v(findBit(ABSTRACT_PKL ))=ABSTRACT + v(findBit(DEFERRED_PKL ))=DEFERRED + v(findBit(METHOD_PKL ))=METHOD + v(findBit(MODULE_PKL ))=MODULE + v(findBit(INTERFACE_PKL))=INTERFACE + var i=findBit(PKL_MASK+1) + while (i <= 62) { + v(i)=1L << i + i += 1 + } + v.toList + } + +} diff --git a/src/library/scala/reflect/generic/Names.scala b/src/library/scala/reflect/generic/Names.scala new file mode 100755 index 0000000000..1b31726e3a --- /dev/null +++ b/src/library/scala/reflect/generic/Names.scala @@ -0,0 +1,21 @@ +package scala.reflect +package generic + +trait Names { + + type Name >: Null <: AnyRef + + def newTermName(cs: Array[Char], offset: Int, len: Int): Name + def newTermName(cs: Array[Byte], offset: Int, len: Int): Name + def newTermName(s: String): Name + + def mkTermName(name: Name): Name + + def newTypeName(cs: Array[Char], offset: Int, len: Int): Name + def newTypeName(cs: Array[Byte], offset: Int, len: Int): Name + def newTypeName(s: String): Name + + def mkTypeName(name: Name): Name +} + + diff --git a/src/library/scala/reflect/generic/PickleBuffer.scala b/src/library/scala/reflect/generic/PickleBuffer.scala new file mode 100755 index 0000000000..2fab02bcfe --- /dev/null +++ b/src/library/scala/reflect/generic/PickleBuffer.scala @@ -0,0 +1,188 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: PickleBuffer.scala 20028 2009-12-07 11:49:19Z cunei $ + +package scala.reflect +package generic + +/** Variable length byte arrays, with methods for basic pickling and unpickling. + * + * @param data The initial buffer + * @param from The first index where defined data are found + * @param to The first index where new data can be written + */ +class PickleBuffer(data: Array[Byte], from: Int, to: Int) { + + var bytes = data + var readIndex = from + var writeIndex = to + + /** Double bytes array */ + private def dble() { + val bytes1 = new Array[Byte](bytes.length * 2) + Array.copy(bytes, 0, bytes1, 0, writeIndex) + bytes = bytes1 + } + + def ensureCapacity(capacity: Int) = + while (bytes.length < writeIndex + capacity) dble() + + // -- Basic output routines -------------------------------------------- + + /** Write a byte of data */ + def writeByte(b: Int) { + if (writeIndex == bytes.length) dble() + bytes(writeIndex) = b.toByte + writeIndex += 1 + } + + /** Write a natural number in big endian format, base 128. + * All but the last digits have bit 0x80 set. + */ + def writeNat(x: Int) = + writeLongNat(x.toLong & 0x00000000FFFFFFFFL) + + /** + * Like writeNat, but for longs. This is not the same as + * writeLong, which writes in base 256. Note that the + * binary representation of LongNat is identical to Nat + * if the long value is in the range Int.MIN_VALUE to + * Int.MAX_VALUE. + */ + def writeLongNat(x: Long) { + def writeNatPrefix(x: Long) { + val y = x >>> 7 + if (y != 0L) writeNatPrefix(y) + writeByte(((x & 0x7f) | 0x80).toInt) + } + val y = x >>> 7 + if (y != 0L) writeNatPrefix(y) + writeByte((x & 0x7f).toInt) + } + + /** Write a natural number <code>x</code> at position <code>pos</code>. + * If number is more than one byte, shift rest of array to make space. + * + * @param pos ... + * @param x ... + */ + def patchNat(pos: Int, x: Int) { + def patchNatPrefix(x: Int) { + writeByte(0) + Array.copy(bytes, pos, bytes, pos+1, writeIndex - (pos+1)) + bytes(pos) = ((x & 0x7f) | 0x80).toByte + val y = x >>> 7 + if (y != 0) patchNatPrefix(y) + } + bytes(pos) = (x & 0x7f).toByte + val y = x >>> 7 + if (y != 0) patchNatPrefix(y) + } + + /** Write a long number <code>x</code> in signed big endian format, base 256. + * + * @param x The long number to be written. + */ + def writeLong(x: Long) { + val y = x >> 8 + val z = x & 0xff + if (-y != (z >> 7)) writeLong(y) + writeByte(z.toInt) + } + + // -- Basic input routines -------------------------------------------- + + /** Peek at the current byte without moving the read index */ + def peekByte(): Int = bytes(readIndex) + + /** Read a byte */ + def readByte(): Int = { + val x = bytes(readIndex); readIndex += 1; x + } + + /** Read a natural number in big endian format, base 128. + * All but the last digits have bit 0x80 set.*/ + def readNat(): Int = readLongNat().toInt + + def readLongNat(): Long = { + var b = 0L + var x = 0L + do { + b = readByte() + x = (x << 7) + (b & 0x7f) + } while ((b & 0x80) != 0L); + x + } + + /** Read a long number in signed big endian format, base 256. */ + def readLong(len: Int): Long = { + var x = 0L + var i = 0 + while (i < len) { + x = (x << 8) + (readByte() & 0xff) + i += 1 + } + val leading = 64 - (len << 3) + x << leading >> leading + } + + /** Returns the buffer as a sequence of (Int, Array[Byte]) representing + * (tag, data) of the individual entries. Saves and restores buffer state. + */ + + def toIndexedSeq: IndexedSeq[(Int, Array[Byte])] = { + val saved = readIndex + readIndex = 0 + readNat() ; readNat() // discarding version + val result = new Array[(Int, Array[Byte])](readNat()) + + result.indices foreach { index => + val tag = readNat() + val len = readNat() + val bytes = data.slice(readIndex, len + readIndex) + readIndex += len + + result(index) = tag -> bytes + } + + readIndex = saved + result.toIndexedSeq + } + + /** Perform operation <code>op</code> until the condition + * <code>readIndex == end</code> is satisfied. + * Concatenate results into a list. + * + * @param end ... + * @param op ... + * @return ... + */ + def until[T](end: Int, op: () => T): List[T] = + if (readIndex == end) List() else op() :: until(end, op); + + /** Perform operation <code>op</code> the number of + * times specified. Concatenate the results into a list. + */ + def times[T](n: Int, op: ()=>T): List[T] = + if (n == 0) List() else op() :: times(n-1, op) + + /** Pickle = majorVersion_Nat minorVersion_Nat nbEntries_Nat {Entry} + * Entry = type_Nat length_Nat [actual entries] + * + * Assumes that the ..Version_Nat are already consumed. + * + * @return an array mapping entry numbers to locations in + * the byte array where the entries start. + */ + def createIndex: Array[Int] = { + val index = new Array[Int](readNat()) // nbEntries_Nat + for (i <- 0 until index.length) { + index(i) = readIndex + readByte() // skip type_Nat + readIndex = readNat() + readIndex // read length_Nat, jump to next entry + } + index + } +} diff --git a/src/library/scala/reflect/generic/PickleFormat.scala b/src/library/scala/reflect/generic/PickleFormat.scala new file mode 100755 index 0000000000..d1e884f513 --- /dev/null +++ b/src/library/scala/reflect/generic/PickleFormat.scala @@ -0,0 +1,223 @@ +package scala.reflect +package generic + +/** This object provides constants for pickling attributes. + * + * If you extend the format, be sure to increase the + * version minor number. + * + * @author Martin Odersky + * @version 1.0 + */ +object PickleFormat { + +/*************************************************** + * Symbol table attribute format: + * Symtab = nentries_Nat {Entry} + * Entry = 1 TERMNAME len_Nat NameInfo + * | 2 TYPENAME len_Nat NameInfo + * | 3 NONEsym len_Nat + * | 4 TYPEsym len_Nat SymbolInfo + * | 5 ALIASsym len_Nat SymbolInfo + * | 6 CLASSsym len_Nat SymbolInfo [thistype_Ref] + * | 7 MODULEsym len_Nat SymbolInfo + * | 8 VALsym len_Nat [defaultGetter_Ref /* no longer needed*/] SymbolInfo [alias_Ref] + * | 9 EXTref len_Nat name_Ref [owner_Ref] + * | 10 EXTMODCLASSref len_Nat name_Ref [owner_Ref] + * | 11 NOtpe len_Nat + * | 12 NOPREFIXtpe len_Nat + * | 13 THIStpe len_Nat sym_Ref + * | 14 SINGLEtpe len_Nat type_Ref sym_Ref + * | 15 CONSTANTtpe len_Nat constant_Ref + * | 16 TYPEREFtpe len_Nat type_Ref sym_Ref {targ_Ref} + * | 17 TYPEBOUNDStpe len_Nat tpe_Ref tpe_Ref + * | 18 REFINEDtpe len_Nat classsym_Ref {tpe_Ref} + * | 19 CLASSINFOtpe len_Nat classsym_Ref {tpe_Ref} + * | 20 METHODtpe len_Nat tpe_Ref {sym_Ref} + * | 21 POLYTtpe len_Nat tpe_Ref {sym_Ref} + * | 22 IMPLICITMETHODtpe len_Nat tpe_Ref {sym_Ref} /* no longer needed */ + * | 52 SUPERtpe len_Nat tpe_Ref tpe_Ref + * | 24 LITERALunit len_Nat + * | 25 LITERALboolean len_Nat value_Long + * | 26 LITERALbyte len_Nat value_Long + * | 27 LITERALshort len_Nat value_Long + * | 28 LITERALchar len_Nat value_Long + * | 29 LITERALint len_Nat value_Long + * | 30 LITERALlong len_Nat value_Long + * | 31 LITERALfloat len_Nat value_Long + * | 32 LITERALdouble len_Nat value_Long + * | 33 LITERALstring len_Nat name_Ref + * | 34 LITERALnull len_Nat + * | 35 LITERALclass len_Nat tpe_Ref + * | 36 LITERALenum len_Nat sym_Ref + * | 40 SYMANNOT len_Nat sym_Ref AnnotInfoBody + * | 41 CHILDREN len_Nat sym_Ref {sym_Ref} + * | 42 ANNOTATEDtpe len_Nat [sym_Ref /* no longer needed */] tpe_Ref {annotinfo_Ref} + * | 43 ANNOTINFO len_Nat AnnotInfoBody + * | 44 ANNOTARGARRAY len_Nat {constAnnotArg_Ref} + * | 47 DEBRUIJNINDEXtpe len_Nat level_Nat index_Nat + * | 48 EXISTENTIALtpe len_Nat type_Ref {symbol_Ref} + * | 49 TREE len_Nat 1 EMPTYtree + * | 49 TREE len_Nat 2 PACKAGEtree type_Ref sym_Ref mods_Ref name_Ref {tree_Ref} + * | 49 TREE len_Nat 3 CLASStree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 4 MODULEtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref + * | 49 TREE len_Nat 5 VALDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 6 DEFDEFtree type_Ref sym_Ref mods_Ref name_Ref numtparams_Nat {tree_Ref} numparamss_Nat {numparams_Nat {tree_Ref}} tree_Ref tree_Ref + * | 49 TREE len_Nat 7 TYPEDEFtree type_Ref sym_Ref mods_Ref name_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 8 LABELtree type_Ref sym_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 9 IMPORTtree type_Ref sym_Ref tree_Ref {name_Ref name_Ref} + * | 49 TREE len_Nat 11 DOCDEFtree type_Ref sym_Ref string_Ref tree_Ref + * | 49 TREE len_Nat 12 TEMPLATEtree type_Ref sym_Ref numparents_Nat {tree_Ref} tree_Ref {tree_Ref} + * | 49 TREE len_Nat 13 BLOCKtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 14 CASEtree type_Ref tree_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 15 SEQUENCEtree type_Ref {tree_Ref} + * | 49 TREE len_Nat 16 ALTERNATIVEtree type_Ref {tree_Ref} + * | 49 TREE len_Nat 17 STARtree type_Ref {tree_Ref} + * | 49 TREE len_Nat 18 BINDtree type_Ref sym_Ref name_Ref tree_Ref + * | 49 TREE len_Nat 19 UNAPPLYtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 20 ARRAYVALUEtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 21 FUNCTIONtree type_Ref sym_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 22 ASSIGNtree type_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 23 IFtree type_Ref tree_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 24 MATCHtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 25 RETURNtree type_Ref sym_Ref tree_Ref + * | 49 TREE len_Nat 26 TREtree type_Ref tree_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 27 THROWtree type_Ref tree_Ref + * | 49 TREE len_Nat 28 NEWtree type_Ref tree_Ref + * | 49 TREE len_Nat 29 TYPEDtree type_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 30 TYPEAPPLYtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 31 APPLYtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 32 APPLYDYNAMICtree type_Ref sym_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 33 SUPERtree type_Ref sym_Ref tree_Ref name_Ref + * | 49 TREE len_Nat 34 THIStree type_Ref sym_Ref name_Ref + * | 49 TREE len_Nat 35 SELECTtree type_Ref sym_Ref tree_Ref name_Ref + * | 49 TREE len_Nat 36 IDENTtree type_Ref sym_Ref name_Ref + * | 49 TREE len_Nat 37 LITERALtree type_Ref constant_Ref + * | 49 TREE len_Nat 38 TYPEtree type_Ref + * | 49 TREE len_Nat 39 ANNOTATEDtree type_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 40 SINGLETONTYPEtree type_Ref tree_Ref + * | 49 TREE len_Nat 41 SELECTFROMTYPEtree type_Ref tree_Ref name_Ref + * | 49 TREE len_Nat 42 COMPOUNDTYPEtree type_Ref tree_Ref + * | 49 TREE len_Nat 43 APPLIEDTYPEtree type_Ref tree_Ref {tree_Ref} + * | 49 TREE len_Nat 44 TYPEBOUNDStree type_Ref tree_Ref tree_Ref + * | 49 TREE len_Nat 45 EXISTENTIALTYPEtree type_Ref tree_Ref {tree_Ref} + * | 50 MODIFIERS len_Nat flags_Long privateWithin_Ref + * SymbolInfo = name_Ref owner_Ref flags_LongNat [privateWithin_Ref] info_Ref + * NameInfo = <character sequence of length len_Nat in Utf8 format> + * NumInfo = <len_Nat-byte signed number in big endian format> + * Ref = Nat + * AnnotInfoBody = info_Ref {annotArg_Ref} {name_Ref constAnnotArg_Ref} + * AnnotArg = Tree | Constant + * ConstAnnotArg = Constant | AnnotInfo | AnnotArgArray + * + * len is remaining length after `len'. + */ + val MajorVersion = 5 + val MinorVersion = 0 + + final val TERMname = 1 + final val TYPEname = 2 + final val NONEsym = 3 + final val TYPEsym = 4 + final val ALIASsym = 5 + final val CLASSsym = 6 + final val MODULEsym = 7 + final val VALsym = 8 + final val EXTref = 9 + final val EXTMODCLASSref = 10 + final val NOtpe = 11 + final val NOPREFIXtpe = 12 + final val THIStpe = 13 + final val SINGLEtpe = 14 + final val CONSTANTtpe = 15 + final val TYPEREFtpe = 16 + final val TYPEBOUNDStpe = 17 + final val REFINEDtpe = 18 + final val CLASSINFOtpe = 19 + final val METHODtpe = 20 + final val POLYtpe = 21 + final val IMPLICITMETHODtpe = 22 + + final val LITERAL = 23 // base line for literals + final val LITERALunit = 24 + final val LITERALboolean = 25 + final val LITERALbyte = 26 + final val LITERALshort = 27 + final val LITERALchar = 28 + final val LITERALint = 29 + final val LITERALlong = 30 + final val LITERALfloat = 31 + final val LITERALdouble = 32 + final val LITERALstring = 33 + final val LITERALnull = 34 + final val LITERALclass = 35 + final val LITERALenum = 36 + final val SYMANNOT = 40 + final val CHILDREN = 41 + final val ANNOTATEDtpe = 42 + final val ANNOTINFO = 43 + final val ANNOTARGARRAY = 44 + + final val SUPERtpe = 46 + final val DEBRUIJNINDEXtpe = 47 + final val EXISTENTIALtpe = 48 + + final val TREE = 49 // prefix code that means a tree is coming + final val EMPTYtree = 1 + final val PACKAGEtree = 2 + final val CLASStree = 3 + final val MODULEtree = 4 + final val VALDEFtree = 5 + final val DEFDEFtree = 6 + final val TYPEDEFtree = 7 + final val LABELtree = 8 + final val IMPORTtree = 9 + final val DOCDEFtree = 11 + final val TEMPLATEtree = 12 + final val BLOCKtree = 13 + final val CASEtree = 14 + // This node type has been removed. + // final val SEQUENCEtree = 15 + final val ALTERNATIVEtree = 16 + final val STARtree = 17 + final val BINDtree = 18 + final val UNAPPLYtree = 19 + final val ARRAYVALUEtree = 20 + final val FUNCTIONtree = 21 + final val ASSIGNtree = 22 + final val IFtree = 23 + final val MATCHtree = 24 + final val RETURNtree = 25 + final val TREtree = 26 + final val THROWtree = 27 + final val NEWtree = 28 + final val TYPEDtree = 29 + final val TYPEAPPLYtree = 30 + final val APPLYtree = 31 + final val APPLYDYNAMICtree = 32 + final val SUPERtree = 33 + final val THIStree = 34 + final val SELECTtree = 35 + final val IDENTtree = 36 + final val LITERALtree = 37 + final val TYPEtree = 38 + final val ANNOTATEDtree = 39 + final val SINGLETONTYPEtree = 40 + final val SELECTFROMTYPEtree = 41 + final val COMPOUNDTYPEtree = 42 + final val APPLIEDTYPEtree = 43 + final val TYPEBOUNDStree = 44 + final val EXISTENTIALTYPEtree = 45 + + final val MODIFIERS = 50 + + final val firstSymTag = NONEsym + final val lastSymTag = VALsym + final val lastExtSymTag = EXTMODCLASSref + + + //The following two are no longer accurate, because ANNOTATEDtpe, + //SUPERtpe, ... are not in the same range as the other types + //final val firstTypeTag = NOtpe + //final val lastTypeTag = POLYtpe +} diff --git a/src/library/scala/reflect/generic/Scopes.scala b/src/library/scala/reflect/generic/Scopes.scala new file mode 100755 index 0000000000..9f8a8ecd19 --- /dev/null +++ b/src/library/scala/reflect/generic/Scopes.scala @@ -0,0 +1,15 @@ +package scala.reflect +package generic + +trait Scopes { self: Universe => + + abstract class AbsScope extends Iterable[Symbol] { + def enter(sym: Symbol): Symbol + } + + type Scope <: AbsScope + + def newScope(): Scope +} + + diff --git a/src/library/scala/reflect/generic/StandardDefinitions.scala b/src/library/scala/reflect/generic/StandardDefinitions.scala new file mode 100755 index 0000000000..24dce7173a --- /dev/null +++ b/src/library/scala/reflect/generic/StandardDefinitions.scala @@ -0,0 +1,67 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: Definitions.scala 20619 2010-01-20 10:55:56Z rytz $ + +package scala.reflect +package generic + +trait StandardDefinitions { self: Universe => + + val definitions: AbsDefinitions + + abstract class AbsDefinitions { + + // outer packages and their classes + def RootPackage: Symbol + def RootClass: Symbol + def EmptyPackage: Symbol + def EmptyPackageClass: Symbol + + def ScalaPackage: Symbol + def ScalaPackageClass: Symbol + + // top types + def AnyClass : Symbol + def AnyValClass: Symbol + def AnyRefClass: Symbol + def ObjectClass: Symbol + + // bottom types + def NullClass : Symbol + def NothingClass: Symbol + + // the scala value classes + def UnitClass : Symbol + def ByteClass : Symbol + def ShortClass : Symbol + def CharClass : Symbol + def IntClass : Symbol + def LongClass : Symbol + def FloatClass : Symbol + def DoubleClass : Symbol + def BooleanClass: Symbol + + // fundamental reference classes + def SymbolClass : Symbol + def StringClass : Symbol + def ClassClass : Symbol + + // fundamental modules + def PredefModule: Symbol + + // fundamental type constructions + def ClassType(arg: Type): Type + + /** The string representation used by the given type in the VM. + */ + def signature(tp: Type): String + + /** Is symbol one of the value classes? */ + def isValueClass(sym: Symbol): Boolean + + /** Is symbol one of the numeric value classes? */ + def isNumericValueClass(sym: Symbol): Boolean + } +} diff --git a/src/library/scala/reflect/generic/StdNames.scala b/src/library/scala/reflect/generic/StdNames.scala new file mode 100755 index 0000000000..7a3b9169d8 --- /dev/null +++ b/src/library/scala/reflect/generic/StdNames.scala @@ -0,0 +1,26 @@ +package scala.reflect +package generic + +trait StdNames { self: Universe => + + val nme: StandardNames + + class StandardNames { + val EXPAND_SEPARATOR_STRING = "$$" + val LOCAL_SUFFIX_STRING = " " + + val ANON_CLASS_NAME = newTermName("$anon") + val ANON_FUN_NAME = newTermName("$anonfun") + val EMPTY_PACKAGE_NAME = newTermName("<empty>") + val IMPORT = newTermName("<import>") + val REFINE_CLASS_NAME = newTermName("<refinement>") + val ROOT = newTermName("<root>") + val ROOTPKG = newTermName("_root_") + val EMPTY = newTermName("") + + /** The expanded name of `name' relative to this class `base` with given `separator` + */ + def expandedName(name: Name, base: Symbol, separator: String = EXPAND_SEPARATOR_STRING): Name = + newTermName(base.fullName('$') + separator + name) + } +} diff --git a/src/library/scala/reflect/generic/Symbols.scala b/src/library/scala/reflect/generic/Symbols.scala new file mode 100755 index 0000000000..2f5e0624ab --- /dev/null +++ b/src/library/scala/reflect/generic/Symbols.scala @@ -0,0 +1,194 @@ +package scala.reflect +package generic + +import Flags._ + +trait Symbols { self: Universe => + + type Symbol >: Null <: AbsSymbol + + abstract class AbsSymbol { this: Symbol => + + /** The owner of this symbol. + */ + def owner: Symbol + + /** The flags of this symbol */ + def flags: Long + + /** The name of the symbol as a member of the `Name` type. + */ + def name: Name + + /** The name of the symbol before decoding, e.g. `$eq$eq` instead of `==`. + */ + def encodedName: String + + /** The decoded name of the symbol, e.g. `==` instead of `$eq$eq`. + */ + def decodedName: String = stripLocalSuffix(NameTransformer.decode(encodedName)) + + /** The encoded full path name of this symbol, where outer names and inner names + * are separated by `separator` characters. + * Never translates expansions of operators back to operator symbol. + * Never adds id. + */ + final def fullName(separator: Char): String = stripLocalSuffix { + if (isRoot || isRootPackage || this == NoSymbol) this.toString + else if (owner.isEffectiveRoot) encodedName + else owner.enclClass.fullName(separator) + separator + encodedName + } + + private def stripLocalSuffix(s: String) = s stripSuffix nme.LOCAL_SUFFIX_STRING + + /** The encoded full path name of this symbol, where outer names and inner names + * are separated by periods. + */ + final def fullName: String = fullName('.') + + /** Does symbol have ANY flag in `mask` set? */ + final def hasFlag(mask: Long): Boolean = (flags & mask) != 0L + + /** Does symbol have ALL the flags in `mask` set? */ + final def hasAllFlags(mask: Long): Boolean = (flags & mask) == mask + + /** Set when symbol has a modifier of the form private[X], NoSymbol otherwise. + */ + def privateWithin: Symbol + + /** The raw info of the type + */ + def rawInfo: Type + + /** The type of the symbol + */ + def tpe: Type = info + + /** The info of the symbol. This is like tpe, except for class symbols where the `info` + * describes the contents of the class whereas the `tpe` is a reference to the class. + */ + def info: Type = { + val tp = rawInfo + tp.complete(this) + tp + } + + /** If this symbol is a class or trait, its self type, otherwise the type of the symbol itse;lf + */ + def typeOfThis: Type + + def owner_=(sym: Symbol) { throw new UnsupportedOperationException("owner_= inapplicable for " + this) } + def flags_=(flags: Long) { throw new UnsupportedOperationException("flags_= inapplicable for " + this) } + def info_=(tp: Type) { throw new UnsupportedOperationException("info_= inapplicable for " + this) } + def typeOfThis_=(tp: Type) { throw new UnsupportedOperationException("typeOfThis_= inapplicable for " + this) } + def privateWithin_=(sym: Symbol) { throw new UnsupportedOperationException("privateWithin_= inapplicable for " + this) } + def sourceModule_=(sym: Symbol) { throw new UnsupportedOperationException("sourceModule_= inapplicable for " + this) } + def addChild(sym: Symbol) { throw new UnsupportedOperationException("addChild inapplicable for " + this) } + def addAnnotation(annot: AnnotationInfo) { throw new UnsupportedOperationException("addAnnotation inapplicable for " + this) } + + /** For a module class its linked class, for a plain class + * the module class of its linked module. + * For instance + * object Foo + * class Foo + * + * Then object Foo has a `moduleClass' (invisible to the user, the backend calls it Foo$ + * linkedClassOfClass goes from class Foo$ to class Foo, and back. + */ + def linkedClassOfClass: Symbol + + /** The module corresponding to this module class (note that this + * is not updated when a module is cloned), or NoSymbol if this is not a ModuleClass + */ + def sourceModule: Symbol = NoSymbol + + /** If symbol is an object definition, it's implied associated class, + * otherwise NoSymbol + */ + def moduleClass: Symbol + +// flags and kind tests + + def isTerm = false // to be overridden + def isType = false // to be overridden + def isClass = false // to be overridden + def isAliasType = false // to be overridden + def isAbstractType = false // to be overridden + private[scala] def isSkolem = false // to be overridden + + def isTrait: Boolean = isClass && hasFlag(TRAIT) // refined later for virtual classes. + final def hasDefault = isParameter && hasFlag(DEFAULTPARAM) + final def isAbstractClass = isClass && hasFlag(ABSTRACT) + final def isAbstractOverride = isTerm && hasFlag(ABSTRACT) && hasFlag(OVERRIDE) + final def isBridge = hasFlag(BRIDGE) + final def isCase = hasFlag(CASE) + final def isCaseAccessor = hasFlag(CASEACCESSOR) + final def isContravariant = isType && hasFlag(CONTRAVARIANT) + final def isCovariant = isType && hasFlag(COVARIANT) + final def isDeferred = hasFlag(DEFERRED) && !isClass + final def isEarlyInitialized: Boolean = isTerm && hasFlag(PRESUPER) + final def isExistentiallyBound = isType && hasFlag(EXISTENTIAL) + final def isFinal = hasFlag(FINAL) + final def isGetterOrSetter = hasFlag(ACCESSOR) + final def isImplClass = isClass && hasFlag(IMPLCLASS) // Is this symbol an implementation class for a mixin? + final def isImplicit = hasFlag(IMPLICIT) + final def isInterface = hasFlag(INTERFACE) + final def isJavaDefined = hasFlag(JAVA) + final def isLazy = hasFlag(LAZY) + final def isMethod = isTerm && hasFlag(METHOD) + final def isModule = isTerm && hasFlag(MODULE) + final def isModuleClass = isClass && hasFlag(MODULE) + final def isMutable = hasFlag(MUTABLE) + final def isOverloaded = hasFlag(OVERLOADED) + final def isOverride = hasFlag(OVERRIDE) + final def isParamAccessor = hasFlag(PARAMACCESSOR) + final def isParameter = hasFlag(PARAM) + final def isRefinementClass = isClass && name == mkTypeName(nme.REFINE_CLASS_NAME) + final def isSealed = isClass && (hasFlag(SEALED) || definitions.isValueClass(this)) + final def isSourceMethod = isTerm && (flags & (METHOD | STABLE)) == METHOD // exclude all accessors!!! + final def isSuperAccessor = hasFlag(SUPERACCESSOR) + final def isSynthetic = hasFlag(SYNTHETIC) + final def isTypeParameter = isType && isParameter && !isSkolem + + /** Access tests */ + final def isPrivate = hasFlag(PRIVATE) + final def isPrivateLocal = hasFlag(PRIVATE) && hasFlag(LOCAL) + final def isProtected = hasFlag(PROTECTED) + final def isProtectedLocal = hasFlag(PROTECTED) && hasFlag(LOCAL) + final def isPublic = !hasFlag(PRIVATE | PROTECTED) && privateWithin == NoSymbol + + /** Package tests */ + final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME + final def isEmptyPackageClass = isPackageClass && name == mkTypeName(nme.EMPTY_PACKAGE_NAME) + final def isPackage = isModule && hasFlag(PACKAGE) + final def isPackageClass = isClass && hasFlag(PACKAGE) + final def isRoot = isPackageClass && owner == NoSymbol + final def isRootPackage = isPackage && owner == NoSymbol + + /** Is this symbol an effective root for fullname string? + */ + def isEffectiveRoot = isRoot || isEmptyPackageClass + + // creators + + def newAbstractType(name: Name, pos: Position = NoPosition): Symbol + def newAliasType(name: Name, pos: Position = NoPosition): Symbol + def newClass(name: Name, pos: Position = NoPosition): Symbol + def newMethod(name: Name, pos: Position = NoPosition): Symbol + def newModule(name: Name, clazz: Symbol, pos: Position = NoPosition): Symbol + def newModuleClass(name: Name, pos: Position = NoPosition): Symbol + def newValue(name: Name, pos: Position = NoPosition): Symbol + + // access to related symbols + + /** The next enclosing class */ + def enclClass: Symbol = if (isClass) this else owner.enclClass + + /** The next enclosing method */ + def enclMethod: Symbol = if (isSourceMethod) this else owner.enclMethod + } + + val NoSymbol: Symbol +} + + diff --git a/src/library/scala/reflect/generic/Trees.scala b/src/library/scala/reflect/generic/Trees.scala new file mode 100755 index 0000000000..df93d157e3 --- /dev/null +++ b/src/library/scala/reflect/generic/Trees.scala @@ -0,0 +1,738 @@ +package scala.reflect +package generic + +import java.io.{PrintWriter, StringWriter} +import Flags._ + +trait Trees { self: Universe => + + abstract class AbsTreePrinter(out: PrintWriter) { + def print(tree: Tree) + def flush() + } + + def newTreePrinter(out: PrintWriter): AbsTreePrinter + + private[scala] var nodeCount = 0 + + /** @param privateWithin the qualifier for a private (a type name) + * or nme.EMPTY.toTypeName, if none is given. + * @param annotations the annotations for the definition. + * <strong>Note:</strong> the typechecker drops these annotations, + * use the AnnotationInfo's (Symbol.annotations) in later phases. + */ + case class Modifiers(flags: Long, privateWithin: Name, annotations: List[Tree], positions: Map[Long, Position]) { + def isAbstract = hasFlag(ABSTRACT ) + def isAccessor = hasFlag(ACCESSOR ) + def isArgument = hasFlag(PARAM ) + def isCase = hasFlag(CASE ) + def isContravariant = hasFlag(CONTRAVARIANT) // marked with `-' + def isCovariant = hasFlag(COVARIANT ) // marked with `+' + def isDeferred = hasFlag(DEFERRED ) + def isFinal = hasFlag(FINAL ) + def isImplicit = hasFlag(IMPLICIT ) + def isLazy = hasFlag(LAZY ) + def isOverride = hasFlag(OVERRIDE ) + def isPrivate = hasFlag(PRIVATE ) + def isProtected = hasFlag(PROTECTED) + def isPublic = !isPrivate && !isProtected + def isSealed = hasFlag(SEALED ) + def isTrait = hasFlag(TRAIT ) + def isVariable = hasFlag(MUTABLE ) + + def hasFlag(flag: Long) = (flag & flags) != 0L + def & (flag: Long): Modifiers = { + val flags1 = flags & flag + if (flags1 == flags) this + else Modifiers(flags1, privateWithin, annotations, positions) + } + def &~ (flag: Long): Modifiers = { + val flags1 = flags & (~flag) + if (flags1 == flags) this + else Modifiers(flags1, privateWithin, annotations, positions) + } + def | (flag: Long): Modifiers = { + val flags1 = flags | flag + if (flags1 == flags) this + else Modifiers(flags1, privateWithin, annotations, positions) + } + def withAnnotations(annots: List[Tree]) = + if (annots.isEmpty) this + else copy(annotations = annotations ::: annots) + def withPosition(flag: Long, position: Position) = + copy(positions = positions + (flag -> position)) + } + + def Modifiers(flags: Long, privateWithin: Name): Modifiers = Modifiers(flags, privateWithin, List(), Map.empty) + def Modifiers(flags: Long): Modifiers = Modifiers(flags, mkTypeName(nme.EMPTY)) + + lazy val NoMods = Modifiers(0) + + abstract class Tree extends Product { + val id = nodeCount + nodeCount += 1 + + private[this] var rawpos: Position = NoPosition + + def pos = rawpos + def pos_=(pos: Position) = rawpos = pos + def setPos(pos: Position): this.type = { rawpos = pos; this } + + private[this] var rawtpe: Type = _ + + def tpe = rawtpe + def tpe_=(t: Type) = rawtpe = t + + /** Set tpe to give `tp` and return this. + */ + def setType(tp: Type): this.type = { rawtpe = tp; this } + + /** Like `setType`, but if this is a previously empty TypeTree + * that fact is remembered so that resetType will snap back. + */ + def defineType(tp: Type): this.type = setType(tp) + + def symbol: Symbol = null + def symbol_=(sym: Symbol) { throw new UnsupportedOperationException("symbol_= inapplicable for " + this) } + def setSymbol(sym: Symbol): this.type = { symbol = sym; this } + + def hasSymbol = false + def isDef = false + def isEmpty = false + + /** The direct child trees of this tree + * EmptyTrees are always omitted. Lists are collapsed. + */ + def children: List[Tree] = { + def subtrees(x: Any): List[Tree] = x match { + case EmptyTree => List() + case t: Tree => List(t) + case xs: List[_] => xs flatMap subtrees + case _ => List() + } + productIterator.toList flatMap subtrees + } + + /** In compiler: Make a copy of this tree, keeping all attributes, + * except that all positions are focussed (so nothing + * in this tree will be found when searching by position). + * If not in compiler may also return tree unchanged. + */ + private[scala] def duplicate: this.type = + duplicateTree(this).asInstanceOf[this.type] + + private[scala] def copyAttrs(tree: Tree): this.type = { + pos = tree.pos + tpe = tree.tpe + if (hasSymbol) symbol = tree.symbol + this + } + + override def toString(): String = { + val buffer = new StringWriter() + val printer = newTreePrinter(new PrintWriter(buffer)) + printer.print(this) + printer.flush() + buffer.toString + } + + override def hashCode(): Int = super.hashCode() + + override def equals(that: Any): Boolean = that match { + case t: Tree => this eq t + case _ => false + } + } + + private[scala] def duplicateTree(tree: Tree): Tree = tree + + trait SymTree extends Tree { + override def hasSymbol = true + override var symbol: Symbol = NoSymbol + } + + trait RefTree extends SymTree { + def name: Name + } + + abstract class DefTree extends SymTree { + def name: Name + override def isDef = true + } + + trait TermTree extends Tree + + /** A tree for a type. Note that not all type trees implement + * this trait; in particular, Ident's are an exception. */ + trait TypTree extends Tree + +// ----- tree node alternatives -------------------------------------- + + /** The empty tree */ + case object EmptyTree extends TermTree { + super.tpe_=(NoType) + override def tpe_=(t: Type) = + if (t != NoType) throw new UnsupportedOperationException("tpe_=("+t+") inapplicable for <empty>") + override def isEmpty = true + } + + abstract class MemberDef extends DefTree { + def mods: Modifiers + def keyword: String = this match { + case TypeDef(_, _, _, _) => "type" + case ClassDef(mods, _, _, _) => if (mods.isTrait) "trait" else "class" + case DefDef(_, _, _, _, _, _) => "def" + case ModuleDef(_, _, _) => "object" + case PackageDef(_, _) => "package" + case ValDef(mods, _, _, _) => if (mods.isVariable) "var" else "val" + case _ => "" + } + final def hasFlag(mask: Long): Boolean = (mods.flags & mask) != 0L + } + + /** Package clause + */ + case class PackageDef(pid: RefTree, stats: List[Tree]) + extends MemberDef { + def name = pid.name + def mods = NoMods + } + + abstract class ImplDef extends MemberDef { + def impl: Template + } + + /** Class definition */ + case class ClassDef(mods: Modifiers, name: Name, tparams: List[TypeDef], impl: Template) + extends ImplDef + + /** Singleton object definition + */ + case class ModuleDef(mods: Modifiers, name: Name, impl: Template) + extends ImplDef + + abstract class ValOrDefDef extends MemberDef { + def tpt: Tree + def rhs: Tree + } + + /** Value definition + */ + case class ValDef(mods: Modifiers, name: Name, tpt: Tree, rhs: Tree) extends ValOrDefDef + + /** Method definition + */ + case class DefDef(mods: Modifiers, name: Name, tparams: List[TypeDef], + vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree) extends ValOrDefDef + + /** Abstract type, type parameter, or type alias */ + case class TypeDef(mods: Modifiers, name: Name, tparams: List[TypeDef], rhs: Tree) + extends MemberDef + + /** <p> + * Labelled expression - the symbols in the array (must be Idents!) + * are those the label takes as argument + * </p> + * <p> + * The symbol that is given to the labeldef should have a MethodType + * (as if it were a nested function) + * </p> + * <p> + * Jumps are apply nodes attributed with label symbol, the arguments + * will get assigned to the idents. + * </p> + * <p> + * Note: on 2005-06-09 Martin, Iuli, Burak agreed to have forward + * jumps within a Block. + * </p> + */ + case class LabelDef(name: Name, params: List[Ident], rhs: Tree) + extends DefTree with TermTree + + + /** Import selector + * + * Representation of an imported name its optional rename and their optional positions + * + * @param name the imported name + * @param namePos its position or -1 if undefined + * @param rename the name the import is renamed to (== name if no renaming) + * @param renamePos the position of the rename or -1 if undefined + */ + case class ImportSelector(name: Name, namePos: Int, rename: Name, renamePos: Int) + + /** Import clause + * + * @param expr + * @param selectors + */ + case class Import(expr: Tree, selectors: List[ImportSelector]) + extends SymTree + // The symbol of an Import is an import symbol @see Symbol.newImport + // It's used primarily as a marker to check that the import has been typechecked. + + /** Instantiation template of a class or trait + * + * @param parents + * @param body + */ + case class Template(parents: List[Tree], self: ValDef, body: List[Tree]) + extends SymTree { + // the symbol of a template is a local dummy. @see Symbol.newLocalDummy + // the owner of the local dummy is the enclosing trait or class. + // the local dummy is itself the owner of any local blocks + // For example: + // + // class C { + // def foo // owner is C + // { + // def bar // owner is local dummy + // } + // System.err.println("TEMPLATE: " + parents) + } + + /** Block of expressions (semicolon separated expressions) */ + case class Block(stats: List[Tree], expr: Tree) + extends TermTree + + /** Case clause in a pattern match, eliminated by TransMatch + * (except for occurrences in switch statements) + */ + case class CaseDef(pat: Tree, guard: Tree, body: Tree) + extends Tree + + /** Alternatives of patterns, eliminated by TransMatch, except for + * occurrences in encoded Switch stmt (=remaining Match(CaseDef(...)) + */ + case class Alternative(trees: List[Tree]) + extends TermTree + + /** Repetition of pattern, eliminated by TransMatch */ + case class Star(elem: Tree) + extends TermTree + + /** Bind of a variable to a rhs pattern, eliminated by TransMatch + * + * @param name + * @param body + */ + case class Bind(name: Name, body: Tree) + extends DefTree + + case class UnApply(fun: Tree, args: List[Tree]) + extends TermTree + + /** Array of expressions, needs to be translated in backend, + */ + case class ArrayValue(elemtpt: Tree, elems: List[Tree]) + extends TermTree + + /** Anonymous function, eliminated by analyzer */ + case class Function(vparams: List[ValDef], body: Tree) + extends TermTree with SymTree + // The symbol of a Function is a synthetic value of name nme.ANON_FUN_NAME + // It is the owner of the function's parameters. + + /** Assignment */ + case class Assign(lhs: Tree, rhs: Tree) + extends TermTree + + /** Conditional expression */ + case class If(cond: Tree, thenp: Tree, elsep: Tree) + extends TermTree + + /** <p> + * Pattern matching expression (before <code>TransMatch</code>) + * Switch statements (after TransMatch) + * </p> + * <p> + * After <code>TransMatch</code>, cases will satisfy the following + * constraints: + * </p> + * <ul> + * <li>all guards are EmptyTree,</li> + * <li>all patterns will be either <code>Literal(Constant(x:Int))</code> + * or <code>Alternative(lit|...|lit)</code></li> + * <li>except for an "otherwise" branch, which has pattern + * <code>Ident(nme.WILDCARD)</code></li> + * </ul> + */ + case class Match(selector: Tree, cases: List[CaseDef]) + extends TermTree + + /** Return expression */ + case class Return(expr: Tree) + extends TermTree with SymTree + // The symbol of a Return node is the enclosing method. + + case class Try(block: Tree, catches: List[CaseDef], finalizer: Tree) + extends TermTree + + /** Throw expression */ + case class Throw(expr: Tree) + extends TermTree + + /** Object instantiation + * One should always use factory method below to build a user level new. + * + * @param tpt a class type + */ + case class New(tpt: Tree) extends TermTree + + /** Type annotation, eliminated by explicit outer */ + case class Typed(expr: Tree, tpt: Tree) + extends TermTree + + // Martin to Sean: Should GenericApply/TypeApply/Apply not be SymTree's? After all, + // ApplyDynamic is a SymTree. + abstract class GenericApply extends TermTree { + val fun: Tree + val args: List[Tree] + } + + /** Type application */ + case class TypeApply(fun: Tree, args: List[Tree]) + extends GenericApply { + override def symbol: Symbol = fun.symbol + override def symbol_=(sym: Symbol) { fun.symbol = sym } + } + + /** Value application */ + case class Apply(fun: Tree, args: List[Tree]) + extends GenericApply { + override def symbol: Symbol = fun.symbol + override def symbol_=(sym: Symbol) { fun.symbol = sym } + } + + /** Dynamic value application. + * In a dynamic application q.f(as) + * - q is stored in qual + * - as is stored in args + * - f is stored as the node's symbol field. + */ + case class ApplyDynamic(qual: Tree, args: List[Tree]) + extends TermTree with SymTree + // The symbol of an ApplyDynamic is the function symbol of `qual', or NoSymbol, if there is none. + + /** Super reference */ + case class Super(qual: Name, mix: Name) + extends TermTree with SymTree + // The symbol of a Super is the class _from_ which the super reference is made. + // For instance in C.super(...), it would be C. + + /** Self reference */ + case class This(qual: Name) + extends TermTree with SymTree + // The symbol of a This is the class to which the this refers. + // For instance in C.this, it would be C. + + /** Designator <qualifier> . <name> */ + case class Select(qualifier: Tree, name: Name) + extends RefTree + + /** Identifier <name> */ + case class Ident(name: Name) + extends RefTree + + class BackQuotedIdent(name: Name) extends Ident(name) + + /** Literal */ + case class Literal(value: Constant) + extends TermTree { + assert(value ne null) + } + + def Literal(value: Any): Literal = + Literal(Constant(value)) + + type TypeTree <: AbsTypeTree + val TypeTree: TypeTreeExtractor + + abstract class TypeTreeExtractor { + def apply(): TypeTree + def unapply(tree: TypeTree): Boolean + } + + class Traverser { + protected var currentOwner: Symbol = definitions.RootClass + def traverse(tree: Tree): Unit = tree match { + case EmptyTree => + ; + case PackageDef(pid, stats) => + traverse(pid) + atOwner(tree.symbol.moduleClass) { + traverseTrees(stats) + } + case ClassDef(mods, name, tparams, impl) => + atOwner(tree.symbol) { + traverseTrees(mods.annotations); traverseTrees(tparams); traverse(impl) + } + case ModuleDef(mods, name, impl) => + atOwner(tree.symbol.moduleClass) { + traverseTrees(mods.annotations); traverse(impl) + } + case ValDef(mods, name, tpt, rhs) => + atOwner(tree.symbol) { + traverseTrees(mods.annotations); traverse(tpt); traverse(rhs) + } + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + atOwner(tree.symbol) { + traverseTrees(mods.annotations); traverseTrees(tparams); traverseTreess(vparamss); traverse(tpt); traverse(rhs) + } + case TypeDef(mods, name, tparams, rhs) => + atOwner(tree.symbol) { + traverseTrees(mods.annotations); traverseTrees(tparams); traverse(rhs) + } + case LabelDef(name, params, rhs) => + traverseTrees(params); traverse(rhs) + case Import(expr, selectors) => + traverse(expr) + case Annotated(annot, arg) => + traverse(annot); traverse(arg) + case Template(parents, self, body) => + traverseTrees(parents) + if (!self.isEmpty) traverse(self) + traverseStats(body, tree.symbol) + case Block(stats, expr) => + traverseTrees(stats); traverse(expr) + case CaseDef(pat, guard, body) => + traverse(pat); traverse(guard); traverse(body) + case Alternative(trees) => + traverseTrees(trees) + case Star(elem) => + traverse(elem) + case Bind(name, body) => + traverse(body) + case UnApply(fun, args) => + traverse(fun); traverseTrees(args) + case ArrayValue(elemtpt, trees) => + traverse(elemtpt); traverseTrees(trees) + case Function(vparams, body) => + atOwner(tree.symbol) { + traverseTrees(vparams); traverse(body) + } + case Assign(lhs, rhs) => + traverse(lhs); traverse(rhs) + case If(cond, thenp, elsep) => + traverse(cond); traverse(thenp); traverse(elsep) + case Match(selector, cases) => + traverse(selector); traverseTrees(cases) + case Return(expr) => + traverse(expr) + case Try(block, catches, finalizer) => + traverse(block); traverseTrees(catches); traverse(finalizer) + case Throw(expr) => + traverse(expr) + case New(tpt) => + traverse(tpt) + case Typed(expr, tpt) => + traverse(expr); traverse(tpt) + case TypeApply(fun, args) => + traverse(fun); traverseTrees(args) + case Apply(fun, args) => + traverse(fun); traverseTrees(args) + case ApplyDynamic(qual, args) => + traverse(qual); traverseTrees(args) + case Super(_, _) => + ; + case This(_) => + ; + case Select(qualifier, selector) => + traverse(qualifier) + case Ident(_) => + ; + case Literal(_) => + ; + case TypeTree() => + ; + case SingletonTypeTree(ref) => + traverse(ref) + case SelectFromTypeTree(qualifier, selector) => + traverse(qualifier) + case CompoundTypeTree(templ) => + traverse(templ) + case AppliedTypeTree(tpt, args) => + traverse(tpt); traverseTrees(args) + case TypeBoundsTree(lo, hi) => + traverse(lo); traverse(hi) + case ExistentialTypeTree(tpt, whereClauses) => + traverse(tpt); traverseTrees(whereClauses) + case SelectFromArray(qualifier, selector, erasure) => + traverse(qualifier) + } + + def traverseTrees(trees: List[Tree]) { + trees foreach traverse + } + def traverseTreess(treess: List[List[Tree]]) { + treess foreach traverseTrees + } + def traverseStats(stats: List[Tree], exprOwner: Symbol) { + stats foreach (stat => + if (exprOwner != currentOwner) atOwner(exprOwner)(traverse(stat)) + else traverse(stat) + ) + } + + def atOwner(owner: Symbol)(traverse: => Unit) { + val prevOwner = currentOwner + currentOwner = owner + traverse + currentOwner = prevOwner + } + } + + /** A synthetic term holding an arbitrary type. Not to be confused with + * with TypTree, the trait for trees that are only used for type trees. + * TypeTree's are inserted in several places, but most notably in + * <code>RefCheck</code>, where the arbitrary type trees are all replaced by + * TypeTree's. */ + abstract class AbsTypeTree extends TypTree { + override def symbol = if (tpe == null) null else tpe.typeSymbol + override def isEmpty = (tpe eq null) || tpe == NoType + } + + /** A tree that has an annotation attached to it. Only used for annotated types and + * annotation ascriptions, annotations on definitions are stored in the Modifiers. + * Eliminated by typechecker (typedAnnotated), the annotations are then stored in + * an AnnotatedType. + */ + case class Annotated(annot: Tree, arg: Tree) extends Tree + + /** Singleton type, eliminated by RefCheck */ + case class SingletonTypeTree(ref: Tree) + extends TypTree + + /** Type selection <qualifier> # <name>, eliminated by RefCheck */ + case class SelectFromTypeTree(qualifier: Tree, name: Name) + extends TypTree with RefTree + + /** Intersection type <parent1> with ... with <parentN> { <decls> }, eliminated by RefCheck */ + case class CompoundTypeTree(templ: Template) + extends TypTree + + /** Applied type <tpt> [ <args> ], eliminated by RefCheck */ + case class AppliedTypeTree(tpt: Tree, args: List[Tree]) + extends TypTree { + override def symbol: Symbol = tpt.symbol + override def symbol_=(sym: Symbol) { tpt.symbol = sym } + } + + case class TypeBoundsTree(lo: Tree, hi: Tree) + extends TypTree + + case class ExistentialTypeTree(tpt: Tree, whereClauses: List[Tree]) + extends TypTree + + /** Array selection <qualifier> . <name> only used during erasure */ + case class SelectFromArray(qualifier: Tree, name: Name, erasure: Type) + extends TermTree with RefTree { } + +/* A standard pattern match + case EmptyTree => + case PackageDef(pid, stats) => + // package pid { stats } + case ClassDef(mods, name, tparams, impl) => + // mods class name [tparams] impl where impl = extends parents { defs } + case ModuleDef(mods, name, impl) => (eliminated by refcheck) + // mods object name impl where impl = extends parents { defs } + case ValDef(mods, name, tpt, rhs) => + // mods val name: tpt = rhs + // note missing type information is expressed by tpt = TypeTree() + case DefDef(mods, name, tparams, vparamss, tpt, rhs) => + // mods def name[tparams](vparams_1)...(vparams_n): tpt = rhs + // note missing type information is expressed by tpt = TypeTree() + case TypeDef(mods, name, tparams, rhs) => (eliminated by erasure) + // mods type name[tparams] = rhs + // mods type name[tparams] >: lo <: hi, where lo, hi are in a TypeBoundsTree, + and DEFERRED is set in mods + case LabelDef(name, params, rhs) => + // used for tailcalls and like + // while/do are desugared to label defs as follows: + // while (cond) body ==> LabelDef($L, List(), if (cond) { body; L$() } else ()) + // do body while (cond) ==> LabelDef($L, List(), body; if (cond) L$() else ()) + case Import(expr, selectors) => (eliminated by typecheck) + // import expr.{selectors} + // Selectors are a list of pairs of names (from, to). + // The last (and maybe only name) may be a nme.WILDCARD + // for instance + // import qual.{x, y => z, _} would be represented as + // Import(qual, List(("x", "x"), ("y", "z"), (WILDCARD, null))) + case Template(parents, self, body) => + // extends parents { self => body } + // if self is missing it is represented as emptyValDef + case Block(stats, expr) => + // { stats; expr } + case CaseDef(pat, guard, body) => (eliminated by transmatch/explicitouter) + // case pat if guard => body + case Alternative(trees) => (eliminated by transmatch/explicitouter) + // pat1 | ... | patn + case Star(elem) => (eliminated by transmatch/explicitouter) + // pat* + case Bind(name, body) => (eliminated by transmatch/explicitouter) + // name @ pat + case UnApply(fun: Tree, args) (introduced by typer, eliminated by transmatch/explicitouter) + // used for unapply's + case ArrayValue(elemtpt, trees) => (introduced by uncurry) + // used to pass arguments to vararg arguments + // for instance, printf("%s%d", foo, 42) is translated to after uncurry to: + // Apply( + // Ident("printf"), + // Literal("%s%d"), + // ArrayValue(<Any>, List(Ident("foo"), Literal(42)))) + case Function(vparams, body) => (eliminated by lambdaLift) + // vparams => body where vparams:List[ValDef] + case Assign(lhs, rhs) => + // lhs = rhs + case If(cond, thenp, elsep) => + // if (cond) thenp else elsep + case Match(selector, cases) => + // selector match { cases } + case Return(expr) => + // return expr + case Try(block, catches, finalizer) => + // try block catch { catches } finally finalizer where catches: List[CaseDef] + case Throw(expr) => + // throw expr + case New(tpt) => + // new tpt always in the context: (new tpt).<init>[targs](args) + case Typed(expr, tpt) => (eliminated by erasure) + // expr: tpt + case TypeApply(fun, args) => + // fun[args] + case Apply(fun, args) => + // fun(args) + // for instance fun[targs](args) is expressed as Apply(TypeApply(fun, targs), args) + case ApplyDynamic(qual, args) (introduced by erasure, eliminated by cleanup) + // fun(args) + case Super(qual, mix) => + // qual.super[mix] if qual and/or mix is empty, ther are nme.EMPTY.toTypeName + case This(qual) => + // qual.this + case Select(qualifier, selector) => + // qualifier.selector + case Ident(name) => + // name + // note: type checker converts idents that refer to enclosing fields or methods + // to selects; name ==> this.name + case Literal(value) => + // value + case TypeTree() => (introduced by refcheck) + // a type that's not written out, but given in the tpe attribute + case Annotated(annot, arg) => (eliminated by typer) + // arg @annot for types, arg: @annot for exprs + case SingletonTypeTree(ref) => (eliminated by uncurry) + // ref.type + case SelectFromTypeTree(qualifier, selector) => (eliminated by uncurry) + // qualifier # selector, a path-dependent type p.T is expressed as p.type # T + case CompoundTypeTree(templ: Template) => (eliminated by uncurry) + // parent1 with ... with parentN { refinement } + case AppliedTypeTree(tpt, args) => (eliminated by uncurry) + // tpt[args] + case TypeBoundsTree(lo, hi) => (eliminated by uncurry) + // >: lo <: hi + case ExistentialTypeTree(tpt, whereClauses) => (eliminated by uncurry) + // tpt forSome { whereClauses } + +*/ +} diff --git a/src/library/scala/reflect/generic/Types.scala b/src/library/scala/reflect/generic/Types.scala new file mode 100755 index 0000000000..17e19715d7 --- /dev/null +++ b/src/library/scala/reflect/generic/Types.scala @@ -0,0 +1,156 @@ +package scala.reflect +package generic + +trait Types { self: Universe => + + abstract class AbsType { + def typeSymbol: Symbol + def decl(name: Name): Symbol + + /** Is this type completed (i.e. not a lazy type)? + */ + def isComplete: Boolean = true + + /** If this is a lazy type, assign a new type to `sym'. */ + def complete(sym: Symbol) {} + + /** Convert toString avoiding infinite recursions by cutting off + * after `maxTostringRecursions` recursion levels. Uses `safeToString` + * to produce a string on each level. + */ + override def toString: String = + if (tostringRecursions >= maxTostringRecursions) + "..." + else + try { + tostringRecursions += 1 + safeToString + } finally { + tostringRecursions -= 1 + } + + /** Method to be implemented in subclasses. + * Converts this type to a string in calling toString for its parts. + */ + def safeToString: String = super.toString + } + + type Type >: Null <: AbsType + + val NoType: Type + val NoPrefix: Type + + type ThisType <: Type + val ThisType: ThisTypeExtractor + + type TypeRef <: Type + val TypeRef: TypeRefExtractor + + type SingleType <: Type + val SingleType: SingleTypeExtractor + + type SuperType <: Type + val SuperType: SuperTypeExtractor + + type TypeBounds <: Type + val TypeBounds: TypeBoundsExtractor + + type CompoundType <: Type + + type RefinedType <: CompoundType + val RefinedType: RefinedTypeExtractor + + type ClassInfoType <: CompoundType + val ClassInfoType: ClassInfoTypeExtractor + + type ConstantType <: Type + val ConstantType: ConstantTypeExtractor + + type MethodType <: Type + val MethodType: MethodTypeExtractor + + type PolyType <: Type + val PolyType: PolyTypeExtractor + + type ExistentialType <: Type + val ExistentialType: ExistentialTypeExtractor + + type AnnotatedType <: Type + val AnnotatedType: AnnotatedTypeExtractor + + type LazyType <: Type with AbsLazyType + + trait AbsLazyType extends AbsType { + override def isComplete: Boolean = false + override def complete(sym: Symbol) + override def safeToString = "<?>" + } + + abstract class ThisTypeExtractor { + def apply(sym: Symbol): Type + def unapply(tpe: ThisType): Option[Symbol] + } + + abstract class SingleTypeExtractor { + def apply(pre: Type, sym: Symbol): Type + def unapply(tpe: SingleType): Option[(Type, Symbol)] + } + + abstract class SuperTypeExtractor { + def apply(thistpe: Type, supertpe: Type): Type + def unapply(tpe: SuperType): Option[(Type, Type)] + } + + abstract class TypeRefExtractor { + def apply(pre: Type, sym: Symbol, args: List[Type]): Type + def unapply(tpe: TypeRef): Option[(Type, Symbol, List[Type])] + } + + abstract class TypeBoundsExtractor { + def apply(lo: Type, hi: Type): TypeBounds + def unapply(tpe: TypeBounds): Option[(Type, Type)] + } + + abstract class RefinedTypeExtractor { + def apply(parents: List[Type], decls: Scope): RefinedType + def apply(parents: List[Type], decls: Scope, clazz: Symbol): RefinedType + def unapply(tpe: RefinedType): Option[(List[Type], Scope)] + } + + abstract class ClassInfoTypeExtractor { + def apply(parents: List[Type], decls: Scope, clazz: Symbol): ClassInfoType + def unapply(tpe: ClassInfoType): Option[(List[Type], Scope, Symbol)] + } + + abstract class ConstantTypeExtractor { + def apply(value: Constant): ConstantType + def unapply(tpe: ConstantType): Option[Constant] + } + + abstract class MethodTypeExtractor { + def apply(params: List[Symbol], resultType: Type): MethodType + def unapply(tpe: MethodType): Option[(List[Symbol], Type)] + } + + abstract class PolyTypeExtractor { + def apply(typeParams: List[Symbol], resultType: Type): PolyType + def unapply(tpe: PolyType): Option[(List[Symbol], Type)] + } + + abstract class ExistentialTypeExtractor { + def apply(quantified: List[Symbol], underlying: Type): ExistentialType + def unapply(tpe: ExistentialType): Option[(List[Symbol], Type)] + } + + abstract class AnnotatedTypeExtractor { + def apply(annotations: List[AnnotationInfo], underlying: Type, selfsym: Symbol): AnnotatedType + def unapply(tpe: AnnotatedType): Option[(List[AnnotationInfo], Type, Symbol)] + } + + /** The maximum number of recursions allowed in toString + */ + final val maxTostringRecursions = 50 + + private var tostringRecursions = 0 +} + diff --git a/src/library/scala/reflect/generic/UnPickler.scala b/src/library/scala/reflect/generic/UnPickler.scala new file mode 100755 index 0000000000..d7eef770cc --- /dev/null +++ b/src/library/scala/reflect/generic/UnPickler.scala @@ -0,0 +1,775 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: UnPickler.scala 20716 2010-01-28 14:14:20Z rytz $ + +package scala.reflect +package generic + +import java.io.IOException +import java.lang.{Float, Double} + +import Flags._ +import PickleFormat._ +import collection.mutable.{HashMap, ListBuffer} +import annotation.switch + +/** @author Martin Odersky + * @version 1.0 + */ +abstract class UnPickler { + + val global: Universe + import global._ + + /** Unpickle symbol table information descending from a class and/or module root + * from an array of bytes. + * @param bytes bytearray from which we unpickle + * @param offset offset from which unpickling starts + * @param classroot the top-level class which is unpickled, or NoSymbol if inapplicable + * @param moduleroot the top-level module which is unpickled, or NoSymbol if inapplicable + * @param filename filename associated with bytearray, only used for error messages + */ + def unpickle(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) { + try { + scan(bytes, offset, classRoot, moduleRoot, filename) + } catch { + case ex: IOException => + throw ex + case ex: Throwable => + /*if (settings.debug.value)*/ ex.printStackTrace() + throw new RuntimeException("error reading Scala signature of "+filename+": "+ex.getMessage()) + } + } + + /** To ne implemented in subclasses. Like `unpickle` but without the catch-all error handling. + */ + def scan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) + + abstract class Scan(bytes: Array[Byte], offset: Int, classRoot: Symbol, moduleRoot: Symbol, filename: String) extends PickleBuffer(bytes, offset, -1) { + //println("unpickle " + classRoot + " and " + moduleRoot)//debug + + protected def debug = false + + checkVersion() + + /** A map from entry numbers to array offsets */ + private val index = createIndex + + /** A map from entry numbers to symbols, types, or annotations */ + private val entries = new Array[AnyRef](index.length) + + /** A map from symbols to their associated `decls' scopes */ + private val symScopes = new HashMap[Symbol, Scope] + + //println("unpickled " + classRoot + ":" + classRoot.rawInfo + ", " + moduleRoot + ":" + moduleRoot.rawInfo);//debug + + def run() { + for (i <- 0 until index.length) { + if (isSymbolEntry(i)) + at(i, readSymbol) + else if (isSymbolAnnotationEntry(i)) + at(i, {() => readSymbolAnnotation(); null}) + else if (isChildrenEntry(i)) + at(i, {() => readChildren(); null}) + } + } + + private def checkVersion() { + val major = readNat() + val minor = readNat() + if (major != MajorVersion || minor > MinorVersion) + throw new IOException("Scala signature " + classRoot.decodedName + + " has wrong version\n expected: " + + MajorVersion + "." + MinorVersion + + "\n found: " + major + "." + minor + + " in "+filename) + } + + /** The `decls' scope associated with given symbol */ + protected def symScope(sym: Symbol) = symScopes.get(sym) match { + case None => val s = newScope; symScopes(sym) = s; s + case Some(s) => s + } + + /** Does entry represent an (internal) symbol */ + protected def isSymbolEntry(i: Int): Boolean = { + val tag = bytes(index(i)).toInt + (firstSymTag <= tag && tag <= lastSymTag && + (tag != CLASSsym || !isRefinementSymbolEntry(i))) + } + + /** Does entry represent an (internal or external) symbol */ + protected def isSymbolRef(i: Int): Boolean = { + val tag = bytes(index(i)) + (firstSymTag <= tag && tag <= lastExtSymTag) + } + + /** Does entry represent a name? */ + protected def isNameEntry(i: Int): Boolean = { + val tag = bytes(index(i)).toInt + tag == TERMname || tag == TYPEname + } + + /** Does entry represent a symbol annotation? */ + protected def isSymbolAnnotationEntry(i: Int): Boolean = { + val tag = bytes(index(i)).toInt + tag == SYMANNOT + } + + /** Does the entry represent children of a symbol? */ + protected def isChildrenEntry(i: Int): Boolean = { + val tag = bytes(index(i)).toInt + tag == CHILDREN + } + + /** Does entry represent a refinement symbol? + * pre: Entry is a class symbol + */ + protected def isRefinementSymbolEntry(i: Int): Boolean = { + val savedIndex = readIndex + readIndex = index(i) + val tag = readByte().toInt + assert(tag == CLASSsym) + + readNat(); // read length + val result = readNameRef() == mkTypeName(nme.REFINE_CLASS_NAME) + readIndex = savedIndex + result + } + + /** If entry at <code>i</code> is undefined, define it by performing + * operation <code>op</code> with <code>readIndex at start of i'th + * entry. Restore <code>readIndex</code> afterwards. + */ + protected def at[T <: AnyRef](i: Int, op: () => T): T = { + var r = entries(i) + if (r eq null) { + val savedIndex = readIndex + readIndex = index(i) + r = op() + assert(entries(i) eq null, entries(i)) + entries(i) = r + readIndex = savedIndex + } + r.asInstanceOf[T] + } + + /** Read a name */ + protected def readName(): Name = { + val tag = readByte() + val len = readNat() + tag match { + case TERMname => newTermName(bytes, readIndex, len) + case TYPEname => newTypeName(bytes, readIndex, len) + case _ => errorBadSignature("bad name tag: " + tag) + } + } + + /** Read a symbol */ + protected def readSymbol(): Symbol = { + val tag = readByte() + val end = readNat() + readIndex + var sym: Symbol = NoSymbol + tag match { + case EXTref | EXTMODCLASSref => + val name = readNameRef() + val owner = if (readIndex == end) definitions.RootClass else readSymbolRef() + def fromName(name: Name) = + if (mkTermName(name) == nme.ROOT) definitions.RootClass + else if (name == nme.ROOTPKG) definitions.RootPackage + else if (tag == EXTref) owner.info.decl(name) + else owner.info.decl(name).moduleClass + sym = fromName(name) + // If sym not found try with expanded name. + // This can happen if references to private symbols are + // read from outside; for instance when checking the children of a class + // (see t1722) + if (sym == NoSymbol) sym = fromName(nme.expandedName(name, owner)) + + // If the owner is overloaded (i.e. a method), it's not possible to select the + // right member => return NoSymbol. This can only happen when unpickling a tree. + // the "case Apply" in readTree() takes care of selecting the correct alternative + // after parsing the arguments. + if (sym == NoSymbol && !owner.isOverloaded) errorMissingRequirement(name, owner) + + case NONEsym => + sym = NoSymbol + + case _ => // symbols that were pickled with Pickler.writeSymInfo + var defaultGetter: Symbol = NoSymbol // @deprecated, to be removed for 2.8 final + var nameref = readNat() + if (tag == VALsym && isSymbolRef(nameref)) { // @deprecated, to be removed for 2.8 final + defaultGetter = at(nameref, readSymbol) + nameref = readNat() + } + val name = at(nameref, readName) + val owner = readSymbolRef() + val flags = pickledToRawFlags(readLongNat()) + var privateWithin: Symbol = NoSymbol + var inforef = readNat() + if (isSymbolRef(inforef)) { + privateWithin = at(inforef, readSymbol) + inforef = readNat() + } + tag match { + case TYPEsym => + sym = owner.newAbstractType(name) + case ALIASsym => + sym = owner.newAliasType(name) + case CLASSsym => + sym = + if (name == classRoot.name && owner == classRoot.owner) + (if ((flags & MODULE) != 0L) moduleRoot.moduleClass + else classRoot) + else + if ((flags & MODULE) != 0L) owner.newModuleClass(name) + else owner.newClass(name) + if (readIndex != end) sym.typeOfThis = newLazyTypeRef(readNat()) + case MODULEsym => + val clazz = at(inforef, readType).typeSymbol + sym = + if (name == moduleRoot.name && owner == moduleRoot.owner) moduleRoot + else { + val m = owner.newModule(name, clazz) + clazz.sourceModule = m + m + } + case VALsym => + sym = if (name == moduleRoot.name && owner == moduleRoot.owner) { assert(false); NoSymbol } + else if ((flags & METHOD) != 0) owner.newMethod(name) + else owner.newValue(name) + case _ => + noSuchSymbolTag(tag, end, name, owner) + } + sym.flags = flags & PickledFlags + sym.privateWithin = privateWithin + if (readIndex != end) assert(sym hasFlag (SUPERACCESSOR | PARAMACCESSOR), sym) + if (sym hasFlag SUPERACCESSOR) assert(readIndex != end) + sym.info = + if (readIndex != end) newLazyTypeRefAndAlias(inforef, readNat()) + else newLazyTypeRef(inforef) + if (sym.owner.isClass && sym != classRoot && sym != moduleRoot && + !sym.isModuleClass && !sym.isRefinementClass && !sym.isTypeParameter && !sym.isExistentiallyBound) + symScope(sym.owner) enter sym + } + sym + } + + def noSuchSymbolTag(tag: Int, end: Int, name: Name, owner: Symbol) = + errorBadSignature("bad symbol tag: " + tag) + + /** Read a type */ + protected def readType(): Type = { + val tag = readByte() + val end = readNat() + readIndex + (tag: @switch) match { + case NOtpe => + NoType + case NOPREFIXtpe => + NoPrefix + case THIStpe => + ThisType(readSymbolRef()) + case SINGLEtpe => + SingleType(readTypeRef(), readSymbolRef()) // !!! was singleType + case SUPERtpe => + val thistpe = readTypeRef() + val supertpe = readTypeRef() + SuperType(thistpe, supertpe) + case CONSTANTtpe => + ConstantType(readConstantRef()) + case TYPEREFtpe => + val pre = readTypeRef() + val sym = readSymbolRef() + var args = until(end, readTypeRef) + TypeRef(pre, sym, args) + case TYPEBOUNDStpe => + TypeBounds(readTypeRef(), readTypeRef()) + case REFINEDtpe => + val clazz = readSymbolRef() + RefinedType(until(end, readTypeRef), symScope(clazz), clazz) + case CLASSINFOtpe => + val clazz = readSymbolRef() + ClassInfoType(until(end, readTypeRef), symScope(clazz), clazz) + case METHODtpe | IMPLICITMETHODtpe => + val restpe = readTypeRef() + val params = until(end, readSymbolRef) + // if the method is overloaded, the params cannot be determined (see readSymbol) => return NoType. + // Only happen for trees, "case Apply" in readTree() takes care of selecting the correct + // alternative after parsing the arguments. + if (params.contains(NoSymbol) || restpe == NoType) NoType + else MethodType(params, restpe) + case POLYtpe => + val restpe = readTypeRef() + val typeParams = until(end, readSymbolRef) + PolyType(typeParams, restpe) + case EXISTENTIALtpe => + val restpe = readTypeRef() + ExistentialType(until(end, readSymbolRef), restpe) + case ANNOTATEDtpe => + var typeRef = readNat() + val selfsym = if (isSymbolRef(typeRef)) { + val s = at(typeRef, readSymbol) + typeRef = readNat() + s + } else NoSymbol // selfsym can go. + val tp = at(typeRef, readType) + val annots = until(end, readAnnotationRef) + if (selfsym == NoSymbol) AnnotatedType(annots, tp, selfsym) + else tp + case _ => + noSuchTypeTag(tag, end) + } + } + + def noSuchTypeTag(tag: Int, end: Int): Type = + errorBadSignature("bad type tag: " + tag) + + /** Read a constant */ + protected def readConstant(): Constant = { + val tag = readByte().toInt + val len = readNat() + (tag: @switch) match { + case LITERALunit => Constant(()) + case LITERALboolean => Constant(readLong(len) != 0L) + case LITERALbyte => Constant(readLong(len).toByte) + case LITERALshort => Constant(readLong(len).toShort) + case LITERALchar => Constant(readLong(len).toChar) + case LITERALint => Constant(readLong(len).toInt) + case LITERALlong => Constant(readLong(len)) + case LITERALfloat => Constant(Float.intBitsToFloat(readLong(len).toInt)) + case LITERALdouble => Constant(Double.longBitsToDouble(readLong(len))) + case LITERALstring => Constant(readNameRef().toString()) + case LITERALnull => Constant(null) + case LITERALclass => Constant(readTypeRef()) + case LITERALenum => Constant(readSymbolRef()) + case _ => noSuchConstantTag(tag, len) + } + } + + def noSuchConstantTag(tag: Int, len: Int): Constant = + errorBadSignature("bad constant tag: " + tag) + + /** Read children and store them into the corresponding symbol. + */ + protected def readChildren() { + val tag = readByte() + assert(tag == CHILDREN) + val end = readNat() + readIndex + val target = readSymbolRef() + while (readIndex != end) target addChild readSymbolRef() + } + + /** Read an annotation argument, which is pickled either + * as a Constant or a Tree. + */ + protected def readAnnotArg(i: Int): Tree = { + if (bytes(index(i)) == TREE) { + at(i, readTree) + } else { + val const = at(i, readConstant) + global.Literal(const).setType(const.tpe) + } + } + + /** Read a ClassfileAnnotArg (argument to a classfile annotation) + */ + protected def readClassfileAnnotArg(i: Int): ClassfileAnnotArg = bytes(index(i)) match { + case ANNOTINFO => + NestedAnnotArg(at(i, readAnnotation)) + case ANNOTARGARRAY => + at(i, () => { + readByte() // skip the `annotargarray` tag + val end = readNat() + readIndex + ArrayAnnotArg(until(end, () => readClassfileAnnotArg(readNat())).toArray(classfileAnnotArgManifest)) + }) + case _ => + LiteralAnnotArg(at(i, readConstant)) + } + + /** Read an AnnotationInfo. Not to be called directly, use + * readAnnotation or readSymbolAnnotation + */ + protected def readAnnotationInfo(end: Int): AnnotationInfo = { + val atp = readTypeRef() + val args = new ListBuffer[Tree] + val assocs = new ListBuffer[(Name, ClassfileAnnotArg)] + while (readIndex != end) { + val argref = readNat() + if (isNameEntry(argref)) { + val name = at(argref, readName) + val arg = readClassfileAnnotArg(readNat()) + assocs += ((name, arg)) + } + else + args += readAnnotArg(argref) + } + AnnotationInfo(atp, args.toList, assocs.toList) + } + + /** Read an annotation and as a side effect store it into + * the symbol it requests. Called at top-level, for all + * (symbol, annotInfo) entries. */ + protected def readSymbolAnnotation() { + val tag = readByte() + if (tag != SYMANNOT) + errorBadSignature("symbol annotation expected ("+ tag +")") + val end = readNat() + readIndex + val target = readSymbolRef() + target.addAnnotation(readAnnotationInfo(end)) + } + + /** Read an annotation and return it. Used when unpickling + * an ANNOTATED(WSELF)tpe or a NestedAnnotArg */ + protected def readAnnotation(): AnnotationInfo = { + val tag = readByte() + if (tag != ANNOTINFO) + errorBadSignature("annotation expected (" + tag + ")") + val end = readNat() + readIndex + readAnnotationInfo(end) + } + + /* Read an abstract syntax tree */ + protected def readTree(): Tree = { + val outerTag = readByte() + if (outerTag != TREE) + errorBadSignature("tree expected (" + outerTag + ")") + val end = readNat() + readIndex + val tag = readByte() + val tpe = if (tag == EMPTYtree) NoType else readTypeRef() + + // Set by the three functions to follow. If symbol is non-null + // after the the new tree 't' has been created, t has its Symbol + // set to symbol; and it always has its Type set to tpe. + var symbol: Symbol = null + var mods: Modifiers = null + var name: Name = null + + /** Read a Symbol, Modifiers, and a Name */ + def setSymModsName() { + symbol = readSymbolRef() + mods = readModifiersRef() + name = readNameRef() + } + /** Read a Symbol and a Name */ + def setSymName() { + symbol = readSymbolRef() + name = readNameRef() + } + /** Read a Symbol */ + def setSym() { + symbol = readSymbolRef() + } + + val t = tag match { + case EMPTYtree => + EmptyTree + + case PACKAGEtree => + setSym() + // val discardedSymbol = readSymbolRef() // XXX is symbol intentionally not set? + val pid = readTreeRef().asInstanceOf[RefTree] + val stats = until(end, readTreeRef) + PackageDef(pid, stats) + + case CLASStree => + setSymModsName() + val impl = readTemplateRef() + val tparams = until(end, readTypeDefRef) + ClassDef(mods, name, tparams, impl) + + case MODULEtree => + setSymModsName() + ModuleDef(mods, name, readTemplateRef()) + + case VALDEFtree => + setSymModsName() + val tpt = readTreeRef() + val rhs = readTreeRef() + ValDef(mods, name, tpt, rhs) + + case DEFDEFtree => + setSymModsName() + val tparams = times(readNat(), readTypeDefRef) + val vparamss = times(readNat(), () => times(readNat(), readValDefRef)) + val tpt = readTreeRef() + val rhs = readTreeRef() + + DefDef(mods, name, tparams, vparamss, tpt, rhs) + + case TYPEDEFtree => + setSymModsName() + val rhs = readTreeRef() + val tparams = until(end, readTypeDefRef) + TypeDef(mods, name, tparams, rhs) + + case LABELtree => + setSymName() + val rhs = readTreeRef() + val params = until(end, readIdentRef) + LabelDef(name, params, rhs) + + case IMPORTtree => + setSym() + val expr = readTreeRef() + val selectors = until(end, () => { + val from = readNameRef() + val to = readNameRef() + ImportSelector(from, -1, to, -1) + }) + + Import(expr, selectors) + + case TEMPLATEtree => + setSym() + val parents = times(readNat(), readTreeRef) + val self = readValDefRef() + val body = until(end, readTreeRef) + + Template(parents, self, body) + + case BLOCKtree => + val expr = readTreeRef() + val stats = until(end, readTreeRef) + Block(stats, expr) + + case CASEtree => + val pat = readTreeRef() + val guard = readTreeRef() + val body = readTreeRef() + CaseDef(pat, guard, body) + + case ALTERNATIVEtree => + Alternative(until(end, readTreeRef)) + + case STARtree => + Star(readTreeRef()) + + case BINDtree => + setSymName() + Bind(name, readTreeRef()) + + case UNAPPLYtree => + val fun = readTreeRef() + val args = until(end, readTreeRef) + UnApply(fun, args) + + case ARRAYVALUEtree => + val elemtpt = readTreeRef() + val trees = until(end, readTreeRef) + ArrayValue(elemtpt, trees) + + case FUNCTIONtree => + setSym() + val body = readTreeRef() + val vparams = until(end, readValDefRef) + Function(vparams, body) + + case ASSIGNtree => + val lhs = readTreeRef() + val rhs = readTreeRef() + Assign(lhs, rhs) + + case IFtree => + val cond = readTreeRef() + val thenp = readTreeRef() + val elsep = readTreeRef() + If(cond, thenp, elsep) + + case MATCHtree => + val selector = readTreeRef() + val cases = until(end, readCaseDefRef) + Match(selector, cases) + + case RETURNtree => + setSym() + Return(readTreeRef()) + + case TREtree => + val block = readTreeRef() + val finalizer = readTreeRef() + val catches = until(end, readCaseDefRef) + Try(block, catches, finalizer) + + case THROWtree => + Throw(readTreeRef()) + + case NEWtree => + New(readTreeRef()) + + case TYPEDtree => + val expr = readTreeRef() + val tpt = readTreeRef() + Typed(expr, tpt) + + case TYPEAPPLYtree => + val fun = readTreeRef() + val args = until(end, readTreeRef) + TypeApply(fun, args) + + case APPLYtree => + val fun = readTreeRef() + val args = until(end, readTreeRef) + if (fun.symbol.isOverloaded) { + fun.setType(fun.symbol.info) + inferMethodAlternative(fun, args map (_.tpe), tpe) + } + Apply(fun, args) + + case APPLYDYNAMICtree => + setSym() + val qual = readTreeRef() + val args = until(end, readTreeRef) + ApplyDynamic(qual, args) + + case SUPERtree => + setSym() + val qual = readNameRef() + val mix = readNameRef() + Super(qual, mix) + + case THIStree => + setSym() + This(readNameRef()) + + case SELECTtree => + setSym() + val qualifier = readTreeRef() + val selector = readNameRef() + Select(qualifier, selector) + + case IDENTtree => + setSymName() + Ident(name) + + case LITERALtree => + global.Literal(readConstantRef()) + + case TYPEtree => + TypeTree() + + case ANNOTATEDtree => + val annot = readTreeRef() + val arg = readTreeRef() + Annotated(annot, arg) + + case SINGLETONTYPEtree => + SingletonTypeTree(readTreeRef()) + + case SELECTFROMTYPEtree => + val qualifier = readTreeRef() + val selector = readNameRef() + SelectFromTypeTree(qualifier, selector) + + case COMPOUNDTYPEtree => + CompoundTypeTree(readTemplateRef()) + + case APPLIEDTYPEtree => + val tpt = readTreeRef() + val args = until(end, readTreeRef) + AppliedTypeTree(tpt, args) + + case TYPEBOUNDStree => + val lo = readTreeRef() + val hi = readTreeRef() + TypeBoundsTree(lo, hi) + + case EXISTENTIALTYPEtree => + val tpt = readTreeRef() + val whereClauses = until(end, readTreeRef) + ExistentialTypeTree(tpt, whereClauses) + + case _ => + noSuchTreeTag(tag, end) + } + + if (symbol == null) t setType tpe + else t setSymbol symbol setType tpe + } + + def noSuchTreeTag(tag: Int, end: Int) = + errorBadSignature("unknown tree type (" + tag + ")") + + def readModifiers(): Modifiers = { + val tag = readNat() + if (tag != MODIFIERS) + errorBadSignature("expected a modifiers tag (" + tag + ")") + val end = readNat() + readIndex + val pflagsHi = readNat() + val pflagsLo = readNat() + val pflags = (pflagsHi.toLong << 32) + pflagsLo + val flags = pickledToRawFlags(pflags) + val privateWithin = readNameRef() + Modifiers(flags, privateWithin, Nil, Map.empty) + } + + /* Read a reference to a pickled item */ + protected def readNameRef(): Name = at(readNat(), readName) + protected def readSymbolRef(): Symbol = at(readNat(), readSymbol) + protected def readTypeRef(): Type = at(readNat(), readType) + protected def readConstantRef(): Constant = at(readNat(), readConstant) + protected def readAnnotationRef(): AnnotationInfo = + at(readNat(), readAnnotation) + protected def readModifiersRef(): Modifiers = + at(readNat(), readModifiers) + protected def readTreeRef(): Tree = + at(readNat(), readTree) + + protected def readTemplateRef(): Template = + readTreeRef() match { + case templ:Template => templ + case other => + errorBadSignature("expected a template (" + other + ")") + } + protected def readCaseDefRef(): CaseDef = + readTreeRef() match { + case tree:CaseDef => tree + case other => + errorBadSignature("expected a case def (" + other + ")") + } + protected def readValDefRef(): ValDef = + readTreeRef() match { + case tree:ValDef => tree + case other => + errorBadSignature("expected a ValDef (" + other + ")") + } + protected def readIdentRef(): Ident = + readTreeRef() match { + case tree:Ident => tree + case other => + errorBadSignature("expected an Ident (" + other + ")") + } + protected def readTypeDefRef(): TypeDef = + readTreeRef() match { + case tree:TypeDef => tree + case other => + errorBadSignature("expected an TypeDef (" + other + ")") + } + + protected def errorBadSignature(msg: String) = + throw new RuntimeException("malformed Scala signature of " + classRoot.name + " at " + readIndex + "; " + msg) + + protected def errorMissingRequirement(msg: String): Nothing = + if (debug) errorBadSignature(msg) + else throw new IOException("class file needed by "+classRoot.name+" is missing.\n"+msg) + + protected def errorMissingRequirement(name: Name, owner: Symbol): Nothing = + errorMissingRequirement("reference " + NameTransformer.decode(name.toString) + " of " + owner.tpe + " refers to nonexisting symbol.") + + /** pre: `fun` points to a symbol with an overloaded type. + * Selects the overloaded alternative of `fun` which best matches given + * argument types `argtpes` and result type `restpe`. Stores this alternative as + * the symbol of `fun`. + */ + def inferMethodAlternative(fun: Tree, argtpes: List[Type], restpe: Type) + + /** Create a lazy type which when completed returns type at index `i`. */ + def newLazyTypeRef(i: Int): LazyType + + /** Create a lazy type which when completed returns type at index `i` and sets alias + * of completed symbol to symbol at index `j` + */ + def newLazyTypeRefAndAlias(i: Int, j: Int): LazyType + } +} diff --git a/src/library/scala/reflect/generic/Universe.scala b/src/library/scala/reflect/generic/Universe.scala new file mode 100755 index 0000000000..101295ae79 --- /dev/null +++ b/src/library/scala/reflect/generic/Universe.scala @@ -0,0 +1,16 @@ +package scala.reflect +package generic + +abstract class Universe extends Symbols + with Types + with Constants + with Scopes + with Names + with StdNames + with Trees + with AnnotationInfos + with StandardDefinitions { + type Position + val NoPosition: Position +} + diff --git a/src/library/scala/runtime/BoxesRunTime.java b/src/library/scala/runtime/BoxesRunTime.java index 087331e1c5..7c27835b5a 100644 --- a/src/library/scala/runtime/BoxesRunTime.java +++ b/src/library/scala/runtime/BoxesRunTime.java @@ -28,7 +28,7 @@ import scala.math.ScalaNumber; * @author Martin Odersky * @contributor Stepan Koltsov * @version 2.0 */ -public class BoxesRunTime +public final class BoxesRunTime { private static final int CHAR = 0, BYTE = 1, SHORT = 2, INT = 3, LONG = 4, FLOAT = 5, DOUBLE = 6, OTHER = 7; @@ -136,38 +136,51 @@ public class BoxesRunTime * in any case, we dispatch to it as soon as we spot one on either side. */ public static boolean equals2(Object x, Object y) { - if (x instanceof Number) { - Number xn = (Number)x; - - if (y instanceof Number) { - Number yn = (Number)y; - int xcode = eqTypeCode(xn); - int ycode = eqTypeCode(yn); - switch (ycode > xcode ? ycode : xcode) { - case INT: - return xn.intValue() == yn.intValue(); - case LONG: - return xn.longValue() == yn.longValue(); - case FLOAT: - return xn.floatValue() == yn.floatValue(); - case DOUBLE: - return xn.doubleValue() == yn.doubleValue(); - default: - if ((yn instanceof ScalaNumber) && !(xn instanceof ScalaNumber)) - return y.equals(x); - } - } else if (y instanceof Character) - return equalsNumChar(xn, (Character)y); - } else if (x instanceof Character) { - Character xc = (Character)x; - if (y instanceof Character) - return xc.charValue() == ((Character)y).charValue(); - if (y instanceof Number) - return equalsNumChar((Number)y, xc); - } + if (x instanceof Number) + return equalsNumObject((Number)x, y); + if (x instanceof Character) + return equalsCharObject((Character)x, y); + return x.equals(y); } + public static boolean equalsNumObject(Number xn, Object y) { + if (y instanceof Number) + return equalsNumNum(xn, (Number)y); + else if (y instanceof Character) + return equalsNumChar(xn, (Character)y); + + return xn.equals(y); + } + + public static boolean equalsNumNum(Number xn, Number yn) { + int xcode = eqTypeCode(xn); + int ycode = eqTypeCode(yn); + switch (ycode > xcode ? ycode : xcode) { + case INT: + return xn.intValue() == yn.intValue(); + case LONG: + return xn.longValue() == yn.longValue(); + case FLOAT: + return xn.floatValue() == yn.floatValue(); + case DOUBLE: + return xn.doubleValue() == yn.doubleValue(); + default: + if ((yn instanceof ScalaNumber) && !(xn instanceof ScalaNumber)) + return yn.equals(xn); + } + return xn.equals(yn); + } + + public static boolean equalsCharObject(Character xc, Object y) { + if (y instanceof Character) + return xc.charValue() == ((Character)y).charValue(); + if (y instanceof Number) + return equalsNumChar((Number)y, xc); + + return xc.equals(y); + } + private static boolean equalsNumChar(Number xn, Character yc) { char ch = yc.charValue(); switch (eqTypeCode(xn)) { @@ -212,27 +225,27 @@ public class BoxesRunTime * verisons are equal. This still needs reconciliation. */ public static int hashFromLong(Long n) { - int iv = n.intValue(); - if (iv == n.longValue()) return iv; - else return n.hashCode(); + int iv = n.intValue(); + if (iv == n.longValue()) return iv; + else return n.hashCode(); } public static int hashFromDouble(Double n) { - int iv = n.intValue(); - double dv = n.doubleValue(); - if (iv == dv) return iv; + int iv = n.intValue(); + double dv = n.doubleValue(); + if (iv == dv) return iv; - long lv = n.longValue(); - if (lv == dv) return Long.valueOf(lv).hashCode(); - else return n.hashCode(); + long lv = n.longValue(); + if (lv == dv) return Long.valueOf(lv).hashCode(); + else return n.hashCode(); } public static int hashFromFloat(Float n) { - int iv = n.intValue(); - float fv = n.floatValue(); - if (iv == fv) return iv; + int iv = n.intValue(); + float fv = n.floatValue(); + if (iv == fv) return iv; - long lv = n.longValue(); - if (lv == fv) return Long.valueOf(lv).hashCode(); - else return n.hashCode(); + long lv = n.longValue(); + if (lv == fv) return Long.valueOf(lv).hashCode(); + else return n.hashCode(); } public static int hashFromNumber(Number n) { if (n instanceof Long) return hashFromLong((Long)n); diff --git a/src/library/scala/runtime/NonLocalReturnControl.scala b/src/library/scala/runtime/NonLocalReturnControl.scala new file mode 100644 index 0000000000..5591d4871b --- /dev/null +++ b/src/library/scala/runtime/NonLocalReturnControl.scala @@ -0,0 +1,16 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2002-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +// $Id$ + + +package scala.runtime + +import scala.util.control.ControlThrowable + +class NonLocalReturnControl[T](val key: AnyRef, val value: T) extends ControlThrowable diff --git a/src/library/scala/runtime/NonLocalReturnException.scala b/src/library/scala/runtime/NonLocalReturnException.scala index 4bd8ceb058..19a216be7c 100644 --- a/src/library/scala/runtime/NonLocalReturnException.scala +++ b/src/library/scala/runtime/NonLocalReturnException.scala @@ -11,6 +11,9 @@ package scala.runtime -import scala.util.control.ControlException +import scala.util.control.ControlThrowable -class NonLocalReturnException[T](val key: AnyRef, val value: T) extends RuntimeException with ControlException +/** !!! This class has been replaced by NonLocalReturnControl and should be deleted. + * But, it can't be deleted until starr is updated to use the new name. + */ +class NonLocalReturnException[T](val key: AnyRef, val value: T) extends ControlThrowable diff --git a/src/library/scala/runtime/RichChar.scala b/src/library/scala/runtime/RichChar.scala index 63fbe20f3c..f5e2625fd8 100644 --- a/src/library/scala/runtime/RichChar.scala +++ b/src/library/scala/runtime/RichChar.scala @@ -12,7 +12,7 @@ package scala.runtime import java.lang.Character -import collection.{IndexedSeq, IndexedSeqView} +import collection.immutable.NumericRange /** <p> * For example, in the following code @@ -82,22 +82,14 @@ final class RichChar(x: Char) extends Proxy with Ordered[Char] { @deprecated("Use ch.isUpper instead") def isUpperCase: Boolean = isUpper - /** Create a <code>[Char]</code> over the characters from 'x' to 'y' - 1 + /** Create a <code>[Char]</code> over the characters from 'x' to 'limit' - 1 */ - def until(limit: Char): IndexedSeqView[Char, IndexedSeq[Char]] = - if (limit <= x) IndexedSeq.empty.view - else - new IndexedSeqView[Char, IndexedSeq[Char]] { - protected def underlying = IndexedSeq.empty[Char] - def length = limit - x - def apply(i: Int): Char = { - require(i >= 0 && i < length) - (x + i).toChar - } - } - - /** Create a <code>IndexedSeqView[Char]</code> over the characters from 'x' to 'y' + def until(limit: Char): NumericRange[Char] = + new NumericRange.Exclusive(x, limit, 1.toChar) + + /** Create a <code>IndexedSeqView[Char]</code> over the characters from 'x' to 'limit' */ - def to(y: Char): IndexedSeqView[Char, IndexedSeq[Char]] = until((y + 1).toChar) + def to(limit: Char): NumericRange[Char] = + new NumericRange.Inclusive(x, limit, 1.toChar) } diff --git a/src/library/scala/runtime/ScalaRunTime.scala b/src/library/scala/runtime/ScalaRunTime.scala index 2f6ffb5535..dffebfc892 100644 --- a/src/library/scala/runtime/ScalaRunTime.scala +++ b/src/library/scala/runtime/ScalaRunTime.scala @@ -12,10 +12,11 @@ package scala.runtime import scala.reflect.ClassManifest -import scala.collection.Seq -import scala.collection.mutable._ +import scala.collection.{ Seq, IndexedSeq, TraversableView } +import scala.collection.mutable.WrappedArray import scala.collection.immutable.{ List, Stream, Nil, :: } -import scala.util.control.ControlException +import scala.xml.{ Node, MetaData } +import scala.util.control.ControlThrowable /* The object <code>ScalaRunTime</code> provides ... */ @@ -89,7 +90,7 @@ object ScalaRunTime { } /** Convert a numeric value array to an object array. - * Needed to deal with vararg arguments of primtive types that are passed + * Needed to deal with vararg arguments of primitive types that are passed * to a generic Java vararg parameter T ... */ def toObjectArray(src: AnyRef): Array[Object] = { @@ -123,7 +124,7 @@ object ScalaRunTime { private var exception: Throwable = try { run() ; null } catch { - case e: ControlException => throw e // don't catch non-local returns etc + case e: ControlThrowable => throw e // don't catch non-local returns etc case e: Throwable => e } @@ -165,7 +166,8 @@ object ScalaRunTime { @inline def inlinedEquals(x: Object, y: Object): Boolean = if (x eq y) true else if (x eq null) false - else if (x.isInstanceOf[java.lang.Number] || x.isInstanceOf[java.lang.Character]) BoxesRunTime.equals2(x, y) + else if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.equalsNumObject(x.asInstanceOf[java.lang.Number], y) + else if (x.isInstanceOf[java.lang.Character]) BoxesRunTime.equalsCharObject(x.asInstanceOf[java.lang.Character], y) else x.equals(y) def _equals(x: Product, y: Any): Boolean = y match { @@ -173,6 +175,50 @@ object ScalaRunTime { case _ => false } + // hashcode ----------------------------------------------------------- + + @inline def hash(x: Any): Int = + if (x.isInstanceOf[java.lang.Number]) BoxesRunTime.hashFromNumber(x.asInstanceOf[java.lang.Number]) + else x.hashCode + + @inline def hash(dv: Double): Int = { + val iv = dv.toInt + if (iv == dv) return iv + + val lv = dv.toLong + if (lv == dv) return lv.hashCode + else dv.hashCode + } + @inline def hash(fv: Float): Int = { + val iv = fv.toInt + if (iv == fv) return iv + + val lv = fv.toLong + if (lv == fv) return lv.hashCode + else fv.hashCode + } + @inline def hash(lv: Long): Int = { + val iv = lv.toInt + if (iv == lv) iv else lv.hashCode + } + @inline def hash(x: Int): Int = x + @inline def hash(x: Short): Int = x.toInt + @inline def hash(x: Byte): Int = x.toInt + @inline def hash(x: Char): Int = x.toInt + + @inline def hash(x: Number): Int = runtime.BoxesRunTime.hashFromNumber(x) + @inline def hash(x: java.lang.Long): Int = { + val iv = x.intValue + if (iv == x.longValue) iv else x.hashCode + } + + /** A helper method for constructing case class equality methods, + * because existential types get in the way of a clean outcome and + * it's performing a series of Any/Any equals comparisons anyway. + * See ticket #2867 for specifics. + */ + def sameElements(xs1: Seq[Any], xs2: Seq[Any]) = xs1 sameElements xs2 + /** Given any Scala value, convert it to a String. * * The primary motivation for this method is to provide a means for @@ -186,12 +232,26 @@ object ScalaRunTime { * @return a string representation of <code>arg</code> * */ - def stringOf(arg : Any): String = arg match { - case null => "null" - case arg: AnyRef if isArray(arg) => - val d: collection.IndexedSeq[Any] = WrappedArray.make(arg).deep - d.toString - case arg: WrappedArray[_] => arg.deep.toString - case arg => arg.toString + def stringOf(arg: Any): String = { + def inner(arg: Any): String = arg match { + case null => "null" + // Node extends NodeSeq extends Seq[Node] strikes again + case x: Node => x toString + // Not to mention MetaData extends Iterable[MetaData] + case x: MetaData => x toString + case x: AnyRef if isArray(x) => WrappedArray make x map inner mkString ("Array(", ", ", ")") + case x: TraversableView[_, _] => x.toString + case x: Traversable[_] if !x.hasDefiniteSize => x.toString + case x: Traversable[_] => + // Some subclasses of AbstractFile implement Iterable, then throw an + // exception if you call iterator. What a world. + // And they can't be infinite either. + if (x.getClass.getName startsWith "scala.tools.nsc.io") x.toString + else (x map inner) mkString (x.stringPrefix + "(", ", ", ")") + case x => x toString + } + val s = inner(arg) + val nl = if (s contains "\n") "\n" else "" + nl + s + "\n" } } diff --git a/src/library/scala/testing/SUnit.scala b/src/library/scala/testing/SUnit.scala index cf43bd1b06..d5d845cb98 100644 --- a/src/library/scala/testing/SUnit.scala +++ b/src/library/scala/testing/SUnit.scala @@ -12,6 +12,7 @@ package scala.testing import scala.collection.mutable.ArrayBuffer +import xml.{ Node, NodeSeq } /** * <p> @@ -237,6 +238,25 @@ object SUnit { assertTrue("(no message)", actual) } + /** Temporary patchwork trying to nurse xml forward. */ + def assertEqualsXML(msg: String, expected: NodeSeq, actual: NodeSeq) { + if (!expected.xml_==(actual)) + fail(msg, expected, actual) + } + def assertEqualsXML(msg: String, expected: Seq[Node], actual: Seq[Node]) { + assertEqualsXML(msg, expected: NodeSeq, actual: NodeSeq) + } + + def assertEqualsXML(expected: NodeSeq, actual: NodeSeq) { + assertEqualsXML("(no message)", expected, actual) + } + + def assertSameElementsXML(actual: Seq[Node], expected: Seq[Node]) { + val res = (actual: NodeSeq) xml_sameElements expected + + assert(res, "\nassertSameElementsXML:\n actual = %s\n expected = %s".format(actual, expected)) + } + /** throws <code>AssertFailed</code> with given message <code>msg</code>. */ def fail(msg: String) { diff --git a/src/library/scala/throws.scala b/src/library/scala/throws.scala index 500db0a30a..b932ccc7ac 100644 --- a/src/library/scala/throws.scala +++ b/src/library/scala/throws.scala @@ -14,13 +14,13 @@ package scala /** <p> * Annotation for specifying the exceptions thrown by a method. * For example: - * </p><pre> - * <b>class</b> Reader(fname: String) { - * <b>private val</b> in = - * <b>new</b> BufferedReader(<b>new</b> <a class="java/io/FileReader" href="" target="_top">FileReader</a>(fname)) - * @throws(classOf[<a class="java/io/IOException" href="" target="_top">IOException</a>]) - * <b>def</b> read() = in.read() - * }</pre> + * {{{ + * class Reader(fname: String) { + * private val in = new BufferedReader(new FileReader(fname)) + * @throws(classOf[IOException]) + * def read() = in.read() + * } + * }}} * * @author Nikolay Mihaylov * @version 1.0, 19/05/2006 diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 73b5cf855a..b781e46be5 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -8,12 +8,18 @@ // $Id$ - package scala.util +import java.io.{ IOException, PrintWriter } + +/** Loads library.properties from the jar. */ +object Properties extends PropertiesTrait { + protected def propCategory = "library" + protected def pickJarBasedOn = classOf[ScalaObject] +} + private[scala] trait PropertiesTrait { - import java.io.{ IOException, PrintWriter } protected def propCategory: String // specializes the remainder of the values protected def pickJarBasedOn: Class[_] // props file comes from jar containing this @@ -21,7 +27,7 @@ private[scala] trait PropertiesTrait protected val propFilename = "/" + propCategory + ".properties" /** The loaded properties */ - protected lazy val props: java.util.Properties = { + protected lazy val scalaProps: java.util.Properties = { val props = new java.util.Properties val stream = pickJarBasedOn getResourceAsStream propFilename if (stream ne null) @@ -30,7 +36,6 @@ private[scala] trait PropertiesTrait props } - protected def onull[T <: AnyRef](x: T) = if (x eq null) None else Some(x) private def quietlyDispose(action: => Unit, disposal: => Unit) = try { action } finally { @@ -38,51 +43,85 @@ private[scala] trait PropertiesTrait catch { case _: IOException => } } - // for values based on system properties - def sysprop(name: String): String = sysprop(name, "") - def sysprop(name: String, default: String): String = System.getProperty(name, default) - def syspropset(name: String, value: String) = System.setProperty(name, value) + def propIsSet(name: String) = System.getProperty(name) != null + def propIsSetTo(name: String, value: String) = propOrNull(name) == value + def propOrElse(name: String, alt: String) = System.getProperty(name, alt) + def propOrEmpty(name: String) = propOrElse(name, "") + def propOrNull(name: String) = propOrElse(name, null) + def propOrNone(name: String) = Option(propOrNull(name)) + def propOrFalse(name: String) = propOrNone(name) exists (x => List("yes", "on", "true") contains x.toLowerCase) + def setProp(name: String, value: String) = System.setProperty(name, value) + def clearProp(name: String) = System.clearProperty(name) + + def envOrElse(name: String, alt: String) = Option(System getenv name) getOrElse alt // for values based on propFilename - def prop(name: String): String = props.getProperty(name, "") - def prop(name: String, default: String): String = props.getProperty(name, default) + def scalaPropOrElse(name: String, alt: String): String = scalaProps.getProperty(name, alt) + def scalaPropOrEmpty(name: String): String = scalaPropOrElse(name, "") /** The version number of the jar this was loaded from plus "version " prefix, * or "version (unknown)" if it cannot be determined. */ - val versionString = "version " + prop("version.number", "(unknown)") - val copyrightString = prop("copyright.string", "(c) 2002-2010 LAMP/EPFL") + val versionString = "version " + scalaPropOrElse("version.number", "(unknown)") + val copyrightString = scalaPropOrElse("copyright.string", "(c) 2002-2010 LAMP/EPFL") /** This is the encoding to use reading in source files, overridden with -encoding * Note that it uses "prop" i.e. looks in the scala jar, not the system properties. */ - val sourceEncoding = prop("file.encoding", "UTF8") + def sourceEncoding = scalaPropOrElse("file.encoding", "UTF-8") /** This is the default text encoding, overridden (unreliably) with * JAVA_OPTS="-Dfile.encoding=Foo" */ - val encodingString = sysprop("file.encoding", "UTF8") - - val isWin = sysprop("os.name") startsWith "Windows" - val isMac = sysprop("java.vendor") startsWith "Apple" - val javaClassPath = sysprop("java.class.path") - val javaHome = sysprop("java.home") - val javaVmName = sysprop("java.vm.name") - val javaVmVersion = sysprop("java.vm.version") - val javaVmInfo = sysprop("java.vm.info") - val javaVersion = sysprop("java.version") - val tmpDir = sysprop("java.io.tmpdir") - val userName = sysprop("user.name") - val scalaHome = sysprop("scala.home", null) // XXX places do null checks... + def encodingString = propOrElse("file.encoding", "UTF-8") + + /** The default end of line character. + */ + def lineSeparator = propOrElse("line.separator", "\n") + + /** Various well-known properties. + */ + def javaClassPath = propOrEmpty("java.class.path") + def javaHome = propOrEmpty("java.home") + def javaVendor = propOrEmpty("java.vendor") + def javaVersion = propOrEmpty("java.version") + def javaVmInfo = propOrEmpty("java.vm.info") + def javaVmName = propOrEmpty("java.vm.name") + def javaVmVendor = propOrEmpty("java.vm.vendor") + def javaVmVersion = propOrEmpty("java.vm.version") + def osName = propOrEmpty("os.name") + def scalaHome = propOrEmpty("scala.home") + def tmpDir = propOrEmpty("java.io.tmpdir") + def userDir = propOrEmpty("user.dir") + def userHome = propOrEmpty("user.home") + def userName = propOrEmpty("user.name") + + /** Some derived values. + */ + def isWin = osName startsWith "Windows" + def isMac = javaVendor startsWith "Apple" - // provide a main method so version info can be obtained by running this - private val writer = new java.io.PrintWriter(Console.err, true) def versionMsg = "Scala %s %s -- %s".format(propCategory, versionString, copyrightString) - def main(args: Array[String]) { writer println versionMsg } -} + def scalaCmd = if (isWin) "scala.bat" else "scala" + def scalacCmd = if (isWin) "scalac.bat" else "scalac" -/** Loads library.properties from the jar. */ -object Properties extends PropertiesTrait { - protected def propCategory = "library" - protected def pickJarBasedOn = classOf[Application] + /** Can the java version be determined to be at least as high as the argument? + * Hard to properly future proof this but at the rate 1.7 is going we can leave + * the issue for our cyborg grandchildren to solve. + */ + def isJavaAtLeast(version: String) = { + val okVersions = version match { + case "1.5" => List("1.5", "1.6", "1.7") + case "1.6" => List("1.6", "1.7") + case "1.7" => List("1.7") + case _ => Nil + } + okVersions exists (javaVersion startsWith _) + } + + // provide a main method so version info can be obtained by running this + def main(args: Array[String]) { + val writer = new PrintWriter(Console.err, true) + writer println versionMsg + } } diff --git a/src/library/scala/util/Random.scala b/src/library/scala/util/Random.scala index 3baa7e33e3..ffa248d638 100644 --- a/src/library/scala/util/Random.scala +++ b/src/library/scala/util/Random.scala @@ -107,19 +107,17 @@ class Random(val self: java.util.Random) { * * @since 2.8 */ -object Random extends Random -{ - import collection.Traversable +object Random extends Random { import collection.mutable.ArrayBuffer import collection.generic.CanBuildFrom /** Returns a new collection of the same type in a randomly chosen order. * - * @param coll the Traversable to shuffle - * @return the shuffled Traversable + * @param coll the TraversableOnce to shuffle + * @return the shuffled TraversableOnce */ - def shuffle[T, CC[X] <: Traversable[X]](coll: CC[T])(implicit bf: CanBuildFrom[CC[T], T, CC[T]]): CC[T] = { - val buf = new ArrayBuffer[T] ++= coll + def shuffle[T, CC[X] <: TraversableOnce[X]](xs: CC[T])(implicit bf: CanBuildFrom[CC[T], T, CC[T]]): CC[T] = { + val buf = new ArrayBuffer[T] ++= xs def swap(i1: Int, i2: Int) { val tmp = buf(i1) @@ -132,6 +130,6 @@ object Random extends Random swap(n - 1, k) } - bf(coll) ++= buf result + bf(xs) ++= buf result } } diff --git a/src/library/scala/util/Sorting.scala b/src/library/scala/util/Sorting.scala index 73228b53d5..4189f2d912 100644 --- a/src/library/scala/util/Sorting.scala +++ b/src/library/scala/util/Sorting.scala @@ -12,46 +12,43 @@ package scala.util import scala.reflect.ClassManifest -/** <p> - * The Sorting object provides functions that can sort various kinds of - * objects. You can provide a comparison function, or you can request a sort - * of items that are viewable as <code>Ordered</code>. Some sorts that - * operate directly on a subset of value types are also provided. These - * implementations are derived from those in the Sun JDK. - * </p> - * <p> - * Note that stability doesn't matter for value types, so use the quickSort - * variants for those. <code>stableSort</code> is intended to be used with - * objects when the prior ordering should be preserved, where possible. - * </p> - * - * @author Ross Judson - * @version 1.0 - */ +/** The Sorting object provides functions that can sort various kinds of + * objects. You can provide a comparison function, or you can request a sort + * of items that are viewable as <code>Ordered</code>. Some sorts that + * operate directly on a subset of value types are also provided. These + * implementations are derived from those in the Sun JDK. + * + * Note that stability doesn't matter for value types, so use the quickSort + * variants for those. <code>stableSort</code> is intended to be used with + * objects when the prior ordering should be preserved, where possible. + * + * @author Ross Judson + * @version 1.0 + */ object Sorting { /** Provides implicit access to sorting on arbitrary sequences of orderable * items. This doesn't quite work the way that I want yet -- K should be * bounded as viewable, but the compiler rejects that. */ - implicit def seq2RichSort[K <: Ordered[K] : ClassManifest](s: Seq[K]) = new RichSorting[K](s) + // implicit def seq2RichSort[K <: Ordered[K] : ClassManifest](s: Seq[K]) = new RichSorting[K](s) /** Quickly sort an array of Doubles. */ - def quickSort(a: Array[Double]) = sort1(a, 0, a.length) + def quickSort(a: Array[Double]) { sort1(a, 0, a.length) } - /** Quickly sort an array of items that are viewable as ordered. */ - def quickSort[K <% Ordered[K]](a: Array[K]) = sort1(a, 0, a.length) + /** Quickly sort an array of items with an implicit Ordering. */ + def quickSort[K](a: Array[K])(implicit ord: Ordering[K]) { sort1(a, 0, a.length) } /** Quickly sort an array of Ints. */ - def quickSort(a: Array[Int]) = sort1(a, 0, a.length) + def quickSort(a: Array[Int]) { sort1(a, 0, a.length) } /** Quickly sort an array of Floats. */ - def quickSort(a: Array[Float]) = sort1(a, 0, a.length) + def quickSort(a: Array[Float]) { sort1(a, 0, a.length) } /** Sort an array of K where K is Ordered, preserving the existing order - where the values are equal. */ - def stableSort[K <% Ordered[K] : ClassManifest](a: Array[K]) { - stableSort(a, 0, a.length-1, new Array[K](a.length), (a:K, b:K) => a < b) + * where the values are equal. */ + def stableSort[K](a: Array[K])(implicit m: ClassManifest[K], ord: Ordering[K]) { + stableSort(a, 0, a.length-1, new Array[K](a.length), ord.lt _) } /** Sorts an array of <code>K</code> given an ordering function @@ -77,8 +74,8 @@ object Sorting { } /** Sorts an arbitrary sequence of items that are viewable as ordered. */ - def stableSort[K <% Ordered[K] : ClassManifest](a: Seq[K]): Array[K] = - stableSort(a, (a:K, b:K) => a < b) + def stableSort[K](a: Seq[K])(implicit m: ClassManifest[K], ord: Ordering[K]): Array[K] = + stableSort(a, ord.lt _) /** Stably sorts a sequence of items given an extraction function that will * return an ordered key from an item. @@ -87,10 +84,11 @@ object Sorting { * @param f the comparison function. * @return the sorted sequence of items. */ - def stableSort[K : ClassManifest, M <% Ordered[M]](a: Seq[K], f: K => M): Array[K] = - stableSort(a, (a: K, b: K) => f(a) < f(b)) + def stableSort[K, M](a: Seq[K], f: K => M)(implicit m: ClassManifest[K], ord: Ordering[M]): Array[K] = + stableSort(a)(m, ord on f) - private def sort1[K <% Ordered[K]](x: Array[K], off: Int, len: Int) { + private def sort1[K](x: Array[K], off: Int, len: Int)(implicit ord: Ordering[K]) { + import ord._ def swap(a: Int, b: Int) { val t = x(a) x(a) = x(b) @@ -532,51 +530,6 @@ object Sorting { } } } - - // for testing - def main(args: Array[String]) { - val tuples = Array( - (1, "one"), (1, "un"), (3, "three"), (2, "deux"), - (2, "two"), (0, "zero"), (3, "trois") - ) - val integers = Array( - 3, 4, 0, 4, 5, 0, 3, 3, 0 - ) - val doubles = Array( - 3.4054752250314283E9, - 4.9663151227666664E10, -// 0.0/0.0 is interpreted as Nan -// 0.0/0.0, - 4.9663171987125E10, - 5.785996973446602E9, -// 0.0/0.0, - 3.973064849653333E10, - 3.724737288678125E10 -// 0.0/0.0 - ) - val floats = Array( - 3.4054752250314283E9f, - 4.9663151227666664E10f, -// 0.0f/0.0f, - 4.9663171987125E10f, - 5.785996973446602E9f, -// 0.0f/0.0f, - 3.973064849653333E10f, - 3.724737288678125E10f -// 0.0f/0.0f - ) - Sorting quickSort tuples - println(tuples.toList) - - Sorting quickSort integers - println(integers.toList) - - Sorting quickSort doubles - println(doubles.toList) - - Sorting quickSort floats - println(floats.toList) - } } /** <p> @@ -585,8 +538,7 @@ object Sorting { * the items are ordered. * </p> */ -class RichSorting[K <: Ordered[K] : ClassManifest](s: Seq[K]) { - +class RichSorting[K](s: Seq[K])(implicit m: ClassManifest[K], ord: Ordering[K]) { /** Returns an array with a sorted copy of the RichSorting's sequence. */ def sort = Sorting.stableSort(s) diff --git a/src/library/scala/util/automata/SubsetConstruction.scala b/src/library/scala/util/automata/SubsetConstruction.scala index 0ebdd160e7..c8fba39f0e 100644 --- a/src/library/scala/util/automata/SubsetConstruction.scala +++ b/src/library/scala/util/automata/SubsetConstruction.scala @@ -57,7 +57,7 @@ class SubsetConstruction[T <: AnyRef](val nfa: NondetWordAutom[T]) { invIndexMap = invIndexMap.updated(ix, P) ix += 1 - // make transitiion map + // make transition map val Pdelta = new mutable.HashMap[T, BitSet] delta.update(P, Pdelta) diff --git a/src/library/scala/util/automata/WordBerrySethi.scala b/src/library/scala/util/automata/WordBerrySethi.scala index d3238b6f67..b54fdc53f2 100644 --- a/src/library/scala/util/automata/WordBerrySethi.scala +++ b/src/library/scala/util/automata/WordBerrySethi.scala @@ -81,7 +81,7 @@ abstract class WordBerrySethi extends BaseBerrySethi { this.labels += label } - // overriden in BindingBerrySethi + // overridden in BindingBerrySethi protected def seenLabel(r: RegExp, label: lang._labelT): Int = { pos += 1 seenLabel(r, pos, label) diff --git a/src/library/scala/util/control/Breaks.scala b/src/library/scala/util/control/Breaks.scala index 7ae4cba63a..1f06f04418 100644 --- a/src/library/scala/util/control/Breaks.scala +++ b/src/library/scala/util/control/Breaks.scala @@ -28,14 +28,14 @@ package scala.util.control */ class Breaks { - private val breakException = new BreakException + private val breakException = new BreakControl /** A block from which one can exit with a `break''. */ def breakable(op: => Unit) { try { op } catch { - case ex: BreakException => + case ex: BreakControl => if (ex ne breakException) throw ex } } @@ -61,5 +61,5 @@ class Breaks { */ object Breaks extends Breaks -private class BreakException extends RuntimeException with ControlException +private class BreakControl extends ControlThrowable diff --git a/src/library/scala/util/control/ControlException.scala b/src/library/scala/util/control/ControlThrowable.scala index 73f2b31e89..090bec4e98 100644 --- a/src/library/scala/util/control/ControlException.scala +++ b/src/library/scala/util/control/ControlThrowable.scala @@ -21,19 +21,19 @@ package scala.util.control * * <p>Instances of <code>Throwable</code> subclasses marked in * this way should not normally be caught. Where catch-all behaviour is - * required <code>ControlException</code>s should be propagated, for + * required <code>ControlThrowable</code>s should be propagated, for * example,</p> * * <pre> - * import scala.util.control.ControlException + * import scala.util.control.ControlThrowable * * try { * // Body might throw arbitrarily * } catch { - * case ce : ControlException => throw ce // propagate + * case ce : ControlThrowable => throw ce // propagate * case t : Exception => log(t) // log and suppress * </pre> * * @author Miles Sabin */ -trait ControlException extends Throwable with NoStackTrace +trait ControlThrowable extends Throwable with NoStackTrace diff --git a/src/library/scala/util/logging/ConsoleLogger.scala b/src/library/scala/util/logging/ConsoleLogger.scala index d4ef268e37..ec4148abc9 100644 --- a/src/library/scala/util/logging/ConsoleLogger.scala +++ b/src/library/scala/util/logging/ConsoleLogger.scala @@ -21,8 +21,6 @@ package scala.util.logging trait ConsoleLogger extends Logged { /** logs argument to Console using <code>Console.println</code> - * - * @param msg ... */ override def log(msg: String): Unit = Console.println(msg) } diff --git a/src/library/scala/util/matching/Regex.scala b/src/library/scala/util/matching/Regex.scala index 2ceef4563c..1384dfa47c 100644 --- a/src/library/scala/util/matching/Regex.scala +++ b/src/library/scala/util/matching/Regex.scala @@ -107,6 +107,32 @@ class Regex(regex: String, groupNames: String*) { m.replaceAll(replacement) } + /** + * Replaces all matches using a replacer function. + * + * @param target The string to match. + * @param replacer The function which maps a match to another string. + * @return The target string after replacements. + */ + def replaceAllIn(target: java.lang.CharSequence, replacer: Match => String): String = { + val it = new Regex.MatchIterator(target, this, groupNames).replacementData + while (it.hasNext) { + val matchdata = it.next + it.replace(replacer(matchdata)) + } + it.replaced + } + + def replaceSomeIn(target: java.lang.CharSequence, replacer: Match => Option[String]): String = { + val it = new Regex.MatchIterator(target, this, groupNames).replacementData + while (it.hasNext) { + val matchdata = it.next + val replaceopt = replacer(matchdata) + if (replaceopt != None) it.replace(replaceopt.get) + } + it.replaced + } + /** Replaces the first match by a string. * * @param target The string to match @@ -227,7 +253,7 @@ object Regex { } - /** A case class for a succesful match. + /** A case class for a successful match. */ class Match(val source: java.lang.CharSequence, matcher: Matcher, @@ -264,12 +290,17 @@ object Regex { def unapply(m: Match): Some[String] = Some(m.matched) } + /** An extractor object that yields groups in the match. */ + object Groups { + def unapplySeq(m: Match): Option[Seq[String]] = if (m.groupCount > 0) Some(1 to m.groupCount map m.group) else None + } + /** A class to step through a sequence of regex matches */ class MatchIterator(val source: java.lang.CharSequence, val regex: Regex, val groupNames: Seq[String]) extends Iterator[String] with MatchData { self => - private val matcher = regex.pattern.matcher(source) + protected val matcher = regex.pattern.matcher(source) private var nextSeen = false /** Is there another match? */ @@ -307,6 +338,31 @@ object Regex { def hasNext = self.hasNext def next = { self.next; new Match(source, matcher, groupNames).force } } + + /** Convert to an iterator that yields MatchData elements instead of Strings and has replacement support */ + private[matching] def replacementData = new Iterator[Match] with Replacement { + def matcher = self.matcher + def hasNext = self.hasNext + def next = { self.next; new Match(source, matcher, groupNames).force } + } + } + + /** + * A trait able to build a string with replacements assuming it has a matcher. + * Meant to be mixed in with iterators. + */ + private[matching] trait Replacement { + protected def matcher: Matcher + + private var sb = new java.lang.StringBuffer + + def replaced = { + val newsb = new java.lang.StringBuffer(sb) + matcher.appendTail(newsb) + newsb.toString + } + + def replace(rs: String) = matcher.appendReplacement(sb, rs) } } diff --git a/src/library/scala/util/parsing/ast/Binders.scala b/src/library/scala/util/parsing/ast/Binders.scala index b397e900da..7a9b8e5dcd 100644 --- a/src/library/scala/util/parsing/ast/Binders.scala +++ b/src/library/scala/util/parsing/ast/Binders.scala @@ -127,10 +127,8 @@ trait Binders extends AbstractSyntax with Mappable { * (e.g. the variable name in a local variable declaration) * * @param b a new binder that is distinct from the existing binders in this scope, - * and shares their conceptual scope - * @pre canAddBinder(b) - * @post binds(b) - * @post getElementFor(b) eq b + * and shares their conceptual scope. canAddBinder(b)` must hold.` + * @return `binds(b)` and `getElementFor(b) eq b` will hold. */ def addBinder(b: binderType) { substitution += Pair(b, b) } @@ -140,7 +138,7 @@ trait Binders extends AbstractSyntax with Mappable { * linked to its `UnderBinder' (i.e., while parsing, BoundElements may be added to the Scope * associated to the UnderBinder, but after that, no changes are allowed, except for substitution)? * - * @returns true if `b' had not been added yet + * @return true if `b' had not been added yet */ def canAddBinder(b: binderType): Boolean = !binds(b) @@ -150,17 +148,15 @@ trait Binders extends AbstractSyntax with Mappable { * a proxy for the element it is bound to by its binder, `substitute' may thus be thought of * as replacing all the bound occurrences of the given binder `b' by their new value `value'. * - * @param b the binder whose bound occurrences should be given a new value + * @param b the binder whose bound occurrences should be given a new value. `binds(b)` must hold. * @param value the new value for the bound occurrences of `b' - * @pre binds(b) - * @post getElementFor(b) eq value + * @return `getElementFor(b) eq value` will hold. */ def substitute(b: binderType, value: Element): Unit = substitution(b) = value /** Returns the current value for the bound occurrences of `b'. * - * @param b the contained binder whose current value should be returned - * @pre binds(b) + * @param b the contained binder whose current value should be returned `binds(b)` must hold. */ def getElementFor(b: binderType): Element = substitution(b) @@ -173,7 +169,7 @@ trait Binders extends AbstractSyntax with Mappable { def allowForwardRef: Scope[binderType] = this // TODO /** Return a nested scope -- binders entered into it won't be visible in this scope, but if this scope allows forward references, - the binding in the returned scope also does, and thus the check that all variables are bound is deferred until this scope is left **/ + * the binding in the returned scope also does, and thus the check that all variables are bound is deferred until this scope is left **/ def nested: Scope[binderType] = this // TODO def onEnter {} @@ -193,7 +189,7 @@ trait Binders extends AbstractSyntax with Mappable { * A `BoundElement' is represented textually by its bound element, followed by its scope's `id'. * For example: `x@1' represents the variable `x' that is bound in the scope with `id' `1'. * - * @invar scope.binds(el) + * @note `scope.binds(el)` holds before and after. */ case class BoundElement[boundElement <: NameElement](el: boundElement, scope: Scope[boundElement]) extends NameElement with Proxy with BindingSensitive { /** Returns the element this `BoundElement' stands for. @@ -300,7 +296,7 @@ trait Binders extends AbstractSyntax with Mappable { * * The name `sequence' comes from the fact that this method's type is equal to the type of monadic sequence. * - * @pre !orig.isEmpty implies orig.forall(ub => ub.scope eq orig(0).scope) + * @note `!orig.isEmpty` implies `orig.forall(ub => ub.scope eq orig(0).scope)` * */ def sequence[bt <: NameElement, st <% Mappable[st]](orig: List[UnderBinder[bt, st]]): UnderBinder[bt, List[st]] = diff --git a/src/library/scala/util/parsing/combinator/Parsers.scala b/src/library/scala/util/parsing/combinator/Parsers.scala index 6fe35ad3b0..d270757189 100644 --- a/src/library/scala/util/parsing/combinator/Parsers.scala +++ b/src/library/scala/util/parsing/combinator/Parsers.scala @@ -48,35 +48,21 @@ import scala.annotation.tailrec * of the input. * </p> * - * @requires Elem the type of elements the provided parsers consume - * (When consuming invidual characters, a parser is typically called a ``scanner'', - * which produces ``tokens'' that are consumed by what is normally called a ``parser''. - * Nonetheless, the same principles apply, regardless of the input type.)</p> - *<p> - * @provides Input = Reader[Elem] - * The type of input the parsers in this component expect.</p> - *<p> - * @provides Parser[+T] extends (Input => ParseResult[T]) - * Essentially, a `Parser[T]' is a function from `Input' to `ParseResult[T]'.</p> - *<p> - * @provides ParseResult[+T] is like an `Option[T]', in the sense that it is either - * `Success[T]', which consists of some result (:T) (and the rest of the input) or - * `Failure[T]', which provides an error message (and the rest of the input).</p> - * * @author Martin Odersky, Iulian Dragos, Adriaan Moors */ trait Parsers { - /** the type of input elements */ + /** the type of input elements the provided parsers consume (When consuming invidual characters, a parser is typically + * called a ``scanner'', which produces ``tokens'' that are consumed by what is normally called a ``parser''. + * Nonetheless, the same principles apply, regardless of the input type.) */ type Elem - /** The parser input is an abstract reader of input elements */ + /** The parser input is an abstract reader of input elements, i.e. the type of input the parsers in this component + * expect. */ type Input = Reader[Elem] - /** A base class for parser results. - * A result is either successful or not (failure may be fatal, i.e., - * an Error, or not, i.e., a Failure) - * On success, provides a result of type <code>T</code>. - */ + /** A base class for parser results. A result is either successful or not (failure may be fatal, i.e., an Error, or + * not, i.e., a Failure). On success, provides a result of type `T` which consists of some result (and the rest of + * the input). */ sealed abstract class ParseResult[+T] { /** Functional composition of ParseResults * @@ -302,7 +288,7 @@ trait Parsers { * characters accepts.</p> * * @param q a parser that accepts if p consumes less characters. - * @return a `Parser' that returns the result of the parser consuming the most characteres (out of `p' and `q'). + * @return a `Parser' that returns the result of the parser consuming the most characters (out of `p' and `q'). */ def ||| [U >: T](q: => Parser[U]): Parser[U] = new Parser[U] { def apply(in: Input) = { @@ -362,7 +348,7 @@ trait Parsers { def ^? [U](f: PartialFunction[T, U]): Parser[U] = ^?(f, r => "Constructor function not defined at "+r) - /** A parser combinator that parameterises a subsequent parser with the result of this one + /** A parser combinator that parameterizes a subsequent parser with the result of this one * *<p> * Use this combinator when a parser depends on the result of a previous parser. `p' should be @@ -592,13 +578,18 @@ trait Parsers { def rep1[T](first: => Parser[T], p: => Parser[T]): Parser[List[T]] = Parser { in => val elems = new ListBuffer[T] - @tailrec def applyp(in0: Input): ParseResult[List[T]] = p(in0) match { - case Success(x, rest) => elems += x ; applyp(rest) - case _ => Success(elems.toList, in0) + def continue(in: Input): ParseResult[List[T]] = { + val p0 = p // avoid repeatedly re-evaluating by-name parser + @tailrec def applyp(in0: Input): ParseResult[List[T]] = p0(in0) match { + case Success(x, rest) => elems += x ; applyp(rest) + case _ => Success(elems.toList, in0) + } + + applyp(in) } first(in) match { - case Success(x, rest) => elems += x ; applyp(rest) + case Success(x, rest) => elems += x ; continue(rest) case ns: NoSuccess => ns } } @@ -616,10 +607,11 @@ trait Parsers { def repN[T](num: Int, p: => Parser[T]): Parser[List[T]] = if (num == 0) success(Nil) else Parser { in => val elems = new ListBuffer[T] + val p0 = p // avoid repeatedly re-evaluating by-name parser @tailrec def applyp(in0: Input): ParseResult[List[T]] = if (elems.length == num) Success(elems.toList, in0) - else p(in0) match { + else p0(in0) match { case Success(x, rest) => elems += x ; applyp(rest) case ns: NoSuccess => return ns } @@ -670,7 +662,7 @@ trait Parsers { /** A parser generator that generalises the rep1sep generator so that `q', which parses the separator, * produces a right-associative function that combines the elements it separates. Additionally, - * The right-most (last) element and the left-most combinating function have to be supplied. + * The right-most (last) element and the left-most combining function have to be supplied. * * rep1sep(p: Parser[T], q) corresponds to chainr1(p, q ^^ cons, cons, Nil) (where val cons = (x: T, y: List[T]) => x :: y) * diff --git a/src/library/scala/util/parsing/combinator/lexical/Lexical.scala b/src/library/scala/util/parsing/combinator/lexical/Lexical.scala index fc3100053a..7a35bcad7d 100644 --- a/src/library/scala/util/parsing/combinator/lexical/Lexical.scala +++ b/src/library/scala/util/parsing/combinator/lexical/Lexical.scala @@ -9,11 +9,12 @@ // $Id$ -package scala.util.parsing.combinator.lexical -import scala.util.parsing.combinator._ +package scala.util.parsing +package combinator +package lexical -import scala.util.parsing.syntax._ -import scala.util.parsing.input.CharArrayReader.EofCh +import token._ +import input.CharArrayReader.EofCh /** <p> * This component complements the <code>Scanners</code> component with diff --git a/src/library/scala/util/parsing/combinator/lexical/Scanners.scala b/src/library/scala/util/parsing/combinator/lexical/Scanners.scala index 07f4975cf8..96e9a76572 100644 --- a/src/library/scala/util/parsing/combinator/lexical/Scanners.scala +++ b/src/library/scala/util/parsing/combinator/lexical/Scanners.scala @@ -9,11 +9,12 @@ // $Id$ -package scala.util.parsing.combinator.lexical -import scala.util.parsing.combinator._ +package scala.util.parsing +package combinator +package lexical -import scala.util.parsing.syntax._ -import scala.util.parsing.input._ +import token._ +import input._ /** <p> * This component provides core functionality for lexical parsers. @@ -23,13 +24,6 @@ import scala.util.parsing.input._ * {@see StdLexical}, for more functionality. * </p> * - * @requires token a parser that produces a token (from a stream of characters) - * @requires whitespace a unit-parser for white-space - * @provides Scanner essentially a parser that parses a stream of characters - * to produce `Token's, which are typically passed to a - * syntactical parser (which operates on `Token's, not on - * individual characters). - * * @author Martin Odersky, Adriaan Moors */ trait Scanners extends Parsers { diff --git a/src/library/scala/util/parsing/combinator/lexical/StdLexical.scala b/src/library/scala/util/parsing/combinator/lexical/StdLexical.scala index 1bb3e7c83f..bc53e3731d 100644 --- a/src/library/scala/util/parsing/combinator/lexical/StdLexical.scala +++ b/src/library/scala/util/parsing/combinator/lexical/StdLexical.scala @@ -9,11 +9,12 @@ // $Id$ -package scala.util.parsing.combinator.lexical -import scala.util.parsing.combinator._ +package scala.util.parsing +package combinator +package lexical -import scala.util.parsing.syntax._ -import scala.util.parsing.input.CharArrayReader.EofCh +import token._ +import input.CharArrayReader.EofCh import collection.mutable.HashSet /** <p> diff --git a/src/library/scala/util/parsing/combinator/syntactical/StandardTokenParsers.scala b/src/library/scala/util/parsing/combinator/syntactical/StandardTokenParsers.scala index 85c0592572..31fa06035c 100644 --- a/src/library/scala/util/parsing/combinator/syntactical/StandardTokenParsers.scala +++ b/src/library/scala/util/parsing/combinator/syntactical/StandardTokenParsers.scala @@ -8,12 +8,12 @@ // $Id$ +package scala.util.parsing +package combinator +package syntactical -package scala.util.parsing.combinator.syntactical -import scala.util.parsing.combinator._ - -import scala.util.parsing.syntax._ -import scala.util.parsing.combinator.lexical.StdLexical +import token._ +import lexical.StdLexical /** This component provides primitive parsers for the standard tokens defined in `StdTokens'. * diff --git a/src/library/scala/util/parsing/combinator/syntactical/StdTokenParsers.scala b/src/library/scala/util/parsing/combinator/syntactical/StdTokenParsers.scala index 544c7f08d5..5b62280b78 100644 --- a/src/library/scala/util/parsing/combinator/syntactical/StdTokenParsers.scala +++ b/src/library/scala/util/parsing/combinator/syntactical/StdTokenParsers.scala @@ -9,11 +9,12 @@ // $Id$ -package scala.util.parsing.combinator.syntactical -import scala.util.parsing.combinator._ +package scala.util.parsing +package combinator +package syntactical -import scala.util.parsing.syntax._ -import scala.collection.mutable.HashMap +import token._ +import collection.mutable.HashMap /** This component provides primitive parsers for the standard tokens defined in `StdTokens'. * diff --git a/src/library/scala/util/parsing/combinator/syntactical/TokenParsers.scala b/src/library/scala/util/parsing/combinator/syntactical/TokenParsers.scala index 01557c32a7..ae4120b402 100644 --- a/src/library/scala/util/parsing/combinator/syntactical/TokenParsers.scala +++ b/src/library/scala/util/parsing/combinator/syntactical/TokenParsers.scala @@ -8,23 +8,17 @@ // $Id$ +package scala.util.parsing +package combinator +package syntactical -package scala.util.parsing.combinator.syntactical -import scala.util.parsing.combinator._ - -/** <p> - * This is the core component for token-based parsers. - * </p> - * <p> - * @requires lexical a component providing the tokens consumed by the - * parsers in this component. - * </p> +/** This is the core component for token-based parsers. * * @author Martin Odersky, Adriaan Moors */ trait TokenParsers extends Parsers { /** Tokens is the abstract type of the `Token's consumed by the parsers in this component*/ - type Tokens <: scala.util.parsing.syntax.Tokens + type Tokens <: token.Tokens /** lexical is the component responsible for consuming some basic kind of * input (usually character-based) and turning it into the tokens diff --git a/src/library/scala/util/parsing/syntax/StdTokens.scala b/src/library/scala/util/parsing/combinator/token/StdTokens.scala index 2321082b92..ea565235d1 100644 --- a/src/library/scala/util/parsing/syntax/StdTokens.scala +++ b/src/library/scala/util/parsing/combinator/token/StdTokens.scala @@ -6,7 +6,9 @@ ** |/ ** \* */ -package scala.util.parsing.syntax +package scala.util.parsing +package combinator +package token /** This component provides the standard `Token's for a simple, Scala-like language. * diff --git a/src/library/scala/util/parsing/syntax/Tokens.scala b/src/library/scala/util/parsing/combinator/token/Tokens.scala index fdc6385b6e..b7a568efea 100644 --- a/src/library/scala/util/parsing/syntax/Tokens.scala +++ b/src/library/scala/util/parsing/combinator/token/Tokens.scala @@ -6,7 +6,9 @@ ** |/ ** \* */ -package scala.util.parsing.syntax +package scala.util.parsing +package combinator +package token /** This component provides the notion of `Token', the unit of information that is passed from lexical * parsers in the `Lexical' component to the parsers in the `TokenParsers' component. diff --git a/src/library/scala/util/parsing/input/Position.scala b/src/library/scala/util/parsing/input/Position.scala index 6922bec19c..482610ca28 100644 --- a/src/library/scala/util/parsing/input/Position.scala +++ b/src/library/scala/util/parsing/input/Position.scala @@ -53,7 +53,7 @@ trait Position { *<pre> List(this, is, a, line, from, the, document) * ^</pre> */ - def longString = lineContents+"\n"+(" " * (column - 1))+"^" + def longString = lineContents+"\n"+lineContents.take(column-1).map{x => if (x == '\t') x else ' ' } + "^" /** Compare this position to another, by first comparing their line numbers, * and then -- if necessary -- using the columns to break a tie. diff --git a/src/library/scala/util/parsing/syntax/package.scala b/src/library/scala/util/parsing/syntax/package.scala new file mode 100644 index 0000000000..9dc909ca60 --- /dev/null +++ b/src/library/scala/util/parsing/syntax/package.scala @@ -0,0 +1,19 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.util.parsing + +import scala.util.parsing.combinator.token + +/** If deprecating the whole package worked, that's what would best + * be done, but it doesn't (yet) so it isn't. + */ +package object syntax { + @deprecated("Moved to scala.util.parsing.combinator.token") type Tokens = token.Tokens + @deprecated("Moved to scala.util.parsing.combinator.token") type StdTokens = token.StdTokens +} diff --git a/src/library/scala/xml/Atom.scala b/src/library/scala/xml/Atom.scala index 129a0803d2..7c66995573 100644 --- a/src/library/scala/xml/Atom.scala +++ b/src/library/scala/xml/Atom.scala @@ -8,9 +8,7 @@ // $Id$ - package scala.xml -import collection.mutable.StringBuilder /** The class <code>Atom</code> provides an XML node for text (PCDATA). * It is used in both non-bound and bound XML representations. @@ -24,17 +22,21 @@ class Atom[+A](val data: A) extends SpecialNode if (data == null) throw new IllegalArgumentException("cannot construct Atom(null)") + override def basisForHashCode: Seq[Any] = Seq(data) + override def strict_==(other: Equality) = other match { + case x: Atom[_] => data == x.data + case _ => false + } + override def canEqual(other: Any) = other match { + case _: Atom[_] => true + case _ => false + } + final override def doCollectNamespaces = false final override def doTransform = false def label = "#PCDATA" - override def equals(x: Any) = x match { - case s:Atom[_] => data == s.data - case _ => false - } - override def hashCode() = data.hashCode() - /** Returns text, with some characters escaped according to the XML * specification. * diff --git a/src/library/scala/xml/Attribute.scala b/src/library/scala/xml/Attribute.scala index 8ff9fb2ed7..3259526d98 100644 --- a/src/library/scala/xml/Attribute.scala +++ b/src/library/scala/xml/Attribute.scala @@ -10,9 +10,6 @@ package scala.xml -import collection.Seq -import collection.mutable.StringBuilder - /** Attribute defines the interface shared by both * PrefixedAttribute and UnprefixedAttribute */ @@ -45,6 +42,7 @@ object Attribute { abstract trait Attribute extends MetaData { + def pre: String // will be null if unprefixed val key: String val value: Seq[Node] val next: MetaData @@ -52,13 +50,43 @@ abstract trait Attribute extends MetaData def apply(key: String): Seq[Node] def apply(namespace: String, scope: NamespaceBinding, key: String): Seq[Node] def copy(next: MetaData): Attribute - def remove(key: String): MetaData - def remove(namespace: String, scope: NamespaceBinding, key: String): MetaData - def isPrefixed: Boolean + def remove(key: String) = + if (!isPrefixed && this.key == key) next + else copy(next remove key) + + def remove(namespace: String, scope: NamespaceBinding, key: String) = + if (isPrefixed && this.key == key && (scope getURI pre) == namespace) next + else next.remove(namespace, scope, key) + + def isPrefixed: Boolean = pre != null def getNamespace(owner: Node): String - def wellformed(scope: NamespaceBinding): Boolean + def wellformed(scope: NamespaceBinding): Boolean = { + val arg = if (isPrefixed) scope getURI pre else null + (next(arg, scope, key) == null) && (next wellformed scope) + } - def equals1(m: MetaData): Boolean - def toString1(sb: StringBuilder): Unit + override def canEqual(other: Any) = other match { + case _: Attribute => true + case _ => false + } + override def strict_==(other: Equality) = other match { + case x: Attribute => (pre == x.pre) && (key == x.key) && (value sameElements x.value) + case _ => false + } + override def basisForHashCode = List(pre, key, value) + + /** Appends string representation of only this attribute to stringbuffer. + */ + def toString1(sb: StringBuilder) { + if (value == null) + return + if (isPrefixed) + sb append pre append ':' + + sb append key append '=' + val sb2 = new StringBuilder() + Utility.sequenceToXML(value, TopScope, sb2, true) + Utility.appendQuoted(sb2.toString(), sb) + } } diff --git a/src/library/scala/xml/Comment.scala b/src/library/scala/xml/Comment.scala index 4e8cff8d75..9608748601 100644 --- a/src/library/scala/xml/Comment.scala +++ b/src/library/scala/xml/Comment.scala @@ -10,7 +10,7 @@ package scala.xml -import collection.mutable.StringBuilder + /** The class <code>Comment</code> implements an XML node for comments. * diff --git a/src/library/scala/xml/Document.scala b/src/library/scala/xml/Document.scala index 3ac50b80b7..6c73252a37 100644 --- a/src/library/scala/xml/Document.scala +++ b/src/library/scala/xml/Document.scala @@ -87,4 +87,8 @@ class Document extends NodeSeq with pull.XMLEvent { def theSeq: Seq[Node] = this.docElem + override def canEqual(other: Any) = other match { + case _: Document => true + case _ => false + } } diff --git a/src/library/scala/xml/Elem.scala b/src/library/scala/xml/Elem.scala index 18b513527c..9c58177417 100644 --- a/src/library/scala/xml/Elem.scala +++ b/src/library/scala/xml/Elem.scala @@ -8,11 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq - /** This singleton object contains the apply and unapplySeq methods for convenient construction and * deconstruction. It is possible to deconstruct any Node instance (that is not a SpecialNode or * a Group) using the syntax @@ -26,8 +23,10 @@ object Elem def apply(prefix: String,label: String, attributes: MetaData, scope: NamespaceBinding, child: Node*) = new Elem(prefix,label,attributes,scope,child:_*) - def unapplySeq(n:Node) = if (n.isInstanceOf[SpecialNode] || n.isInstanceOf[Group]) None else - Some((n.prefix, n.label, n.attributes, n.scope, n.child)) + def unapplySeq(n: Node) = n match { + case _: SpecialNode | _: Group => None + case _ => Some((n.prefix, n.label, n.attributes, n.scope, n.child)) + } } /** The case class <code>Elem</code> extends the <code>Node</code> class, @@ -54,18 +53,17 @@ extends Node final override def doCollectNamespaces = true final override def doTransform = true - if ((null != prefix) && 0 == prefix.length()) + if (prefix == "") throw new IllegalArgumentException("prefix of zero length, use null instead") - if (null == scope) - throw new IllegalArgumentException("scope is null, try xml.TopScope for empty scope") + if (scope == null) + throw new IllegalArgumentException("scope is null, use xml.TopScope for empty scope") //@todo: copy the children, // setting namespace scope if necessary // cleaning adjacent text nodes if necessary - override def hashCode(): Int = - Utility.hashCode(prefix, label, attributes.hashCode(), scope.hashCode(), child) + override def basisForHashCode: Seq[Any] = prefix :: label :: attributes :: child.toList /** Returns a new element with updated attributes, resolving namespace uris from this element's scope. * See MetaData.update for details. diff --git a/src/library/scala/xml/EntityRef.scala b/src/library/scala/xml/EntityRef.scala index 0806b8fa68..fbc1f351cf 100644 --- a/src/library/scala/xml/EntityRef.scala +++ b/src/library/scala/xml/EntityRef.scala @@ -10,7 +10,7 @@ package scala.xml -import collection.mutable.StringBuilder + /** The class <code>EntityRef</code> implements an XML node for entity diff --git a/src/library/scala/xml/Equality.scala b/src/library/scala/xml/Equality.scala new file mode 100644 index 0000000000..d09ae10b2d --- /dev/null +++ b/src/library/scala/xml/Equality.scala @@ -0,0 +1,115 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.xml + +/** In an attempt to contain the damage being inflicted on + * consistency by the ad hoc equals methods spread around + * xml, the logic is centralized and all the xml classes + * go through the xml.Equality trait. There are two forms + * of xml comparison. + * + * 1) def strict_==(other: xml.Equality) + * + * This one tries to honor the little things like symmetry + * and hashCode contracts. The equals method routes all + * comparisons through this. + * + * 2) xml_==(other: Any) + * + * This one picks up where strict_== leaves off. It might + * declare any two things equal. + * + * As things stood, the logic not only made a mockery of + * the collections equals contract, but also laid waste to + * that of case classes. + * + * Among the obstacles to sanity are/were: + * + * Node extends NodeSeq extends Seq[Node] + * MetaData extends Iterable[MetaData] + * The hacky "Group" xml node which throws exceptions + * with wild abandon, so don't get too close + * Rampant asymmetry and impossible hashCodes + * Most classes claiming to be equal to "String" if + * some specific stringification of it was the same. + * String was never going to return the favor. + */ + +object Equality { + def asRef(x: Any): AnyRef = x.asInstanceOf[AnyRef] + + /** Note - these functions assume strict equality has already failed. + */ + def compareBlithely(x1: AnyRef, x2: String): Boolean = x1 match { + case x: Atom[_] => x.data == x2 + case x: NodeSeq => x.text == x2 + case _ => false + } + def compareBlithely(x1: AnyRef, x2: Node): Boolean = x1 match { + case x: NodeSeq if x.length == 1 => x2 == x(0) + case _ => false + } + def compareBlithely(x1: AnyRef, x2: AnyRef): Boolean = { + if (x1 == null || x2 == null) + return (x1 eq x2) + + x2 match { + case s: String => compareBlithely(x1, s) + case n: Node => compareBlithely(x1, n) + case _ => false + } + } +} +import Equality._ + +private[xml] +trait Equality extends scala.Equals { + def basisForHashCode: Seq[Any] + def strict_==(other: Equality): Boolean + def strict_!=(other: Equality) = !strict_==(other) + + private def hashOf(x: Any) = if (x == null) 1 else x.hashCode() + + /** We insist we're only equal to other xml.Equality implementors, + * which heads off a lot of inconsistency up front. + */ + override def canEqual(other: Any): Boolean = other match { + case x: Equality => true + case _ => false + } + + /** It's be nice to make these final, but there are probably + * people out there subclassing the XML types, especially when + * it comes to equals. However WE at least can pretend they + * are final since clearly individual classes cannot be trusted + * to maintain a semblance of order. + */ + override def hashCode() = basisForHashCode match { + case Nil => 0 + case x :: xs => hashOf(x) * 41 + (xs map hashOf).foldLeft(0)(_ * 7 + _) + } + override def equals(other: Any) = doComparison(other, false) + final def xml_==(other: Any) = doComparison(other, true) + final def xml_!=(other: Any) = !xml_==(other) + + /** The "blithe" parameter expresses the caller's unconcerned attitude + * regarding the usual constraints on equals. The method is thereby + * given carte blanche to declare any two things equal. + */ + private def doComparison(other: Any, blithe: Boolean) = { + val strictlyEqual = other match { + case x: AnyRef if this eq x => true + case x: Equality => (x canEqual this) && (this strict_== x) + case _ => false + } + + strictlyEqual || (blithe && compareBlithely(this, asRef(other))) + } +} + diff --git a/src/library/scala/xml/Group.scala b/src/library/scala/xml/Group.scala index 91ddba6ce6..8b714d2813 100644 --- a/src/library/scala/xml/Group.scala +++ b/src/library/scala/xml/Group.scala @@ -8,9 +8,7 @@ // $Id$ - package scala.xml -import collection.Seq /** A hack to group XML nodes in one node for output. * @@ -18,49 +16,27 @@ import collection.Seq * @version 1.0 */ @serializable -case class Group(val nodes: Seq[Node]) extends Node { - // final override def doTransform = false +final case class Group(val nodes: Seq[Node]) extends Node { override def theSeq = nodes - /** XXX this is ridiculous, we can't do equality like this. */ - override def equals(x: Any) = x match { - case z:Group => (length == z.length) && sameElements(z) - case z:Node => (length == 1) && z == apply(0) - case z:Seq[_] => sameElements(z) - case z:String => text == z - case _ => false + override def canEqual(other: Any) = other match { + case x: Group => true + case _ => false } - /* As if there were a hashCode which could back up the above implementation! */ - override def hashCode = nodes.hashCode - - /** - * @throws Predef.UnsupportedOperationException (always) - */ - final def label = - throw new UnsupportedOperationException("class Group does not support method 'label'") - - /** - * @throws Predef.UnsupportedOperationException (always) - */ - final override def attributes = - throw new UnsupportedOperationException("class Group does not support method 'attributes'") - - /** - * @throws Predef.UnsupportedOperationException (always) - */ - final override def namespace = - throw new UnsupportedOperationException("class Group does not support method 'namespace'") + override def strict_==(other: Equality) = other match { + case Group(xs) => nodes sameElements xs + case _ => false + } + override def basisForHashCode = nodes - /** - * @throws Predef.UnsupportedOperationException (always) + /** Since Group is very much a hack it throws an exception if you + * try to do anything with it. */ - final override def child = - throw new UnsupportedOperationException("class Group does not support method 'child'") + private def fail(msg: String) = throw new UnsupportedOperationException("class Group does not support method '%s'" format msg) - /** - * @throws Predef.UnsupportedOperationException (always) - */ - def buildString(sb: StringBuilder) = - throw new UnsupportedOperationException( - "class Group does not support method toString(StringBuilder)") + def label = fail("label") + override def attributes = fail("attributes") + override def namespace = fail("namespace") + override def child = fail("child") + def buildString(sb: StringBuilder) = fail("toString(StringBuilder)") } diff --git a/src/library/scala/xml/MetaData.scala b/src/library/scala/xml/MetaData.scala index 01b1cbc1d9..744b662fb8 100644 --- a/src/library/scala/xml/MetaData.scala +++ b/src/library/scala/xml/MetaData.scala @@ -8,14 +8,10 @@ // $Id$ - package scala.xml import Utility.sbToString import annotation.tailrec -import collection.immutable.List -import collection.{Seq, Iterator, Iterable} -import collection.mutable.StringBuilder /** @@ -77,7 +73,7 @@ object MetaData { * @author Burak Emir <bqe@google.com> */ @serializable -abstract class MetaData extends Iterable[MetaData] +abstract class MetaData extends Iterable[MetaData] with Equality { /** Updates this MetaData with the MetaData given as argument. All attributes that occur in updates * are part of the resulting MetaData. If an attribute occurs in both this instance and @@ -118,13 +114,6 @@ abstract class MetaData extends Iterable[MetaData] */ def apply(namespace_uri:String, scp:NamespaceBinding, k:String): Seq[Node] - /** - * @param m ... - * @return <code>true</code> iff ... - */ - def containedIn1(m: MetaData): Boolean = - m != null && (m.equals1(this) || containedIn1(m.next)) - /** returns a copy of this MetaData item with next field set to argument. * * @param next ... @@ -143,22 +132,20 @@ abstract class MetaData extends Iterable[MetaData] def isPrefixed: Boolean - /** deep equals method - XXX */ - override def equals(that: Any) = that match { - case m: MetaData => - (this.length == m.length) && - (this.hashCode == m.hashCode) && - (this forall (_ containedIn1 m)) + override def canEqual(other: Any) = other match { + case _: MetaData => true + case _ => false + } + override def strict_==(other: Equality) = other match { + case m: MetaData => this.toSet == m.toSet case _ => false } + def basisForHashCode: Seq[Any] = List(this.toSet) /** Returns an iterator on attributes */ - def iterator: Iterator[MetaData] = Iterator.iterate(this)(_.next) takeWhile (_ != Null) + def iterator: Iterator[MetaData] = Iterator.single(this) ++ next.iterator override def size: Int = 1 + iterator.length - /** shallow equals method */ - def equals1(that: MetaData): Boolean - /** filters this sequence of meta data */ override def filter(f: MetaData => Boolean): MetaData = if (f(this)) copy(next filter f) @@ -170,8 +157,18 @@ abstract class MetaData extends Iterable[MetaData] /** returns value of this MetaData item */ def value: Seq[Node] - /** maps this sequence of meta data */ - def map(f: MetaData => Text): List[Text] = (iterator map f).toList + /** Returns a String containing "prefix:key" if the first key is + * prefixed, and "key" otherwise. + */ + def prefixedKey = this match { + case x: Attribute if x.isPrefixed => x.pre + ":" + key + case _ => key + } + + /** Returns a Map containing the attributes stored as key/value pairs. + */ + def asAttrMap: Map[String, String] = + iterator map (x => (x.prefixedKey, x.value.text)) toMap /** returns Null or the next MetaData item */ def next: MetaData @@ -198,8 +195,6 @@ abstract class MetaData extends Iterable[MetaData] final def get(uri: String, scope: NamespaceBinding, key: String): Option[Seq[Node]] = Option(apply(uri, scope, key)) - override def hashCode(): Int - def toString1(): String = sbToString(toString1) // appends string representations of single attribute to StringBuilder diff --git a/src/library/scala/xml/NamespaceBinding.scala b/src/library/scala/xml/NamespaceBinding.scala index 7381f0129b..47ca8fed87 100644 --- a/src/library/scala/xml/NamespaceBinding.scala +++ b/src/library/scala/xml/NamespaceBinding.scala @@ -12,7 +12,7 @@ package scala.xml import Utility.sbToString -import collection.mutable.StringBuilder + /** The class <code>NamespaceBinding</code> represents namespace bindings * and scopes. The binding for the default namespace is treated as a null @@ -23,7 +23,7 @@ import collection.mutable.StringBuilder * @version 1.0 */ @SerialVersionUID(0 - 2518644165573446725L) -case class NamespaceBinding(prefix: String, uri: String, parent: NamespaceBinding) extends AnyRef +case class NamespaceBinding(prefix: String, uri: String, parent: NamespaceBinding) extends AnyRef with Equality { if (prefix == "") throw new IllegalArgumentException("zero length prefix not allowed") @@ -41,6 +41,15 @@ case class NamespaceBinding(prefix: String, uri: String, parent: NamespaceBindin if (_uri == uri) prefix else parent getPrefix _uri override def toString(): String = sbToString(buildString(_, TopScope)) + override def canEqual(other: Any) = other match { + case _: NamespaceBinding => true + case _ => false + } + override def strict_==(other: Equality) = other match { + case x: NamespaceBinding => (prefix == x.prefix) && (uri == x.uri) && (parent == x.parent) + case _ => false + } + def basisForHashCode: Seq[Any] = List(prefix, uri, parent) def buildString(stop: NamespaceBinding): String = sbToString(buildString(_, stop)) def buildString(sb: StringBuilder, stop: NamespaceBinding): Unit = { diff --git a/src/library/scala/xml/Node.scala b/src/library/scala/xml/Node.scala index f206140fd4..5117bb9282 100644 --- a/src/library/scala/xml/Node.scala +++ b/src/library/scala/xml/Node.scala @@ -8,13 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq -import collection.immutable.{List, Nil} -import collection.mutable.StringBuilder - /** * This object provides methods ... * @@ -22,7 +17,6 @@ import collection.mutable.StringBuilder * @version 1.0 */ object Node { - /** the constant empty attribute sequence */ final def NoAttributes: MetaData = Null @@ -30,7 +24,6 @@ object Node { val EmptyNamespace = "" def unapplySeq(n: Node) = Some((n.label, n.attributes, n.child)) - } /** @@ -116,6 +109,10 @@ abstract class Node extends NodeSeq { */ def child: Seq[Node] + /** Children which do not stringify to "" (needed for equality) + */ + def nonEmptyChildren: Seq[Node] = child filterNot (_.toString == "") + /** * Descendant axis (all descendants of this node, not including node itself) * includes all text nodes, element nodes, comments and processing instructions. @@ -129,41 +126,24 @@ abstract class Node extends NodeSeq { */ def descendant_or_self: List[Node] = this :: descendant - /** - * Returns true if x is structurally equal to this node. Compares prefix, - * label, attributes and children. - * - * @param x ... - * @return <code>true</code> if .. - */ - override def equals(x: Any): Boolean = x match { - case g: Group => false - case that: Node => - this.prefix == that.prefix && - this.label == that.label && - this.attributes == that.attributes && - this.scope == that.scope && - equalChildren(that) + override def canEqual(other: Any) = other match { + case x: Group => false + case x: Node => true case _ => false } - - // children comparison has to be done carefully - see bug #1773. - // It would conceivably be a better idea for a scala block which - // generates the empty string not to generate a child rather than - // our having to filter it later, but that approach would be more - // delicate to implement. - private def equalChildren(that: Node) = { - def noEmpties(xs: Seq[Node]) = xs filter (_.toString() != "") - noEmpties(this.child) sameElements noEmpties(that.child) + override def basisForHashCode: Seq[Any] = prefix :: label :: attributes :: nonEmptyChildren.toList + override def strict_==(other: Equality) = other match { + case _: Group => false + case x: Node => + (prefix == x.prefix) && + (label == x.label) && + (attributes == x.attributes) && + // (scope == x.scope) // note - original code didn't compare scopes so I left it as is. + (nonEmptyChildren sameElements x.nonEmptyChildren) + case _ => + false } - /** <p> - * Returns a hashcode. - * </p> - */ - override def hashCode(): Int = - Utility.hashCode(prefix, label, attributes.hashCode(), scope.hashCode(), child) - // implementations of NodeSeq methods /** @@ -213,9 +193,10 @@ abstract class Node extends NodeSeq { * Martin to Burak: to do: if you make this method abstract, the compiler will now * complain if there's no implementation in a subclass. Is this what we want? Note that * this would break doc/DocGenator and doc/ModelToXML, with an error message like: -doc\DocGenerator.scala:1219: error: object creation impossible, since there is a deferred declaration of method text in class Node of type => String which is not implemented in a subclass - new SpecialNode { - ^ - */ + * {{{ + * doc\DocGenerator.scala:1219: error: object creation impossible, since there is a deferred declaration of method text in class Node of type => String which is not implemented in a subclass + * new SpecialNode { + * ^ + * }}} */ override def text: String = super.text } diff --git a/src/library/scala/xml/NodeBuffer.scala b/src/library/scala/xml/NodeBuffer.scala index 49efe0a5ca..2cf999e8a4 100644 --- a/src/library/scala/xml/NodeBuffer.scala +++ b/src/library/scala/xml/NodeBuffer.scala @@ -8,11 +8,8 @@ // $Id$ - package scala.xml -import collection.{Iterator, Seq, Iterable} - /** * <p> * This class acts as a Buffer for nodes. If it is used as a sequence diff --git a/src/library/scala/xml/NodeSeq.scala b/src/library/scala/xml/NodeSeq.scala index 17ea9228f6..3b56ba25e4 100644 --- a/src/library/scala/xml/NodeSeq.scala +++ b/src/library/scala/xml/NodeSeq.scala @@ -11,11 +11,9 @@ package scala.xml -import collection.immutable -import collection.immutable.{List, Nil, ::} -import collection.{Seq, SeqLike} -import collection.mutable.{Builder, ListBuffer} -import collection.generic.CanBuildFrom +import collection.{ mutable, immutable, generic, SeqLike } +import mutable.{ Builder, ListBuffer } +import generic.{ CanBuildFrom } /** This object ... * @@ -43,7 +41,7 @@ object NodeSeq { * @author Burak Emir * @version 1.0 */ -abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] { +abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] with Equality { import NodeSeq.seqToNodeSeq // import view magic for NodeSeq wrappers /** Creates a list buffer as builder for this class */ @@ -56,12 +54,23 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] { def apply(i: Int): Node = theSeq(i) def apply(f: Node => Boolean): NodeSeq = filter(f) - /** structural equality (XXX - this shatters any hope of hashCode equality) */ - override def equals(x: Any): Boolean = x match { - case z:Node => (length == 1) && z == apply(0) - case z:Seq[_] => sameElements(z) - case z:String => text == z - case _ => false + def xml_sameElements[A](that: Iterable[A]): Boolean = { + val these = this.iterator + val those = that.iterator + while (these.hasNext && those.hasNext) + if (these.next xml_!= those.next) + return false + + !these.hasNext && !those.hasNext + } + def basisForHashCode: Seq[Any] = theSeq + override def canEqual(other: Any) = other match { + case _: NodeSeq => true + case _ => false + } + override def strict_==(other: Equality) = other match { + case x: NodeSeq => (length == x.length) && (theSeq sameElements x.theSeq) + case _ => false } /** Projection function. Similar to XPath, use <code>this \ "foo"</code> @@ -80,8 +89,8 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] { * @return ... */ def \(that: String): NodeSeq = { + def fail = throw new IllegalArgumentException(that) def atResult = { - def fail = throw new IllegalArgumentException(that) lazy val y = this(0) val attr = if (that.length == 1) fail @@ -92,7 +101,7 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] { if (uri == "" || key == "") fail else y.attribute(uri, key) } - else y.attribute(that.substring(1)) + else y.attribute(that drop 1) attr match { case Some(x) => Group(x) @@ -104,6 +113,7 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] { NodeSeq fromSeq (this flatMap (_.child) filter cond) that match { + case "" => fail case "_" => makeSeq(!_.isAtom) case _ if (that(0) == '@' && this.length == 1) => atResult case _ => makeSeq(_.label == that) diff --git a/src/library/scala/xml/Null.scala b/src/library/scala/xml/Null.scala index a3246d4b57..d6f06fc3cd 100644 --- a/src/library/scala/xml/Null.scala +++ b/src/library/scala/xml/Null.scala @@ -12,70 +12,49 @@ package scala.xml import Utility.{ isNameStart } -import collection.Iterator -import collection.immutable.{Nil, List} -import collection.mutable.StringBuilder +/** Essentially, every method in here is a dummy, returning Zero[T]. + * It provides a backstop for the unusual collection defined by MetaData, + * sort of a linked list of tails. + */ case object Null extends MetaData { - - /** appends given MetaData items to this MetaData list */ - override def append(m: MetaData, scope: NamespaceBinding = TopScope): MetaData = m - - override def containedIn1(m: MetaData): Boolean = false - - /** returns its argument */ - def copy(next: MetaData) = next - override def iterator = Iterator.empty - + override def append(m: MetaData, scope: NamespaceBinding = TopScope): MetaData = m override def filter(f: MetaData => Boolean): MetaData = this + def copy(next: MetaData) = next def getNamespace(owner: Node) = null - final override def hasNext = false + override def hasNext = false def next = null def key = null def value = null - - final override def length = 0 - final override def length(i: Int) = i - def isPrefixed = false - /** deep equals method - XXX */ - override def equals(that: Any) = that match { - case m: MetaData => m.length == 0 - case _ => false - } + override def length = 0 + override def length(i: Int) = i - def equals1(that:MetaData) = that.length == 0 - - override def map(f: MetaData => Text): List[Text] = Nil + override def strict_==(other: Equality) = other match { + case x: MetaData => x.length == 0 + case _ => false + } + override def basisForHashCode: Seq[Any] = Nil - /** null */ + def apply(namespace: String, scope: NamespaceBinding, key: String) = null def apply(key: String) = { - if(!isNameStart(key charAt 0)) + if (!isNameStart(key.head)) throw new IllegalArgumentException("not a valid attribute name '"+key+"', so can never match !") + null } - /** gets value of qualified (prefixed) attribute with given key */ - def apply(namespace: String, scope: NamespaceBinding, key: String) = null - - override def hashCode(): Int = 0 - + def toString1(sb: StringBuilder) = () override def toString1(): String = "" - - //appends string representations of single attribute to StringBuilder - def toString1(sb:StringBuilder) = {} - override def toString(): String = "" override def buildString(sb: StringBuilder): StringBuilder = sb - override def wellformed(scope: NamespaceBinding) = true def remove(key: String) = this - def remove(namespace: String, scope: NamespaceBinding, key: String) = this } diff --git a/src/library/scala/xml/PCData.scala b/src/library/scala/xml/PCData.scala index 5cf4bda070..fa44591496 100644 --- a/src/library/scala/xml/PCData.scala +++ b/src/library/scala/xml/PCData.scala @@ -7,16 +7,9 @@ package scala.xml * and is to be preserved as CDATA section in the output. */ case class PCData(_data: String) extends Atom[String](_data) { - /* The following code is a derivative work of scala.xml.Text */ if (null == data) throw new IllegalArgumentException("tried to construct PCData with null") - final override def equals(x: Any) = x match { - case s: String => s.equals(data) - case s: Atom[_] => data == s.data - case _ => false - } - /** Returns text, with some characters escaped according to the XML * specification. * diff --git a/src/library/scala/xml/PrefixedAttribute.scala b/src/library/scala/xml/PrefixedAttribute.scala index a465e61ba3..d7c04ab6ad 100644 --- a/src/library/scala/xml/PrefixedAttribute.scala +++ b/src/library/scala/xml/PrefixedAttribute.scala @@ -8,13 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq -import collection.mutable.StringBuilder - - /** prefixed attributes always have a non-null namespace. * * @param pre ... @@ -36,24 +31,12 @@ extends Attribute def this(pre: String, key: String, value: String, next: MetaData) = this(pre, key, Text(value), next) - /* - // the problem here is the fact that we cannot remove the proper attribute from - // next, and thus cannot guarantee that hashcodes are computed properly - def this(pre: String, key: String, value: scala.AllRef, next: MetaData) = - throw new UnsupportedOperationException("can't construct prefixed nil attributes") - */ - /** Returns a copy of this unprefixed attribute with the given * next field. */ def copy(next: MetaData) = new PrefixedAttribute(pre, key, value, next) - def equals1(m: MetaData) = - (m.isPrefixed && - (m.asInstanceOf[PrefixedAttribute].pre == pre) && - (m.key == key) && (m.value sameElements value)) - def getNamespace(owner: Node) = owner.getNamespace(pre) @@ -68,41 +51,8 @@ extends Attribute else next(namespace, scope, key) } - - /** returns true */ - final def isPrefixed = true - - /** returns the hashcode. - */ - override def hashCode() = - pre.hashCode() * 41 + key.hashCode() * 7 + next.hashCode() - - - /** appends string representation of only this attribute to stringbuffer */ - def toString1(sb:StringBuilder): Unit = if(value ne null) { - sb.append(pre) - sb.append(':') - sb.append(key) - sb.append('=') - val sb2 = new StringBuilder() - Utility.sequenceToXML(value, TopScope, sb2, true) - Utility.appendQuoted(sb2.toString(), sb) - } - - def wellformed(scope: NamespaceBinding): Boolean = - (null == next(scope.getURI(pre), scope, key) && - next.wellformed(scope)) - - def remove(key: String) = - copy(next.remove(key)) - - def remove(namespace: String, scope: NamespaceBinding, key: String): MetaData = - if (key == this.key && scope.getURI(pre) == namespace) - next - else - next.remove(namespace, scope, key) - } + object PrefixedAttribute { def unapply(x: PrefixedAttribute) = Some(x.pre, x.key, x.value, x.next) } diff --git a/src/library/scala/xml/PrettyPrinter.scala b/src/library/scala/xml/PrettyPrinter.scala index 1fb922eb95..77199ca367 100644 --- a/src/library/scala/xml/PrettyPrinter.scala +++ b/src/library/scala/xml/PrettyPrinter.scala @@ -8,10 +8,8 @@ // $Id$ - package scala.xml -import scala.collection.Map import Utility.sbToString /** Class for pretty printing. After instantiating, you can use the @@ -23,7 +21,7 @@ import Utility.sbToString * @version 1.0 * * @param width the width to fit the output into - * @step indentation + * @param step indentation */ class PrettyPrinter(width: Int, step: Int) { @@ -39,7 +37,6 @@ class PrettyPrinter(width: Int, step: Int) { protected var items: List[Item] = Nil protected var cur = 0 - //protected var pmap:Map[String,String] = _ protected def reset() = { cur = 0 diff --git a/src/library/scala/xml/ProcInstr.scala b/src/library/scala/xml/ProcInstr.scala index 5a4e67e647..051fd499f4 100644 --- a/src/library/scala/xml/ProcInstr.scala +++ b/src/library/scala/xml/ProcInstr.scala @@ -9,7 +9,6 @@ // $Id$ package scala.xml -import collection.mutable.StringBuilder /** an XML node for processing instructions (PI) * diff --git a/src/library/scala/xml/SpecialNode.scala b/src/library/scala/xml/SpecialNode.scala index d40d829c4b..1688cd1e15 100644 --- a/src/library/scala/xml/SpecialNode.scala +++ b/src/library/scala/xml/SpecialNode.scala @@ -8,12 +8,8 @@ // $Id$ - package scala.xml -import collection.immutable.{List, Nil, ::} -import collection.mutable.StringBuilder - /** <p> * <code>SpecialNode</code> is a special XML node which * represents either text (PCDATA), a comment, a PI, or an entity ref. diff --git a/src/library/scala/xml/Text.scala b/src/library/scala/xml/Text.scala index 3090883bb8..5f0b010c9f 100644 --- a/src/library/scala/xml/Text.scala +++ b/src/library/scala/xml/Text.scala @@ -8,11 +8,8 @@ // $Id$ - package scala.xml -import collection.mutable.StringBuilder - // XXX This attempt to make Text not a case class revealed a bug in the pattern // matcher (see ticket #2883) so I've put the case back. (It was/is desirable that // it not be a case class because it is using the antipattern of passing constructor @@ -42,13 +39,6 @@ case class Text(_data: String) extends Atom[String](_data) if (_data == null) throw new IllegalArgumentException("tried to construct Text with null") - /** XXX More hashCode flailing. */ - final override def equals(x: Any) = x match { - case s:String => s == data - case s:Atom[_] => data == s.data - case _ => false - } - /** Returns text, with some characters escaped according to the XML * specification. * diff --git a/src/library/scala/xml/TextBuffer.scala b/src/library/scala/xml/TextBuffer.scala index 17c40aad2f..84c6c24146 100644 --- a/src/library/scala/xml/TextBuffer.scala +++ b/src/library/scala/xml/TextBuffer.scala @@ -8,12 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq -import collection.mutable.StringBuilder -import collection.immutable.{List, Nil, ::} import Utility.isSpace object TextBuffer { diff --git a/src/library/scala/xml/TopScope.scala b/src/library/scala/xml/TopScope.scala index c638b80b2d..8b3c1383c9 100644 --- a/src/library/scala/xml/TopScope.scala +++ b/src/library/scala/xml/TopScope.scala @@ -10,8 +10,6 @@ package scala.xml -import collection.mutable.StringBuilder - /** top level namespace scope. only contains the predefined binding * for the "xml" prefix which is bound to * "http://www.w3.org/XML/1998/namespace" diff --git a/src/library/scala/xml/Unparsed.scala b/src/library/scala/xml/Unparsed.scala index a570b83fb5..d3c63172e8 100644 --- a/src/library/scala/xml/Unparsed.scala +++ b/src/library/scala/xml/Unparsed.scala @@ -22,13 +22,6 @@ class Unparsed(data: String) extends Atom[String](data) if (null == data) throw new IllegalArgumentException("tried to construct Unparsed with null") - /** XXX another hashCode fail */ - final override def equals(x: Any) = x match { - case s:String => s == data - case s:Atom[_] => data == s.data - case _ => false - } - /** returns text, with some characters escaped according to XML spec */ override def buildString(sb: StringBuilder) = sb append data } diff --git a/src/library/scala/xml/UnprefixedAttribute.scala b/src/library/scala/xml/UnprefixedAttribute.scala index 283cc3a1d0..a8720f13e1 100644 --- a/src/library/scala/xml/UnprefixedAttribute.scala +++ b/src/library/scala/xml/UnprefixedAttribute.scala @@ -8,13 +8,8 @@ // $Id$ - package scala.xml -import collection.Seq -import collection.mutable.StringBuilder - - /** Unprefixed attributes have the null namespace, and no prefix field * * @author Burak Emir @@ -25,6 +20,7 @@ class UnprefixedAttribute( next1: MetaData) extends Attribute { + final val pre = null val next = if (value ne null) next1 else next1.remove(key) /** same as this(key, Text(value), next) */ @@ -38,9 +34,6 @@ extends Attribute /** returns a copy of this unprefixed attribute with the given next field*/ def copy(next: MetaData) = new UnprefixedAttribute(key, value, next) - def equals1(m: MetaData) = - !m.isPrefixed && (m.key == key) && (m.value sameElements value) - final def getNamespace(owner: Node): String = null /** @@ -62,33 +55,6 @@ extends Attribute */ def apply(namespace: String, scope: NamespaceBinding, key: String): Seq[Node] = next(namespace, scope, key) - - override def hashCode() = - key.hashCode() * 7 + { if(value ne null) value.hashCode() * 53 else 0 } + next.hashCode() - - final def isPrefixed = false - - /** appends string representation of only this attribute to stringbuffer. - * - * @param sb .. - */ - def toString1(sb: StringBuilder): Unit = if (value ne null) { - sb.append(key) - sb.append('=') - val sb2 = new StringBuilder() - Utility.sequenceToXML(value, TopScope, sb2, true) - Utility.appendQuoted(sb2.toString(), sb) - } - - def wellformed(scope: NamespaceBinding): Boolean = - (null == next(null, scope, key)) && next.wellformed(scope) - - def remove(key: String) = - if (this.key == key) next else copy(next.remove(key)) - - def remove(namespace: String, scope: NamespaceBinding, key: String): MetaData = - next.remove(namespace, scope, key) - } object UnprefixedAttribute { def unapply(x: UnprefixedAttribute) = Some(x.key, x.value, x.next) diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 1cfe9c79c9..48a23dc389 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -11,8 +11,8 @@ package scala.xml -import collection.mutable.{Set, HashSet, StringBuilder} -import collection.Seq +import collection.mutable +import mutable.{ Set, HashSet } import parsing.XhtmlEntities /** @@ -84,7 +84,7 @@ object Utility extends AnyRef with parsing.TokenTests object Escapes { /** For reasons unclear escape and unescape are a long ways from - being logical inverses. */ + * being logical inverses. */ val pairs = Map( "lt" -> '<', "gt" -> '>', @@ -106,11 +106,29 @@ object Utility extends AnyRef with parsing.TokenTests * @param s ... * @return ... */ - final def escape(text: String, s: StringBuilder): StringBuilder = - text.foldLeft(s)((s, c) => escMap.get(c) match { - case Some(str) => s append str - case None => s append c - }) + final def escape(text: String, s: StringBuilder): StringBuilder = { + // Implemented per XML spec: + // http://www.w3.org/International/questions/qa-controls + // imperative code 3x-4x faster than current implementation + // dpp (David Pollak) 2010/02/03 + val len = text.length + var pos = 0 + while (pos < len) { + text.charAt(pos) match { + case '<' => s.append("<") + case '>' => s.append(">") + case '&' => s.append("&") + case '"' => s.append(""") + case '\n' => s.append('\n') + case '\r' => s.append('\r') + case '\t' => s.append('\t') + case c => if (c >= ' ') s.append(c) + } + + pos += 1 + } + s + } /** * Appends unescaped string to <code>s</code>, amp becomes & @@ -131,7 +149,7 @@ object Utility extends AnyRef with parsing.TokenTests * @param nodes ... * @return ... */ - def collectNamespaces(nodes: Seq[Node]): Set[String] = + def collectNamespaces(nodes: Seq[Node]): mutable.Set[String] = nodes.foldLeft(new HashSet[String]) { (set, x) => collectNamespaces(x, set) ; set } /** @@ -140,7 +158,7 @@ object Utility extends AnyRef with parsing.TokenTests * @param n ... * @param set ... */ - def collectNamespaces(n: Node, set: Set[String]) { + def collectNamespaces(n: Node, set: mutable.Set[String]) { if (n.doCollectNamespaces) { set += n.namespace for (a <- n.attributes) a match { diff --git a/src/library/scala/xml/XML.scala b/src/library/scala/xml/XML.scala index 1e85d4ae06..dd85b58e50 100644 --- a/src/library/scala/xml/XML.scala +++ b/src/library/scala/xml/XML.scala @@ -11,12 +11,10 @@ package scala.xml -import scala.xml.parsing.NoBindingFactoryAdapter -import scala.xml.factory.XMLLoader -import org.xml.sax.InputSource -import javax.xml.parsers.{ SAXParser, SAXParserFactory } -import java.io.{File, FileDescriptor, FileInputStream, FileOutputStream} -import java.io.{InputStream, Reader, StringReader, Writer} +import parsing.NoBindingFactoryAdapter +import factory.XMLLoader +import java.io.{ File, FileDescriptor, FileInputStream, FileOutputStream } +import java.io.{ InputStream, Reader, StringReader, Writer } import java.nio.channels.Channels import scala.util.control.Exception.ultimately @@ -56,11 +54,11 @@ object XML extends XMLLoader[Elem] @deprecated("Use save() instead") final def saveFull(filename: String, node: Node, xmlDecl: Boolean, doctype: dtd.DocType): Unit = - saveFull(filename, node, encoding, xmlDecl, doctype) + save(filename, node, encoding, xmlDecl, doctype) @deprecated("Use save() instead") final def saveFull(filename: String, node: Node, enc: String, xmlDecl: Boolean, doctype: dtd.DocType): Unit = - saveFull(filename, node, enc, xmlDecl, doctype) + save(filename, node, enc, xmlDecl, doctype) /** Saves a node to a file with given filename using given encoding * optionally with xmldecl and doctype declaration. @@ -82,7 +80,7 @@ object XML extends XMLLoader[Elem] val fos = new FileOutputStream(filename) val w = Channels.newWriter(fos.getChannel(), enc) - ultimately({ w.close() ; fos.close() })( + ultimately(w.close())( write(w, node, enc, xmlDecl, doctype) ) } diff --git a/src/library/scala/xml/dtd/ContentModel.scala b/src/library/scala/xml/dtd/ContentModel.scala index d5d4b95cce..772d8ec599 100644 --- a/src/library/scala/xml/dtd/ContentModel.scala +++ b/src/library/scala/xml/dtd/ContentModel.scala @@ -13,10 +13,7 @@ package scala.xml package dtd import util.regexp.WordExp -import util.automata.{DetWordAutom, SubsetConstruction, WordBerrySethi} -import collection.mutable.{HashSet, StringBuilder} -import collection.immutable.{List, Nil} -import collection.Seq +import util.automata._ import Utility.sbToString import PartialFunction._ diff --git a/src/library/scala/xml/dtd/ContentModelParser.scala b/src/library/scala/xml/dtd/ContentModelParser.scala index c260a9fc46..2b0df3f6a5 100644 --- a/src/library/scala/xml/dtd/ContentModelParser.scala +++ b/src/library/scala/xml/dtd/ContentModelParser.scala @@ -8,12 +8,9 @@ // $Id$ - package scala.xml package dtd -import collection.immutable.List - /** Parser for regexps (content models in DTD element declarations) */ object ContentModelParser extends Scanner { // a bit too permissive concerning #PCDATA diff --git a/src/library/scala/xml/dtd/DTD.scala b/src/library/scala/xml/dtd/DTD.scala index 14c16f8489..0fde1188f3 100644 --- a/src/library/scala/xml/dtd/DTD.scala +++ b/src/library/scala/xml/dtd/DTD.scala @@ -8,31 +8,25 @@ // $Id$ - package scala.xml package dtd -import scala.collection.mutable.{HashMap, Map} +import collection.mutable +import mutable.HashMap /** A document type declaration. * * @author Burak Emir */ abstract class DTD { - - var externalID: ExternalID = null - - def notations: Seq[NotationDecl] = Nil - + var externalID: ExternalID = null + var decls: List[Decl] = Nil + def notations: Seq[NotationDecl] = Nil def unparsedEntities: Seq[EntityDecl] = Nil - var elem: Map[String, ElemDecl] = new HashMap[String, ElemDecl]() - - var attr: Map[String, AttListDecl] = new HashMap[String, AttListDecl]() - - var ent: Map[String, EntityDecl] = new HashMap[String, EntityDecl]() - - var decls: List[Decl] = Nil + var elem: mutable.Map[String, ElemDecl] = new HashMap[String, ElemDecl]() + var attr: mutable.Map[String, AttListDecl] = new HashMap[String, AttListDecl]() + var ent: mutable.Map[String, EntityDecl] = new HashMap[String, EntityDecl]() override def toString() = "DTD [\n%s%s]".format( diff --git a/src/library/scala/xml/dtd/Decl.scala b/src/library/scala/xml/dtd/Decl.scala index 25ee30b356..2ac3d42a67 100644 --- a/src/library/scala/xml/dtd/Decl.scala +++ b/src/library/scala/xml/dtd/Decl.scala @@ -8,14 +8,10 @@ // $Id$ - package scala.xml package dtd import Utility.sbToString -import collection.immutable.List -import collection.mutable.StringBuilder - abstract class Decl @@ -114,7 +110,7 @@ case class IntDef(value:String) extends EntityDef { val n = tmp.substring(ix, iz); if( !Utility.isName( n )) - throw new IllegalArgumentException("interal entity def: \""+n+"\" must be an XML Name"); + throw new IllegalArgumentException("internal entity def: \""+n+"\" must be an XML Name"); tmp = tmp.substring(iz+1, tmp.length()); ix = tmp.indexOf('%'); diff --git a/src/library/scala/xml/dtd/DocType.scala b/src/library/scala/xml/dtd/DocType.scala index dab1d9ff6b..7da38b3e73 100644 --- a/src/library/scala/xml/dtd/DocType.scala +++ b/src/library/scala/xml/dtd/DocType.scala @@ -8,12 +8,9 @@ // $Id$ - package scala.xml package dtd -import collection.Seq - /** An XML node for document type declaration. * * @author Burak Emir diff --git a/src/library/scala/xml/dtd/ElementValidator.scala b/src/library/scala/xml/dtd/ElementValidator.scala index cc37e2b527..9ebed8d87c 100644 --- a/src/library/scala/xml/dtd/ElementValidator.scala +++ b/src/library/scala/xml/dtd/ElementValidator.scala @@ -95,7 +95,7 @@ class ElementValidator() extends Function1[Node,Boolean] { } /** check children, return true if conform to content model - * @pre contentModel != null + * @note contentModel != null */ def check(nodes: Seq[Node]): Boolean = contentModel match { case ANY => true @@ -120,7 +120,7 @@ class ElementValidator() extends Function1[Node,Boolean] { } /** applies various validations - accumulates error messages in exc - * @todo: fail on first error, ignore other errors (rearranging conditions) + * @todo fail on first error, ignore other errors (rearranging conditions) */ def apply(n: Node): Boolean = //- ? check children diff --git a/src/library/scala/xml/dtd/ExternalID.scala b/src/library/scala/xml/dtd/ExternalID.scala index 784273083a..b0d311e54a 100644 --- a/src/library/scala/xml/dtd/ExternalID.scala +++ b/src/library/scala/xml/dtd/ExternalID.scala @@ -8,14 +8,9 @@ // $Id$ - package scala.xml package dtd -import collection.immutable.{List, Nil} -import collection.mutable.StringBuilder - - /** an ExternalIDs - either PublicID or SystemID * * @author Burak Emir diff --git a/src/library/scala/xml/dtd/Scanner.scala b/src/library/scala/xml/dtd/Scanner.scala index 1a45a186a0..7b3e2acfe0 100644 --- a/src/library/scala/xml/dtd/Scanner.scala +++ b/src/library/scala/xml/dtd/Scanner.scala @@ -8,13 +8,9 @@ // $Id$ - package scala.xml package dtd -import collection.{Seq, Iterator} -import collection.immutable.{List, Nil} - /** Scanner for regexps (content models in DTD element declarations) * todo: cleanup */ diff --git a/src/library/scala/xml/factory/Binder.scala b/src/library/scala/xml/factory/Binder.scala index caad009b9b..3996ef2d36 100644 --- a/src/library/scala/xml/factory/Binder.scala +++ b/src/library/scala/xml/factory/Binder.scala @@ -12,7 +12,7 @@ package scala.xml package factory -import scala.xml.parsing.ValidatingMarkupHandler +import parsing.ValidatingMarkupHandler /** * @author Burak Emir diff --git a/src/library/scala/xml/factory/NodeFactory.scala b/src/library/scala/xml/factory/NodeFactory.scala index 45dac6ccda..2dd52242db 100644 --- a/src/library/scala/xml/factory/NodeFactory.scala +++ b/src/library/scala/xml/factory/NodeFactory.scala @@ -12,11 +12,7 @@ package scala.xml package factory import parsing.{ FactoryAdapter, NoBindingFactoryAdapter } -import collection.Seq -import collection.immutable.{List, Nil} -import org.xml.sax.InputSource import java.io.{ InputStream, Reader, StringReader, File, FileDescriptor, FileInputStream } -import javax.xml.parsers.{ SAXParser, SAXParserFactory } trait NodeFactory[A <: Node] { diff --git a/src/library/scala/xml/factory/XMLLoader.scala b/src/library/scala/xml/factory/XMLLoader.scala index a1bca21b40..8bb0cf4188 100644 --- a/src/library/scala/xml/factory/XMLLoader.scala +++ b/src/library/scala/xml/factory/XMLLoader.scala @@ -11,11 +11,9 @@ package scala.xml package factory +import javax.xml.parsers.SAXParserFactory import parsing.{ FactoryAdapter, NoBindingFactoryAdapter } -import org.xml.sax.InputSource import java.io.{ InputStream, Reader, StringReader, File, FileDescriptor, FileInputStream } -import javax.xml.parsers.{ SAXParser, SAXParserFactory } -import java.net.URL /** Presents collection of XML loading methods which use the parser * created by "def parser". diff --git a/src/library/scala/xml/include/XIncludeException.scala b/src/library/scala/xml/include/XIncludeException.scala index 26c66f9b1d..a671f32dca 100644 --- a/src/library/scala/xml/include/XIncludeException.scala +++ b/src/library/scala/xml/include/XIncludeException.scala @@ -43,7 +43,7 @@ class XIncludeException(message: String) extends Exception(message) { * This method allows you to store the original exception. * * @param nestedException the underlying exception which - caused the XIncludeException to be thrown + * caused the XIncludeException to be thrown */ def setRootCause(nestedException: Throwable ) { this.rootCause = nestedException diff --git a/src/library/scala/xml/include/sax/Main.scala b/src/library/scala/xml/include/sax/Main.scala index e7e986e0f8..60031b4b6a 100644 --- a/src/library/scala/xml/include/sax/Main.scala +++ b/src/library/scala/xml/include/sax/Main.scala @@ -13,11 +13,10 @@ package include.sax import scala.xml.include._ import scala.util.control.Exception.{ catching, ignoring } -import org.xml.sax.{ SAXException, SAXParseException, EntityResolver, XMLReader } +import org.xml.sax.XMLReader import org.xml.sax.helpers.XMLReaderFactory object Main { - private val xercesClass = "org.apache.xerces.parsers.SAXParser" private val namespacePrefixes = "http://xml.org/sax/features/namespace-prefixes" private val lexicalHandler = "http://xml.org/sax/properties/lexical-handler" @@ -27,7 +26,7 @@ object Main { * </p> * * @param args contains the URLs and/or filenames - * of the documents to be procesed. + * of the documents to be processed. */ def main(args: Array[String]) { def saxe[T](body: => T) = catching[T](classOf[SAXException]) opt body @@ -35,7 +34,7 @@ object Main { val parser: XMLReader = saxe[XMLReader](XMLReaderFactory.createXMLReader()) getOrElse ( - saxe[XMLReader](XMLReaderFactory.createXMLReader(xercesClass)) getOrElse ( + saxe[XMLReader](XMLReaderFactory.createXMLReader(XercesClassName)) getOrElse ( return error("Could not find an XML parser") ) ) diff --git a/src/library/scala/xml/include/sax/XIncludeFilter.scala b/src/library/scala/xml/include/sax/XIncludeFilter.scala index b469086e73..6e64fa9aa5 100644 --- a/src/library/scala/xml/include/sax/XIncludeFilter.scala +++ b/src/library/scala/xml/include/sax/XIncludeFilter.scala @@ -12,11 +12,10 @@ package scala.xml package include.sax import scala.xml.include._ -import org.xml.sax.{ Attributes, SAXException, XMLReader, EntityResolver, Locator } +import org.xml.sax.{ Attributes, XMLReader, Locator } import org.xml.sax.helpers.{ XMLReaderFactory, XMLFilterImpl, NamespaceSupport, AttributesImpl } -import java.net.{ URL, URLConnection, MalformedURLException } -import java.io.{ UnsupportedEncodingException, IOException, InputStream, BufferedInputStream, InputStreamReader } +import java.io.{ InputStream, BufferedInputStream, InputStreamReader } import java.util.Stack /** @@ -351,61 +350,49 @@ class XIncludeFilter extends XMLFilterImpl { be downloaded from the specified URL. */ private def includeXMLDocument(url: String) { - var source: URL = null - try { - val base = bases.peek().asInstanceOf[URL] - source = new URL(base, url) - } - catch { - case e:MalformedURLException => - val ex = new UnavailableResourceException("Unresolvable URL " + url - + getLocation()); - ex.setRootCause(e) - throw new SAXException("Unresolvable URL " + url + getLocation(), ex) - } + val source = + try new URL(bases.peek(), url) + catch { + case e: MalformedURLException => + val ex = new UnavailableResourceException("Unresolvable URL " + url + getLocation()) + ex setRootCause e + throw new SAXException("Unresolvable URL " + url + getLocation(), ex) + } try { - // make this more robust - var parser: XMLReader = null - try { - parser = XMLReaderFactory.createXMLReader() - } catch { - case e:SAXException => - try { - parser = XMLReaderFactory.createXMLReader( - "org.apache.xerces.parsers.SAXParser" - ); - } catch { - case e2: SAXException => - System.err.println("Could not find an XML parser") - } - } - if(parser != null) { - parser.setContentHandler(this) - val resolver = this.getEntityResolver() - if (resolver != null) parser.setEntityResolver(resolver); - // save old level and base - val previousLevel = level - this.level = 0 - if (bases.contains(source)) { - val e = new CircularIncludeException( - "Circular XInclude Reference to " + source + getLocation() - ); - throw new SAXException("Circular XInclude Reference", e) + val parser: XMLReader = + try XMLReaderFactory.createXMLReader() + catch { + case e: SAXException => + try XMLReaderFactory.createXMLReader(XercesClassName) + catch { case _: SAXException => return System.err.println("Could not find an XML parser") } } - bases.push(source) - atRoot = true - parser.parse(source.toExternalForm()) - // restore old level and base - this.level = previousLevel - bases.pop() - } + + parser setContentHandler this + val resolver = this.getEntityResolver() + if (resolver != null) + parser setEntityResolver resolver + + // save old level and base + val previousLevel = level + this.level = 0 + if (bases contains source) + throw new SAXException( + "Circular XInclude Reference", + new CircularIncludeException("Circular XInclude Reference to " + source + getLocation()) + ) + + bases push source + atRoot = true + parser parse source.toExternalForm() + + // restore old level and base + this.level = previousLevel + bases.pop() } catch { - case e:IOException => - throw new SAXException("Document not found: " - + source.toExternalForm() + getLocation(), e) + case e: IOException => + throw new SAXException("Document not found: " + source.toExternalForm() + getLocation(), e) } - } } diff --git a/src/library/scala/xml/include/sax/XIncluder.scala b/src/library/scala/xml/include/sax/XIncluder.scala index 3417dd78f0..bd9da10c59 100644 --- a/src/library/scala/xml/include/sax/XIncluder.scala +++ b/src/library/scala/xml/include/sax/XIncluder.scala @@ -10,22 +10,13 @@ package scala.xml package include.sax + import scala.xml.include._ +import collection.mutable.Stack -import org.xml.sax.SAXException -import org.xml.sax.SAXParseException -import org.xml.sax.ContentHandler -import org.xml.sax.EntityResolver -import org.xml.sax.helpers.XMLReaderFactory -import org.xml.sax.XMLReader -import org.xml.sax.Locator -import org.xml.sax.Attributes +import org.xml.sax.{ ContentHandler, XMLReader, Locator, Attributes } import org.xml.sax.ext.LexicalHandler - -import java.io.{File, IOException, OutputStream, OutputStreamWriter, - UnsupportedEncodingException, Writer} -import java.net.{MalformedURLException, URL} -import java.util.Stack +import java.io.{ File, OutputStream, OutputStreamWriter, Writer } /** XIncluder is a SAX <code>ContentHandler</code> * that writes its XML document onto an output stream after resolving @@ -35,8 +26,7 @@ import java.util.Stack * based on Eliotte Rusty Harold's SAXXIncluder * </p> */ -class XIncluder(outs:OutputStream, encoding:String) extends Object -with ContentHandler with LexicalHandler { +class XIncluder(outs: OutputStream, encoding: String) extends ContentHandler with LexicalHandler { var out = new OutputStreamWriter(outs, encoding) @@ -153,7 +143,7 @@ with ContentHandler with LexicalHandler { def startDTD(name: String, publicID: String, systemID: String) { inDTD = true // if this is the source document, output a DOCTYPE declaration - if (entities.size() == 0) { + if (entities.isEmpty) { var id = "" if (publicID != null) id = " PUBLIC \"" + publicID + "\" \"" + systemID + '"'; else if (systemID != null) id = " SYSTEM \"" + systemID + '"'; @@ -169,7 +159,7 @@ with ContentHandler with LexicalHandler { def endDTD() {} def startEntity(name: String) { - entities.push(name) + entities push name } def endEntity(name: String) { diff --git a/src/library/scala/xml/package.scala b/src/library/scala/xml/package.scala new file mode 100644 index 0000000000..33639ed978 --- /dev/null +++ b/src/library/scala/xml/package.scala @@ -0,0 +1,18 @@ +package scala + +package object xml { + val XercesClassName = "org.apache.xerces.parsers.SAXParser" + + type SAXException = org.xml.sax.SAXException + type SAXParseException = org.xml.sax.SAXParseException + type EntityResolver = org.xml.sax.EntityResolver + type InputSource = org.xml.sax.InputSource + + type SAXParser = javax.xml.parsers.SAXParser + + type IOException = java.io.IOException + type UnsupportedEncodingException = java.io.UnsupportedEncodingException + + type URL = java.net.URL + type MalformedURLException = java.net.MalformedURLException +}
\ No newline at end of file diff --git a/src/library/scala/xml/parsing/ConstructingParser.scala b/src/library/scala/xml/parsing/ConstructingParser.scala index f029fc745a..00f195e9fd 100644 --- a/src/library/scala/xml/parsing/ConstructingParser.scala +++ b/src/library/scala/xml/parsing/ConstructingParser.scala @@ -25,28 +25,27 @@ object ConstructingParser { } /** An xml parser. parses XML and invokes callback methods of a MarkupHandler. - * Don't forget to call next.ch on a freshly instantiated parser in order to - * initialize it. If you get the parser from the object method, initialization - * is already done for you. - * - *<pre> -object parseFromURL { - def main(args:Array[String]): Unit = { - val url = args(0); - val src = scala.io.Source.fromURL(url); - val cpa = scala.xml.parsing.ConstructingParser.fromSource(src, false); // fromSource initializes automatically - val doc = cpa.document(); - - // let's see what it is - val ppr = new scala.xml.PrettyPrinter(80,5); - val ele = doc.docElem; - Console.println("finished parsing"); - val out = ppr.format(ele); - Console.println(out); - } -} -</pre> - */ + * Don't forget to call next.ch on a freshly instantiated parser in order to + * initialize it. If you get the parser from the object method, initialization + * is already done for you. + * + * {{{ + * object parseFromURL { + * def main(args:Array[String]): Unit = { + * val url = args(0); + * val src = scala.io.Source.fromURL(url); + * val cpa = scala.xml.parsing.ConstructingParser.fromSource(src, false); // fromSource initializes automatically + * val doc = cpa.document(); + * + * // let's see what it is + * val ppr = new scala.xml.PrettyPrinter(80,5); + * val ele = doc.docElem; + * Console.println("finished parsing"); + * val out = ppr.format(ele); + * Console.println(out); + * } + * } + * }}} */ class ConstructingParser(val input: Source, val preserveWS: Boolean) extends ConstructingHandler with ExternalSources diff --git a/src/library/scala/xml/parsing/DefaultMarkupHandler.scala b/src/library/scala/xml/parsing/DefaultMarkupHandler.scala index 69c59c30cf..0a8bd7c4d6 100644 --- a/src/library/scala/xml/parsing/DefaultMarkupHandler.scala +++ b/src/library/scala/xml/parsing/DefaultMarkupHandler.scala @@ -13,7 +13,7 @@ package scala.xml package parsing -/** default implemenation of markup handler always returns NodeSeq.Empty */ +/** default implementation of markup handler always returns NodeSeq.Empty */ abstract class DefaultMarkupHandler extends MarkupHandler { def elem(pos: Int, pre: String, label: String, attrs: MetaData, diff --git a/src/library/scala/xml/parsing/FactoryAdapter.scala b/src/library/scala/xml/parsing/FactoryAdapter.scala index a83f9677a1..6960e05d25 100644 --- a/src/library/scala/xml/parsing/FactoryAdapter.scala +++ b/src/library/scala/xml/parsing/FactoryAdapter.scala @@ -12,20 +12,15 @@ package scala.xml package parsing -import java.io.{InputStream, Reader, File, FileDescriptor, FileInputStream} -import collection.mutable.{Stack, StringBuilder} -import collection.immutable.{List, Nil} -import collection.{Seq, Iterator} +import java.io.{ InputStream, Reader, File, FileDescriptor, FileInputStream } +import collection.mutable.Stack -import org.xml.sax.{ Attributes, InputSource } +import org.xml.sax.Attributes import org.xml.sax.helpers.DefaultHandler -import javax.xml.parsers.{ SAXParser, SAXParserFactory } // can be mixed into FactoryAdapter if desired trait ConsoleErrorHandler extends DefaultHandler { - import org.xml.sax.SAXParseException - // ignore warning, crimson warns even for entity resolution! override def warning(ex: SAXParseException): Unit = { } override def error(ex: SAXParseException): Unit = printError("Error", ex) diff --git a/src/library/scala/xml/parsing/FatalError.scala b/src/library/scala/xml/parsing/FatalError.scala index 01b68f6591..73634298fa 100644 --- a/src/library/scala/xml/parsing/FatalError.scala +++ b/src/library/scala/xml/parsing/FatalError.scala @@ -10,7 +10,8 @@ package scala.xml -package parsing; +package parsing - -case class FatalError(msg:String) extends java.lang.RuntimeException(msg); +/** !!! This is poorly named, but I guess it's in the API. + */ +case class FatalError(msg: String) extends java.lang.RuntimeException(msg) diff --git a/src/library/scala/xml/parsing/MarkupHandler.scala b/src/library/scala/xml/parsing/MarkupHandler.scala index a0058e8bc4..bcb0e03a07 100644 --- a/src/library/scala/xml/parsing/MarkupHandler.scala +++ b/src/library/scala/xml/parsing/MarkupHandler.scala @@ -12,7 +12,8 @@ package scala.xml package parsing -import scala.collection.mutable.{HashMap, Map} +import collection.mutable +import mutable.HashMap import scala.io.Source import scala.util.logging.Logged import scala.xml.dtd._ @@ -32,7 +33,7 @@ abstract class MarkupHandler extends Logged val isValidating: Boolean = false var decls: List[Decl] = Nil - var ent: Map[String, EntityDecl] = new HashMap[String, EntityDecl]() + var ent: mutable.Map[String, EntityDecl] = new HashMap[String, EntityDecl]() def lookupElemDecl(Label: String): ElemDecl = { for (z @ ElemDecl(Label, _) <- decls) @@ -69,7 +70,7 @@ abstract class MarkupHandler extends Logged */ def elemEnd(pos: Int, pre: String, label: String): Unit = () - /** callback method invoked by MarkupParser after parsing an elementm, + /** callback method invoked by MarkupParser after parsing an element, * between the elemStart and elemEnd callbacks * * @param pos the position in the source file diff --git a/src/library/scala/xml/parsing/MarkupParser.scala b/src/library/scala/xml/parsing/MarkupParser.scala index a15cd0f7e4..24e0d78c6f 100644 --- a/src/library/scala/xml/parsing/MarkupParser.scala +++ b/src/library/scala/xml/parsing/MarkupParser.scala @@ -32,7 +32,13 @@ trait MarkupParser extends MarkupParserCommon with TokenTests self: MarkupParser with MarkupHandler => type PositionType = Int - type InputType = Source + type InputType = Source + type ElementType = NodeSeq + type AttributesType = (MetaData, NamespaceBinding) + type NamespaceType = NamespaceBinding + + def truncatedError(msg: String): Nothing = throw FatalError(msg) + def errorNoEnd(tag: String) = throw FatalError("expected closing tag of " + tag) def xHandleError(that: Char, msg: String) = reportSyntaxError(msg) @@ -102,30 +108,28 @@ trait MarkupParser extends MarkupParserCommon with TokenTests md } - /** <? prolog ::= xml S? - * // this is a bit more lenient than necessary... + /** Factored out common code. */ - def prolog(): Tuple3[Option[String], Option[String], Option[Boolean]] = { - - //Console.println("(DEBUG) prolog") - var n = 0 + private def prologOrTextDecl(isProlog: Boolean): (Option[String], Option[String], Option[Boolean]) = { var info_ver: Option[String] = None var info_enc: Option[String] = None var info_stdl: Option[Boolean] = None var m = xmlProcInstr() + var n = 0 - xSpaceOpt + if (isProlog) + xSpaceOpt m("version") match { - case null => ; + case null => ; case Text("1.0") => info_ver = Some("1.0"); n += 1 case _ => reportSyntaxError("cannot deal with versions != 1.0") } m("encoding") match { case null => ; - case Text(enc) => + case Text(enc) => if (!isValidIANAEncoding(enc)) reportSyntaxError("\"" + enc + "\" is not a valid encoding") else { @@ -133,52 +137,33 @@ trait MarkupParser extends MarkupParserCommon with TokenTests n += 1 } } - m("standalone") match { - case null => ; - case Text("yes") => info_stdl = Some(true); n += 1 - case Text("no") => info_stdl = Some(false); n += 1 - case _ => reportSyntaxError("either 'yes' or 'no' expected") + + if (isProlog) { + m("standalone") match { + case null => ; + case Text("yes") => info_stdl = Some(true); n += 1 + case Text("no") => info_stdl = Some(false); n += 1 + case _ => reportSyntaxError("either 'yes' or 'no' expected") + } } if (m.length - n != 0) { - reportSyntaxError("VersionInfo EncodingDecl? SDDecl? or '?>' expected!"); + val s = if (isProlog) "SDDecl? " else "" + reportSyntaxError("VersionInfo EncodingDecl? %sor '?>' expected!" format s) } - //Console.println("[MarkupParser::prolog] finished parsing prolog!"); - Tuple3(info_ver,info_enc,info_stdl) - } - /** prolog, but without standalone */ - def textDecl(): Tuple2[Option[String],Option[String]] = { - - var info_ver: Option[String] = None - var info_enc: Option[String] = None - - var m = xmlProcInstr() - var n = 0 - - m("version") match { - case null => ; - case Text("1.0") => info_ver = Some("1.0"); n += 1 - case _ => reportSyntaxError("cannot deal with versions != 1.0") - } + (info_ver, info_enc, info_stdl) + } - m("encoding") match { - case null => ; - case Text(enc) => - if (!isValidIANAEncoding(enc)) - reportSyntaxError("\"" + enc + "\" is not a valid encoding") - else { - info_enc = Some(enc) - n += 1 - } - } + /** <? prolog ::= xml S? + * // this is a bit more lenient than necessary... + */ + def prolog(): (Option[String], Option[String], Option[Boolean]) = + prologOrTextDecl(true) - if (m.length - n != 0) { - reportSyntaxError("VersionInfo EncodingDecl? or '?>' expected!"); - } - //Console.println("[MarkupParser::textDecl] finished parsing textdecl"); - Tuple2(info_ver, info_enc); - } + /** prolog, but without standalone */ + def textDecl(): (Option[String], Option[String]) = + prologOrTextDecl(false) match { case (x1, x2, _) => (x1, x2) } /** *[22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? @@ -190,8 +175,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests */ def document(): Document = { - - //Console.println("(DEBUG) document") doc = new Document() this.dtd = null @@ -204,7 +187,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests nextch // is prolog ? var children: NodeSeq = null if ('?' == ch) { - //Console.println("[MarkupParser::document] starts with xml declaration"); nextch; info_prolog = prolog() doc.version = info_prolog._1 @@ -212,10 +194,8 @@ trait MarkupParser extends MarkupParserCommon with TokenTests doc.standAlone = info_prolog._3 children = content(TopScope) // DTD handled as side effect - } else { - //Console.println("[MarkupParser::document] does not start with xml declaration"); - // - + } + else { val ts = new NodeBuffer(); content1(TopScope, ts); // DTD handled as side effect ts &+ content(TopScope); @@ -228,7 +208,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests case _:ProcInstr => ; case _:Comment => ; case _:EntityRef => // todo: fix entities, shouldn't be "special" - reportSyntaxError("no entity references alllowed here"); + reportSyntaxError("no entity references allowed here"); case s:SpecialNode => if (s.toString().trim().length > 0) //non-empty text nodes not allowed elemCount = elemCount + 2; @@ -257,6 +237,14 @@ trait MarkupParser extends MarkupParserCommon with TokenTests this } + def ch_returning_nextch = { val res = ch ; nextch ; res } + def mkProcInstr(position: Int, name: String, text: String): NodeSeq = + handle.procInstr(position, name, text) + + def mkAttributes(name: String, pscope: NamespaceBinding) = + if (isNameStart (ch)) xAttributes(pscope) + else (Null, pscope) + /** this method assign the next character to ch and advances in input */ def nextch = { if (curInput.hasNext) { @@ -315,27 +303,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests (aMap,scope) } - /** attribute value, terminated by either ' or ". value may not contain <. - * AttValue ::= `'` { _ } `'` - * | `"` { _ } `"` - */ - def xAttributeValue(): String = { - val endch = ch - nextch - while (ch != endch) { - if ('<' == ch) - reportSyntaxError( "'<' not allowed in attrib value" ); - putChar(ch) - nextch - } - nextch - val str = cbuf.toString() - cbuf.length = 0 - - // well-formedness constraint - normalizeAttributeValue(str) - } - /** entity value, terminated by either ' or ". value may not contain <. * AttValue ::= `'` { _ } `'` * | `"` { _ } `"` @@ -353,35 +320,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests str } - - /** parse a start or empty tag. - * [40] STag ::= '<' Name { S Attribute } [S] - * [44] EmptyElemTag ::= '<' Name { S Attribute } [S] - */ - protected def xTag(pscope:NamespaceBinding): (String, MetaData, NamespaceBinding) = { - val qname = xName - - xSpaceOpt - val (aMap: MetaData, scope: NamespaceBinding) = { - if (isNameStart(ch)) - xAttributes(pscope) - else - (Null, pscope) - } - (qname, aMap, scope) - } - - /** [42] '<' xmlEndTag ::= '<' '/' Name S? '>' - */ - def xEndTag(n: String) = { - xToken('/') - val m = xName - if (n != m) - reportSyntaxError("expected closing tag of " + n/* +", not "+m*/); - xSpaceOpt - xToken('>') - } - /** '<! CharData ::= [CDATA[ ( {char} - {char}"]]>"{char} ) ']]>' * * see [15] @@ -392,14 +330,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests xTakeUntil(mkResult, () => pos, "]]>") } - /** CharRef ::= "&#" '0'..'9' {'0'..'9'} ";" - * | "&#x" '0'..'9'|'A'..'F'|'a'..'f' { hexdigit } ";" - * - * see [66] - */ - def xCharRef(ch: () => Char, nextch: () => Unit): String = - Utility.parseCharRef(ch, nextch, reportSyntaxError _) - /** Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' * * see [15] @@ -576,7 +506,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests */ def element1(pscope: NamespaceBinding): NodeSeq = { val pos = this.pos - val (qname, aMap, scope) = xTag(pscope) + val (qname, (aMap, scope)) = xTag(pscope) val (pre, local) = Utility.prefix(qname) match { case Some(p) => (p, qname drop p.length+1) case _ => (null, qname) @@ -600,50 +530,6 @@ trait MarkupParser extends MarkupParserCommon with TokenTests res } - //def xEmbeddedExpr: MarkupType; - - /** Name ::= (Letter | '_' | ':') (NameChar)* - * - * see [5] of XML 1.0 specification - */ - def xName: String = { - if (isNameStart(ch)) { - while (isNameChar(ch)) { - putChar(ch) - nextch - } - val n = cbuf.toString().intern() - cbuf.length = 0 - n - } else { - reportSyntaxError("name expected") - "" - } - } - - /** '<?' ProcInstr ::= Name [S ({Char} - ({Char}'>?' {Char})]'?>' - * - * see [15] - */ - def xProcInstr: NodeSeq = { - val sb:StringBuilder = new StringBuilder() - val n = xName - if (isSpace(ch)) { - xSpace - while (true) { - if (ch == '?' && { sb.append( ch ); nextch; ch == '>' }) { - sb.length = sb.length - 1; - nextch; - return handle.procInstr(tmppos, n, sb.toString); - } else - sb.append(ch); - nextch - } - }; - xToken("?>") - handle.procInstr(tmppos, n, sb.toString) - } - /** parse character data. * precondition: xEmbeddedBlock == false (we are not in a scala block) */ @@ -815,8 +701,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests nextch } - /** "rec-xml/#ExtSubset" pe references may not occur within markup - declarations + /** "rec-xml/#ExtSubset" pe references may not occur within markup declarations */ def intSubset() { //Console.println("(DEBUG) intSubset()") @@ -996,50 +881,4 @@ trait MarkupParser extends MarkupParserCommon with TokenTests pos = curInput.pos eof = false // must be false, because of places where entity refs occur } - - /** for the moment, replace only character references - * see spec 3.3.3 - * precond: cbuf empty - */ - def normalizeAttributeValue(attval: String): String = { - val s: Seq[Char] = attval - val it = s.iterator - while (it.hasNext) { - it.next match { - case ' '|'\t'|'\n'|'\r' => - cbuf.append(' '); - case '&' => it.next match { - case '#' => - var c = it.next - val s = xCharRef ({ () => c }, { () => c = it.next }) - cbuf.append(s) - case nchar => - val nbuf = new StringBuilder() - var d = nchar - do { - nbuf.append(d) - d = it.next - } while(d != ';'); - nbuf.toString() match { - case "lt" => cbuf.append('<') - case "gt" => cbuf.append('>') - case "amp" => cbuf.append('&') - case "apos" => cbuf.append('\'') - case "quot" => cbuf.append('"') - case "quote" => cbuf.append('"') - case name => - cbuf.append('&') - cbuf.append(name) - cbuf.append(';') - } - } - case c => - cbuf.append(c) - } - } - val name = cbuf.toString() - cbuf.length = 0 - name - } - } diff --git a/src/library/scala/xml/parsing/MarkupParserCommon.scala b/src/library/scala/xml/parsing/MarkupParserCommon.scala index 57c46c4685..936515852b 100644 --- a/src/library/scala/xml/parsing/MarkupParserCommon.scala +++ b/src/library/scala/xml/parsing/MarkupParserCommon.scala @@ -11,30 +11,191 @@ package parsing import scala.io.Source import scala.xml.dtd._ +import scala.annotation.switch import Utility.Escapes.{ pairs => unescape } +object MarkupParserCommon { + final val SU = '\u001A' +} +import MarkupParserCommon._ + /** This is not a public trait - it contains common code shared * between the library level XML parser and the compiler's. * All members should be accessed through those. */ private[scala] trait MarkupParserCommon extends TokenTests { - private final val SU: Char = 0x1A protected def unreachable = Predef.error("Cannot be reached.") - // type HandleType // MarkupHandler, SymbolicXMLBuilder - + // type HandleType // MarkupHandler, SymbolicXMLBuilder type InputType // Source, CharArrayReader type PositionType // Int, Position + type ElementType // NodeSeq, Tree + type NamespaceType // NamespaceBinding, Any + type AttributesType // (MetaData, NamespaceBinding), mutable.Map[String, Tree] + + def mkAttributes(name: String, pscope: NamespaceType): AttributesType + def mkProcInstr(position: PositionType, name: String, text: String): ElementType + + /** parse a start or empty tag. + * [40] STag ::= '<' Name { S Attribute } [S] + * [44] EmptyElemTag ::= '<' Name { S Attribute } [S] + */ + protected def xTag(pscope: NamespaceType): (String, AttributesType) = { + val name = xName + xSpaceOpt + + (name, mkAttributes(name, pscope)) + } + + /** '<?' ProcInstr ::= Name [S ({Char} - ({Char}'>?' {Char})]'?>' + * + * see [15] + */ + def xProcInstr: ElementType = { + val n = xName + xSpaceOpt + xTakeUntil(mkProcInstr(_, n, _), () => tmppos, "?>") + } + + /** attribute value, terminated by either ' or ". value may not contain <. + * @param endch either ' or " + */ + def xAttributeValue(endCh: Char): String = { + val buf = new StringBuilder + while (ch != endCh) { + // well-formedness constraint + if (ch == '<') return errorAndResult("'<' not allowed in attrib value", "") + else if (ch == SU) truncatedError("") + else buf append ch_returning_nextch + } + ch_returning_nextch + // @todo: normalize attribute value + buf.toString + } + + def xAttributeValue(): String = { + val str = xAttributeValue(ch_returning_nextch) + // well-formedness constraint + normalizeAttributeValue(str) + } + + private def takeUntilChar(it: Iterator[Char], end: Char): String = { + val buf = new StringBuilder + while (it.hasNext) it.next match { + case `end` => return buf.toString + case ch => buf append ch + } + error("Expected '%s'".format(end)) + } + + /** [42] '<' xmlEndTag ::= '<' '/' Name S? '>' + */ + def xEndTag(startName: String) { + xToken('/') + if (xName != startName) + errorNoEnd(startName) + + xSpaceOpt + xToken('>') + } + + /** actually, Name ::= (Letter | '_' | ':') (NameChar)* but starting with ':' cannot happen + * Name ::= (Letter | '_') (NameChar)* + * + * see [5] of XML 1.0 specification + * + * pre-condition: ch != ':' // assured by definition of XMLSTART token + * post-condition: name does neither start, nor end in ':' + */ + def xName: String = { + if (ch == SU) + truncatedError("") + else if (!isNameStart(ch)) + return errorAndResult("name expected, but char '%s' cannot start a name" format ch, "") + + val buf = new StringBuilder + + do buf append ch_returning_nextch + while (isNameChar(ch)) + + if (buf.last == ':') { + reportSyntaxError( "name cannot end in ':'" ) + buf.toString dropRight 1 + } + else buf.toString + } + + private def attr_unescape(s: String) = s match { + case "lt" => "<" + case "gt" => ">" + case "amp" => "&" + case "apos" => "'" + case "quot" => "\"" + case "quote" => "\"" + case _ => "&" + s + ";" + } + + /** Replaces only character references right now. + * see spec 3.3.3 + */ + private def normalizeAttributeValue(attval: String): String = { + val buf = new StringBuilder + val it = attval.iterator.buffered + + while (it.hasNext) buf append (it.next match { + case ' ' | '\t' | '\n' | '\r' => " " + case '&' if it.head == '#' => it.next ; xCharRef(it) + case '&' => attr_unescape(takeUntilChar(it, ';')) + case c => c + }) + + buf.toString + } + + /** CharRef ::= "&#" '0'..'9' {'0'..'9'} ";" + * | "&#x" '0'..'9'|'A'..'F'|'a'..'f' { hexdigit } ";" + * + * see [66] + */ + def xCharRef(ch: () => Char, nextch: () => Unit): String = + Utility.parseCharRef(ch, nextch, reportSyntaxError _) + + def xCharRef(it: Iterator[Char]): String = { + var c = it.next + Utility.parseCharRef(() => c, () => { c = it.next }, reportSyntaxError _) + } + + def xCharRef: String = xCharRef(() => ch, () => nextch) /** Create a lookahead reader which does not influence the input */ def lookahead(): BufferedIterator[Char] + /** The library and compiler parsers had the interesting distinction of + * different behavior for nextch (a function for which there are a total + * of two plausible behaviors, so we know the design space was fully + * explored.) One of them returned the value of nextch before the increment + * and one of them the new value. So to unify code we have to at least + * temporarily abstract over the nextchs. + */ def ch: Char def nextch: Char + def ch_returning_nextch: Char + def eof: Boolean + + // def handle: HandleType + var tmppos: PositionType + def xHandleError(that: Char, msg: String): Unit def reportSyntaxError(str: String): Unit def reportSyntaxError(pos: Int, str: String): Unit - def eof: Boolean + + def truncatedError(msg: String): Nothing + def errorNoEnd(tag: String): Nothing + + protected def errorAndResult[T](msg: String, x: T): T = { + reportSyntaxError(msg) + x + } def xToken(that: Char) { if (ch == that) nextch @@ -53,9 +214,16 @@ private[scala] trait MarkupParserCommon extends TokenTests { if (isSpace(ch)) { nextch; xSpaceOpt } else xHandleError(ch, "whitespace expected") - // + /** Apply a function and return the passed value */ def returning[T](x: T)(f: T => Unit): T = { f(x) ; x } + /** Execute body with a variable saved and restored after execution */ + def saving[A,B](getter: A, setter: (A) => Unit)(body: => B): B = { + val saved = getter + try body + finally setter(saved) + } + /** Take characters from input stream until given String "until" * is seen. Once seen, the accumulated characters are passed * along with the current Position to the supplied handler function. @@ -73,7 +241,7 @@ private[scala] trait MarkupParserCommon extends TokenTests { if (ch == head && peek(rest)) return handler(positioner(), sb.toString) else if (ch == SU) - xHandleError(ch, "") // throws TruncatedXML in compiler + truncatedError("") // throws TruncatedXMLControl in compiler sb append ch nextch diff --git a/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala b/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala index 05d535155b..083465bc41 100644 --- a/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala +++ b/src/library/scala/xml/parsing/NoBindingFactoryAdapter.scala @@ -12,10 +12,6 @@ package scala.xml package parsing import factory.NodeFactory -import collection.Seq -import collection.immutable.List -import org.xml.sax.InputSource -import javax.xml.parsers.{ SAXParser, SAXParserFactory } /** nobinding adaptor providing callbacks to parser to create elements. * implements hash-consing diff --git a/src/library/scala/xml/parsing/TokenTests.scala b/src/library/scala/xml/parsing/TokenTests.scala index e41cff20a3..13500e8510 100644 --- a/src/library/scala/xml/parsing/TokenTests.scala +++ b/src/library/scala/xml/parsing/TokenTests.scala @@ -12,8 +12,6 @@ package scala.xml package parsing -import collection.Seq -import collection.immutable.List /** * Helper functions for parsing XML fragments */ diff --git a/src/library/scala/xml/parsing/ValidatingMarkupHandler.scala b/src/library/scala/xml/parsing/ValidatingMarkupHandler.scala index 06828b7320..00126c4881 100644 --- a/src/library/scala/xml/parsing/ValidatingMarkupHandler.scala +++ b/src/library/scala/xml/parsing/ValidatingMarkupHandler.scala @@ -51,7 +51,7 @@ abstract class ValidatingMarkupHandler extends MarkupHandler with Logged { log("advanceDFA(trans): " + trans) trans.get(ContentModel.ElemName(label)) match { case Some(qNew) => qCurrent = qNew - case _ => reportValidationError(pos, "DTD says, wrong element, expected one of "+trans.keysIterator); + case _ => reportValidationError(pos, "DTD says, wrong element, expected one of "+trans.keys); } } // advance in current automaton diff --git a/src/library/scala/xml/parsing/XhtmlEntities.scala b/src/library/scala/xml/parsing/XhtmlEntities.scala index dbc2ae0621..6e35aa9606 100644 --- a/src/library/scala/xml/parsing/XhtmlEntities.scala +++ b/src/library/scala/xml/parsing/XhtmlEntities.scala @@ -8,11 +8,10 @@ // $Id$ - package scala.xml package parsing -import scala.xml.dtd.{IntDef, ParsedEntityDecl} +import scala.xml.dtd.{ IntDef, ParsedEntityDecl } /** <p> * (c) David Pollak 2007 WorldWide Conferencing, LLC. |