summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/mutable
diff options
context:
space:
mode:
Diffstat (limited to 'src/library/scala/collection/mutable')
-rw-r--r--src/library/scala/collection/mutable/AVLTree.scala250
-rw-r--r--src/library/scala/collection/mutable/AnyRefMap.scala32
-rw-r--r--src/library/scala/collection/mutable/ArrayBuffer.scala13
-rw-r--r--src/library/scala/collection/mutable/ArrayBuilder.scala181
-rw-r--r--src/library/scala/collection/mutable/ArrayOps.scala28
-rw-r--r--src/library/scala/collection/mutable/ArraySeq.scala2
-rw-r--r--src/library/scala/collection/mutable/ArrayStack.scala7
-rw-r--r--src/library/scala/collection/mutable/BitSet.scala6
-rw-r--r--src/library/scala/collection/mutable/BufferLike.scala16
-rw-r--r--src/library/scala/collection/mutable/BufferProxy.scala2
-rw-r--r--src/library/scala/collection/mutable/Builder.scala16
-rw-r--r--src/library/scala/collection/mutable/GrowingBuilder.scala4
-rw-r--r--src/library/scala/collection/mutable/IndexedSeqView.scala1
-rw-r--r--src/library/scala/collection/mutable/LazyBuilder.scala4
-rw-r--r--src/library/scala/collection/mutable/ListBuffer.scala25
-rw-r--r--src/library/scala/collection/mutable/LongMap.scala26
-rw-r--r--src/library/scala/collection/mutable/MapBuilder.scala2
-rw-r--r--src/library/scala/collection/mutable/MapLike.scala12
-rw-r--r--src/library/scala/collection/mutable/MutableList.scala2
-rw-r--r--src/library/scala/collection/mutable/PriorityQueue.scala182
-rw-r--r--src/library/scala/collection/mutable/PriorityQueueProxy.scala96
-rw-r--r--src/library/scala/collection/mutable/RedBlackTree.scala580
-rw-r--r--src/library/scala/collection/mutable/ResizableArray.scala2
-rw-r--r--src/library/scala/collection/mutable/ReusableBuilder.scala49
-rw-r--r--src/library/scala/collection/mutable/SetBuilder.scala4
-rw-r--r--src/library/scala/collection/mutable/SetLike.scala11
-rw-r--r--src/library/scala/collection/mutable/SortedMap.scala57
-rw-r--r--src/library/scala/collection/mutable/SortedSet.scala7
-rw-r--r--src/library/scala/collection/mutable/StringBuilder.scala8
-rw-r--r--src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala101
-rw-r--r--src/library/scala/collection/mutable/SynchronizedStack.scala1
-rw-r--r--src/library/scala/collection/mutable/TreeMap.scala185
-rw-r--r--src/library/scala/collection/mutable/TreeSet.scala181
-rw-r--r--src/library/scala/collection/mutable/UnrolledBuffer.scala11
-rw-r--r--src/library/scala/collection/mutable/WrappedArray.scala9
-rw-r--r--src/library/scala/collection/mutable/WrappedArrayBuilder.scala16
36 files changed, 1433 insertions, 696 deletions
diff --git a/src/library/scala/collection/mutable/AVLTree.scala b/src/library/scala/collection/mutable/AVLTree.scala
deleted file mode 100644
index b63d0aae33..0000000000
--- a/src/library/scala/collection/mutable/AVLTree.scala
+++ /dev/null
@@ -1,250 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-package scala
-package collection
-package mutable
-
-/**
- * An immutable AVL Tree implementation formerly used by mutable.TreeSet
- *
- * @author Lucien Pereira
- */
-@deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.2")
-private[mutable] sealed trait AVLTree[+A] extends Serializable {
- def balance: Int
-
- def depth: Int
-
- def iterator[B >: A]: Iterator[B] = Iterator.empty
-
- def contains[B >: A](value: B, ordering: Ordering[B]): Boolean = false
-
- /**
- * Returns a new tree containing the given element.
- * Throws an IllegalArgumentException if element is already present.
- *
- */
- def insert[B >: A](value: B, ordering: Ordering[B]): AVLTree[B] = Node(value, Leaf, Leaf)
-
- /**
- * Return a new tree which not contains given element.
- *
- */
- def remove[B >: A](value: B, ordering: Ordering[B]): AVLTree[A] =
- throw new NoSuchElementException(String.valueOf(value))
-
- /**
- * Return a tuple containing the smallest element of the provided tree
- * and a new tree from which this element has been extracted.
- *
- */
- def removeMin[B >: A]: (B, AVLTree[B]) = sys.error("Should not happen.")
-
- /**
- * Return a tuple containing the biggest element of the provided tree
- * and a new tree from which this element has been extracted.
- *
- */
- def removeMax[B >: A]: (B, AVLTree[B]) = sys.error("Should not happen.")
-
- def rebalance[B >: A]: AVLTree[B] = this
-
- def leftRotation[B >: A]: Node[B] = sys.error("Should not happen.")
-
- def rightRotation[B >: A]: Node[B] = sys.error("Should not happen.")
-
- def doubleLeftRotation[B >: A]: Node[B] = sys.error("Should not happen.")
-
- def doubleRightRotation[B >: A]: Node[B] = sys.error("Should not happen.")
-}
-
-/**
- * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0")
- */
-private case object Leaf extends AVLTree[Nothing] {
- override val balance: Int = 0
-
- override val depth: Int = -1
-}
-
-/**
- * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0")
- */
-private case class Node[A](data: A, left: AVLTree[A], right: AVLTree[A]) extends AVLTree[A] {
- override val balance: Int = right.depth - left.depth
-
- override val depth: Int = math.max(left.depth, right.depth) + 1
-
- override def iterator[B >: A]: Iterator[B] = new AVLIterator(this)
-
- override def contains[B >: A](value: B, ordering: Ordering[B]) = {
- val ord = ordering.compare(value, data)
- if (0 == ord)
- true
- else if (ord < 0)
- left.contains(value, ordering)
- else
- right.contains(value, ordering)
- }
-
- /**
- * Returns a new tree containing the given element.
- * Throws an IllegalArgumentException if element is already present.
- *
- */
- override def insert[B >: A](value: B, ordering: Ordering[B]) = {
- val ord = ordering.compare(value, data)
- if (0 == ord)
- throw new IllegalArgumentException()
- else if (ord < 0)
- Node(data, left.insert(value, ordering), right).rebalance
- else
- Node(data, left, right.insert(value, ordering)).rebalance
- }
-
- /**
- * Return a new tree which not contains given element.
- *
- */
- override def remove[B >: A](value: B, ordering: Ordering[B]): AVLTree[A] = {
- val ord = ordering.compare(value, data)
- if(ord == 0) {
- if (Leaf == left) {
- if (Leaf == right) {
- Leaf
- } else {
- val (min, newRight) = right.removeMin
- Node(min, left, newRight).rebalance
- }
- } else {
- val (max, newLeft) = left.removeMax
- Node(max, newLeft, right).rebalance
- }
- } else if (ord < 0) {
- Node(data, left.remove(value, ordering), right).rebalance
- } else {
- Node(data, left, right.remove(value, ordering)).rebalance
- }
- }
-
- /**
- * Return a tuple containing the smallest element of the provided tree
- * and a new tree from which this element has been extracted.
- *
- */
- override def removeMin[B >: A]: (B, AVLTree[B]) = {
- if (Leaf == left)
- (data, right)
- else {
- val (min, newLeft) = left.removeMin
- (min, Node(data, newLeft, right).rebalance)
- }
- }
-
- /**
- * Return a tuple containing the biggest element of the provided tree
- * and a new tree from which this element has been extracted.
- *
- */
- override def removeMax[B >: A]: (B, AVLTree[B]) = {
- if (Leaf == right)
- (data, left)
- else {
- val (max, newRight) = right.removeMax
- (max, Node(data, left, newRight).rebalance)
- }
- }
-
- override def rebalance[B >: A] = {
- if (-2 == balance) {
- if (1 == left.balance)
- doubleRightRotation
- else
- rightRotation
- } else if (2 == balance) {
- if (-1 == right.balance)
- doubleLeftRotation
- else
- leftRotation
- } else {
- this
- }
- }
-
- override def leftRotation[B >: A] = {
- if (Leaf != right) {
- val r: Node[A] = right.asInstanceOf[Node[A]]
- Node(r.data, Node(data, left, r.left), r.right)
- } else sys.error("Should not happen.")
- }
-
- override def rightRotation[B >: A] = {
- if (Leaf != left) {
- val l: Node[A] = left.asInstanceOf[Node[A]]
- Node(l.data, l.left, Node(data, l.right, right))
- } else sys.error("Should not happen.")
- }
-
- override def doubleLeftRotation[B >: A] = {
- if (Leaf != right) {
- val r: Node[A] = right.asInstanceOf[Node[A]]
- // Let's save an instanceOf by 'inlining' the left rotation
- val rightRotated = r.rightRotation
- Node(rightRotated.data, Node(data, left, rightRotated.left), rightRotated.right)
- } else sys.error("Should not happen.")
- }
-
- override def doubleRightRotation[B >: A] = {
- if (Leaf != left) {
- val l: Node[A] = left.asInstanceOf[Node[A]]
- // Let's save an instanceOf by 'inlining' the right rotation
- val leftRotated = l.leftRotation
- Node(leftRotated.data, leftRotated.left, Node(data, leftRotated.right, right))
- } else sys.error("Should not happen.")
- }
-}
-
-/**
- * @deprecated("AVLTree and its related classes are being removed from the standard library since they're not different enough from RedBlackTree to justify keeping them.", "2.11.0")
- */
-private class AVLIterator[A](root: Node[A]) extends Iterator[A] {
- val stack = mutable.ArrayStack[Node[A]](root)
- diveLeft()
-
- private def diveLeft(): Unit = {
- if (Leaf != stack.head.left) {
- val left: Node[A] = stack.head.left.asInstanceOf[Node[A]]
- stack.push(left)
- diveLeft()
- }
- }
-
- private def engageRight(): Unit = {
- if (Leaf != stack.head.right) {
- val right: Node[A] = stack.head.right.asInstanceOf[Node[A]]
- stack.pop()
- stack.push(right)
- diveLeft()
- } else
- stack.pop()
- }
-
- override def hasNext: Boolean = !stack.isEmpty
-
- override def next(): A = {
- if (stack.isEmpty)
- throw new NoSuchElementException()
- else {
- val result = stack.head.data
- // Let's maintain stack for the next invocation
- engageRight()
- result
- }
- }
-}
diff --git a/src/library/scala/collection/mutable/AnyRefMap.scala b/src/library/scala/collection/mutable/AnyRefMap.scala
index 369d596ec3..6ff79dd1b8 100644
--- a/src/library/scala/collection/mutable/AnyRefMap.scala
+++ b/src/library/scala/collection/mutable/AnyRefMap.scala
@@ -27,10 +27,12 @@ import generic.CanBuildFrom
* rapidly as 2^30^ is approached.
*
*/
+@SerialVersionUID(1L)
final class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initialBufferSize: Int, initBlank: Boolean)
extends AbstractMap[K, V]
with Map[K, V]
with MapLike[K, V, AnyRefMap[K, V]]
+ with Serializable
{
import AnyRefMap._
def this() = this(AnyRefMap.exceptionDefault, 16, true)
@@ -335,6 +337,24 @@ extends AbstractMap[K, V]
arm
}
+ override def +[V1 >: V](kv: (K, V1)): AnyRefMap[K, V1] = {
+ val arm = clone().asInstanceOf[AnyRefMap[K, V1]]
+ arm += kv
+ arm
+ }
+
+ override def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): AnyRefMap[K, V1] = {
+ val arm = clone().asInstanceOf[AnyRefMap[K, V1]]
+ xs.foreach(kv => arm += kv)
+ arm
+ }
+
+ override def updated[V1 >: V](key: K, value: V1): AnyRefMap[K, V1] = {
+ val arm = clone().asInstanceOf[AnyRefMap[K, V1]]
+ arm += (key, value)
+ arm
+ }
+
private[this] def foreachElement[A,B](elems: Array[AnyRef], f: A => B) {
var i,j = 0
while (i < _hashes.length & j < _size) {
@@ -399,7 +419,11 @@ object AnyRefMap {
private final val VacantBit = 0x40000000
private final val MissVacant = 0xC0000000
- private val exceptionDefault = (k: Any) => throw new NoSuchElementException(if (k == null) "(null)" else k.toString)
+ @SerialVersionUID(1L)
+ private class ExceptionDefault extends (Any => Nothing) with Serializable {
+ def apply(k: Any): Nothing = throw new NoSuchElementException(if (k == null) "(null)" else k.toString)
+ }
+ private val exceptionDefault = new ExceptionDefault
implicit def canBuildFrom[K <: AnyRef, V, J <: AnyRef, U]: CanBuildFrom[AnyRefMap[K,V], (J, U), AnyRefMap[J,U]] =
new CanBuildFrom[AnyRefMap[K,V], (J, U), AnyRefMap[J,U]] {
@@ -407,7 +431,11 @@ object AnyRefMap {
def apply(): AnyRefMapBuilder[J, U] = new AnyRefMapBuilder[J, U]
}
- final class AnyRefMapBuilder[K <: AnyRef, V] extends Builder[(K, V), AnyRefMap[K, V]] {
+ /** A builder for instances of `AnyRefMap`.
+ *
+ * This builder can be reused to create multiple instances.
+ */
+ final class AnyRefMapBuilder[K <: AnyRef, V] extends ReusableBuilder[(K, V), AnyRefMap[K, V]] {
private[collection] var elems: AnyRefMap[K, V] = new AnyRefMap[K, V]
def +=(entry: (K, V)): this.type = {
elems += entry
diff --git a/src/library/scala/collection/mutable/ArrayBuffer.scala b/src/library/scala/collection/mutable/ArrayBuffer.scala
index 011fd415ee..167e04ccbd 100644
--- a/src/library/scala/collection/mutable/ArrayBuffer.scala
+++ b/src/library/scala/collection/mutable/ArrayBuffer.scala
@@ -149,13 +149,16 @@ class ArrayBuffer[A](override protected val initialSize: Int)
/** Removes the element on a given index position. It takes time linear in
* the buffer size.
*
- * @param n the index which refers to the first element to delete.
- * @param count the number of elements to delete
- * @throws IndexOutOfBoundsException if `n` is out of bounds.
+ * @param n the index which refers to the first element to remove.
+ * @param count the number of elements to remove.
+ * @throws IndexOutOfBoundsException if the index `n` is not in the valid range
+ * `0 <= n <= length - count` (with `count > 0`).
+ * @throws IllegalArgumentException if `count < 0`.
*/
override def remove(n: Int, count: Int) {
- require(count >= 0, "removing negative number of elements")
- if (n < 0 || n > size0 - count) throw new IndexOutOfBoundsException(n.toString)
+ if (count < 0) throw new IllegalArgumentException("removing negative number of elements: " + count.toString)
+ else if (count == 0) return // Did nothing
+ if (n < 0 || n > size0 - count) throw new IndexOutOfBoundsException("at " + n.toString + " deleting " + count.toString)
copy(n + count, n, size0 - (n + count))
reduceToSize(size0 - count)
}
diff --git a/src/library/scala/collection/mutable/ArrayBuilder.scala b/src/library/scala/collection/mutable/ArrayBuilder.scala
index 6e53824cbe..d023110c1b 100644
--- a/src/library/scala/collection/mutable/ArrayBuilder.scala
+++ b/src/library/scala/collection/mutable/ArrayBuilder.scala
@@ -11,7 +11,6 @@ package collection
package mutable
import scala.reflect.ClassTag
-import scala.runtime.ScalaRunTime
/** A builder class for arrays.
*
@@ -19,7 +18,7 @@ import scala.runtime.ScalaRunTime
*
* @tparam T the type of the elements for the builder.
*/
-abstract class ArrayBuilder[T] extends Builder[T, Array[T]] with Serializable
+abstract class ArrayBuilder[T] extends ReusableBuilder[T, Array[T]] with Serializable
/** A companion object for array builders.
*
@@ -50,10 +49,11 @@ object ArrayBuilder {
/** A class for array builders for arrays of reference types.
*
+ * This builder can be reused.
+ *
* @tparam T type of elements for the array builder, subtype of `AnyRef` with a `ClassTag` context bound.
*/
- @deprecatedInheritance("ArrayBuilder.ofRef is an internal implementation not intended for subclassing.", "2.11.0")
- class ofRef[T <: AnyRef : ClassTag] extends ArrayBuilder[T] {
+ final class ofRef[T <: AnyRef : ClassTag] extends ArrayBuilder[T] {
private var elems: Array[T] = _
private var capacity: Int = 0
@@ -99,12 +99,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -116,9 +117,8 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofRef"
}
- /** A class for array builders for arrays of `byte`s. */
- @deprecatedInheritance("ArrayBuilder.ofByte is an internal implementation not intended for subclassing.", "2.11.0")
- class ofByte extends ArrayBuilder[Byte] {
+ /** A class for array builders for arrays of `byte`s. It can be reused. */
+ final class ofByte extends ArrayBuilder[Byte] {
private var elems: Array[Byte] = _
private var capacity: Int = 0
@@ -164,12 +164,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -181,9 +182,8 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofByte"
}
- /** A class for array builders for arrays of `short`s. */
- @deprecatedInheritance("ArrayBuilder.ofShort is an internal implementation not intended for subclassing.", "2.11.0")
- class ofShort extends ArrayBuilder[Short] {
+ /** A class for array builders for arrays of `short`s. It can be reused. */
+ final class ofShort extends ArrayBuilder[Short] {
private var elems: Array[Short] = _
private var capacity: Int = 0
@@ -229,12 +229,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -246,9 +247,8 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofShort"
}
- /** A class for array builders for arrays of `char`s. */
- @deprecatedInheritance("ArrayBuilder.ofChar is an internal implementation not intended for subclassing.", "2.11.0")
- class ofChar extends ArrayBuilder[Char] {
+ /** A class for array builders for arrays of `char`s. It can be reused. */
+ final class ofChar extends ArrayBuilder[Char] {
private var elems: Array[Char] = _
private var capacity: Int = 0
@@ -294,12 +294,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -311,9 +312,8 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofChar"
}
- /** A class for array builders for arrays of `int`s. */
- @deprecatedInheritance("ArrayBuilder.ofInt is an internal implementation not intended for subclassing.", "2.11.0")
- class ofInt extends ArrayBuilder[Int] {
+ /** A class for array builders for arrays of `int`s. It can be reused. */
+ final class ofInt extends ArrayBuilder[Int] {
private var elems: Array[Int] = _
private var capacity: Int = 0
@@ -359,12 +359,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -376,9 +377,8 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofInt"
}
- /** A class for array builders for arrays of `long`s. */
- @deprecatedInheritance("ArrayBuilder.ofLong is an internal implementation not intended for subclassing.", "2.11.0")
- class ofLong extends ArrayBuilder[Long] {
+ /** A class for array builders for arrays of `long`s. It can be reused. */
+ final class ofLong extends ArrayBuilder[Long] {
private var elems: Array[Long] = _
private var capacity: Int = 0
@@ -424,12 +424,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -441,9 +442,8 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofLong"
}
- /** A class for array builders for arrays of `float`s. */
- @deprecatedInheritance("ArrayBuilder.ofFloat is an internal implementation not intended for subclassing.", "2.11.0")
- class ofFloat extends ArrayBuilder[Float] {
+ /** A class for array builders for arrays of `float`s. It can be reused. */
+ final class ofFloat extends ArrayBuilder[Float] {
private var elems: Array[Float] = _
private var capacity: Int = 0
@@ -489,12 +489,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -506,9 +507,8 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofFloat"
}
- /** A class for array builders for arrays of `double`s. */
- @deprecatedInheritance("ArrayBuilder.ofDouble is an internal implementation not intended for subclassing.", "2.11.0")
- class ofDouble extends ArrayBuilder[Double] {
+ /** A class for array builders for arrays of `double`s. It can be reused. */
+ final class ofDouble extends ArrayBuilder[Double] {
private var elems: Array[Double] = _
private var capacity: Int = 0
@@ -554,12 +554,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -571,7 +572,7 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofDouble"
}
- /** A class for array builders for arrays of `boolean`s. */
+ /** A class for array builders for arrays of `boolean`s. It can be reused. */
class ofBoolean extends ArrayBuilder[Boolean] {
private var elems: Array[Boolean] = _
@@ -618,12 +619,13 @@ object ArrayBuilder {
super.++=(xs)
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}
@@ -635,65 +637,32 @@ object ArrayBuilder {
override def toString = "ArrayBuilder.ofBoolean"
}
- /** A class for array builders for arrays of `Unit` type. */
- @deprecatedInheritance("ArrayBuilder.ofUnit is an internal implementation not intended for subclassing.", "2.11.0")
- class ofUnit extends ArrayBuilder[Unit] {
+ /** A class for array builders for arrays of `Unit` type. It can be reused. */
+ final class ofUnit extends ArrayBuilder[Unit] {
- private var elems: Array[Unit] = _
- private var capacity: Int = 0
private var size: Int = 0
- private def mkArray(size: Int): Array[Unit] = {
- val newelems = new Array[Unit](size)
- if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
- newelems
- }
-
- private def resize(size: Int) {
- elems = mkArray(size)
- capacity = size
- }
-
- override def sizeHint(size: Int) {
- if (capacity < size) resize(size)
- }
-
- private def ensureSize(size: Int) {
- if (capacity < size || capacity == 0) {
- var newsize = if (capacity == 0) 16 else capacity * 2
- while (newsize < size) newsize *= 2
- resize(newsize)
- }
- }
-
def +=(elem: Unit): this.type = {
- ensureSize(size + 1)
- elems(size) = elem
size += 1
this
}
- 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)
- size += xs.length
- this
- case _ =>
- super.++=(xs)
+ override def ++=(xs: TraversableOnce[Unit]): this.type = {
+ size += xs.size
+ this
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
- else mkArray(size)
+ val ans = new Array[Unit](size)
+ var i = 0
+ while (i < size) { ans(i) = (); i += 1 }
+ ans
}
override def equals(other: Any): Boolean = other match {
- case x: ofUnit => (size == x.size) && (elems == x.elems)
+ case x: ofUnit => (size == x.size)
case _ => false
}
diff --git a/src/library/scala/collection/mutable/ArrayOps.scala b/src/library/scala/collection/mutable/ArrayOps.scala
index 00491ef20e..507585b9cf 100644
--- a/src/library/scala/collection/mutable/ArrayOps.scala
+++ b/src/library/scala/collection/mutable/ArrayOps.scala
@@ -10,9 +10,7 @@ package scala
package collection
package mutable
-import scala.compat.Platform.arraycopy
import scala.reflect.ClassTag
-import scala.runtime.ScalaRunTime._
import parallel.mutable.ParArray
/** This class serves as a wrapper for `Array`s with all the operations found in
@@ -33,20 +31,18 @@ import parallel.mutable.ParArray
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
-@deprecatedInheritance("ArrayOps will be sealed to facilitate greater flexibility with array/collections integration in future releases.", "2.11.0")
-trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] {
+sealed trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParallelizable[T, ParArray[T]] {
private def elementClass: Class[_] =
- arrayElementClass(repr.getClass)
+ repr.getClass.getComponentType
override def copyToArray[U >: T](xs: Array[U], start: Int, len: Int) {
- var l = math.min(len, repr.length)
- if (xs.length - start < l) l = xs.length - start max 0
- Array.copy(repr, 0, xs, start, l)
+ val l = len min repr.length min (xs.length - start)
+ if (l > 0) Array.copy(repr, 0, xs, start, l)
}
override def toArray[U >: T : ClassTag]: Array[U] = {
- val thatElementClass = arrayElementClass(implicitly[ClassTag[U]])
+ val thatElementClass = implicitly[ClassTag[U]].runtimeClass
if (elementClass eq thatElementClass)
repr.asInstanceOf[Array[U]]
else
@@ -94,7 +90,7 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza
val bb: Builder[Array[U], Array[Array[U]]] = Array.newBuilder(ClassTag[Array[U]](elementClass))
if (isEmpty) bb.result()
else {
- def mkRowBuilder() = Array.newBuilder(ClassTag[U](arrayElementClass(elementClass)))
+ def mkRowBuilder() = Array.newBuilder(ClassTag[U](elementClass.getComponentType))
val bs = asArray(head) map (_ => mkRowBuilder())
for (xs <- this) {
var i = 0
@@ -107,9 +103,9 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza
bb.result()
}
}
-
+
/** Converts an array of pairs into an array of first elements and an array of second elements.
- *
+ *
* @tparam T1 the type of the first half of the element pairs
* @tparam T2 the type of the second half of the element pairs
* @param asPair an implicit conversion which asserts that the element type
@@ -135,9 +131,9 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza
}
(a1, a2)
}
-
+
/** Converts an array of triples into three arrays, one containing the elements from each position of the triple.
- *
+ *
* @tparam T1 the type of the first of three elements in the triple
* @tparam T2 the type of the second of three elements in the triple
* @tparam T3 the type of the third of three elements in the triple
@@ -169,7 +165,7 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza
}
(a1, a2, a3)
}
-
+
def seq = thisCollection
@@ -187,7 +183,7 @@ object ArrayOps {
override protected[this] def thisCollection: WrappedArray[T] = new WrappedArray.ofRef[T](repr)
override protected[this] def toCollection(repr: Array[T]): WrappedArray[T] = new WrappedArray.ofRef[T](repr)
- override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](arrayElementClass(repr.getClass)))
+ override protected[this] def newBuilder = new ArrayBuilder.ofRef[T]()(ClassTag[T](repr.getClass.getComponentType))
def length: Int = repr.length
def apply(index: Int): T = repr(index)
diff --git a/src/library/scala/collection/mutable/ArraySeq.scala b/src/library/scala/collection/mutable/ArraySeq.scala
index ddb48627af..1e82096baf 100644
--- a/src/library/scala/collection/mutable/ArraySeq.scala
+++ b/src/library/scala/collection/mutable/ArraySeq.scala
@@ -87,7 +87,7 @@ extends AbstractSeq[A]
*/
override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) {
val len1 = len min (xs.length - start) min length
- Array.copy(array, 0, xs, start, len1)
+ if (len1 > 0) Array.copy(array, 0, xs, start, len1)
}
override def clone(): ArraySeq[A] = {
diff --git a/src/library/scala/collection/mutable/ArrayStack.scala b/src/library/scala/collection/mutable/ArrayStack.scala
index 8ff128c026..951a90b084 100644
--- a/src/library/scala/collection/mutable/ArrayStack.scala
+++ b/src/library/scala/collection/mutable/ArrayStack.scala
@@ -64,9 +64,10 @@ object ArrayStack extends SeqFactory[ArrayStack] {
class ArrayStack[T] private(private var table : Array[AnyRef],
private var index : Int)
extends AbstractSeq[T]
- with Seq[T]
- with SeqLike[T, ArrayStack[T]]
+ with IndexedSeq[T]
+ with IndexedSeqLike[T, ArrayStack[T]]
with GenericTraversableTemplate[T, ArrayStack]
+ with IndexedSeqOptimized[T, ArrayStack[T]]
with Cloneable[ArrayStack[T]]
with Builder[T, ArrayStack[T]]
with Serializable
@@ -224,7 +225,7 @@ extends AbstractSeq[T]
/** Creates and iterator over the stack in LIFO order.
* @return an iterator over the elements of the stack.
*/
- def iterator: Iterator[T] = new AbstractIterator[T] {
+ override def iterator: Iterator[T] = new AbstractIterator[T] {
var currentIndex = index
def hasNext = currentIndex > 0
def next() = {
diff --git a/src/library/scala/collection/mutable/BitSet.scala b/src/library/scala/collection/mutable/BitSet.scala
index e92d48cfeb..feef694e01 100644
--- a/src/library/scala/collection/mutable/BitSet.scala
+++ b/src/library/scala/collection/mutable/BitSet.scala
@@ -13,7 +13,7 @@ package collection
package mutable
import generic._
-import BitSetLike.{LogWL, MaxSize, updateArray}
+import BitSetLike.{LogWL, MaxSize}
/** A class for mutable bitsets.
*
@@ -56,7 +56,7 @@ class BitSet(protected final var elems: Array[Long]) extends AbstractSet[Int]
@deprecatedOverriding("Internal implementation does not admit sensible overriding of this method.", "2.11.0")
protected def nwords = elems.length
-
+
@deprecatedOverriding("Internal implementation does not admit sensible overriding of this method.", "2.11.0")
protected def word(idx: Int): Long =
if (idx < nwords) elems(idx) else 0L
@@ -100,7 +100,7 @@ class BitSet(protected final var elems: Array[Long]) extends AbstractSet[Int]
@deprecatedOverriding("Override add to prevent += and add from exhibiting different behavior.", "2.11.0")
def += (elem: Int): this.type = { add(elem); this }
-
+
@deprecatedOverriding("Override add to prevent += and add from exhibiting different behavior.", "2.11.0")
def -= (elem: Int): this.type = { remove(elem); this }
diff --git a/src/library/scala/collection/mutable/BufferLike.scala b/src/library/scala/collection/mutable/BufferLike.scala
index 3c57387c03..98c9771a05 100644
--- a/src/library/scala/collection/mutable/BufferLike.scala
+++ b/src/library/scala/collection/mutable/BufferLike.scala
@@ -14,7 +14,7 @@ package mutable
import generic._
import script._
-import scala.annotation.{migration, bridge}
+import scala.annotation.migration
/** A template trait for buffers of type `Buffer[A]`.
*
@@ -105,15 +105,18 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]]
*/
def remove(n: Int): A
- /** Removes a number of elements from a given index position.
+ /** Removes a number of elements from a given index position. Subclasses of `BufferLike`
+ * will typically override this method to provide better performance than `count`
+ * successive calls to single-element `remove`.
*
* @param n the index which refers to the first element to remove.
* @param count the number of elements to remove.
* @throws IndexOutOfBoundsException if the index `n` is not in the valid range
- * `0 <= n <= length - count`.
+ * `0 <= n <= length - count` (with `count > 0`).
* @throws IllegalArgumentException if `count < 0`.
*/
def remove(n: Int, count: Int) {
+ if (count < 0) throw new IllegalArgumentException("removing negative number of elements: " + count.toString)
for (i <- 0 until count) remove(n)
}
@@ -211,13 +214,6 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]]
*/
override def stringPrefix: String = "Buffer"
- /** Returns the current evolving(!) state of this buffer as a read-only sequence.
- *
- * @return A sequence that forwards to this buffer for all its operations.
- */
- @deprecated("The returned sequence changes as this buffer is mutated. For an immutable copy, use, e.g., toList.", "2.11.0")
- def readOnly: scala.collection.Seq[A] = toSeq
-
/** Creates a new collection containing both the elements of this collection and the provided
* traversable object.
*
diff --git a/src/library/scala/collection/mutable/BufferProxy.scala b/src/library/scala/collection/mutable/BufferProxy.scala
index d9632cce91..2d52831d37 100644
--- a/src/library/scala/collection/mutable/BufferProxy.scala
+++ b/src/library/scala/collection/mutable/BufferProxy.scala
@@ -43,8 +43,6 @@ trait BufferProxy[A] extends Buffer[A] with Proxy {
*/
def +=(elem: A): this.type = { self.+=(elem); this }
- override def readOnly = self.readOnly
-
/** Appends a number of elements provided by a traversable object.
*
* @param xs the traversable object.
diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala
index 75560580cc..8d6a0ec69d 100644
--- a/src/library/scala/collection/mutable/Builder.scala
+++ b/src/library/scala/collection/mutable/Builder.scala
@@ -18,6 +18,14 @@ import generic._
* elements to the builder with `+=` and then converting to the required
* collection type with `result`.
*
+ * One cannot assume that a single `Builder` can build more than one
+ * instance of the desired collection. Particular subclasses may allow
+ * such behavior. Otherwise, `result` should be treated as a terminal
+ * operation: after it is called, no further methods should be called on
+ * the builder. Extend the [[collection.mutable.ReusableBuilder]] trait
+ * instead of `Builder` for builders that may be reused to build multiple
+ * instances.
+ *
* @tparam Elem the type of elements that get added to the builder.
* @tparam To the type of collection that it produced.
*
@@ -36,8 +44,10 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
*/
def clear()
- /** Produces a collection from the added elements.
- * The builder's contents are undefined after this operation.
+ /** Produces a collection from the added elements. This is a terminal operation:
+ * the builder's contents are undefined after this operation, and no further
+ * methods should be called.
+ *
* @return a collection containing the elements added to this builder.
*/
def result(): To
@@ -112,6 +122,8 @@ trait Builder[-Elem, +To] extends Growable[Elem] {
* @tparam NewTo the type of collection returned by `f`.
* @return a new builder which is the same as the current builder except
* that a transformation function is applied to this builder's result.
+ *
+ * @note The original builder should no longer be used after `mapResult` is called.
*/
def mapResult[NewTo](f: To => NewTo): Builder[Elem, NewTo] =
new Builder[Elem, NewTo] with Proxy {
diff --git a/src/library/scala/collection/mutable/GrowingBuilder.scala b/src/library/scala/collection/mutable/GrowingBuilder.scala
index c4b5e546aa..27d554d98e 100644
--- a/src/library/scala/collection/mutable/GrowingBuilder.scala
+++ b/src/library/scala/collection/mutable/GrowingBuilder.scala
@@ -15,6 +15,8 @@ import generic._
/** The canonical builder for collections that are growable, i.e. that support an
* efficient `+=` method which adds an element to the collection.
*
+ * GrowableBuilders can produce only a single instance of the collection they are growing.
+ *
* @author Paul Phillips
* @version 2.8
* @since 2.8
@@ -25,6 +27,6 @@ import generic._
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 clear() { empty.clear }
def result: To = elems
}
diff --git a/src/library/scala/collection/mutable/IndexedSeqView.scala b/src/library/scala/collection/mutable/IndexedSeqView.scala
index 7acdeeff18..b525baaf5f 100644
--- a/src/library/scala/collection/mutable/IndexedSeqView.scala
+++ b/src/library/scala/collection/mutable/IndexedSeqView.scala
@@ -15,7 +15,6 @@ package mutable
import generic._
import TraversableView.NoBuilder
-import scala.language.implicitConversions
/** A non-strict view of a mutable `IndexedSeq`.
* $viewInfo
diff --git a/src/library/scala/collection/mutable/LazyBuilder.scala b/src/library/scala/collection/mutable/LazyBuilder.scala
index ebee38b77f..f0a5e6971a 100644
--- a/src/library/scala/collection/mutable/LazyBuilder.scala
+++ b/src/library/scala/collection/mutable/LazyBuilder.scala
@@ -13,12 +13,14 @@ package mutable
/** A builder that constructs its result lazily. Iterators or iterables to
* be added to this builder with `++=` are not evaluated until `result` is called.
*
+ * This builder can be reused.
+ *
* @since 2.8
*
* @tparam Elem type of the elements for this builder.
* @tparam To type of the collection this builder builds.
*/
-abstract class LazyBuilder[Elem, +To] extends Builder[Elem, To] {
+abstract class LazyBuilder[Elem, +To] extends ReusableBuilder[Elem, To] {
/** The different segments of elements to be added to the builder, represented as iterators */
protected var parts = new ListBuffer[TraversableOnce[Elem]]
def +=(x: Elem): this.type = { parts += List(x); this }
diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala
index f9bab40a1e..02fcced3ac 100644
--- a/src/library/scala/collection/mutable/ListBuffer.scala
+++ b/src/library/scala/collection/mutable/ListBuffer.scala
@@ -12,8 +12,7 @@ package mutable
import generic._
import immutable.{List, Nil, ::}
-import java.io._
-import scala.annotation.migration
+import java.io.{ObjectOutputStream, ObjectInputStream}
/** A `Buffer` implementation backed by a list. It provides constant time
* prepend and append. Most other operations are linear.
@@ -47,7 +46,7 @@ final class ListBuffer[A]
with Buffer[A]
with GenericTraversableTemplate[A, ListBuffer]
with BufferLike[A, ListBuffer[A]]
- with Builder[A, List[A]]
+ with ReusableBuilder[A, List[A]]
with SeqForwarder[A]
with Serializable
{
@@ -262,13 +261,14 @@ final class ListBuffer[A]
*
* @param n the index which refers to the first element to remove.
* @param count the number of elements to remove.
+ * @throws IndexOutOfBoundsException if the index `n` is not in the valid range
+ * `0 <= n <= length - count` (with `count > 0`).
+ * @throws IllegalArgumentException if `count < 0`.
*/
- @migration("Invalid input values will be rejected in future releases.", "2.11")
override def remove(n: Int, count: Int) {
- if (n >= len)
- return
- if (count < 0)
- throw new IllegalArgumentException(s"removing negative number ($count) of elements")
+ if (count < 0) throw new IllegalArgumentException("removing negative number of elements: " + count.toString)
+ else if (count == 0) return // Nothing to do
+ if (n < 0 || n > len - count) throw new IndexOutOfBoundsException("at " + n.toString + " deleting " + count.toString)
if (exported) copy()
val n1 = n max 0
val count1 = count min (len - n1)
@@ -297,6 +297,10 @@ final class ListBuffer[A]
// Implementation of abstract method in Builder
+ /** Returns the accumulated `List`.
+ *
+ * This method may be called multiple times to obtain snapshots of the list in different stages of construction.
+ */
def result: List[A] = toList
/** Converts this buffer to a list. Takes constant time. The buffer is
@@ -408,9 +412,6 @@ final class ListBuffer[A]
}
}
- @deprecated("The result of this method will change along with this buffer, which is often not what's expected.", "2.11.0")
- override def readOnly: List[A] = start
-
// Private methods
/** Copy contents of this buffer */
@@ -426,7 +427,7 @@ final class ListBuffer[A]
}
override def equals(that: Any): Boolean = that match {
- case that: ListBuffer[_] => this.readOnly equals that.readOnly
+ case that: ListBuffer[_] => this.start equals that.start
case _ => super.equals(that)
}
diff --git a/src/library/scala/collection/mutable/LongMap.scala b/src/library/scala/collection/mutable/LongMap.scala
index 198e34bd29..ecbb1952af 100644
--- a/src/library/scala/collection/mutable/LongMap.scala
+++ b/src/library/scala/collection/mutable/LongMap.scala
@@ -415,6 +415,24 @@ extends AbstractMap[Long, V]
lm
}
+ override def +[V1 >: V](kv: (Long, V1)): LongMap[V1] = {
+ val lm = clone().asInstanceOf[LongMap[V1]]
+ lm += kv
+ lm
+ }
+
+ override def ++[V1 >: V](xs: GenTraversableOnce[(Long, V1)]): LongMap[V1] = {
+ val lm = clone().asInstanceOf[LongMap[V1]]
+ xs.foreach(kv => lm += kv)
+ lm
+ }
+
+ override def updated[V1 >: V](key: Long, value: V1): LongMap[V1] = {
+ val lm = clone().asInstanceOf[LongMap[V1]]
+ lm += (key, value)
+ lm
+ }
+
/** Applies a function to all keys of this map. */
def foreachKey[A](f: Long => A) {
if ((extraKeys & 1) == 1) f(0L)
@@ -501,7 +519,11 @@ object LongMap {
def apply(): LongMapBuilder[U] = new LongMapBuilder[U]
}
- final class LongMapBuilder[V] extends Builder[(Long, V), LongMap[V]] {
+ /** A builder for instances of `LongMap`.
+ *
+ * This builder can be reused to create multiple instances.
+ */
+ final class LongMapBuilder[V] extends ReusableBuilder[(Long, V), LongMap[V]] {
private[collection] var elems: LongMap[V] = new LongMap[V]
def +=(entry: (Long, V)): this.type = {
elems += entry
@@ -541,7 +563,7 @@ object LongMap {
/** Creates a new `LongMap` from keys and values.
* Equivalent to but more efficient than `LongMap((keys zip values): _*)`.
*/
- def fromZip[V](keys: Iterable[Long], values: Iterable[V]): LongMap[V] = {
+ def fromZip[V](keys: collection.Iterable[Long], values: collection.Iterable[V]): LongMap[V] = {
val sz = math.min(keys.size, values.size)
val lm = new LongMap[V](sz * 2)
val ki = keys.iterator
diff --git a/src/library/scala/collection/mutable/MapBuilder.scala b/src/library/scala/collection/mutable/MapBuilder.scala
index a5a6b12ea9..cfc3079f41 100644
--- a/src/library/scala/collection/mutable/MapBuilder.scala
+++ b/src/library/scala/collection/mutable/MapBuilder.scala
@@ -23,7 +23,7 @@ package mutable
* @since 2.8
*/
class MapBuilder[A, B, Coll <: scala.collection.GenMap[A, B] with scala.collection.GenMapLike[A, B, Coll]](empty: Coll)
-extends Builder[(A, B), Coll] {
+extends ReusableBuilder[(A, B), Coll] {
protected var elems: Coll = empty
def +=(x: (A, B)): this.type = {
elems = (elems + x).asInstanceOf[Coll]
diff --git a/src/library/scala/collection/mutable/MapLike.scala b/src/library/scala/collection/mutable/MapLike.scala
index 44af886cf5..949e5e3536 100644
--- a/src/library/scala/collection/mutable/MapLike.scala
+++ b/src/library/scala/collection/mutable/MapLike.scala
@@ -61,6 +61,18 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]]
override protected[this] def newBuilder: Builder[(A, B), This] = empty
protected[this] override def parCombiner = ParMap.newCombiner[A, B]
+
+ /** Converts this $coll to a sequence.
+ *
+ * ```Note```: assumes a fast `size` method. Subclasses should override if this is not true.
+ */
+ override def toSeq: collection.Seq[(A, B)] = {
+ // ArrayBuffer for efficiency, preallocated to the right size.
+ val result = new ArrayBuffer[(A, B)](size)
+ foreach(result += _)
+ result
+ }
+
/** Adds a new key/value pair to this map and optionally returns previously bound value.
* If the map already contains a
diff --git a/src/library/scala/collection/mutable/MutableList.scala b/src/library/scala/collection/mutable/MutableList.scala
index 646023f469..a333eedb1a 100644
--- a/src/library/scala/collection/mutable/MutableList.scala
+++ b/src/library/scala/collection/mutable/MutableList.scala
@@ -11,7 +11,7 @@ package collection
package mutable
import generic._
-import immutable.{List, Nil}
+import immutable.List
/**
* This class is used internally to represent mutable lists. It is the
diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala
index 2562f60355..d5b7673c37 100644
--- a/src/library/scala/collection/mutable/PriorityQueue.scala
+++ b/src/library/scala/collection/mutable/PriorityQueue.scala
@@ -16,7 +16,7 @@ import generic._
* To prioritize elements of type A there must be an implicit
* Ordering[A] available at creation.
*
- * Only the `dequeue` and `dequeueAll` methods will return methods in priority
+ * Only the `dequeue` and `dequeueAll` methods will return elements in priority
* order (while removing elements from the heap). Standard collection methods
* including `drop`, `iterator`, and `toString` will remove or traverse the heap
* in whichever order seems most convenient.
@@ -46,8 +46,7 @@ import generic._
* @define mayNotTerminateInf
* @define willNotTerminateInf
*/
-@deprecatedInheritance("PriorityQueue is not intended to be subclassed due to extensive private implementation details.", "2.11.0")
-class PriorityQueue[A](implicit val ord: Ordering[A])
+sealed class PriorityQueue[A](implicit val ord: Ordering[A])
extends AbstractIterable[A]
with Iterable[A]
with GenericOrderedTraversableTemplate[A, PriorityQueue]
@@ -201,9 +200,7 @@ class PriorityQueue[A](implicit val ord: Ordering[A])
* @return A reversed priority queue.
*/
def reverse = {
- val revq = new PriorityQueue[A]()(new scala.math.Ordering[A] {
- def compare(x: A, y: A) = ord.compare(y, x)
- })
+ val revq = new PriorityQueue[A]()(ord.reverse)
for (i <- 1 until resarr.length) revq += resarr(i)
revq
}
@@ -266,3 +263,176 @@ object PriorityQueue extends OrderedTraversableFactory[PriorityQueue] {
implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, PriorityQueue[A]] = new GenericCanBuildFrom[A]
}
+
+/** This class servers as a proxy for priority queues. The
+ * elements of the queue have to be ordered in terms of the
+ * `Ordered[T]` class.
+ *
+ * @author Matthias Zenger
+ * @version 1.0, 03/05/2004
+ * @since 1
+ */
+@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0")
+sealed abstract class PriorityQueueProxy[A](implicit ord: Ordering[A]) extends PriorityQueue[A]
+ with Proxy
+{
+ def self: PriorityQueue[A]
+
+ /** Creates a new iterator over all elements contained in this
+ * object.
+ *
+ * @return the new iterator
+ */
+ override def iterator: Iterator[A] = self.iterator
+
+ /** Returns the length of this priority queue.
+ */
+ override def length: Int = self.length
+
+ /** Checks if the queue is empty.
+ *
+ * @return true, iff there is no element in the queue.
+ */
+ override def isEmpty: Boolean = self.isEmpty
+
+ /** Inserts a single element into the priority queue.
+ *
+ * @param elem the element to insert
+ */
+ override def +=(elem: A): this.type = { self += elem; this }
+
+ /** Adds all elements provided by an iterator into the priority queue.
+ *
+ * @param it an iterator
+ */
+ override def ++=(it: TraversableOnce[A]): this.type = {
+ self ++= it
+ this
+ }
+
+ /** Adds all elements to the queue.
+ *
+ * @param elems the elements to add.
+ */
+ override def enqueue(elems: A*): Unit = self ++= elems
+
+ /** Returns the element with the highest priority in the queue,
+ * and removes this element from the queue.
+ *
+ * @return the element with the highest priority.
+ */
+ override def dequeue(): A = self.dequeue()
+
+ /** Returns the element with the highest priority in the queue,
+ * or throws an error if there is no element contained in the queue.
+ *
+ * @return the element with the highest priority.
+ */
+ override def head: A = self.head
+
+ /** Removes all elements from the queue. After this operation is completed,
+ * the queue will be empty.
+ */
+ override def clear(): Unit = self.clear()
+
+ /** Returns a regular queue containing the same elements.
+ */
+ override def toQueue: Queue[A] = self.toQueue
+
+ /** This method clones the priority queue.
+ *
+ * @return a priority queue with the same elements.
+ */
+ override def clone(): PriorityQueue[A] = new PriorityQueueProxy[A] {
+ def self = PriorityQueueProxy.this.self.clone()
+ }
+}
+
+
+/** This class implements synchronized priority queues using a binary heap.
+ * The elements of the queue have to be ordered in terms of the `Ordered[T]` class.
+ *
+ * @tparam A type of the elements contained in this synchronized priority queue
+ * @param ord implicit ordering used to compared elements of type `A`
+ *
+ * @author Matthias Zenger
+ * @version 1.0, 03/05/2004
+ * @since 1
+ * @define Coll `SynchronizedPriorityQueue`
+ * @define coll synchronized priority queue
+ */
+@deprecated("Comprehensive synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentSkipListSet as an alternative.", "2.11.0")
+sealed class SynchronizedPriorityQueue[A](implicit ord: Ordering[A]) extends PriorityQueue[A] {
+
+ /** Checks if the queue is empty.
+ *
+ * @return true, iff there is no element in the queue.
+ */
+ override def isEmpty: Boolean = synchronized { super.isEmpty }
+
+ /** Inserts a single element into the priority queue.
+ *
+ * @param elem the element to insert
+ */
+ override def +=(elem: A): this.type = {
+ synchronized {
+ super.+=(elem)
+ }
+ this
+ }
+
+ /** Adds all elements of a traversable object into the priority queue.
+ *
+ * @param xs a traversable object
+ */
+ override def ++=(xs: TraversableOnce[A]): this.type = {
+ synchronized {
+ super.++=(xs)
+ }
+ this
+ }
+
+ /** Adds all elements to the queue.
+ *
+ * @param elems the elements to add.
+ */
+ override def enqueue(elems: A*): Unit = synchronized { super.++=(elems) }
+
+ /** Returns the element with the highest priority in the queue,
+ * and removes this element from the queue.
+ *
+ * @return the element with the highest priority.
+ */
+ override def dequeue(): A = synchronized { super.dequeue() }
+
+ /** Returns the element with the highest priority in the queue,
+ * or throws an error if there is no element contained in the queue.
+ *
+ * @return the element with the highest priority.
+ */
+ override def head: A = synchronized { super.head }
+
+ /** Removes all elements from the queue. After this operation is completed,
+ * the queue will be empty.
+ */
+ override def clear(): Unit = synchronized { super.clear() }
+
+ /** 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.
+ */
+ override def iterator: Iterator[A] = synchronized { super.iterator }
+
+ /** Checks if two queues are structurally identical.
+ *
+ * @return true, iff both queues contain the same sequence of elements.
+ */
+ override def equals(that: Any): Boolean = synchronized { super.equals(that) }
+
+ /** Returns a textual representation of a queue as a string.
+ *
+ * @return the string representation of this queue.
+ */
+ override def toString(): String = synchronized { super.toString() }
+}
diff --git a/src/library/scala/collection/mutable/PriorityQueueProxy.scala b/src/library/scala/collection/mutable/PriorityQueueProxy.scala
deleted file mode 100644
index b24551a6b7..0000000000
--- a/src/library/scala/collection/mutable/PriorityQueueProxy.scala
+++ /dev/null
@@ -1,96 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-
-package scala
-package collection
-package mutable
-
-/** This class servers as a proxy for priority queues. The
- * elements of the queue have to be ordered in terms of the
- * `Ordered[T]` class.
- *
- * @author Matthias Zenger
- * @version 1.0, 03/05/2004
- * @since 1
- */
-@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0")
-abstract class PriorityQueueProxy[A](implicit ord: Ordering[A]) extends PriorityQueue[A]
- with Proxy
-{
- def self: PriorityQueue[A]
-
- /** Creates a new iterator over all elements contained in this
- * object.
- *
- * @return the new iterator
- */
- override def iterator: Iterator[A] = self.iterator
-
- /** Returns the length of this priority queue.
- */
- override def length: Int = self.length
-
- /** Checks if the queue is empty.
- *
- * @return true, iff there is no element in the queue.
- */
- override def isEmpty: Boolean = self.isEmpty
-
- /** Inserts a single element into the priority queue.
- *
- * @param elem the element to insert
- */
- override def +=(elem: A): this.type = { self += elem; this }
-
- /** Adds all elements provided by an iterator into the priority queue.
- *
- * @param it an iterator
- */
- override def ++=(it: TraversableOnce[A]): this.type = {
- self ++= it
- this
- }
-
- /** Adds all elements to the queue.
- *
- * @param elems the elements to add.
- */
- override def enqueue(elems: A*): Unit = self ++= elems
-
- /** Returns the element with the highest priority in the queue,
- * and removes this element from the queue.
- *
- * @return the element with the highest priority.
- */
- override def dequeue(): A = self.dequeue()
-
- /** Returns the element with the highest priority in the queue,
- * or throws an error if there is no element contained in the queue.
- *
- * @return the element with the highest priority.
- */
- override def head: A = self.head
-
- /** Removes all elements from the queue. After this operation is completed,
- * the queue will be empty.
- */
- override def clear(): Unit = self.clear()
-
- /** Returns a regular queue containing the same elements.
- */
- override def toQueue: Queue[A] = self.toQueue
-
- /** This method clones the priority queue.
- *
- * @return a priority queue with the same elements.
- */
- override def clone(): PriorityQueue[A] = new PriorityQueueProxy[A] {
- def self = PriorityQueueProxy.this.self.clone()
- }
-}
diff --git a/src/library/scala/collection/mutable/RedBlackTree.scala b/src/library/scala/collection/mutable/RedBlackTree.scala
new file mode 100644
index 0000000000..e4793242bf
--- /dev/null
+++ b/src/library/scala/collection/mutable/RedBlackTree.scala
@@ -0,0 +1,580 @@
+package scala.collection.mutable
+
+import scala.annotation.tailrec
+import scala.collection.Iterator
+
+/**
+ * An object containing the red-black tree implementation used by mutable `TreeMaps`.
+ *
+ * The trees implemented in this object are *not* thread safe.
+ *
+ * @author Rui Gonçalves
+ * @version 2.12
+ * @since 2.12
+ */
+private[collection] object RedBlackTree {
+
+ // ---- class structure ----
+
+ // For performance reasons, this implementation uses `null` references to represent leaves instead of a sentinel node.
+ // Currently, the internal nodes do not store their subtree size - only the tree object keeps track of their size.
+ // Therefore, while obtaining the size of the whole tree is O(1), knowing the number of entries inside a range is O(n)
+ // on the size of the range.
+
+ @SerialVersionUID(21575944040195605L)
+ final class Tree[A, B](var root: Node[A, B], var size: Int) extends Serializable
+
+ @SerialVersionUID(1950599696441054720L)
+ final class Node[A, B](var key: A, var value: B, var red: Boolean,
+ var left: Node[A, B], var right: Node[A, B], var parent: Node[A, B]) extends Serializable {
+
+ override def toString: String = "Node(" + key + ", " + value + ", " + red + ", " + left + ", " + right + ")"
+ }
+
+ object Tree {
+ def empty[A, B]: Tree[A, B] = new Tree(null, 0)
+ }
+
+ object Node {
+
+ @inline def apply[A, B](key: A, value: B, red: Boolean,
+ left: Node[A, B], right: Node[A, B], parent: Node[A, B]): Node[A, B] =
+ new Node(key, value, red, left, right, parent)
+
+ @inline def leaf[A, B](key: A, value: B, red: Boolean, parent: Node[A, B]): Node[A, B] =
+ new Node(key, value, red, null, null, parent)
+
+ def unapply[A, B](t: Node[A, B]) = Some((t.key, t.value, t.left, t.right, t.parent))
+ }
+
+ // ---- getters ----
+
+ def isRed(node: Node[_, _]) = (node ne null) && node.red
+ def isBlack(node: Node[_, _]) = (node eq null) || !node.red
+
+ // ---- size ----
+
+ def size(node: Node[_, _]): Int = if (node eq null) 0 else 1 + size(node.left) + size(node.right)
+ def size(tree: Tree[_, _]): Int = tree.size
+ def isEmpty(tree: Tree[_, _]) = tree.root eq null
+ def clear(tree: Tree[_, _]): Unit = { tree.root = null; tree.size = 0 }
+
+ // ---- search ----
+
+ def get[A: Ordering, B](tree: Tree[A, B], key: A): Option[B] = getNode(tree.root, key) match {
+ case null => None
+ case node => Some(node.value)
+ }
+
+ @tailrec private[this] def getNode[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] =
+ if (node eq null) null
+ else {
+ val cmp = ord.compare(key, node.key)
+ if (cmp < 0) getNode(node.left, key)
+ else if (cmp > 0) getNode(node.right, key)
+ else node
+ }
+
+ def contains[A: Ordering](tree: Tree[A, _], key: A) = getNode(tree.root, key) ne null
+
+ def min[A, B](tree: Tree[A, B]): Option[(A, B)] = minNode(tree.root) match {
+ case null => None
+ case node => Some((node.key, node.value))
+ }
+
+ def minKey[A](tree: Tree[A, _]): Option[A] = minNode(tree.root) match {
+ case null => None
+ case node => Some(node.key)
+ }
+
+ private def minNode[A, B](node: Node[A, B]): Node[A, B] =
+ if (node eq null) null else minNodeNonNull(node)
+
+ @tailrec def minNodeNonNull[A, B](node: Node[A, B]): Node[A, B] =
+ if (node.left eq null) node else minNodeNonNull(node.left)
+
+ def max[A, B](tree: Tree[A, B]): Option[(A, B)] = maxNode(tree.root) match {
+ case null => None
+ case node => Some((node.key, node.value))
+ }
+
+ def maxKey[A](tree: Tree[A, _]): Option[A] = maxNode(tree.root) match {
+ case null => None
+ case node => Some(node.key)
+ }
+
+ private def maxNode[A, B](node: Node[A, B]): Node[A, B] =
+ if (node eq null) null else maxNodeNonNull(node)
+
+ @tailrec def maxNodeNonNull[A, B](node: Node[A, B]): Node[A, B] =
+ if (node.right eq null) node else maxNodeNonNull(node.right)
+
+ /**
+ * Returns the first (lowest) map entry with a key equal or greater than `key`. Returns `None` if there is no such
+ * node.
+ */
+ def minAfter[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Option[(A, B)] =
+ minNodeAfter(tree.root, key) match {
+ case null => None
+ case node => Some((node.key, node.value))
+ }
+
+ def minKeyAfter[A](tree: Tree[A, _], key: A)(implicit ord: Ordering[A]): Option[A] =
+ minNodeAfter(tree.root, key) match {
+ case null => None
+ case node => Some(node.key)
+ }
+
+ private[this] def minNodeAfter[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = {
+ if (node eq null) null
+ else {
+ var y: Node[A, B] = null
+ var x = node
+ var cmp = 1
+ while ((x ne null) && cmp != 0) {
+ y = x
+ cmp = ord.compare(key, x.key)
+ x = if (cmp < 0) x.left else x.right
+ }
+ if (cmp <= 0) y else successor(y)
+ }
+ }
+
+ /**
+ * Returns the last (highest) map entry with a key smaller than `key`. Returns `None` if there is no such node.
+ */
+ def maxBefore[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Option[(A, B)] =
+ maxNodeBefore(tree.root, key) match {
+ case null => None
+ case node => Some((node.key, node.value))
+ }
+
+ def maxKeyBefore[A](tree: Tree[A, _], key: A)(implicit ord: Ordering[A]): Option[A] =
+ maxNodeBefore(tree.root, key) match {
+ case null => None
+ case node => Some(node.key)
+ }
+
+ private[this] def maxNodeBefore[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = {
+ if (node eq null) null
+ else {
+ var y: Node[A, B] = null
+ var x = node
+ var cmp = 1
+ while ((x ne null) && cmp != 0) {
+ y = x
+ cmp = ord.compare(key, x.key)
+ x = if (cmp < 0) x.left else x.right
+ }
+ if (cmp > 0) y else predecessor(y)
+ }
+ }
+
+ // ---- insertion ----
+
+ def insert[A, B](tree: Tree[A, B], key: A, value: B)(implicit ord: Ordering[A]): Unit = {
+ var y: Node[A, B] = null
+ var x = tree.root
+ var cmp = 1
+ while ((x ne null) && cmp != 0) {
+ y = x
+ cmp = ord.compare(key, x.key)
+ x = if (cmp < 0) x.left else x.right
+ }
+
+ if (cmp == 0) y.value = value
+ else {
+ val z = Node.leaf(key, value, red = true, y)
+
+ if (y eq null) tree.root = z
+ else if (cmp < 0) y.left = z
+ else y.right = z
+
+ fixAfterInsert(tree, z)
+ tree.size += 1
+ }
+ }
+
+ private[this] def fixAfterInsert[A, B](tree: Tree[A, B], node: Node[A, B]): Unit = {
+ var z = node
+ while (isRed(z.parent)) {
+ if (z.parent eq z.parent.parent.left) {
+ val y = z.parent.parent.right
+ if (isRed(y)) {
+ z.parent.red = false
+ y.red = false
+ z.parent.parent.red = true
+ z = z.parent.parent
+ } else {
+ if (z eq z.parent.right) {
+ z = z.parent
+ rotateLeft(tree, z)
+ }
+ z.parent.red = false
+ z.parent.parent.red = true
+ rotateRight(tree, z.parent.parent)
+ }
+ } else { // symmetric cases
+ val y = z.parent.parent.left
+ if (isRed(y)) {
+ z.parent.red = false
+ y.red = false
+ z.parent.parent.red = true
+ z = z.parent.parent
+ } else {
+ if (z eq z.parent.left) {
+ z = z.parent
+ rotateRight(tree, z)
+ }
+ z.parent.red = false
+ z.parent.parent.red = true
+ rotateLeft(tree, z.parent.parent)
+ }
+ }
+ }
+ tree.root.red = false
+ }
+
+ // ---- deletion ----
+
+ def delete[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Unit = {
+ val z = getNode(tree.root, key)
+ if (z ne null) {
+ var y = z
+ var yIsRed = y.red
+ var x: Node[A, B] = null
+ var xParent: Node[A, B] = null
+
+ if (z.left eq null) {
+ x = z.right
+ transplant(tree, z, z.right)
+ xParent = z.parent
+ }
+ else if (z.right eq null) {
+ x = z.left
+ transplant(tree, z, z.left)
+ xParent = z.parent
+ }
+ else {
+ y = minNodeNonNull(z.right)
+ yIsRed = y.red
+ x = y.right
+
+ if (y.parent eq z) xParent = y
+ else {
+ xParent = y.parent
+ transplant(tree, y, y.right)
+ y.right = z.right
+ y.right.parent = y
+ }
+ transplant(tree, z, y)
+ y.left = z.left
+ y.left.parent = y
+ y.red = z.red
+ }
+
+ if (!yIsRed) fixAfterDelete(tree, x, xParent)
+ tree.size -= 1
+ }
+ }
+
+ private[this] def fixAfterDelete[A, B](tree: Tree[A, B], node: Node[A, B], parent: Node[A, B]): Unit = {
+ var x = node
+ var xParent = parent
+ while ((x ne tree.root) && isBlack(x)) {
+ if (x eq xParent.left) {
+ var w = xParent.right
+ // assert(w ne null)
+
+ if (w.red) {
+ w.red = false
+ xParent.red = true
+ rotateLeft(tree, xParent)
+ w = xParent.right
+ }
+ if (isBlack(w.left) && isBlack(w.right)) {
+ w.red = true
+ x = xParent
+ } else {
+ if (isBlack(w.right)) {
+ w.left.red = false
+ w.red = true
+ rotateRight(tree, w)
+ w = xParent.right
+ }
+ w.red = xParent.red
+ xParent.red = false
+ w.right.red = false
+ rotateLeft(tree, xParent)
+ x = tree.root
+ }
+ } else { // symmetric cases
+ var w = xParent.left
+ // assert(w ne null)
+
+ if (w.red) {
+ w.red = false
+ xParent.red = true
+ rotateRight(tree, xParent)
+ w = xParent.left
+ }
+ if (isBlack(w.right) && isBlack(w.left)) {
+ w.red = true
+ x = xParent
+ } else {
+ if (isBlack(w.left)) {
+ w.right.red = false
+ w.red = true
+ rotateLeft(tree, w)
+ w = xParent.left
+ }
+ w.red = xParent.red
+ xParent.red = false
+ w.left.red = false
+ rotateRight(tree, xParent)
+ x = tree.root
+ }
+ }
+ xParent = x.parent
+ }
+ if (x ne null) x.red = false
+ }
+
+ // ---- helpers ----
+
+ /**
+ * Returns the node that follows `node` in an in-order tree traversal. If `node` has the maximum key (and is,
+ * therefore, the last node), this method returns `null`.
+ */
+ private[this] def successor[A, B](node: Node[A, B]): Node[A, B] = {
+ if (node.right ne null) minNodeNonNull(node.right)
+ else {
+ var x = node
+ var y = x.parent
+ while ((y ne null) && (x eq y.right)) {
+ x = y
+ y = y.parent
+ }
+ y
+ }
+ }
+
+ /**
+ * Returns the node that precedes `node` in an in-order tree traversal. If `node` has the minimum key (and is,
+ * therefore, the first node), this method returns `null`.
+ */
+ private[this] def predecessor[A, B](node: Node[A, B]): Node[A, B] = {
+ if (node.left ne null) maxNodeNonNull(node.left)
+ else {
+ var x = node
+ var y = x.parent
+ while ((y ne null) && (x eq y.left)) {
+ x = y
+ y = y.parent
+ }
+ y
+ }
+ }
+
+ private[this] def rotateLeft[A, B](tree: Tree[A, B], x: Node[A, B]): Unit = if (x ne null) {
+ // assert(x.right ne null)
+ val y = x.right
+ x.right = y.left
+
+ if (y.left ne null) y.left.parent = x
+ y.parent = x.parent
+
+ if (x.parent eq null) tree.root = y
+ else if (x eq x.parent.left) x.parent.left = y
+ else x.parent.right = y
+
+ y.left = x
+ x.parent = y
+ }
+
+ private[this] def rotateRight[A, B](tree: Tree[A, B], x: Node[A, B]): Unit = if (x ne null) {
+ // assert(x.left ne null)
+ val y = x.left
+ x.left = y.right
+
+ if (y.right ne null) y.right.parent = x
+ y.parent = x.parent
+
+ if (x.parent eq null) tree.root = y
+ else if (x eq x.parent.right) x.parent.right = y
+ else x.parent.left = y
+
+ y.right = x
+ x.parent = y
+ }
+
+ /**
+ * Transplant the node `from` to the place of node `to`. This is done by setting `from` as a child of `to`'s previous
+ * parent and setting `from`'s parent to the `to`'s previous parent. The children of `from` are left unchanged.
+ */
+ private[this] def transplant[A, B](tree: Tree[A, B], to: Node[A, B], from: Node[A, B]): Unit = {
+ if (to.parent eq null) tree.root = from
+ else if (to eq to.parent.left) to.parent.left = from
+ else to.parent.right = from
+
+ if (from ne null) from.parent = to.parent
+ }
+
+ // ---- tree traversal ----
+
+ def foreach[A, B, U](tree: Tree[A, B], f: ((A, B)) => U): Unit = foreachNode(tree.root, f)
+
+ private[this] def foreachNode[A, B, U](node: Node[A, B], f: ((A, B)) => U): Unit =
+ if (node ne null) foreachNodeNonNull(node, f)
+
+ private[this] def foreachNodeNonNull[A, B, U](node: Node[A, B], f: ((A, B)) => U): Unit = {
+ if (node.left ne null) foreachNodeNonNull(node.left, f)
+ f((node.key, node.value))
+ if (node.right ne null) foreachNodeNonNull(node.right, f)
+ }
+
+ def foreachKey[A, U](tree: Tree[A, _], f: A => U): Unit = foreachNodeKey(tree.root, f)
+
+ private[this] def foreachNodeKey[A, U](node: Node[A, _], f: A => U): Unit =
+ if (node ne null) foreachNodeKeyNonNull(node, f)
+
+ private[this] def foreachNodeKeyNonNull[A, U](node: Node[A, _], f: A => U): Unit = {
+ if (node.left ne null) foreachNodeKeyNonNull(node.left, f)
+ f(node.key)
+ if (node.right ne null) foreachNodeKeyNonNull(node.right, f)
+ }
+
+ def transform[A, B](tree: Tree[A, B], f: (A, B) => B): Unit = transformNode(tree.root, f)
+
+ private[this] def transformNode[A, B, U](node: Node[A, B], f: (A, B) => B): Unit =
+ if (node ne null) transformNodeNonNull(node, f)
+
+ private[this] def transformNodeNonNull[A, B, U](node: Node[A, B], f: (A, B) => B): Unit = {
+ if (node.left ne null) transformNodeNonNull(node.left, f)
+ node.value = f(node.key, node.value)
+ if (node.right ne null) transformNodeNonNull(node.right, f)
+ }
+
+ def iterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[(A, B)] =
+ new EntriesIterator(tree, start, end)
+
+ def keysIterator[A: Ordering](tree: Tree[A, _], start: Option[A] = None, end: Option[A] = None): Iterator[A] =
+ new KeysIterator(tree, start, end)
+
+ def valuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[B] =
+ new ValuesIterator(tree, start, end)
+
+ private[this] abstract class TreeIterator[A, B, R](tree: Tree[A, B], start: Option[A], end: Option[A])
+ (implicit ord: Ordering[A]) extends Iterator[R] {
+
+ protected[this] def nextResult(node: Node[A, B]): R
+
+ def hasNext: Boolean = nextNode ne null
+
+ def next(): R = nextNode match {
+ case null => throw new NoSuchElementException("next on empty iterator")
+ case node =>
+ nextNode = successor(node)
+ setNullIfAfterEnd()
+ nextResult(node)
+ }
+
+ private[this] var nextNode: Node[A, B] = start match {
+ case None => minNode(tree.root)
+ case Some(from) => minNodeAfter(tree.root, from)
+ }
+
+ private[this] def setNullIfAfterEnd(): Unit =
+ if (end.isDefined && (nextNode ne null) && ord.compare(nextNode.key, end.get) >= 0)
+ nextNode = null
+
+ setNullIfAfterEnd()
+ }
+
+ private[this] final class EntriesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A])
+ extends TreeIterator[A, B, (A, B)](tree, start, end) {
+
+ def nextResult(node: Node[A, B]) = (node.key, node.value)
+ }
+
+ private[this] final class KeysIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A])
+ extends TreeIterator[A, B, A](tree, start, end) {
+
+ def nextResult(node: Node[A, B]) = node.key
+ }
+
+ private[this] final class ValuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A])
+ extends TreeIterator[A, B, B](tree, start, end) {
+
+ def nextResult(node: Node[A, B]) = node.value
+ }
+
+ // ---- debugging ----
+
+ /**
+ * Checks if the tree is in a valid state. That happens if:
+ * - It is a valid binary search tree;
+ * - All red-black properties are satisfied;
+ * - All non-null nodes have their `parent` reference correct;
+ * - The size variable in `tree` corresponds to the actual size of the tree.
+ */
+ def isValid[A: Ordering, B](tree: Tree[A, B]): Boolean =
+ isValidBST(tree.root) && hasProperParentRefs(tree) && isValidRedBlackTree(tree) && size(tree.root) == tree.size
+
+ /**
+ * Returns true if all non-null nodes have their `parent` reference correct.
+ */
+ private[this] def hasProperParentRefs[A, B](tree: Tree[A, B]): Boolean = {
+
+ def hasProperParentRefs(node: Node[A, B]): Boolean = {
+ if (node eq null) true
+ else {
+ if ((node.left ne null) && (node.left.parent ne node) ||
+ (node.right ne null) && (node.right.parent ne node)) false
+ else hasProperParentRefs(node.left) && hasProperParentRefs(node.right)
+ }
+ }
+
+ if(tree.root eq null) true
+ else (tree.root.parent eq null) && hasProperParentRefs(tree.root)
+ }
+
+ /**
+ * Returns true if this node follows the properties of a binary search tree.
+ */
+ private[this] def isValidBST[A, B](node: Node[A, B])(implicit ord: Ordering[A]): Boolean = {
+ if (node eq null) true
+ else {
+ if ((node.left ne null) && (ord.compare(node.key, node.left.key) <= 0) ||
+ (node.right ne null) && (ord.compare(node.key, node.right.key) >= 0)) false
+ else isValidBST(node.left) && isValidBST(node.right)
+ }
+ }
+
+ /**
+ * Returns true if the tree has all the red-black tree properties: if the root node is black, if all children of red
+ * nodes are black and if the path from any node to any of its null children has the same number of black nodes.
+ */
+ private[this] def isValidRedBlackTree[A, B](tree: Tree[A, B]): Boolean = {
+
+ def noRedAfterRed(node: Node[A, B]): Boolean = {
+ if (node eq null) true
+ else if (node.red && (isRed(node.left) || isRed(node.right))) false
+ else noRedAfterRed(node.left) && noRedAfterRed(node.right)
+ }
+
+ def blackHeight(node: Node[A, B]): Int = {
+ if (node eq null) 1
+ else {
+ val lh = blackHeight(node.left)
+ val rh = blackHeight(node.right)
+
+ if (lh == -1 || lh != rh) -1
+ else if (isRed(node)) lh
+ else lh + 1
+ }
+ }
+
+ isBlack(tree.root) && noRedAfterRed(tree.root) && blackHeight(tree.root) >= 0
+ }
+}
diff --git a/src/library/scala/collection/mutable/ResizableArray.scala b/src/library/scala/collection/mutable/ResizableArray.scala
index c3047522e2..85a299216e 100644
--- a/src/library/scala/collection/mutable/ResizableArray.scala
+++ b/src/library/scala/collection/mutable/ResizableArray.scala
@@ -74,7 +74,7 @@ trait ResizableArray[A] extends IndexedSeq[A]
*/
override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int) {
val len1 = len min (xs.length - start) min length
- Array.copy(array, 0, xs, start, len1)
+ if (len1 > 0) Array.copy(array, 0, xs, start, len1)
}
//##########################################################################
diff --git a/src/library/scala/collection/mutable/ReusableBuilder.scala b/src/library/scala/collection/mutable/ReusableBuilder.scala
new file mode 100644
index 0000000000..83a4fcfc29
--- /dev/null
+++ b/src/library/scala/collection/mutable/ReusableBuilder.scala
@@ -0,0 +1,49 @@
+/* __ *\
+** ________ ___ / / ___ Scala API **
+** / __/ __// _ | / / / _ | (c) 2003-2016, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
+** /____/\___/_/ |_/____/_/ | | **
+** |/ **
+\* */
+
+
+package scala
+package collection
+package mutable
+
+/** `ReusableBuilder` is a marker trait that indicates that a `Builder`
+ * can be reused to build more than one instance of a collection. In
+ * particular, calling `result` followed by `clear` will produce a
+ * collection and reset the builder to begin building a new collection
+ * of the same type.
+ *
+ * It is up to subclasses to implement this behavior, and to document any
+ * other behavior that varies from standard `ReusableBuilder` usage
+ * (e.g. operations being well-defined after a call to `result`, or allowing
+ * multiple calls to result to obtain different snapshots of a collection under
+ * construction).
+ *
+ * @tparam Elem the type of elements that get added to the builder.
+ * @tparam To the type of collection that it produced.
+ *
+ * @since 2.12
+ */
+trait ReusableBuilder[-Elem, +To] extends Builder[Elem, To] {
+ /** Clears the contents of this builder.
+ * After execution of this method, the builder will contain no elements.
+ *
+ * If executed immediately after a call to `result`, this allows a new
+ * instance of the same type of collection to be built.
+ */
+ override def clear(): Unit // Note: overriding for scaladoc only!
+
+ /** Produces a collection from the added elements.
+ *
+ * After a call to `result`, the behavior of all other methods is undefined
+ * save for `clear`. If `clear` is called, then the builder is reset and
+ * may be used to build another instance.
+ *
+ * @return a collection containing the elements added to this builder.
+ */
+ override def result(): To // Note: overriding for scaladoc only!
+}
diff --git a/src/library/scala/collection/mutable/SetBuilder.scala b/src/library/scala/collection/mutable/SetBuilder.scala
index 01bfdc96ed..5d1e9ffc3a 100644
--- a/src/library/scala/collection/mutable/SetBuilder.scala
+++ b/src/library/scala/collection/mutable/SetBuilder.scala
@@ -17,7 +17,9 @@ package mutable
* @param empty The empty element of the collection.
* @since 2.8
*/
-class SetBuilder[A, Coll <: scala.collection.Set[A] with scala.collection.SetLike[A, Coll]](empty: Coll) extends Builder[A, Coll] {
+class SetBuilder[A, Coll <: scala.collection.Set[A]
+with scala.collection.SetLike[A, Coll]](empty: Coll)
+extends ReusableBuilder[A, Coll] {
protected var elems: Coll = empty
def +=(x: A): this.type = { elems = elems + x; this }
def clear() { elems = empty }
diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala
index 01075a2633..a19130e742 100644
--- a/src/library/scala/collection/mutable/SetLike.scala
+++ b/src/library/scala/collection/mutable/SetLike.scala
@@ -72,6 +72,17 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]]
protected[this] override def parCombiner = ParSet.newCombiner[A]
+ /** Converts this $coll to a sequence.
+ *
+ * ```Note```: assumes a fast `size` method. Subclasses should override if this is not true.
+ */
+ override def toSeq: collection.Seq[A] = {
+ // ArrayBuffer for efficiency, preallocated to the right size.
+ val result = new ArrayBuffer[A](size)
+ foreach(result += _)
+ result
+ }
+
/** Adds an element to this $coll.
*
* @param elem the element to be added
diff --git a/src/library/scala/collection/mutable/SortedMap.scala b/src/library/scala/collection/mutable/SortedMap.scala
new file mode 100644
index 0000000000..806b30e79a
--- /dev/null
+++ b/src/library/scala/collection/mutable/SortedMap.scala
@@ -0,0 +1,57 @@
+package scala
+package collection
+package mutable
+
+import generic._
+
+/**
+ * A mutable map whose keys are sorted.
+ *
+ * @tparam A the type of the keys contained in this sorted map.
+ * @tparam B the type of the values associated with the keys.
+ *
+ * @author Rui Gonçalves
+ * @version 2.12
+ * @since 2.12
+ *
+ * @define Coll mutable.SortedMap
+ * @define coll mutable sorted map
+ */
+trait SortedMap[A, B]
+ extends Map[A, B]
+ with collection.SortedMap[A, B]
+ with MapLike[A, B, SortedMap[A, B]]
+ with SortedMapLike[A, B, SortedMap[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))
+
+ override def +[B1 >: B](kv: (A, B1)): SortedMap[A, B1] = clone().asInstanceOf[SortedMap[A, B1]] += kv
+
+ override def +[B1 >: B](elem1: (A, B1), elem2: (A, B1), elems: (A, B1)*): SortedMap[A, B1] =
+ clone().asInstanceOf[SortedMap[A, B1]] += elem1 += elem2 ++= elems
+
+ override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): SortedMap[A, B1] =
+ clone().asInstanceOf[SortedMap[A, B1]] ++= xs.seq
+}
+
+/**
+ * $factoryInfo
+ *
+ * @define Coll mutable.SortedMap
+ * @define coll mutable sorted map
+ */
+object SortedMap extends MutableSortedMapFactory[SortedMap] {
+
+ def empty[A, B](implicit ord: Ordering[A]): SortedMap[A, B] = TreeMap.empty[A, B]
+
+ /** $sortedMapCanBuildFromInfo */
+ implicit def canBuildFrom[A, B](implicit ord: Ordering[A]): CanBuildFrom[Coll, (A, B), SortedMap[A, B]] =
+ new SortedMapCanBuildFrom[A, B]
+}
+
+/** Explicit instantiation of the `SortedMap` trait to reduce class file size in subclasses. */
+abstract class AbstractSortedMap[A, B] extends scala.collection.mutable.AbstractMap[A, B] with SortedMap[A, B]
diff --git a/src/library/scala/collection/mutable/SortedSet.scala b/src/library/scala/collection/mutable/SortedSet.scala
index 0f2fa75abd..304469916d 100644
--- a/src/library/scala/collection/mutable/SortedSet.scala
+++ b/src/library/scala/collection/mutable/SortedSet.scala
@@ -43,8 +43,13 @@ trait SortedSet[A] extends scala.collection.SortedSet[A] with scala.collection.S
*
*/
object SortedSet extends MutableSortedSetFactory[SortedSet] {
- implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = new SortedSetCanBuildFrom[A]
+ def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = new SortedSetCanBuildFrom[A]
def empty[A](implicit ord: Ordering[A]): SortedSet[A] = TreeSet.empty[A]
+ // Force a declaration here so that BitSet (which does not inherit from SortedSetFactory) can be more specific
+ override implicit def newCanBuildFrom[A](implicit ord : Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = super.newCanBuildFrom
}
+
+/** Explicit instantiation of the `SortedSet` trait to reduce class file size in subclasses. */
+abstract class AbstractSortedSet[A] extends scala.collection.mutable.AbstractSet[A] with SortedSet[A]
diff --git a/src/library/scala/collection/mutable/StringBuilder.scala b/src/library/scala/collection/mutable/StringBuilder.scala
index c56d40786e..b5b9498374 100644
--- a/src/library/scala/collection/mutable/StringBuilder.scala
+++ b/src/library/scala/collection/mutable/StringBuilder.scala
@@ -33,7 +33,7 @@ final class StringBuilder(private val underlying: JavaStringBuilder)
with java.lang.CharSequence
with IndexedSeq[Char]
with StringLike[StringBuilder]
- with Builder[Char, String]
+ with ReusableBuilder[Char, String]
with Serializable {
override protected[this] def thisCollection: StringBuilder = this
@@ -435,7 +435,11 @@ final class StringBuilder(private val underlying: JavaStringBuilder)
*/
override def mkString = toString
- /** Returns the result of this Builder (a String)
+ /** Returns the result of this Builder (a String).
+ *
+ * If this method is called multiple times, each call will result in a snapshot of the buffer at that point in time.
+ * In particular, a `StringBuilder` can be used to build multiple independent strings by emptying the buffer with `clear`
+ * after each call to `result`.
*
* @return the string assembled by this StringBuilder
*/
diff --git a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala b/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala
deleted file mode 100644
index d3c0b85f69..0000000000
--- a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala
+++ /dev/null
@@ -1,101 +0,0 @@
-/* __ *\
-** ________ ___ / / ___ Scala API **
-** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL **
-** __\ \/ /__/ __ |/ /__/ __ | **
-** /____/\___/_/ |_/____/_/ | | **
-** |/ **
-\* */
-
-
-
-package scala
-package collection
-package mutable
-
-/** This class implements synchronized priority queues using a binary heap.
- * The elements of the queue have to be ordered in terms of the `Ordered[T]` class.
- *
- * @tparam A type of the elements contained in this synchronized priority queue
- * @param ord implicit ordering used to compared elements of type `A`
- *
- * @author Matthias Zenger
- * @version 1.0, 03/05/2004
- * @since 1
- * @define Coll `SynchronizedPriorityQueue`
- * @define coll synchronized priority queue
- */
-@deprecated("Comprehensive synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentSkipListSet as an alternative.", "2.11.0")
-class SynchronizedPriorityQueue[A](implicit ord: Ordering[A]) extends PriorityQueue[A] {
-
- /** Checks if the queue is empty.
- *
- * @return true, iff there is no element in the queue.
- */
- override def isEmpty: Boolean = synchronized { super.isEmpty }
-
- /** Inserts a single element into the priority queue.
- *
- * @param elem the element to insert
- */
- override def +=(elem: A): this.type = {
- synchronized {
- super.+=(elem)
- }
- this
- }
-
- /** Adds all elements of a traversable object into the priority queue.
- *
- * @param xs a traversable object
- */
- override def ++=(xs: TraversableOnce[A]): this.type = {
- synchronized {
- super.++=(xs)
- }
- this
- }
-
- /** Adds all elements to the queue.
- *
- * @param elems the elements to add.
- */
- override def enqueue(elems: A*): Unit = synchronized { super.++=(elems) }
-
- /** Returns the element with the highest priority in the queue,
- * and removes this element from the queue.
- *
- * @return the element with the highest priority.
- */
- override def dequeue(): A = synchronized { super.dequeue() }
-
- /** Returns the element with the highest priority in the queue,
- * or throws an error if there is no element contained in the queue.
- *
- * @return the element with the highest priority.
- */
- override def head: A = synchronized { super.head }
-
- /** Removes all elements from the queue. After this operation is completed,
- * the queue will be empty.
- */
- override def clear(): Unit = synchronized { super.clear() }
-
- /** 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.
- */
- override def iterator: Iterator[A] = synchronized { super.iterator }
-
- /** Checks if two queues are structurally identical.
- *
- * @return true, iff both queues contain the same sequence of elements.
- */
- override def equals(that: Any): Boolean = synchronized { super.equals(that) }
-
- /** Returns a textual representation of a queue as a string.
- *
- * @return the string representation of this queue.
- */
- override def toString(): String = synchronized { super.toString() }
-}
diff --git a/src/library/scala/collection/mutable/SynchronizedStack.scala b/src/library/scala/collection/mutable/SynchronizedStack.scala
index bbb6f5a9bb..c77a6fad62 100644
--- a/src/library/scala/collection/mutable/SynchronizedStack.scala
+++ b/src/library/scala/collection/mutable/SynchronizedStack.scala
@@ -27,7 +27,6 @@ package mutable
*/
@deprecated("Synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.LinkedBlockingDequeue instead.", "2.11.0")
class SynchronizedStack[A] extends Stack[A] {
- import scala.collection.Traversable
/** Checks if the stack is empty.
*
diff --git a/src/library/scala/collection/mutable/TreeMap.scala b/src/library/scala/collection/mutable/TreeMap.scala
new file mode 100644
index 0000000000..dc7d5d750e
--- /dev/null
+++ b/src/library/scala/collection/mutable/TreeMap.scala
@@ -0,0 +1,185 @@
+package scala
+package collection
+package mutable
+
+import scala.collection.generic._
+import scala.collection.mutable.{RedBlackTree => RB}
+
+/**
+ * $factoryInfo
+ *
+ * @define Coll mutable.TreeMap
+ * @define coll mutable tree map
+ */
+object TreeMap extends MutableSortedMapFactory[TreeMap] {
+
+ def empty[A, B](implicit ord: Ordering[A]) = new TreeMap[A, B]()(ord)
+
+ /** $sortedMapCanBuildFromInfo */
+ implicit def canBuildFrom[A, B](implicit ord: Ordering[A]): CanBuildFrom[Coll, (A, B), TreeMap[A, B]] =
+ new SortedMapCanBuildFrom[A, B]
+}
+
+/**
+ * A mutable sorted map implemented using a mutable red-black tree as underlying data structure.
+ *
+ * @param ordering the implicit ordering used to compare objects of type `A`.
+ * @tparam A the type of the keys contained in this tree map.
+ * @tparam B the type of the values associated with the keys.
+ *
+ * @author Rui Gonçalves
+ * @version 2.12
+ * @since 2.12
+ *
+ * @define Coll mutable.TreeMap
+ * @define coll mutable tree map
+ */
+@SerialVersionUID(-2558985573956740112L)
+sealed class TreeMap[A, B] private (tree: RB.Tree[A, B])(implicit val ordering: Ordering[A])
+ extends AbstractSortedMap[A, B]
+ with SortedMap[A, B]
+ with MapLike[A, B, TreeMap[A, B]]
+ with SortedMapLike[A, B, TreeMap[A, B]]
+ with Serializable {
+
+ /**
+ * Creates an empty `TreeMap`.
+ * @param ord the implicit ordering used to compare objects of type `A`.
+ * @return an empty `TreeMap`.
+ */
+ def this()(implicit ord: Ordering[A]) = this(RB.Tree.empty)(ord)
+
+ override def empty = TreeMap.empty
+ override protected[this] def newBuilder = TreeMap.newBuilder[A, B]
+
+ /**
+ * Creates a ranged projection of this map. Any mutations in the ranged projection will update the original map and
+ * vice versa.
+ *
+ * Only entries with keys between this projection's key range will ever appear as elements of this map, independently
+ * of whether the entries are added through the original map or through this view. That means that if one inserts a
+ * key-value in a view whose key is outside the view's bounds, calls to `get` or `contains` will _not_ consider the
+ * newly added entry. Mutations are always reflected in the original map, though.
+ *
+ * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower
+ * bound.
+ * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper
+ * bound.
+ */
+ def rangeImpl(from: Option[A], until: Option[A]): TreeMap[A, B] = new TreeMapView(from, until)
+
+ def -=(key: A): this.type = { RB.delete(tree, key); this }
+ def +=(kv: (A, B)): this.type = { RB.insert(tree, kv._1, kv._2); this }
+
+ def get(key: A) = RB.get(tree, key)
+
+ def iterator = RB.iterator(tree)
+ def iteratorFrom(start: A) = RB.iterator(tree, Some(start))
+ def keysIteratorFrom(start: A) = RB.keysIterator(tree, Some(start))
+ def valuesIteratorFrom(start: A) = RB.valuesIterator(tree, Some(start))
+
+ override def size = RB.size(tree)
+ override def isEmpty = RB.isEmpty(tree)
+ override def contains(key: A) = RB.contains(tree, key)
+
+ override def head = RB.min(tree).get
+ override def headOption = RB.min(tree)
+ override def last = RB.max(tree).get
+ override def lastOption = RB.max(tree)
+
+ override def keysIterator = RB.keysIterator(tree)
+ override def valuesIterator = RB.valuesIterator(tree)
+
+ override def foreach[U](f: ((A, B)) => U): Unit = RB.foreach(tree, f)
+ override def transform(f: (A, B) => B) = { RB.transform(tree, f); this }
+ override def clear(): Unit = RB.clear(tree)
+
+ override def stringPrefix = "TreeMap"
+
+ /**
+ * A ranged projection of a [[TreeMap]]. Mutations on this map affect the original map and vice versa.
+ *
+ * Only entries with keys between this projection's key range will ever appear as elements of this map, independently
+ * of whether the entries are added through the original map or through this view. That means that if one inserts a
+ * key-value in a view whose key is outside the view's bounds, calls to `get` or `contains` will _not_ consider the
+ * newly added entry. Mutations are always reflected in the original map, though.
+ *
+ * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower
+ * bound.
+ * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper
+ * bound.
+ */
+ @SerialVersionUID(2219159283273389116L)
+ private[this] final class TreeMapView(from: Option[A], until: Option[A]) extends TreeMap[A, B](tree) {
+
+ /**
+ * Given a possible new lower bound, chooses and returns the most constraining one (the maximum).
+ */
+ private[this] def pickLowerBound(newFrom: Option[A]): Option[A] = (from, newFrom) match {
+ case (Some(fr), Some(newFr)) => Some(ordering.max(fr, newFr))
+ case (None, _) => newFrom
+ case _ => from
+ }
+
+ /**
+ * Given a possible new upper bound, chooses and returns the most constraining one (the minimum).
+ */
+ private[this] def pickUpperBound(newUntil: Option[A]): Option[A] = (until, newUntil) match {
+ case (Some(unt), Some(newUnt)) => Some(ordering.min(unt, newUnt))
+ case (None, _) => newUntil
+ case _ => until
+ }
+
+ /**
+ * Returns true if the argument is inside the view bounds (between `from` and `until`).
+ */
+ private[this] def isInsideViewBounds(key: A): Boolean = {
+ val afterFrom = from.isEmpty || ordering.compare(from.get, key) <= 0
+ val beforeUntil = until.isEmpty || ordering.compare(key, until.get) < 0
+ afterFrom && beforeUntil
+ }
+
+ override def rangeImpl(from: Option[A], until: Option[A]): TreeMap[A, B] =
+ new TreeMapView(pickLowerBound(from), pickUpperBound(until))
+
+ override def get(key: A) = if (isInsideViewBounds(key)) RB.get(tree, key) else None
+
+ override def iterator = RB.iterator(tree, from, until)
+ override def iteratorFrom(start: A) = RB.iterator(tree, pickLowerBound(Some(start)), until)
+ override def keysIteratorFrom(start: A) = RB.keysIterator(tree, pickLowerBound(Some(start)), until)
+ override def valuesIteratorFrom(start: A) = RB.valuesIterator(tree, pickLowerBound(Some(start)), until)
+
+ override def size = iterator.length
+ override def isEmpty = !iterator.hasNext
+ override def contains(key: A) = isInsideViewBounds(key) && RB.contains(tree, key)
+
+ override def head = headOption.get
+ override def headOption = {
+ val entry = if (from.isDefined) RB.minAfter(tree, from.get) else RB.min(tree)
+ (entry, until) match {
+ case (Some(e), Some(unt)) if ordering.compare(e._1, unt) >= 0 => None
+ case _ => entry
+ }
+ }
+
+ override def last = lastOption.get
+ override def lastOption = {
+ val entry = if (until.isDefined) RB.maxBefore(tree, until.get) else RB.max(tree)
+ (entry, from) match {
+ case (Some(e), Some(fr)) if ordering.compare(e._1, fr) < 0 => None
+ case _ => entry
+ }
+ }
+
+ // Using the iterator should be efficient enough; if performance is deemed a problem later, specialized
+ // `foreach(f, from, until)` and `transform(f, from, until)` methods can be created in `RedBlackTree`. See
+ // https://github.com/scala/scala/pull/4608#discussion_r34307985 for a discussion about this.
+ override def foreach[U](f: ((A, B)) => U): Unit = iterator.foreach(f)
+ override def transform(f: (A, B) => B) = {
+ iterator.foreach { case (key, value) => update(key, f(key, value)) }
+ this
+ }
+
+ override def clone() = super.clone().rangeImpl(from, until)
+ }
+}
diff --git a/src/library/scala/collection/mutable/TreeSet.scala b/src/library/scala/collection/mutable/TreeSet.scala
index f849eea569..ada6f145ad 100644
--- a/src/library/scala/collection/mutable/TreeSet.scala
+++ b/src/library/scala/collection/mutable/TreeSet.scala
@@ -11,8 +11,7 @@ package collection
package mutable
import generic._
-import scala.collection.immutable.{RedBlackTree => RB}
-import scala.runtime.ObjectRef
+import scala.collection.mutable.{RedBlackTree => RB}
/**
* @define Coll `mutable.TreeSet`
@@ -29,88 +28,162 @@ object TreeSet extends MutableSortedSetFactory[TreeSet] {
*/
def empty[A](implicit ordering: Ordering[A]) = new TreeSet[A]()
+ /** $sortedMapCanBuildFromInfo */
+ implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, TreeSet[A]] =
+ new SortedSetCanBuildFrom[A]
}
/**
- * A mutable SortedSet using an immutable RedBlack Tree as underlying data structure.
+ * A mutable sorted set implemented using a mutable red-black tree as underlying data structure.
*
- * @author Lucien Pereira
+ * @param ordering the implicit ordering used to compare objects of type `A`.
+ * @tparam A the type of the keys contained in this tree set.
+ *
+ * @author Rui Gonçalves
+ * @version 2.12
+ * @since 2.10
*
+ * @define Coll mutable.TreeSet
+ * @define coll mutable tree set
*/
-@deprecatedInheritance("TreeSet is not designed to enable meaningful subclassing.", "2.11.0")
-class TreeSet[A] private (treeRef: ObjectRef[RB.Tree[A, Null]], from: Option[A], until: Option[A])(implicit val ordering: Ordering[A])
- extends SortedSet[A] with SetLike[A, TreeSet[A]]
- with SortedSetLike[A, TreeSet[A]] with Set[A] with Serializable {
+// Original API designed in part by Lucien Pereira
+@SerialVersionUID(-3642111301929493640L)
+sealed class TreeSet[A] private (tree: RB.Tree[A, Null])(implicit val ordering: Ordering[A])
+ extends AbstractSortedSet[A]
+ with SortedSet[A]
+ with SetLike[A, TreeSet[A]]
+ with SortedSetLike[A, TreeSet[A]]
+ with Serializable {
if (ordering eq null)
throw new NullPointerException("ordering must not be null")
- def this()(implicit ordering: Ordering[A]) = this(new ObjectRef(null), None, None)
+ /**
+ * Creates an empty `TreeSet`.
+ * @param ord the implicit ordering used to compare objects of type `A`.
+ * @return an empty `TreeSet`.
+ */
+ def this()(implicit ord: Ordering[A]) = this(RB.Tree.empty)(ord)
- override def size: Int = RB.countInRange(treeRef.elem, from, until)
+ override def empty = TreeSet.empty
+ override protected[this] def newBuilder = TreeSet.newBuilder[A]
- override def stringPrefix = "TreeSet"
+ /**
+ * Creates a ranged projection of this set. Any mutations in the ranged projection affect will update the original set
+ * and vice versa.
+ *
+ * Only keys between this projection's key range will ever appear as elements of this set, independently of whether
+ * the elements are added through the original set or through this view. That means that if one inserts an element in
+ * a view whose key is outside the view's bounds, calls to `contains` will _not_ consider the newly added element.
+ * Mutations are always reflected in the original set, though.
+ *
+ * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower
+ * bound.
+ * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper
+ * bound.
+ */
+ def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] = new TreeSetView(from, until)
- override def empty: TreeSet[A] = TreeSet.empty
+ def -=(key: A): this.type = { RB.delete(tree, key); this }
+ def +=(elem: A): this.type = { RB.insert(tree, elem, null); this }
- private def pickBound(comparison: (A, A) => A, oldBound: Option[A], newBound: Option[A]) = (newBound, oldBound) match {
- case (Some(newB), Some(oldB)) => Some(comparison(newB, oldB))
- case (None, _) => oldBound
- case _ => newBound
- }
+ def contains(elem: A) = RB.contains(tree, elem)
- override def rangeImpl(fromArg: Option[A], untilArg: Option[A]): TreeSet[A] = {
- val newFrom = pickBound(ordering.max, fromArg, from)
- val newUntil = pickBound(ordering.min, untilArg, until)
+ def iterator = RB.keysIterator(tree)
+ def keysIteratorFrom(start: A) = RB.keysIterator(tree, Some(start))
+ override def iteratorFrom(start: A) = RB.keysIterator(tree, Some(start))
- new TreeSet(treeRef, newFrom, newUntil)
- }
+ override def size = RB.size(tree)
+ override def isEmpty = RB.isEmpty(tree)
- override def -=(elem: A): this.type = {
- treeRef.elem = RB.delete(treeRef.elem, elem)
- this
- }
+ override def head = RB.minKey(tree).get
+ override def headOption = RB.minKey(tree)
+ override def last = RB.maxKey(tree).get
+ override def lastOption = RB.maxKey(tree)
- override def +=(elem: A): this.type = {
- treeRef.elem = RB.update(treeRef.elem, elem, null, overwrite = false)
- this
- }
+ override def foreach[U](f: A => U): Unit = RB.foreachKey(tree, f)
+ override def clear(): Unit = RB.clear(tree)
+
+ override def stringPrefix = "TreeSet"
/**
- * Thanks to the immutable nature of the
- * underlying Tree, we can share it with
- * the clone. So clone complexity in time is O(1).
+ * A ranged projection of a [[TreeSet]]. Mutations on this set affect the original set and vice versa.
*
+ * Only keys between this projection's key range will ever appear as elements of this set, independently of whether
+ * the elements are added through the original set or through this view. That means that if one inserts an element in
+ * a view whose key is outside the view's bounds, calls to `contains` will _not_ consider the newly added element.
+ * Mutations are always reflected in the original set, though.
+ *
+ * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower
+ * bound.
+ * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper
+ * bound.
*/
- override def clone(): TreeSet[A] =
- new TreeSet[A](new ObjectRef(treeRef.elem), from, until)
-
- private val notProjection = !(from.isDefined || until.isDefined)
+ @SerialVersionUID(7087824939194006086L)
+ private[this] final class TreeSetView(from: Option[A], until: Option[A]) extends TreeSet[A](tree) {
+
+ /**
+ * Given a possible new lower bound, chooses and returns the most constraining one (the maximum).
+ */
+ private[this] def pickLowerBound(newFrom: Option[A]): Option[A] = (from, newFrom) match {
+ case (Some(fr), Some(newFr)) => Some(ordering.max(fr, newFr))
+ case (None, _) => newFrom
+ case _ => from
+ }
- override def contains(elem: A): Boolean = {
- def leftAcceptable: Boolean = from match {
- case Some(lb) => ordering.gteq(elem, lb)
- case _ => true
+ /**
+ * Given a possible new upper bound, chooses and returns the most constraining one (the minimum).
+ */
+ private[this] def pickUpperBound(newUntil: Option[A]): Option[A] = (until, newUntil) match {
+ case (Some(unt), Some(newUnt)) => Some(ordering.min(unt, newUnt))
+ case (None, _) => newUntil
+ case _ => until
}
- def rightAcceptable: Boolean = until match {
- case Some(ub) => ordering.lt(elem, ub)
- case _ => true
+ /**
+ * Returns true if the argument is inside the view bounds (between `from` and `until`).
+ */
+ private[this] def isInsideViewBounds(key: A): Boolean = {
+ val afterFrom = from.isEmpty || ordering.compare(from.get, key) <= 0
+ val beforeUntil = until.isEmpty || ordering.compare(key, until.get) < 0
+ afterFrom && beforeUntil
}
- (notProjection || (leftAcceptable && rightAcceptable)) &&
- RB.contains(treeRef.elem, elem)
- }
+ override def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] =
+ new TreeSetView(pickLowerBound(from), pickUpperBound(until))
+
+ override def contains(key: A) = isInsideViewBounds(key) && RB.contains(tree, key)
+
+ override def iterator = RB.keysIterator(tree, from, until)
+ override def keysIteratorFrom(start: A) = RB.keysIterator(tree, pickLowerBound(Some(start)), until)
+ override def iteratorFrom(start: A) = RB.keysIterator(tree, pickLowerBound(Some(start)), until)
- override def iterator: Iterator[A] = iteratorFrom(None)
+ override def size = iterator.length
+ override def isEmpty = !iterator.hasNext
- override def keysIteratorFrom(start: A) = iteratorFrom(Some(start))
+ override def head = headOption.get
+ override def headOption = {
+ val elem = if (from.isDefined) RB.minKeyAfter(tree, from.get) else RB.minKey(tree)
+ (elem, until) match {
+ case (Some(e), Some(unt)) if ordering.compare(e, unt) >= 0 => None
+ case _ => elem
+ }
+ }
- private def iteratorFrom(start: Option[A]) = {
- val it = RB.keysIterator(treeRef.elem, pickBound(ordering.max, from, start))
- until match {
- case None => it
- case Some(ub) => it takeWhile (k => ordering.lt(k, ub))
+ override def last = lastOption.get
+ override def lastOption = {
+ val elem = if (until.isDefined) RB.maxKeyBefore(tree, until.get) else RB.maxKey(tree)
+ (elem, from) match {
+ case (Some(e), Some(fr)) if ordering.compare(e, fr) < 0 => None
+ case _ => elem
+ }
}
+
+ // Using the iterator should be efficient enough; if performance is deemed a problem later, a specialized
+ // `foreachKey(f, from, until)` method can be created in `RedBlackTree`. See
+ // https://github.com/scala/scala/pull/4608#discussion_r34307985 for a discussion about this.
+ override def foreach[U](f: A => U): Unit = iterator.foreach(f)
+
+ override def clone() = super.clone().rangeImpl(from, until)
}
}
diff --git a/src/library/scala/collection/mutable/UnrolledBuffer.scala b/src/library/scala/collection/mutable/UnrolledBuffer.scala
index 2212486bcf..b49d009a17 100644
--- a/src/library/scala/collection/mutable/UnrolledBuffer.scala
+++ b/src/library/scala/collection/mutable/UnrolledBuffer.scala
@@ -43,8 +43,7 @@ import scala.reflect.ClassTag
*
*/
@SerialVersionUID(1L)
-@deprecatedInheritance("UnrolledBuffer is not designed to enable meaningful subclassing.", "2.11.0")
-class UnrolledBuffer[T](implicit val tag: ClassTag[T])
+sealed class UnrolledBuffer[T](implicit val tag: ClassTag[T])
extends scala.collection.mutable.AbstractBuffer[T]
with scala.collection.mutable.Buffer[T]
with scala.collection.mutable.BufferLike[T, UnrolledBuffer[T]]
@@ -350,3 +349,11 @@ object UnrolledBuffer extends ClassTagTraversableFactory[UnrolledBuffer] {
}
}
+
+
+// This is used by scala.collection.parallel.mutable.UnrolledParArrayCombiner:
+// Todo -- revisit whether inheritance is the best way to achieve this functionality
+private[collection] class DoublingUnrolledBuffer[T](implicit t: ClassTag[T]) extends UnrolledBuffer[T]()(t) {
+ override def calcNextLength(sz: Int) = if (sz < 10000) sz * 2 else sz
+ protected override def newUnrolled = new UnrolledBuffer.Unrolled[T](0, new Array[T](4), null, this)
+}
diff --git a/src/library/scala/collection/mutable/WrappedArray.scala b/src/library/scala/collection/mutable/WrappedArray.scala
index 8740bda835..01dcd9bde5 100644
--- a/src/library/scala/collection/mutable/WrappedArray.scala
+++ b/src/library/scala/collection/mutable/WrappedArray.scala
@@ -13,7 +13,6 @@ package collection
package mutable
import scala.reflect.ClassTag
-import scala.runtime.ScalaRunTime._
import scala.collection.generic._
import scala.collection.parallel.mutable.ParArray
@@ -46,7 +45,7 @@ extends AbstractSeq[T]
def elemTag: ClassTag[T]
@deprecated("use elemTag instead", "2.10.0")
- def elemManifest: ClassManifest[T] = ClassManifest.fromClass[T](arrayElementClass(elemTag).asInstanceOf[Class[T]])
+ def elemManifest: ClassManifest[T] = ClassManifest.fromClass[T](elemTag.runtimeClass.asInstanceOf[Class[T]])
/** The length of the array */
def length: Int
@@ -63,10 +62,10 @@ extends AbstractSeq[T]
override def par = ParArray.handoff(array)
private def elementClass: Class[_] =
- arrayElementClass(array.getClass)
+ array.getClass.getComponentType
override def toArray[U >: T : ClassTag]: Array[U] = {
- val thatElementClass = arrayElementClass(implicitly[ClassTag[U]])
+ val thatElementClass = implicitly[ClassTag[U]].runtimeClass
if (elementClass eq thatElementClass)
array.asInstanceOf[Array[U]]
else
@@ -122,7 +121,7 @@ object WrappedArray {
def newBuilder[A]: Builder[A, IndexedSeq[A]] = new ArrayBuffer
final class ofRef[T <: AnyRef](val array: Array[T]) extends WrappedArray[T] with Serializable {
- lazy val elemTag = ClassTag[T](arrayElementClass(array.getClass))
+ lazy val elemTag = ClassTag[T](array.getClass.getComponentType)
def length: Int = array.length
def apply(index: Int): T = array(index).asInstanceOf[T]
def update(index: Int, elem: T) { array(index) = elem }
diff --git a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
index bfe95a11ab..5bc5811450 100644
--- a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
+++ b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala
@@ -13,16 +13,17 @@ package collection
package mutable
import scala.reflect.ClassTag
-import scala.runtime.ScalaRunTime._
/** A builder class for arrays.
*
+ * This builder can be reused.
+ *
* @tparam A type of elements that can be added to this builder.
* @param tag class tag for objects of type `A`.
*
* @since 2.8
*/
-class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A]] {
+class WrappedArrayBuilder[A](tag: ClassTag[A]) extends ReusableBuilder[A, WrappedArray[A]] {
@deprecated("use tag instead", "2.10.0")
val manifest: ClassTag[A] = tag
@@ -32,7 +33,7 @@ class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A
private var size: Int = 0
private def mkArray(size: Int): WrappedArray[A] = {
- val runtimeClass = arrayElementClass(tag)
+ val runtimeClass = tag.runtimeClass
val newelems = runtimeClass match {
case java.lang.Byte.TYPE => new WrappedArray.ofByte(new Array[Byte](size)).asInstanceOf[WrappedArray[A]]
case java.lang.Short.TYPE => new WrappedArray.ofShort(new Array[Short](size)).asInstanceOf[WrappedArray[A]]
@@ -73,12 +74,13 @@ class WrappedArrayBuilder[A](tag: ClassTag[A]) extends Builder[A, WrappedArray[A
this
}
- def clear() {
- size = 0
- }
+ def clear() { size = 0 }
def result() = {
- if (capacity != 0 && capacity == size) elems
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ elems
+ }
else mkArray(size)
}