diff options
Diffstat (limited to 'src/library')
45 files changed, 514 insertions, 686 deletions
diff --git a/src/library/scala/Array.scala b/src/library/scala/Array.scala index f89e8b48a5..c9d929b88c 100644 --- a/src/library/scala/Array.scala +++ b/src/library/scala/Array.scala @@ -207,6 +207,7 @@ object Array extends FallbackArrayBuilding { */ def fill[T: ClassManifest](n: Int)(elem: => T): Array[T] = { val b = newBuilder[T] + b.sizeHint(n) var i = 0 while (i < n) { b += elem @@ -270,6 +271,7 @@ object Array extends FallbackArrayBuilding { */ def tabulate[T: ClassManifest](n: Int)(f: Int => T): Array[T] = { val b = newBuilder[T] + b.sizeHint(n) var i = 0 while (i < n) { b += f(i) @@ -343,6 +345,8 @@ object Array extends FallbackArrayBuilding { def range(start: Int, end: Int, step: Int): Array[Int] = { if (step == 0) throw new IllegalArgumentException("zero step") val b = newBuilder[Int] + b.sizeHint(Range.count(start, end, step, false)) + var i = start while (if (step < 0) end < i else i < end) { b += i @@ -360,6 +364,7 @@ object Array extends FallbackArrayBuilding { */ def iterate[T: ClassManifest](start: T, len: Int)(f: T => T): Array[T] = { val b = newBuilder[T] + b.sizeHint(len) var acc = start var i = 0 while (i < len) { diff --git a/src/library/scala/collection/BitSet.scala b/src/library/scala/collection/BitSet.scala index b43b681888..e362271f70 100644 --- a/src/library/scala/collection/BitSet.scala +++ b/src/library/scala/collection/BitSet.scala @@ -27,6 +27,8 @@ trait BitSet extends Set[Int] */ object BitSet extends BitSetFactory[BitSet] { val empty: BitSet = immutable.BitSet.empty + def newBuilder = immutable.BitSet.newBuilder + /** $canBuildFromInfo */ implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom } diff --git a/src/library/scala/collection/BitSetLike.scala b/src/library/scala/collection/BitSetLike.scala index 3028cca6eb..b4e9682d88 100644 --- a/src/library/scala/collection/BitSetLike.scala +++ b/src/library/scala/collection/BitSetLike.scala @@ -25,7 +25,7 @@ import mutable.StringBuilder * * @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 + * variable-size arrays of bits packed into 64-bit words. The memory footprint of a bitset is * determined by the largest number stored in it. * @author Martin Odersky * @version 2.8 diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 24c447b24b..5eca806933 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -11,8 +11,7 @@ package scala.collection -import mutable.{Buffer, ArrayBuffer, ListBuffer, StringBuilder} -import immutable.{List, Stream} +import mutable.ArrayBuffer import annotation.{ tailrec, migration } /** The `Iterator` object provides various functions for @@ -110,9 +109,15 @@ object Iterator { * @return the iterator producing the infinite sequence of values `start, f(start), f(f(start)), ...` */ def iterate[T](start: T)(f: T => T): Iterator[T] = new Iterator[T] { + private[this] var first = true private[this] var acc = start def hasNext: Boolean = true - def next(): T = { val res = acc ; acc = f(acc) ; res } + def next(): T = { + if (first) first = false + else acc = f(acc) + + acc + } } /** Creates an infinite-length iterator which returns successive values from some start value. diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index b9ac28cb2d..d80539d0b0 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -20,6 +20,7 @@ import generic._ object SeqLike { /** A KMP implementation, based on the undoubtedly reliable wikipedia entry. + * * @author paulp * @since 2.8 */ @@ -72,7 +73,23 @@ object SeqLike { None } - /** Waiting for a doc comment from Paul + /** Finds a particular index at which one sequence occurs in another sequence. + * Both the source sequence and the target sequence are expressed in terms + * other sequences S' and T' with offset and length parameters. This + * function is designed to wrap the KMP machinery in a sufficiently general + * way that all library sequence searches can use it. It is unlikely you + * have cause to call it directly: prefer functions such as StringBuilder#indexOf + * and Seq#lastIndexOf. + * + * @param source the sequence to search in + * @param sourceOffset the starting offset in source + * @param sourceCount the length beyond sourceOffset to search + * @param target the sequence being searched for + * @param targetOffset the starting offset in target + * @param targetCount the length beyond targetOffset which makes up the target string + * @param fromIndex the smallest index at which the target sequence may start + * + * @return the applicable index in source where target exists, or -1 if not found */ def indexOf[B]( source: Seq[B], sourceOffset: Int, sourceCount: Int, @@ -83,7 +100,10 @@ object SeqLike { case Some(x) => x + fromIndex } - /** Waiting for a doc comment from Paul + /** Finds a particular index at which one sequence occurs in another sequence. + * Like indexOf, but finds the latest occurrence rather than earliest. + * + * @see SeqLike#indexOf */ def lastIndexOf[B]( source: Seq[B], sourceOffset: Int, sourceCount: Int, diff --git a/src/library/scala/collection/Set.scala b/src/library/scala/collection/Set.scala index 034d9f1705..f1c1e43731 100644 --- a/src/library/scala/collection/Set.scala +++ b/src/library/scala/collection/Set.scala @@ -37,6 +37,7 @@ trait Set[A] extends (A => Boolean) * @define Coll Set */ object Set extends SetFactory[Set] { + def newBuilder[A] = immutable.Set.newBuilder[A] override def empty[A]: Set[A] = immutable.Set.empty[A] implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A] } diff --git a/src/library/scala/collection/generic/BitSetFactory.scala b/src/library/scala/collection/generic/BitSetFactory.scala index 5679b25351..08cf7bd0e0 100644 --- a/src/library/scala/collection/generic/BitSetFactory.scala +++ b/src/library/scala/collection/generic/BitSetFactory.scala @@ -13,7 +13,7 @@ package scala.collection package generic import scala.collection._ -import mutable.{Builder, AddingBuilder} +import mutable.Builder /** @define coll collection * @define Coll Traversable @@ -28,8 +28,8 @@ import mutable.{Builder, AddingBuilder} * The standard `CanBuildFrom` instance for bitsets. */ trait BitSetFactory[Coll <: BitSet with BitSetLike[Coll]] { - def newBuilder: Builder[Int, Coll] = new AddingBuilder[Int, Coll](empty) def empty: Coll + def newBuilder: Builder[Int, Coll] def apply(elems: Int*): Coll = (empty /: elems) (_ + _) def bitsetCanBuildFrom = new CanBuildFrom[Coll, Int, Coll] { def apply(from: Coll) = newBuilder diff --git a/src/library/scala/concurrent/AsyncInvokable.scala b/src/library/scala/collection/generic/ImmutableSetFactory.scala index ac465c7fe5..a551786f25 100644 --- a/src/library/scala/concurrent/AsyncInvokable.scala +++ b/src/library/scala/collection/generic/ImmutableSetFactory.scala @@ -6,19 +6,13 @@ ** |/ ** \* */ -// $Id$ +package scala.collection +package generic +import mutable.{ Builder, AddingBuilder } -package scala.concurrent - -/** The <code>AsyncInvokable</code> trait... - * - * @author Philipp Haller - */ -trait AsyncInvokable[-T, +R] { - - type Future[+S] <: () => S - - def !!(task: T): Future[R] +abstract class ImmutableSetFactory[CC[X] <: immutable.Set[X] with SetLike[X, CC[X]]] + extends SetFactory[CC] { + def newBuilder[A]: Builder[A, CC[A]] = new AddingBuilder[A, CC[A]](empty[A]) } diff --git a/src/library/scala/collection/generic/MutableSetFactory.scala b/src/library/scala/collection/generic/MutableSetFactory.scala new file mode 100644 index 0000000000..28b5fdd897 --- /dev/null +++ b/src/library/scala/collection/generic/MutableSetFactory.scala @@ -0,0 +1,18 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2003-2010, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala.collection +package generic + +import mutable.{ Builder, GrowingBuilder } + +abstract class MutableSetFactory[CC[X] <: mutable.Set[X] with mutable.SetLike[X, CC[X]]] + extends SetFactory[CC] { + + def newBuilder[A]: Builder[A, CC[A]] = new GrowingBuilder[A, CC[A]](empty[A]) +} diff --git a/src/library/scala/collection/generic/SetFactory.scala b/src/library/scala/collection/generic/SetFactory.scala index 1c4ec3e7e3..d43664bd39 100644 --- a/src/library/scala/collection/generic/SetFactory.scala +++ b/src/library/scala/collection/generic/SetFactory.scala @@ -12,7 +12,7 @@ package scala.collection package generic -import mutable.{Builder, AddingBuilder} +import mutable.Builder /** A template for companion objects of `Set` and subclasses thereof. * @@ -34,7 +34,7 @@ import mutable.{Builder, AddingBuilder} abstract class SetFactory[CC[X] <: Set[X] with SetLike[X, CC[X]]] extends GenericCompanion[CC] { - def newBuilder[A]: Builder[A, CC[A]] = new AddingBuilder[A, CC[A]](empty[A]) + def newBuilder[A]: Builder[A, CC[A]] /** $setCanBuildFromInfo */ diff --git a/src/library/scala/collection/generic/TraversableFactory.scala b/src/library/scala/collection/generic/TraversableFactory.scala index b7fda70922..ffc4f16466 100644 --- a/src/library/scala/collection/generic/TraversableFactory.scala +++ b/src/library/scala/collection/generic/TraversableFactory.scala @@ -62,6 +62,10 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl */ def concat[A](xss: Traversable[A]*): CC[A] = { val b = newBuilder[A] + // At present we're using IndexedSeq as a proxy for "has a cheap size method". + if (xss forall (_.isInstanceOf[IndexedSeq[_]])) + b.sizeHint(xss map (_.size) sum) + for (xs <- xss) b ++= xs b.result } @@ -73,6 +77,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl */ def fill[A](n: Int)(elem: => A): CC[A] = { val b = newBuilder[A] + b.sizeHint(n) var i = 0 while (i < n) { b += elem @@ -130,6 +135,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl */ def tabulate[A](n: Int)(f: Int => A): CC[A] = { val b = newBuilder[A] + b.sizeHint(n) var i = 0 while (i < n) { b += f(i) @@ -201,6 +207,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl def range(start: Int, end: Int, step: Int): CC[Int] = { if (step == 0) throw new IllegalArgumentException("zero step") val b = newBuilder[Int] + b.sizeHint(Range.count(start, end, step, false)) var i = start while (if (step < 0) end < i else i < end) { b += i @@ -218,6 +225,7 @@ abstract class TraversableFactory[CC[X] <: Traversable[X] with GenericTraversabl */ def iterate[A](start: A, len: Int)(f: A => A): CC[A] = { val b = newBuilder[A] + b.sizeHint(len) var acc = start var i = 0 while (i < len) { diff --git a/src/library/scala/collection/immutable/BitSet.scala b/src/library/scala/collection/immutable/BitSet.scala index 9b801f26cb..8fa23c3ddf 100644 --- a/src/library/scala/collection/immutable/BitSet.scala +++ b/src/library/scala/collection/immutable/BitSet.scala @@ -14,6 +14,7 @@ package immutable import generic._ import BitSetLike.{LogWL, updateArray} +import mutable.{ Builder, AddingBuilder } /** A class for immutable bitsets. * $bitsetinfo @@ -60,10 +61,12 @@ abstract class BitSet extends Set[Int] * @define coll immutable bitset */ object BitSet extends BitSetFactory[BitSet] { - /** The empty bitset */ val empty: BitSet = new BitSet1(0L) + /** An adding builder for immutable Sets. */ + def newBuilder: Builder[Int, BitSet] = new AddingBuilder[Int, BitSet](empty) + /** $bitsetCanBuildFrom */ implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom diff --git a/src/library/scala/collection/immutable/DefaultMap.scala b/src/library/scala/collection/immutable/DefaultMap.scala index 667d86d352..4f36679119 100755 --- a/src/library/scala/collection/immutable/DefaultMap.scala +++ b/src/library/scala/collection/immutable/DefaultMap.scala @@ -50,7 +50,7 @@ trait DefaultMap[A, +B] extends Map[A, B] { self => */ override def - (key: A): Map[A, B] = { val b = newBuilder - b ++= this filter (key !=) + for (kv <- this ; if kv._1 != key) b += kv b.result } } diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index 68da0cef50..481b1c3204 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -88,7 +88,7 @@ class HashSet[A] extends Set[A] * @define mayNotTerminateInf * @define willNotTerminateInf */ -object HashSet extends SetFactory[HashSet] { +object HashSet extends ImmutableSetFactory[HashSet] { /** $setCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A] override def empty[A]: HashSet[A] = EmptyHashSet.asInstanceOf[HashSet[A]] diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 4ce441ca55..f9937f6925 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -19,9 +19,9 @@ import annotation.tailrec /** A class for immutable linked lists representing ordered collections * of elements of type. * - * This class comes with two implementing case classes `scala.Nil` - * and `scala.::` that implement the abstract members `isEmpty`, - * `head` and `tail`. + * This class comes with two implementing case classes `scala.Nil` + * and `scala.::` that implement the abstract members `isEmpty`, + * `head` and `tail`. * * @author Martin Odersky and others * @version 2.8 diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala index 2a202df9ef..979fdff552 100644 --- a/src/library/scala/collection/immutable/ListSet.scala +++ b/src/library/scala/collection/immutable/ListSet.scala @@ -19,7 +19,7 @@ import generic._ * @define coll immutable list set * @since 1 */ -object ListSet extends SetFactory[ListSet] { +object ListSet extends ImmutableSetFactory[ListSet] { /** setCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] = setCanBuildFrom[A] override def empty[A] = new ListSet[A] diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala index 7a903cb201..7ffceb6be8 100644 --- a/src/library/scala/collection/immutable/Queue.scala +++ b/src/library/scala/collection/immutable/Queue.scala @@ -14,6 +14,7 @@ package immutable import generic._ import mutable.{ Builder, ListBuffer } +import annotation.tailrec /** `Queue` objects implement data structures that allow to * insert and retrieve elements in a first-in-first-out (FIFO) manner. @@ -29,9 +30,9 @@ import mutable.{ Builder, ListBuffer } @serializable @SerialVersionUID(-7622936493364270175L) class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) - extends Seq[A] + extends LinearSeq[A] with GenericTraversableTemplate[A, Queue] - with SeqLike[A, Queue[A]] { + with LinearSeqLike[A, Queue[A]] { override def companion: GenericCompanion[Queue] = Queue @@ -42,7 +43,7 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) * @return the element at position `n` in this queue. * @throws Predef.NoSuchElementException if the queue is too short. */ - def apply(n: Int): A = { + override def apply(n: Int): A = { val len = out.length if (n < len) out.apply(n) else { @@ -62,9 +63,19 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) */ override def isEmpty: Boolean = in.isEmpty && out.isEmpty + override def head: A = + if (out.nonEmpty) out.head + else if (in.nonEmpty) in.last + else throw new NoSuchElementException("head on empty queue") + + override def tail: Queue[A] = + if (out.nonEmpty) new Queue(in, out.tail) + else if (in.nonEmpty) new Queue(Nil, in.reverse.tail) + else throw new NoSuchElementException("tail on empty queue") + /** Returns the length of the queue. */ - def length = in.length + out.length + override def length = in.length + out.length /** Creates a new queue with element added at the end * of the old queue. @@ -101,7 +112,7 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) * @param iter an iterable object */ def enqueue[B >: A](iter: Iterable[B]) = - new Queue(iter.iterator.toList.reverse ::: in, out) + new Queue(iter.toList.reverse ::: in, out) /** Returns a tuple with the first element in the queue, * and a new queue with this element removed. @@ -121,10 +132,7 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) * @throws Predef.NoSuchElementException * @return the first element. */ - def front: A = - if (!out.isEmpty) out.head - else if (!in.isEmpty) in.last - else throw new NoSuchElementException("front on empty queue") + def front: A = head /** Returns a string representation of this queue. */ diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index 8f1f7d58a6..0f20b1ea04 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -219,6 +219,23 @@ class Range(val start: Int, val end: Int, val step: Int) extends IndexedSeq[Int] object Range { private[immutable] val MAX_PRINT = 512 // some arbitrary value + /** Calculates the number of elements in a range given start, end, step, and + * whether or not it is inclusive. Returns -1 if parameters are invalid. + */ + def count(start: Int, end: Int, step: Int): Int = count(start, end, step, false) + def count(start: Int, end: Int, step: Int, isInclusive: Boolean): Int = { + def last = + if (isInclusive && step < 0) end - 1 + else if (isInclusive && step > 0) end + 1 + else end + + if (step == 0) -1 + else if (start == end) { if (isInclusive) 1 else 0 } + else if (end > start != step > 0) -1 + else if (step == 1 || step == -1) last - start + else ((last - start - 1) / step) + 1 + } + class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) { override def isInclusive = true override protected def copy(start: Int, end: Int, step: Int): Range = new Inclusive(start, end, step) diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala index 769ee37f6b..745b0034e8 100644 --- a/src/library/scala/collection/immutable/Set.scala +++ b/src/library/scala/collection/immutable/Set.scala @@ -36,7 +36,7 @@ trait Set[A] extends Iterable[A] * @define Coll immutable.Set * @define coll immutable set */ -object Set extends SetFactory[Set] { +object Set extends ImmutableSetFactory[Set] { /** $setCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A] override def empty[A]: Set[A] = EmptySet.asInstanceOf[Set[A]] diff --git a/src/library/scala/collection/immutable/Stack.scala b/src/library/scala/collection/immutable/Stack.scala index 0323db7211..c90ab379af 100644 --- a/src/library/scala/collection/immutable/Stack.scala +++ b/src/library/scala/collection/immutable/Stack.scala @@ -48,7 +48,8 @@ object Stack extends SeqFactory[Stack] { * @define willNotTerminateInf */ @serializable @SerialVersionUID(1976480595012942526L) -class Stack[+A] protected (protected val elems: List[A]) extends LinearSeq[A] +class Stack[+A] protected (protected val elems: List[A]) + extends LinearSeq[A] with GenericTraversableTemplate[A, Stack] with LinearSeqOptimized[A, Stack[A]] { override def companion: GenericCompanion[Stack] = Stack diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index 50fa07c2cf..fbda0b918b 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -104,6 +104,16 @@ self => loop(this, "") } + override def length: Int = { + var len = 0 + var left = this + while (!left.isEmpty) { + len += 1 + left = left.tail + } + len + } + /** It's an imperfect world, but at least we can bottle up the * imperfection in a capsule. */ diff --git a/src/library/scala/collection/immutable/TreeSet.scala b/src/library/scala/collection/immutable/TreeSet.scala index 7b1f71df5b..18c65dd373 100644 --- a/src/library/scala/collection/immutable/TreeSet.scala +++ b/src/library/scala/collection/immutable/TreeSet.scala @@ -13,7 +13,7 @@ package scala.collection package immutable import generic._ -import mutable.{Builder, AddingBuilder} +import mutable.{ Builder, AddingBuilder } /** $factoryInfo * @define Coll immutable.TreeSet diff --git a/src/library/scala/collection/mutable/AddingBuilder.scala b/src/library/scala/collection/mutable/AddingBuilder.scala index 14636c9feb..54137b6a26 100644 --- a/src/library/scala/collection/mutable/AddingBuilder.scala +++ b/src/library/scala/collection/mutable/AddingBuilder.scala @@ -17,9 +17,12 @@ import generic._ * 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. - * @tparam Elem the type of elements that get added to the builder. - * @tparam To the type of the built collection. + * @param empty the empty element of the collection. + * @tparam Elem the type of elements that get added to the builder. + * @tparam To the type of the built collection. + * + * @note "efficient `+`" is not idle talk. Do not use this on mutable collections or any others + * for which `+` may perform an unshared copy! See GrowingBuilder comments for more. * * @author Martin Odersky * @version 2.8 diff --git a/src/library/scala/collection/mutable/BitSet.scala b/src/library/scala/collection/mutable/BitSet.scala index 5d0f5863ca..da3e95fce7 100644 --- a/src/library/scala/collection/mutable/BitSet.scala +++ b/src/library/scala/collection/mutable/BitSet.scala @@ -114,6 +114,10 @@ class BitSet(protected var elems: Array[Long]) extends Set[Int] */ object BitSet extends BitSetFactory[BitSet] { def empty: BitSet = new BitSet + + /** A growing builder for mutable Sets. */ + def newBuilder: Builder[Int, BitSet] = new GrowingBuilder[Int, BitSet](empty) + /** $bitsetCanBuildFrom */ implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom } diff --git a/src/library/scala/collection/mutable/GrowingBuilder.scala b/src/library/scala/collection/mutable/GrowingBuilder.scala index cd1c8bec8c..781753c24d 100644 --- a/src/library/scala/collection/mutable/GrowingBuilder.scala +++ b/src/library/scala/collection/mutable/GrowingBuilder.scala @@ -18,6 +18,11 @@ import generic._ * interacting surprisingly with any2stringadd thus driving '+' out of the `Seq` * hierarchy. The tendrils of original sin should never be underestimated. * + * Addendum: of even greater significance is that '+' on mutable collections now + * creates a new collection. This means using AddingBuilder on them will create + * a new intermediate collection for every element given to the builder, taking + * '+' from an O(1) to O(n) operation. + * * @author Paul Phillips * @version 2.8 * @since 2.8 diff --git a/src/library/scala/collection/mutable/HashSet.scala b/src/library/scala/collection/mutable/HashSet.scala index 3d9dc3e55d..41f9a17dd6 100644 --- a/src/library/scala/collection/mutable/HashSet.scala +++ b/src/library/scala/collection/mutable/HashSet.scala @@ -79,7 +79,7 @@ class HashSet[A] extends Set[A] * @define Coll mutable.HashSet * @define coll mutable hash set */ -object HashSet extends SetFactory[HashSet] { +object HashSet extends MutableSetFactory[HashSet] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A] override def empty[A]: HashSet[A] = new HashSet[A] } diff --git a/src/library/scala/collection/mutable/IndexedSeqLike.scala b/src/library/scala/collection/mutable/IndexedSeqLike.scala index 0c2d3f17bb..5e932effe0 100644 --- a/src/library/scala/collection/mutable/IndexedSeqLike.scala +++ b/src/library/scala/collection/mutable/IndexedSeqLike.scala @@ -45,7 +45,7 @@ trait IndexedSeqLike[A, +Repr] extends scala.collection.IndexedSeqLike[A, Repr] /** Replaces element at given index with a new value. * * @param n the index of the element to replace. - * @param lem the new value. + * @param elem the new value. * @throws IndexOutofBoundsException if the index is not valid. */ def update(idx: Int, elem: A) diff --git a/src/library/scala/collection/mutable/LinkedHashSet.scala b/src/library/scala/collection/mutable/LinkedHashSet.scala index 7ecb71e23b..e91b03048d 100644 --- a/src/library/scala/collection/mutable/LinkedHashSet.scala +++ b/src/library/scala/collection/mutable/LinkedHashSet.scala @@ -87,7 +87,7 @@ class LinkedHashSet[A] extends Set[A] * @define Coll LinkedHashSet * @define coll linked hash set */ -object LinkedHashSet extends SetFactory[LinkedHashSet] { +object LinkedHashSet extends MutableSetFactory[LinkedHashSet] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, LinkedHashSet[A]] = setCanBuildFrom[A] override def empty[A]: LinkedHashSet[A] = new LinkedHashSet[A] } diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala index 676a325c9b..f9c0f7232c 100644 --- a/src/library/scala/collection/mutable/MapLike.scala +++ b/src/library/scala/collection/mutable/MapLike.scala @@ -191,9 +191,10 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * * @param p The test predicate */ - @deprecated("cannot be type inferred because of retain in Iterable.") def retain(p: (A, B) => Boolean): this.type = { - for ((k, v) <- this) if (!p(k, v)) -=(k) + for ((k, v) <- this ; if !p(k, v)) + this -= k + this } diff --git a/src/library/scala/collection/mutable/Set.scala b/src/library/scala/collection/mutable/Set.scala index 2e7f1cbc6b..bebf66157a 100644 --- a/src/library/scala/collection/mutable/Set.scala +++ b/src/library/scala/collection/mutable/Set.scala @@ -32,7 +32,7 @@ trait Set[A] extends Iterable[A] * @define coll mutable set * @define Coll mutable.Set */ -object Set extends SetFactory[Set] { +object Set extends MutableSetFactory[Set] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A] override def empty[A]: Set[A] = HashSet.empty[A] } diff --git a/src/library/scala/collection/mutable/StringBuilder.scala b/src/library/scala/collection/mutable/StringBuilder.scala index 40e7e991ee..f43acdc796 100644 --- a/src/library/scala/collection/mutable/StringBuilder.scala +++ b/src/library/scala/collection/mutable/StringBuilder.scala @@ -15,14 +15,17 @@ package mutable import generic._ import compat.Platform.arraycopy import scala.reflect.Manifest +import annotation.migration +import StringBuilder._ -/** A builder for mutable sequence of characters. This class provides an API compatible - * with <a class="java/lang/StringBuilder" href="" target="_top">`java.lang.StringBuilder`</a>. +/** A builder for mutable sequence of characters. This class provides an API + * mostly compatible with java.lang.StringBuilder, except where there are conflicts + * with the Scala collections API (such as the `reverse` method.) * * @author Stephane Micheloud * @author Martin Odersky * @version 2.8 - * @since 2.8 + * @since 2.7 */ @serializable @SerialVersionUID(0 - 8525408645367278351L) @@ -70,71 +73,50 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) */ def clear(): Unit = setLength(0) - /** Sets the length of the character sequence. + /** Sets the length of the character sequence. If the current sequence + * is shorter than the given length, it is padded with nulls; if it is + * longer, it is truncated. * - * @param newLength the new length - * @throws IndexOutOfBoundsException if the <code>n</code> argument is negative. + * @param len the new length + * @throws IndexOutOfBoundsException if the argument is negative. */ - def setLength(n: Int) { - require(n >= 0, n) - while (count < n) append('\0') - count = n + def setLength(len: Int) { + require(len >= 0, len) + while (count < len) append('\0') + count = len } - /** Returns the current capacity. The capacity is the amount of storage - * available for newly inserted characters, beyond which an allocation - * will occur. + /** Returns the current capacity, which is the size of the underlying array. + * A new array will be allocated if the current capacity is exceeded. * - * @return the current capacity + * @return the capacity */ def capacity: Int = array.length - /** Same as <code>ensureCapacity</code>. */ - @deprecated("use `ensureCapacity' instead. An assignment is misleading because\n"+ + @deprecated("Use `ensureCapacity' instead. An assignment is misleading because\n"+ "it can never decrease the capacity.") def capacity_=(n: Int) { ensureCapacity(n) } - /** <p> - * Ensures that the capacity is at least equal to the specified minimum. - * If the current capacity is less than the argument, then a new internal - * array is allocated with greater capacity. The new capacity is the larger of: - * </p> - * <ul> - * <li>The <code>n</code> argument. - * <li>Twice the old capacity, plus <code>2</code>. - * </ul> - * <p> - * If the <code>n</code> argument is non-positive, this - * method takes no action and simply returns. - * </p> - * - * @param n the minimum desired capacity. - */ - def ensureCapacity(n: Int) { - if (n > array.length) { - var newsize = (array.length * 2) max 1 - while (n > newsize) - newsize = newsize * 2 - val newar = new Array[Char](newsize) - arraycopy(array, 0, newar, 0, count) - array = newar + /** Ensure that the capacity is at least the given argument. + * If the argument is greater than the current capacity, new + * storage will be allocated with size equal to the given + * argument or to (2 * capacity + 2), whichever is larger. + * + * @param newCapacity the minimum desired capacity. + */ + def ensureCapacity(newCapacity: Int): Unit = + if (newCapacity > array.length) { + val newSize = (array.length * 2 + 2) max newCapacity + val newArray = new Array[Char](newSize) + arraycopy(array, 0, newArray, 0, count) + array = newArray } - } - /** <p> - * Returns the <code>Char</code> value in this sequence at the specified index. - * The first <code>Char</code> value is at index <code>0</code>, the next at index - * <code>1</code>, and so on, as in array indexing. - * </p> - * <p> - * The index argument must be greater than or equal to - * <code>0</code>, and less than the length of this sequence. - * </p> - * - * @param index the index of the desired <code>Char</code> value. - * @return the <code>Char</code> value at the specified index. - * @throws IndexOutOfBoundsException if <code>index</code> is - * negative or greater than or equal to <code>length()</code>. + /** Returns the Char at the specified index, counting from 0 as in Arrays. + * + * @param index the index to look up + * @return the Char at the given index. + * @throws IndexOutOfBoundsException if the index is out of bounds. */ def charAt(index: Int): Char = { if (index < 0 || index >= count) @@ -142,18 +124,16 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) array(index) } - /** Same as <code>charAt</code>. */ + /** Equivalent to charAt. + */ def apply(i: Int): Char = charAt(i) - /** <p> - * Removes the <code>Char</code> at the specified position in this - * sequence. This sequence is shortened by one <code>Char</code>. - * </p> + /** Removes the Char at the specified index. The sequence is + * shortened by one. * - * @param index Index of <code>Char</code> to remove - * @return This object. - * @throws StringIndexOutOfBoundsException if the <code>index</code> - * is negative or greater than or equal to <code>length()</code>. + * @param index The index to remove. + * @return This StringBuilder. + * @throws IndexOutOfBoundsException if the index is out of bounds. */ def deleteCharAt(index: Int): StringBuilder = { if (index < 0 || index >= count) @@ -163,21 +143,11 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) this } - /** <p> - * The character at the specified index is set to <code>ch</code>. This - * sequence is altered to represent a new character sequence that is - * identical to the old character sequence, except that it contains the - * character <code>ch</code> at position <code>index</code>. - * </p> - * <p> - * The index argument must be greater than or equal to - * <code>0</code>, and less than the length of this sequence. - * </p> - * - * @param index the index of the character to modify. - * @param ch the new character. - * @throws IndexOutOfBoundsException if <code>index</code> is - * negative or greater than or equal to <code>length()</code>. + /** Update the sequence at the given index to hold the specified Char. + * + * @param index the index to modify. + * @param ch the new Char. + * @throws IndexOutOfBoundsException if the index is out of bounds. */ def setCharAt(index: Int, ch: Char) { if (index < 0 || index >= count) @@ -185,33 +155,32 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) array(index) = ch } - /** Same as <code>setCharAt</code>. */ + /** Equivalent to setCharAt. + */ def update(i: Int, c: Char) { setCharAt(i, c) } - /** Returns a new <code>String</code> that contains a subsequence of - * characters currently contained in this character sequence. The - * substring begins at the specified index and extends to the end of - * this sequence. + /** Returns a new String made up of a subsequence of this sequence, + * beginning at the given index and extending to the end of the sequence. * - * @param start The beginning index, inclusive. - * @return The new string. - * @throws StringIndexOutOfBoundsException if <code>start</code> is - * less than zero, or greater than the length of this object. + * target.substring(start) is equivalent to target.drop(start) + * + * @param start The starting index, inclusive. + * @return The new String. + * @throws IndexOutOfBoundsException if the index is out of bounds. */ - def substring(start: Int): String = substring(start, count) + def substring(start: Int): String = substring(start, length) - /** Returns a new <code>String</code> that contains a subsequence of - * characters currently contained in this sequence. The - * substring begins at the specified <code>start</code> and - * extends to the character at index <code>end - 1</code>. + /** Returns a new String made up of a subsequence of this sequence, + * beginning at the start index (inclusive) and extending to the + * end index (exclusive). + * + * target.substring(start, end) is equivalent to target.slice(start, end).mkString * * @param start The beginning index, inclusive. * @param end The ending index, exclusive. - * @return The new string. - * @throws StringIndexOutOfBoundsException if <code>start</code> - * or <code>end</code> are negative or greater than - * <code>length()</code>, or <code>start</code> is - * greater than <code>end</code>. + * @return The new String. + * @throws StringIndexOutOfBoundsException If either index is out of bounds, + * or if start > end. */ def substring(start: Int, end: Int): String = { if (start < 0) @@ -225,36 +194,29 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) def subSequence(start: Int, end: Int): java.lang.CharSequence = substring(start, end) - /* Appends the string representation of the <code>Any</code> argument. + /** Appends the given Char to the end of the sequence. */ def +=(x: Char): this.type = { append(x); this } + /** !!! This should create a new sequence. + */ def +(x: Char): this.type = { +=(x); this } - - /** <p> - * Appends the string representation of the <code>Any</code> - * argument. - * </p> - * <p> - * The argument is converted to a string as if by the method - * <code>String.valueOf</code>, and the characters of that - * string are then appended to this sequence. - * </p> + /** Appends the string representation of the given argument, + * which is converted to a String with String.valueOf. * * @param x an <code>Any</code> object. - * @return a reference to this object. + * @return this StringBuilder. */ - def append(x: Any): StringBuilder = - append(String.valueOf(x)) + def append(x: Any): StringBuilder = append(String.valueOf(x)) - /** Appends the specified string to this character sequence. + /** Appends the given String to this sequence. * - * @param s a string. - * @return a reference to this object. + * @param s a String. + * @return this StringBuilder. */ def append(s: String): StringBuilder = { - val str = if (s == null) "null" else s + val str = onull(s) val len = str.length ensureCapacity(count + len) str.getChars(0, len, array, count) @@ -278,92 +240,48 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) this } - /** <p> - * Appends the string representation of the <code>Char</code> sequence - * argument to this sequence. - * </p> - * <p> - * The characters of the sequence argument are appended, in order, - * to the contents of this sequence. The length of this sequence - * increases by the length of the argument. - * </p> + /** Appends all the Chars in the given Seq[Char] to this sequence. * - * @param x the characters to be appended. - * @return a reference to this object. + * @param xs the characters to be appended. + * @return this StringBuilder. */ - def appendAll(x: Seq[Char]): StringBuilder = - appendAll(x.toArray, 0, x.length) + def appendAll(xs: Seq[Char]): StringBuilder = appendAll(xs.toArray, 0, xs.length) - @deprecated("use appendAll instead. This method is deprecated because of the\n"+ - "possible confusion with `append(Any)'.") - def append(x: Seq[Char]): StringBuilder = - appendAll(x) - - /** <p> - * Appends the string representation of the <code>Char</code> array - * argument to this sequence. - * </p> - * <p> - * The characters of the array argument are appended, in order, to - * the contents of this sequence. The length of this sequence - * increases by the length of the argument. - * </p> + /** Appends all the Chars in the given Array[Char] to this sequence. * - * @param x the characters to be appended. - * @return a reference to this object. + * @param xs the characters to be appended. + * @return a reference to this object. */ - def appendAll(x: Array[Char]): StringBuilder = - appendAll(x, 0, x.length) + def appendAll(xs: Array[Char]): StringBuilder = appendAll(xs, 0, xs.length) - @deprecated("use appendAll instead. This method is deprecated because\n"+ - "of the possible confusion with `append(Any)'.") - def append(x: Array[Char]): StringBuilder = - appendAll(x) - - /** <p> - * Appends the string representation of a subarray of the - * <code>char</code> array argument to this sequence. - * </p> - * <p> - * Characters of the <code>Char</code> array <code>x</code>, starting at - * index <code>offset</code>, are appended, in order, to the contents - * of this sequence. The length of this sequence increases - * by the value of <code>len</code>. - * </p> - * - * @param x the characters to be appended. - * @param offset the index of the first <code>Char</code> to append. - * @param len the number of <code>Char</code>s to append. - * @return a reference to this object. - */ - def appendAll(x: Array[Char], offset: Int, len: Int): StringBuilder = { + /** Appends a portion of the given Array[Char] to this sequence. + * + * @param xs the Array containing Chars to be appended. + * @param offset the index of the first Char to append. + * @param len the numbers of Chars to append. + * @return this StringBuilder. + */ + def appendAll(xs: Array[Char], offset: Int, len: Int): StringBuilder = { ensureCapacity(count + len) - arraycopy(x, offset, array, count, len) + arraycopy(xs, offset, array, count, len) count += len this } - @deprecated("use appendAll instead. This method is deprecated because\n"+ - "of the possible confusion with `append(Any, Int, Int)'.") - def append(x: Array[Char], offset: Int, len: Int): StringBuilder = - appendAll(x, offset, len) - - /** <p> - * Appends the string representation of the <code>Boolean</code> - * argument to the sequence. - * </p> - * <p> - * The argument is converted to a string as if by the method - * <code>String.valueOf</code>, and the characters of that - * string are then appended to this sequence. - * </p> - * - * @param x a <code>Boolean</code>. - * @return a reference to this object. + /** Append the String representation of the given primitive type + * to this sequence. The argument is converted to a String with + * String.valueOf. + * + * @param x a primitive value + * @return This StringBuilder. */ def append(x: Boolean): StringBuilder = append(String.valueOf(x)) def append(x: Byte): StringBuilder = append(String.valueOf(x)) - + def append(x: Short): StringBuilder = append(String.valueOf(x)) + def append(x: Int): StringBuilder = append(String.valueOf(x)) + def append(x: Long): StringBuilder = append(String.valueOf(x)) + def append(x: Float): StringBuilder = append(String.valueOf(x)) + def append(x: Double): StringBuilder = append(String.valueOf(x)) def append(x: Char): StringBuilder = { ensureCapacity(count + 1) array(count) = x @@ -371,33 +289,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) this } - def append(x: Short): StringBuilder = - append(String.valueOf(x)) - - def append(x: Int): StringBuilder = - append(String.valueOf(x)) - - def append(x: Long): StringBuilder = - append(String.valueOf(x)) - - def append(x: Float): StringBuilder = - append(String.valueOf(x)) - - def append(x: Double): StringBuilder = - append(String.valueOf(x)) - - /** Removes the characters in a substring of this sequence. - * The substring begins at the specified <code>start</code> and extends to - * the character at index <code>end - 1</code> or to the end of the - * sequence if no such character exists. If - * <code>start</code> is equal to <code>end</code>, no changes are made. + /** Remove a subsequence of Chars from this sequence, starting at the + * given start index (inclusive) and extending to the end index (exclusive) + * or to the end of the String, whichever comes first. * * @param start The beginning index, inclusive. * @param end The ending index, exclusive. - * @return This object. - * @throws StringIndexOutOfBoundsException if <code>start</code> - * is negative, greater than <code>length()</code>, or - * greater than <code>end</code>. + * @return This StringBuilder. + * @throws StringIndexOutOfBoundsException if start < 0 || start > end */ def delete(start: Int, end: Int): StringBuilder = { if (start < 0 || start > end) @@ -411,20 +310,14 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) this } - /** Replaces the characters in a substring of this sequence - * with characters in the specified <code>String</code>. The substring - * begins at the specified <code>start</code> and extends to the character - * at index <code>end - 1</code> or to the end of the sequence if no such - * character exists. First the characters in the substring are removed and - * then the specified <code>String</code> is inserted at <code>start</code>. + /** Replaces a subsequence of Chars with the given String. The semantics + * are as in delete, with the String argument then inserted at index 'start'. * * @param start The beginning index, inclusive. * @param end The ending index, exclusive. - * @param str String that will replace previous contents. - * @return This object. - * @throws StringIndexOutOfBoundsException if <code>start</code> - * is negative, greater than <code>length()</code>, or - * greater than <code>end</code>. + * @param str The String to be inserted at the start index. + * @return This StringBuilder. + * @throws StringIndexOutOfBoundsException if start < 0, start > length, or start > end */ def replace(start: Int, end: Int, str: String) { if (start < 0 || start > count || start > end) @@ -441,25 +334,17 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) this } - /** Inserts the string representation of a subarray of the <code>str</code> - * array argument into this sequence. The subarray begins at the specified - * <code>offset</code> and extends <code>len</code> <code>char</code>s. - * The characters of the subarray are inserted into this sequence at - * the position indicated by <code>index</code>. The length of this - * sequence increases by <code>len</code> <code>Char</code>s. - * - * @param index position at which to insert subarray. - * @param str a <code>Char</code> array. - * @param offset the index of the first <code>char</code> in subarray to - * be inserted. - * @param len the number of <code>Char</code>s in the subarray to - * be inserted. - * @return This object - * @throws StringIndexOutOfBoundsException if <code>index</code> - * is negative or greater than <code>length()</code>, or - * <code>offset</code> or <code>len</code> are negative, or - * <code>(offset+len)</code> is greater than - * <code>str.length</code>. + /** Inserts a subarray of the given Array[Char] at the given index + * of this sequence. + * + * @param index index at which to insert the subarray. + * @param str the Array from which Chars will be taken. + * @param offset the index of the first Char to insert. + * @param len the number of Chars from 'str' to insert. + * @return This StringBuilder. + * + * @throws StringIndexOutOfBoundsException if index < 0, index > length, + * offset < 0, len < 0, or (offset + len) > str.length. */ def insertAll(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder = { if (index < 0 || index > count) @@ -475,368 +360,172 @@ final class StringBuilder(initCapacity: Int, private val initValue: String) this } - @deprecated("use insertAll instead. This method is deprecated because of the\n"+ - "possible confusion with `insert(Int, Any, Int, Int)'.") - def insert(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder = - insertAll(index, str, offset, len) - - /** <p> - * Inserts the string representation of the <code>Any</code> - * argument into this character sequence. - * </p> - * <p> - * The second argument is converted to a string as if by the method - * <code>String.valueOf</code>, and the characters of that - * string are then inserted into this sequence at the indicated - * offset. - * </p> - * <p> - * The offset argument must be greater than or equal to - * <code>0</code>, and less than or equal to the length of this - * sequence. - * </p> - * - * @param offset the offset. - * @param x an <code>Any</code> value. - * @return a reference to this object. - * @throws StringIndexOutOfBoundsException if the offset is invalid. - */ - def insert(at: Int, x: Any): StringBuilder = - insert(at, String.valueOf(x)) - - /** Inserts the string into this character sequence. - * - * @param at the offset position. - * @param x a string. - * @return a reference to this object. - * @throws StringIndexOutOfBoundsException if the offset is invalid. + /** Inserts the String representation (via String.valueOf) of the given + * argument into this sequence at the given index. + * + * @param index the index at which to insert. + * @param x a value. + * @return this StringBuilder. + * @throws StringIndexOutOfBoundsException if the index is out of bounds. */ - def insert(at: Int, x: String): StringBuilder = { - if (at < 0 || at > count) - throw new StringIndexOutOfBoundsException(at) - val str = if (x == null) "null" else x - val len = str.length - ensureCapacity(count + len) - arraycopy(array, at, array, at + len, count - at) - str.getChars(0, len, array, at) - count += len - this - } + def insert(index: Int, x: Any): StringBuilder = insert(index, String.valueOf(x)) - /** Inserts the string representation of the <code>Char</code> sequence - * argument into this sequence. + /** Inserts the String into this character sequence. * - * @param at the offset position. - * @param x a character sequence. - * @return a reference to this object. - * @throws StringIndexOutOfBoundsException if the offset is invalid. + * @param index the index at which to insert. + * @param x a String. + * @return this StringBuilder. + * @throws StringIndexOutOfBoundsException if the index is out of bounds. */ - def insertAll(at: Int, x: Seq[Char]): StringBuilder = - insertAll(at, x.toArray) + def insert(index: Int, x: String): StringBuilder = insertAll(index, x.toArray) - @deprecated("use insertAll instead. This method is deprecated because of\n"+ - "the possible confusion with `insert(Int, Any)'.") - def insert(at: Int, x: Seq[Char]): StringBuilder = - insertAll(at, x) + /** Inserts the given Seq[Char] into this sequence at the given index. + * + * @param index the index at which to insert. + * @param xs the Seq[Char]. + * @return this StringBuilder. + * @throws StringIndexOutOfBoundsException if the index is out of bounds. + */ + def insertAll(index: Int, xs: Seq[Char]): StringBuilder = insertAll(index, xs.toArray) - /** Inserts the string representation of the <code>Char</code> array - * argument into this sequence. + /** Inserts the given Array[Char] into this sequence at the given index. * - * @param at the offset position. - * @param x a character array. - * @return a reference to this object. - * @throws StringIndexOutOfBoundsException if the offset is invalid. + * @param index the index at which to insert. + * @param xs the Array[Char]. + * @return this StringBuilder. + * @throws StringIndexOutOfBoundsException if the index is out of bounds. */ - def insertAll(at: Int, x: Array[Char]): StringBuilder = { - if (at < 0 || at > count) - throw new StringIndexOutOfBoundsException(at) - val len = x.length + def insertAll(index: Int, xs: Array[Char]): StringBuilder = { + if (index < 0 || index > count) + throw new StringIndexOutOfBoundsException(index) + val len = xs.length ensureCapacity(count + len) - arraycopy(array, at, array, at + len, count - at) - arraycopy(x, 0, array, at, len) + arraycopy(array, index, array, index + len, count - index) + arraycopy(xs, 0, array, index, len) count += len this } + /** Calls String.valueOf on the given primitive value, and inserts the + * String at the given index. + * + * @param index the offset position. + * @param x a primitive value. + * @return this StringBuilder. + */ + def insert(index: Int, x: Boolean): StringBuilder = insert(index, String.valueOf(x)) + def insert(index: Int, x: Byte): StringBuilder = insert(index, String.valueOf(x)) + def insert(index: Int, x: Short): StringBuilder = insert(index, String.valueOf(x)) + def insert(index: Int, x: Int): StringBuilder = insert(index, String.valueOf(x)) + def insert(index: Int, x: Long): StringBuilder = insert(index, String.valueOf(x)) + def insert(index: Int, x: Float): StringBuilder = insert(index, String.valueOf(x)) + def insert(index: Int, x: Double): StringBuilder = insert(index, String.valueOf(x)) + def insert(index: Int, x: Char): StringBuilder = { + if (index < 0 || index > count) + throw new StringIndexOutOfBoundsException(index) + ensureCapacity(count + 1) + arraycopy(array, index, array, index + 1, count - index) + array(index) = x + count += 1 + this + } + + @deprecated("Use appendAll instead. This method is deprecated because of the\n"+ + "possible confusion with `append(Any)'.") + def append(x: Seq[Char]): StringBuilder = appendAll(x) + + @deprecated("use appendAll instead. This method is deprecated because\n"+ + "of the possible confusion with `append(Any)'.") + def append(x: Array[Char]): StringBuilder = appendAll(x) + + @deprecated("use appendAll instead. This method is deprecated because\n"+ + "of the possible confusion with `append(Any, Int, Int)'.") + def append(x: Array[Char], offset: Int, len: Int): StringBuilder = appendAll(x, offset, len) + + @deprecated("use insertAll instead. This method is deprecated because of the\n"+ + "possible confusion with `insert(Int, Any, Int, Int)'.") + def insert(index: Int, str: Array[Char], offset: Int, len: Int): StringBuilder = + insertAll(index, str, offset, len) + + @deprecated("use insertAll instead. This method is deprecated because of\n"+ + "the possible confusion with `insert(Int, Any)'.") + def insert(at: Int, x: Seq[Char]): StringBuilder = insertAll(at, x) + @deprecated("use insertAll instead. This method is deprecated because of\n"+ "the possible confusion with `insert(Int, Any)'.") def insert(at: Int, x: Array[Char]): StringBuilder = insertAll(at, x) - /** <p> - * Inserts the string representation of the <code>Boolean</code> argument - * into this sequence. - * </p> - * <p> - * The offset argument must be greater than or equal to 0, and less than - * or equal to the length of this sequence. - * </p> - * - * @param at the offset position. - * @param x a <code>Boolean</code> value. - * @return a reference to this object. - */ - def insert(at: Int, x: Boolean): StringBuilder = - insert(at, String.valueOf(x)) - - /** <p> - * Inserts the string representation of the <code>Byte</code> argument - * into this sequence. - * </p> - * <p> - * The offset argument must be greater than or equal to 0, and less than - * or equal to the length of this sequence. - * </p> + /** Finds the index of the first occurrence of the specified substring. * - * @param at the offset position. - * @param x a <code>Byte</code> value. - * @return a reference to this object. + * @param str the target string to search for + * @return the first applicable index where target occurs, or -1 if not found. */ - def insert(at: Int, x: Byte): StringBuilder = - insert(at, String.valueOf(x)) + def indexOf(str: String): Int = indexOf(str, 0) - /** <p> - * Inserts the string representation of the <code>Char</code> argument - * into this sequence. - * </p> - * <p> - * The offset argument must be greater than or equal to 0, and less than - * or equal to the length of this sequence. - * </p> + /** Finds the index of the first occurrence of the specified substring. * - * @param at the offset position. - * @param x a <code>Char</code> value. - * @return a reference to this object. - */ - def insert(at: Int, x: Char): StringBuilder = { - if (at < 0 || at > count) - throw new StringIndexOutOfBoundsException(at) - ensureCapacity(count + 1) - arraycopy(array, at, array, at + 1, count - at) - array(at) = x - count += 1 - this - } - - /** <p> - * Inserts the string representation of the <code>Short</code> argument - * into this sequence. - * </p> - * <p> - * The offset argument must be greater than or equal to 0, and less than - * or equal to the length of this sequence. - * </p> - * - * @param at the offset position. - * @param x a <code>Short</code> value. - * @return a reference to this object. + * @param str the target string to search for + * @param fromIndex the smallest index in the source string to consider + * @return the first applicable index where target occurs, or -1 if not found. */ - def insert(at: Int, x: Short): StringBuilder = - insert(at, String.valueOf(x)) + def indexOf(str: String, fromIndex: Int): Int = indexOfSlice(str.toIndexedSeq, fromIndex) - /** <p> - * Inserts the string representation of the <code>Int</code> argument - * into this sequence. - * </p> - * <p> - * The offset argument must be greater than or equal to 0, and less than - * or equal to the length of this sequence. - * </p> + /** Finds the index of the last occurrence of the specified substring. * - * @param at the offset position. - * @param x a <code>Int</code> value. - * @return a reference to this object. + * @param str the target string to search for + * @return the last applicable index where target occurs, or -1 if not found. */ - def insert(at: Int, x: Int): StringBuilder = - insert(at, String.valueOf(x)) + def lastIndexOf(str: String): Int = lastIndexOf(str, count) - /** <p> - * Inserts the string representation of the <code>Long</code> argument - * into this sequence. - * </p> - * <p> - * The offset argument must be greater than or equal to 0, and less than - * or equal to the length of this sequence. - * </p> + /** Finds the index of the last occurrence of the specified substring. * - * @param at the offset position. - * @param x a <code>Long</code> value. - * @return a reference to this object. + * @param str the target string to search for + * @param fromIndex the smallest index in the source string to consider + * @return the last applicable index where target occurs, or -1 if not found. */ - def insert(at: Int, x: Long): StringBuilder = - insert(at, String.valueOf(x)) + def lastIndexOf(str: String, fromIndex: Int): Int = lastIndexOfSlice(str.toIndexedSeq, fromIndex) - /** <p> - * Inserts the string representation of the <code>Float</code> argument - * into this sequence. - * </p> - * <p> - * The offset argument must be greater than or equal to 0, and less than - * or equal to the length of this sequence. - * </p> + /** Creates a new StringBuilder with the reversed contents of this one. + * If surrogate pairs are present, they are treated as indivisible units: each + * pair will appear in the same order in the updated sequence. * - * @param at the offset position. - * @param x a <code>Float</code> value. - * @return a reference to this object. + * @return the reversed StringBuilder */ - def insert(at: Int, x: Float): StringBuilder = - insert(at, String.valueOf(x)) + @migration(2, 8, "Since 2.8 reverse returns a new instance. Use 'reverseContents' to update in place.") + override def reverse: StringBuilder = new StringBuilder(this.toString).reverseContents() - /** <p> - * Inserts the string representation of the <code>Double</code> argument - * into this sequence. - * </p> - * <p> - * The offset argument must be greater than or equal to 0, and less than - * or equal to the length of this sequence. - * </p> + /** Like reverse, but destructively updates the target StringBuilder. * - * @param at the offset position. - * @param x a <code>Double</code> value. - * @return a reference to this object. - */ - def insert(at: Int, x: Double): StringBuilder = - insert(at, String.valueOf(x)) - - /** <p> - * Returns the index within this string of the first occurrence of the - * specified substring. The integer returned is the smallest value - * <i>k</i> such that: - * </p> - * <blockquote><pre> - * this.toString().startsWith(str, <i>k</i>)</pre> - * </blockquote> - * <p> - * is <code>true</code>. - * </p> - * - * @param str any string. - * @return if the string argument occurs as a substring within this - * object, then the index of the first character of the first - * such substring is returned; if it does not occur as a - * substring, <code>-1</code> is returned. - * @throws NullPointerException if <code>str</code> is <code>null</code>. + * @return the reversed StringBuilder (same as the target StringBuilder) */ - def indexOf(str: String): Int = indexOf(str, 0) + def reverseContents(): StringBuilder = { + // record of indices of pairs which need to be swapped + val surrogates = new ListBuffer[(Int, Int)] + val half = count / 2 - /** <p> - * Returns the index within this string of the first occurrence of the - * specified substring, starting at the specified index. The integer - * returned is the smallest value <code>k</code> for which: - * </p><pre> - * k >= math.min(fromIndex, str.length()) && - * this.toString().startsWith(str, k)</pre> - * <p> - * If no such value of <code>k</code> exists, then <code>-1</code> - * is returned. - * </p> - * - * @param str the substring for which to search. - * @param fromIndex the index from which to start the search. - * @return the index within this string of the first occurrence - * of the specified substring, starting at the specified index. - */ - def indexOf(str: String, fromIndex: Int): Int = indexOfSlice(str.toIndexedSeq, fromIndex) - - /** <p> - * Returns the index within this string of the rightmost occurrence - * of the specified substring. The rightmost empty string "" is - * considered to occur at the index value <code>this.length()</code>. - * The returned index is the largest value <i>k</i> such that - * </p> - * <blockquote><pre> - * this.toString().startsWith(str, k)</pre> - * </blockquote> - * <p> - * is true. - * </p> - * - * @param str the substring to search for. - * @return if the string argument occurs one or more times as a substring - * within this object, then the index of the first character of - * the last such substring is returned. If it does not occur as - * a substring, <code>-1</code> is returned. - * @throws NullPointerException if <code>str</code> is <code>null</code>. - */ - def lastIndexOf(str: String): Int = lastIndexOf(str, count) + def mirror(x: Int) = count - 1 - x + def swap(i1: Int, i2: Int) { + val tmp = array(i2) + array(i2) = array(i1) + array(i1) = tmp + } - /** <p> - * Returns the index within this string of the last occurrence of the - * specified substring. The integer returned is the largest value - * <code>k</code> such that: - * </p><pre>val - * k <= math.min(fromIndex, str.length()) && - * this.toString().startsWith(str, k)</pre> - * <p> - * If no such value of <code>k</code> exists, then <code>-1</code> - * is returned. - * </p> - * - * @param str the substring to search for. - * @param fromIndex the index to start the search from. - * @return the index within this sequence of the last occurrence - * of the specified substring. - */ - def lastIndexOf(str: String, fromIndex: Int): Int = lastIndexOfSlice(str.toIndexedSeq, fromIndex) + for ((i, j) <- 0 until half zip (count - 1 to half by -1)) { + if (array(i).isSurrogate && array(i + 1).isSurrogate) + surrogates += ((j - 1, j)) + if (array(j).isSurrogate && array(j - 1).isSurrogate) + surrogates += ((i, i + 1)) - /** <p> - * Causes this character sequence to be replaced by the reverse of the - * sequence. If there are any surrogate pairs included in the sequence, - * these are treated as single characters for the reverse operation. - * Thus, the order of the high-low surrogates is never reversed. - * </p> - * <p> - * Let <i>n</i> be the character length of this character sequence - * (not the length in <code>Char</code> values) just prior to - * execution of the <code>reverse</code> method. Then the - * character at index <i>k</i> in the new character sequence is - * equal to the character at index <i>n-k-1</i> in the old - * character sequence. - * </p> - * - * @return a reference to this object. - */ - override def reverse(): StringBuilder = { - var hasSurrogate = false - val n = count - 1 - var j = (n-1) >> 1 - while (j >= 0) { - val temp = array(j) - val temp2 = array(n - j) - if (!hasSurrogate) - hasSurrogate = - (temp >= Character.MIN_HIGH_SURROGATE && temp <= Character.MAX_LOW_SURROGATE) || - (temp2 >= Character.MIN_HIGH_SURROGATE && temp2 <= Character.MAX_LOW_SURROGATE) - array(j) = temp2 - array(n - j) = temp - j -= 1 - } - if (hasSurrogate) { - // Reverse back all valid surrogate pairs - var i = 0 - while (i < count - 1) { - val c2 = array(i) - if (Character.isLowSurrogate(c2)) { - val c1 = array(i + 1) - if (Character.isHighSurrogate(c1)) { - array(i) = c1; i += 1 - array(i) = c2 - } - } - i += 1 - } + swap(i, j) } + surrogates foreach (swap _).tupled this } - /** Returns a string representing the data in this sequence. - * A new <code>String</code> object is allocated and initialized to - * contain the character sequence currently represented by this - * object. This <code>String</code> is then returned. Subsequent - * changes to this sequence do not affect the contents of the - * <code>String</code>. + /** Returns a new String representing the data in this sequence. * - * @return a string representation of this sequence of characters. + * @return the current contents of this sequence as a String */ override def toString: String = new String(array, 0, count) @@ -852,4 +541,7 @@ object StringBuilder arraycopy(src, 0, dest, 0, src.length min newLength) dest } + + // for mimicking java's propensity to make null into "null" + private def onull(s: String): String = if (s == null) "null" else s } diff --git a/src/library/scala/concurrent/TaskRunner.scala b/src/library/scala/concurrent/TaskRunner.scala index 0853007a28..f7d3002b83 100644 --- a/src/library/scala/concurrent/TaskRunner.scala +++ b/src/library/scala/concurrent/TaskRunner.scala @@ -25,9 +25,4 @@ trait TaskRunner { def shutdown(): Unit - /** If expression computed successfully return it in <code>Right</code>, - * otherwise return exception in <code>Left</code>. - */ - protected def tryCatch[A](body: => A): Either[Exception, A] = - ops tryCatchEx body } diff --git a/src/library/scala/concurrent/ThreadRunner.scala b/src/library/scala/concurrent/ThreadRunner.scala index 13bf20ff2a..5cfc076699 100644 --- a/src/library/scala/concurrent/ThreadRunner.scala +++ b/src/library/scala/concurrent/ThreadRunner.scala @@ -25,6 +25,14 @@ class ThreadRunner extends FutureTaskRunner { implicit def functionAsTask[S](fun: () => S): Task[S] = fun implicit def futureAsFunction[S](x: Future[S]): () => S = x + /* If expression computed successfully return it in `Right`, + * otherwise return exception in `Left`. + */ + private def tryCatch[A](body: => A): Either[Exception, A] = + try Right(body) catch { + case ex: Exception => Left(ex) + } + def execute[S](task: Task[S]) { val runnable = new Runnable { def run() { tryCatch(task()) } @@ -38,7 +46,7 @@ class ThreadRunner extends FutureTaskRunner { def run() { result set tryCatch(task()) } } (new Thread(runnable)).start() - () => ops getOrThrow result.get + () => result.get.fold[S](throw _, identity _) } def managedBlock(blocker: ManagedBlocker) { diff --git a/src/library/scala/concurrent/ops.scala b/src/library/scala/concurrent/ops.scala index 6537a47258..49be1b882c 100644 --- a/src/library/scala/concurrent/ops.scala +++ b/src/library/scala/concurrent/ops.scala @@ -23,21 +23,13 @@ object ops val defaultRunner: FutureTaskRunner = TaskRunners.threadRunner /** - * If expression computed successfully return it in <code>Right</code>, - * otherwise return exception in <code>Left</code>. + * If expression computed successfully return it in `Right`, + * otherwise return exception in `Left`. */ - //TODO: make private - def tryCatch[A](body: => A): Either[Throwable, A] = + private def tryCatch[A](body: => A): Either[Throwable, A] = allCatch[A] either body - //TODO: make private - def tryCatchEx[A](body: => A): Either[Exception, A] = - try Right(body) catch { - case ex: Exception => Left(ex) - } - - //TODO: make private - def getOrThrow[T <: Throwable, A](x: Either[T, A]): A = + private def getOrThrow[T <: Throwable, A](x: Either[T, A]): A = x.fold[A](throw _, identity _) /** Evaluates an expression asynchronously. diff --git a/src/library/scala/math/BigDecimal.scala b/src/library/scala/math/BigDecimal.scala index c4cccd1f52..67604e8b78 100644 --- a/src/library/scala/math/BigDecimal.scala +++ b/src/library/scala/math/BigDecimal.scala @@ -19,24 +19,23 @@ import scala.collection.immutable.NumericRange * @version 1.0 * @since 2.7 */ -object BigDecimal -{ - @serializable - object RoundingMode extends Enumeration(java.math.RoundingMode.values map (_.toString) : _*) { - type RoundingMode = Value - val UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY = Value - } - +object BigDecimal { private val minCached = -512 private val maxCached = 512 - val MinLong = BigDecimal(Long.MinValue) - val MaxLong = BigDecimal(Long.MaxValue) + val defaultMathContext = MathContext.UNLIMITED + + val MinLong = new BigDecimal(BigDec valueOf Long.MinValue, defaultMathContext) + val MaxLong = new BigDecimal(BigDec valueOf Long.MaxValue, defaultMathContext) /** Cache ony for defaultMathContext using BigDecimals in a small range. */ private lazy val cache = new Array[BigDecimal](maxCached - minCached + 1) - val defaultMathContext = MathContext.UNLIMITED + @serializable + object RoundingMode extends Enumeration(java.math.RoundingMode.values map (_.toString) : _*) { + type RoundingMode = Value + val UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY = Value + } /** Constructs a <code>BigDecimal</code> using the java BigDecimal static * valueOf constructor. diff --git a/src/library/scala/reflect/Manifest.scala b/src/library/scala/reflect/Manifest.scala index b7cb86e1bd..d718011ff9 100644 --- a/src/library/scala/reflect/Manifest.scala +++ b/src/library/scala/reflect/Manifest.scala @@ -245,16 +245,15 @@ object Manifest { override def toString = prefix.toString+"#"+name+argString } - /** Manifest for the abstract type `prefix # name'. `upperBound' is not - * strictly necessary as it could be obtained by reflection. It was - * added so that erasure can be calculated without reflection. - * todo: remove after next bootstrap + /** Manifest for the unknown type `_ >: L <: U' in an existential. */ - def abstractType[T](prefix: Manifest[_], name: String, upperbound: ClassManifest[_], args: Manifest[_]*): Manifest[T] = + def wildcardType[T](lowerBound: Manifest[_], upperBound: Manifest[_]): Manifest[T] = new (Manifest[T] @serializable) { - def erasure = upperbound.erasure - override val typeArguments = args.toList - override def toString = prefix.toString+"#"+name+argString + def erasure = upperBound.erasure + override def toString = + "_" + + (if (lowerBound eq Nothing) "" else " >: "+lowerBound) + + (if (upperBound eq Nothing) "" else " <: "+upperBound) } /** Manifest for the intersection type `parents_0 with ... with parents_n'. */ diff --git a/src/library/scala/reflect/generic/Flags.scala b/src/library/scala/reflect/generic/Flags.scala index f0f1f14ade..c8ef529bc1 100755 --- a/src/library/scala/reflect/generic/Flags.scala +++ b/src/library/scala/reflect/generic/Flags.scala @@ -53,9 +53,10 @@ class Flags { 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 PARAMACCESSOR = 0x20000000 // for field definitions generated for primary constructor + // parameters (no matter if it's a 'val' parameter or not) + // for parameters of a primary constructor ('val' or not) + // for the accessor methods generated for 'val' or 'var' parameters 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 diff --git a/src/library/scala/reflect/generic/Trees.scala b/src/library/scala/reflect/generic/Trees.scala index df93d157e3..c880a335de 100755 --- a/src/library/scala/reflect/generic/Trees.scala +++ b/src/library/scala/reflect/generic/Trees.scala @@ -37,6 +37,7 @@ trait Trees { self: Universe => def isProtected = hasFlag(PROTECTED) def isPublic = !isPrivate && !isProtected def isSealed = hasFlag(SEALED ) + def isSynthetic = hasFlag(SYNTHETIC) def isTrait = hasFlag(TRAIT ) def isVariable = hasFlag(MUTABLE ) diff --git a/src/library/scala/runtime/RichChar.scala b/src/library/scala/runtime/RichChar.scala index f5e2625fd8..1c95186558 100644 --- a/src/library/scala/runtime/RichChar.scala +++ b/src/library/scala/runtime/RichChar.scala @@ -48,6 +48,7 @@ final class RichChar(x: Char) extends Proxy with Ordered[Char] { def isSpaceChar: Boolean = Character.isSpaceChar(x) def isHighSurrogate: Boolean = Character.isHighSurrogate(x) def isLowSurrogate: Boolean = Character.isLowSurrogate(x) + def isSurrogate: Boolean = isHighSurrogate || isLowSurrogate def isUnicodeIdentifierStart: Boolean = Character.isUnicodeIdentifierStart(x) def isUnicodeIdentifierPart: Boolean = Character.isUnicodeIdentifierPart(x) def isIdentifierIgnorable: Boolean = Character.isIdentifierIgnorable(x) diff --git a/src/library/scala/transient.scala b/src/library/scala/transient.scala index d8b8ee4d86..aea7ba7b5f 100644 --- a/src/library/scala/transient.scala +++ b/src/library/scala/transient.scala @@ -11,4 +11,7 @@ package scala +import annotation.target._ + +@field class transient extends StaticAnnotation diff --git a/src/library/scala/util/parsing/combinator/RegexParsers.scala b/src/library/scala/util/parsing/combinator/RegexParsers.scala index 89c5050431..fd8ee60db0 100644 --- a/src/library/scala/util/parsing/combinator/RegexParsers.scala +++ b/src/library/scala/util/parsing/combinator/RegexParsers.scala @@ -67,6 +67,25 @@ trait RegexParsers extends Parsers { } } + /** `positioned' decorates a parser's result with the start position of the input it consumed. + * If whitespace is being skipped, then it is skipped before the start position is recorded. + * + * @param p a `Parser' whose result conforms to `Positional'. + * @return A parser that has the same behaviour as `p', but which marks its result with the + * start position of the input it consumed after whitespace has been skipped, if it + * didn't already have a position. + */ + override def positioned[T <: Positional](p: => Parser[T]): Parser[T] = { + val pp = super.positioned(p) + new Parser[T] { + def apply(in: Input) = { + val offset = in.offset + val start = handleWhiteSpace(in.source, offset) + pp(in.drop (start - offset)) + } + } + } + override def phrase[T](p: Parser[T]): Parser[T] = super.phrase(p <~ opt("""\z""".r)) diff --git a/src/library/scala/volatile.scala b/src/library/scala/volatile.scala index dda0493bf9..005cd6628c 100644 --- a/src/library/scala/volatile.scala +++ b/src/library/scala/volatile.scala @@ -11,4 +11,7 @@ package scala +import annotation.target._ + +@field class volatile extends StaticAnnotation diff --git a/src/library/scala/xml/NodeSeq.scala b/src/library/scala/xml/NodeSeq.scala index 3b56ba25e4..0cab5422b6 100644 --- a/src/library/scala/xml/NodeSeq.scala +++ b/src/library/scala/xml/NodeSeq.scala @@ -73,16 +73,18 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] w case _ => false } - /** Projection function. Similar to XPath, use <code>this \ "foo"</code> - * to get a list of all elements of this sequence that are labelled with - * <code>"foo"</code>. Use <code>\ "_"</code> as a wildcard. Use - * <code>ns \ "@foo"</code> to get the unprefixed attribute "foo". - * Use <code>ns \ "@{uri}foo"</code> to get the prefixed attribute - * "pre:foo" whose prefix "pre" is resolved to the namespace "uri". - * For attribute projections, the resulting NodeSeq attribute values are - * wrapped in a Group. - * There is no support for searching a prefixed attribute by - * its literal prefix. + /** Projection function, which returns elements of `this` sequence based on the string `that`. Use: + * - `this \ "foo"` to get a list of all elements that are labelled with `"foo"`; + * - `\ "_"` to get a list of all elements (wildcard); + * - `ns \ "@foo"` to get the unprefixed attribute `"foo"`; + * - `ns \ "@{uri}foo"` to get the prefixed attribute `"pre:foo"` whose prefix `"pre"` is resolved to the + * namespace `"uri"`. + * + * For attribute projections, the resulting [[scala.xml.NodeSeq]] attribute values are wrapped in a + * [[scala.xml.Group]]. + * + * There is no support for searching a prefixed attribute by its literal prefix. + * * The document order is preserved. * * @param that ... @@ -120,16 +122,19 @@ abstract class NodeSeq extends immutable.Seq[Node] with SeqLike[Node, NodeSeq] w } } - /** projection function. Similar to XPath, use <code>this \\ 'foo</code> - * to get a list of all elements of this sequence that are labelled with - * <code>"foo"</code>. Use <code>\\ "_"</code> as a wildcard. Use - * <code>ns \\ "@foo"</code> to get the unprefixed attribute "foo". - * Use <code>ns \\ "@{uri}foo"</code> to get each prefixed attribute - * "pre:foo" whose prefix "pre" is resolved to the namespace "uri". - * For attribute projections, the resulting NodeSeq attribute values are - * wrapped in a Group. - * There is no support for searching a prefixed attribute by - * its literal prefix. + /** Projection function, which returns elements of `this` sequence and of all its subsequences, based on + * the string `that`. Use: + * - `this \\ 'foo` to get a list of all elements that are labelled with `"foo"`; + * - `\\ "_"` to get a list of all elements (wildcard); + * - `ns \\ "@foo"` to get the unprefixed attribute `"foo"`; + * - `ns \\ "@{uri}foo"` to get each prefixed attribute `"pre:foo"` whose prefix `"pre"` is resolved to the + * namespace `"uri"`. + * + * For attribute projections, the resulting [[scala.xml.NodeSeq]] attribute values are wrapped in a + * [[scala.xml.Group]]. + * + * There is no support for searching a prefixed attribute by its literal prefix. + * * The document order is preserved. * * @param that ... diff --git a/src/library/scala/xml/Utility.scala b/src/library/scala/xml/Utility.scala index 48a23dc389..8637148489 100644 --- a/src/library/scala/xml/Utility.scala +++ b/src/library/scala/xml/Utility.scala @@ -194,22 +194,24 @@ object Utility extends AnyRef with parsing.TokenTests minimizeTags: Boolean = false): StringBuilder = { x match { - case c: Comment if !stripComments => c buildString sb - case x: SpecialNode => x buildString sb - case g: Group => for (c <- g.nodes) toXML(c, x.scope, sb) ; sb + case c: Comment => if (!stripComments) c buildString sb else sb + case x: SpecialNode => x buildString sb + case g: Group => + g.nodes foreach {toXML(_, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags)} + sb case _ => // print tag with namespace declarations sb.append('<') x.nameToString(sb) if (x.attributes ne null) x.attributes.buildString(sb) x.scope.buildString(sb, pscope) - if (x.child.isEmpty && minimizeTags) + if (x.child.isEmpty && minimizeTags) { // no children, so use short form: <xyz .../> sb.append(" />") - else { + } else { // children, so use long form: <xyz ...>...</xyz> sb.append('>') - sequenceToXML(x.child, x.scope, sb, stripComments) + sequenceToXML(x.child, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) sb.append("</") x.nameToString(sb) sb.append('>') @@ -221,20 +223,23 @@ object Utility extends AnyRef with parsing.TokenTests children: Seq[Node], pscope: NamespaceBinding = TopScope, sb: StringBuilder = new StringBuilder, - stripComments: Boolean = false): Unit = + stripComments: Boolean = false, + decodeEntities: Boolean = true, + preserveWhitespace: Boolean = false, + minimizeTags: Boolean = false): Unit = { if (children.isEmpty) return else if (children forall isAtomAndNotText) { // add space val it = children.iterator val f = it.next - toXML(f, pscope, sb) + toXML(f, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) while (it.hasNext) { val x = it.next sb.append(' ') - toXML(x, pscope, sb) + toXML(x, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) } } - else children foreach { toXML(_, pscope, sb) } + else children foreach { toXML(_, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) } } /** diff --git a/src/library/scala/xml/Xhtml.scala b/src/library/scala/xml/Xhtml.scala index 744fe260c2..162ea5696a 100644 --- a/src/library/scala/xml/Xhtml.scala +++ b/src/library/scala/xml/Xhtml.scala @@ -49,11 +49,11 @@ object Xhtml (minimizableElements contains x.label) x match { - case c: Comment if !stripComments => c buildString sb + case c: Comment => if (!stripComments) c buildString sb case er: EntityRef if decodeEntities => decode(er) case x: SpecialNode => x buildString sb case g: Group => - g.nodes foreach { toXhtml(_, x.scope, sb) } + g.nodes foreach { toXhtml(_, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) } case _ => sb.append('<') @@ -64,7 +64,7 @@ object Xhtml if (shortForm) sb.append(" />") else { sb.append('>') - sequenceToXML(x.child, x.scope, sb) + sequenceToXML(x.child, x.scope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) sb.append("</") x.nameToString(sb) sb.append('>') @@ -89,9 +89,9 @@ object Xhtml val doSpaces = children forall isAtomAndNotText // interleave spaces for (c <- children.take(children.length - 1)) { - toXhtml(c, pscope, sb) + toXhtml(c, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) if (doSpaces) sb append ' ' } - toXhtml(children.last, pscope, sb) + toXhtml(children.last, pscope, sb, stripComments, decodeEntities, preserveWhitespace, minimizeTags) } } |