diff options
Diffstat (limited to 'src/library/scala/collection')
169 files changed, 4326 insertions, 2882 deletions
diff --git a/src/library/scala/collection/BitSetLike.scala b/src/library/scala/collection/BitSetLike.scala index 29369447d1..f0a70170c2 100644 --- a/src/library/scala/collection/BitSetLike.scala +++ b/src/library/scala/collection/BitSetLike.scala @@ -77,26 +77,26 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe def rangeImpl(from: Option[Int], until: Option[Int]): This = { val a = toBitMask val len = a.length - if(from.isDefined) { + if (from.isDefined) { var f = from.get var pos = 0 - while(f >= 64 && pos < len) { + while (f >= 64 && pos < len) { f -= 64 a(pos) = 0 pos += 1 } - if(f > 0 && pos < len) a(pos) &= ~((1L << f)-1) + if (f > 0 && pos < len) a(pos) &= ~((1L << f)-1) } - if(until.isDefined) { + if (until.isDefined) { val u = until.get val w = u / 64 val b = u % 64 var clearw = w+1 - while(clearw < len) { + while (clearw < len) { a(clearw) = 0 clearw += 1 } - if(w < len) a(w) &= (1L << b)-1 + if (w < len) a(w) &= (1L << b)-1 } fromBitMaskNoCopy(a) } @@ -204,12 +204,33 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe def subsetOf(other: BitSet): Boolean = (0 until nwords) forall (idx => (this.word(idx) & ~ other.word(idx)) == 0L) + override def head: Int = { + val n = nwords + var i = 0 + while (i < n) { + val wi = word(i) + if (wi != 0L) return WordLength*i + java.lang.Long.numberOfTrailingZeros(wi) + i += 1 + } + throw new NoSuchElementException("Empty BitSet") + } + + override def last: Int = { + var i = nwords - 1 + while (i >= 0) { + val wi = word(i) + if (wi != 0L) return WordLength*i + 63 - java.lang.Long.numberOfLeadingZeros(wi) + i -= 1 + } + throw new NoSuchElementException("Empty BitSet") + } + override def addString(sb: StringBuilder, start: String, sep: String, end: String) = { sb append start var pre = "" val max = nwords * WordLength var i = 0 - while(i != max) { + while (i != max) { if (contains(i)) { sb append pre append i pre = sep diff --git a/src/library/scala/collection/BufferedIterator.scala b/src/library/scala/collection/BufferedIterator.scala index e6e97d584c..1424ef2fd0 100644 --- a/src/library/scala/collection/BufferedIterator.scala +++ b/src/library/scala/collection/BufferedIterator.scala @@ -24,5 +24,11 @@ trait BufferedIterator[+A] extends Iterator[A] { */ def head: A + /** Returns an option of the next element of an iterator without advancing beyond it. + * @return the next element of this iterator if it has a next element + * `None` if it does not + */ + def headOption : Option[A] = if (hasNext) Some(head) else None + override def buffered: this.type = this } diff --git a/src/library/scala/collection/GenMap.scala b/src/library/scala/collection/GenMap.scala index d17a2de179..6bc507ae93 100644 --- a/src/library/scala/collection/GenMap.scala +++ b/src/library/scala/collection/GenMap.scala @@ -18,18 +18,18 @@ import generic._ * @author Aleksandar Prokopec * @since 2.9 */ -trait GenMap[A, +B] -extends GenMapLike[A, B, GenMap[A, B]] - with GenIterable[(A, B)] +trait GenMap[K, +V] +extends GenMapLike[K, V, GenMap[K, V]] + with GenIterable[(K, V)] { - def seq: Map[A, B] + def seq: Map[K, V] - def updated [B1 >: B](key: A, value: B1): GenMap[A, B1] + def updated [V1 >: V](key: K, value: V1): GenMap[K, V1] } object GenMap extends GenMapFactory[GenMap] { - def empty[A, B]: immutable.Map[A, B] = immutable.Map.empty + def empty[K, V]: immutable.Map[K, V] = immutable.Map.empty /** $mapCanBuildFromInfo */ - implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), GenMap[A, B]] = new MapCanBuildFrom[A, B] + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), GenMap[K, V]] = new MapCanBuildFrom[K, V] } diff --git a/src/library/scala/collection/GenMapLike.scala b/src/library/scala/collection/GenMapLike.scala index 2b39fa2289..f6c2d071b5 100644 --- a/src/library/scala/collection/GenMapLike.scala +++ b/src/library/scala/collection/GenMapLike.scala @@ -22,13 +22,13 @@ package collection * A map is a collection of bindings from keys to values, where there are * no duplicate keys. */ -trait GenMapLike[A, +B, +Repr] extends GenIterableLike[(A, B), Repr] with Equals with Parallelizable[(A, B), parallel.ParMap[A, B]] { - def default(key: A): B - def get(key: A): Option[B] - def apply(key: A): B - def seq: Map[A, B] - def +[B1 >: B](kv: (A, B1)): GenMap[A, B1] - def - (key: A): Repr +trait GenMapLike[K, +V, +Repr] extends GenIterableLike[(K, V), Repr] with Equals with Parallelizable[(K, V), parallel.ParMap[K, V]] { + def default(key: K): V + def get(key: K): Option[V] + def apply(key: K): V + def seq: Map[K, V] + def +[V1 >: V](kv: (K, V1)): GenMap[K, V1] + def - (key: K): Repr // This hash code must be symmetric in the contents but ought not // collide trivially. @@ -41,17 +41,17 @@ trait GenMapLike[A, +B, +Repr] extends GenIterableLike[(A, B), Repr] with Equals * @tparam B1 the result type of the default computation. * @return the value associated with `key` if it exists, * otherwise the result of the `default` computation. - * @usecase def getOrElse(key: A, default: => B): B + * @usecase def getOrElse(key: K, default: => V): V * @inheritdoc */ - def getOrElse[B1 >: B](key: A, default: => B1): B1 + def getOrElse[V1 >: V](key: K, default: => V1): V1 /** Tests whether this map contains a binding for a key. * * @param key the key * @return `true` if there is a binding for `key` in this map, `false` otherwise. */ - def contains(key: A): Boolean + def contains(key: K): Boolean /** Tests whether this map contains a binding for a key. This method, * which implements an abstract method of trait `PartialFunction`, @@ -60,47 +60,47 @@ trait GenMapLike[A, +B, +Repr] extends GenIterableLike[(A, B), Repr] with Equals * @param key the key * @return `true` if there is a binding for `key` in this map, `false` otherwise. */ - def isDefinedAt(key: A): Boolean + def isDefinedAt(key: K): Boolean - def keySet: GenSet[A] + def keySet: GenSet[K] /** Collects all keys of this map in an iterable collection. * * @return the keys of this map as an iterable. */ - def keys: GenIterable[A] + def keys: GenIterable[K] /** Collects all values of this map in an iterable collection. * * @return the values of this map as an iterable. */ - def values: GenIterable[B] + def values: GenIterable[V] /** Creates an iterator for all keys. * * @return an iterator over all keys. */ - def keysIterator: Iterator[A] + def keysIterator: Iterator[K] /** Creates an iterator for all values in this map. * * @return an iterator over all values that are associated with some key in this map. */ - def valuesIterator: Iterator[B] + def valuesIterator: Iterator[V] /** Filters this map by retaining only keys satisfying a predicate. * @param p the predicate used to test keys * @return an immutable map consisting only of those key value pairs of this map where the key satisfies * the predicate `p`. The resulting map wraps the original map without copying any elements. */ - def filterKeys(p: A => Boolean): GenMap[A, B] + def filterKeys(p: K => Boolean): GenMap[K, V] /** Transforms this map by applying a function to every retrieved value. * @param f the function used to transform values of this map. * @return a map view which maps every key of this map * to `f(this(key))`. The resulting map wraps the original map without copying any elements. */ - def mapValues[C](f: B => C): GenMap[A, C] + def mapValues[W](f: V => W): GenMap[K, W] /** Compares two maps structurally; i.e., checks if all mappings * contained in this map are also contained in the other map, diff --git a/src/library/scala/collection/GenSeqLike.scala b/src/library/scala/collection/GenSeqLike.scala index be1da1660a..405d8d7e57 100644 --- a/src/library/scala/collection/GenSeqLike.scala +++ b/src/library/scala/collection/GenSeqLike.scala @@ -58,6 +58,7 @@ trait GenSeqLike[+A, +Repr] extends Any with GenIterableLike[A, Repr] with Equal * Note: `xs.length` and `xs.size` yield the same result. * * @return the number of elements in this $coll. + * @throws IllegalArgumentException if the length of the sequence cannot be represented in an `Int`, for example, `(-1 to Int.MaxValue).length`. */ def length: Int diff --git a/src/library/scala/collection/GenTraversableLike.scala b/src/library/scala/collection/GenTraversableLike.scala index d730996be2..0ee5542e30 100644 --- a/src/library/scala/collection/GenTraversableLike.scala +++ b/src/library/scala/collection/GenTraversableLike.scala @@ -24,7 +24,7 @@ import scala.annotation.migration * is found. * @define bfinfo an implicit value of class `CanBuildFrom` which determines * the result class `That` from the current representation type `Repr` and - * and the new element type `B`. + * the new element type `B`. * @define orderDependent * * Note: might return different results for different runs, unless the @@ -249,30 +249,6 @@ trait GenTraversableLike[+A, +Repr] extends Any with GenTraversableOnce[A] with * @param bf $bfinfo * @return a new collection of type `That` which contains all elements * of this $coll followed by all elements of `that`. - * - * @usecase def ++[B](that: GenTraversableOnce[B]): $Coll[B] - * @inheritdoc - * - * Example: - * {{{ - * scala> val a = List(1) - * a: List[Int] = List(1) - * - * scala> val b = List(2) - * b: List[Int] = List(2) - * - * scala> val c = a ++ b - * c: List[Int] = List(1, 2) - * - * scala> val d = List('a') - * d: List[Char] = List(a) - * - * scala> val e = c ++ d - * e: List[AnyVal] = List(1, 2, a) - * }}} - * - * @return a new $coll which contains all elements of this $coll - * followed by all elements of `that`. */ def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 4af2ca23be..f87f7654bc 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -96,6 +96,12 @@ trait GenTraversableOnce[+A] extends Any { */ def size: Int + /** The size of this $coll, if it can be cheaply computed + * + * @return the number of elements in this $coll, or -1 if the size cannot be determined cheaply + */ + protected[collection] def sizeHintIfCheap: Int = -1 + /** Tests whether the $coll is empty. * * Note: Implementations in subclasses that are not repeatedly traversable must take diff --git a/src/library/scala/collection/IndexedSeqLike.scala b/src/library/scala/collection/IndexedSeqLike.scala index 18c9175ee1..f0cede224d 100644 --- a/src/library/scala/collection/IndexedSeqLike.scala +++ b/src/library/scala/collection/IndexedSeqLike.scala @@ -9,9 +9,6 @@ package scala package collection -import mutable.ArrayBuffer -import scala.annotation.tailrec - /** A template trait for indexed sequences of type `IndexedSeq[A]`. * * $indexedSeqInfo @@ -95,4 +92,6 @@ trait IndexedSeqLike[+A, +Repr] extends Any with SeqLike[A, Repr] { copyToBuffer(result) result } + + override protected[collection] def sizeHintIfCheap: Int = size } diff --git a/src/library/scala/collection/IndexedSeqOptimized.scala b/src/library/scala/collection/IndexedSeqOptimized.scala index a7e06b4d1a..320725c30e 100644 --- a/src/library/scala/collection/IndexedSeqOptimized.scala +++ b/src/library/scala/collection/IndexedSeqOptimized.scala @@ -10,7 +10,6 @@ package scala package collection import generic._ -import mutable.ArrayBuffer import scala.annotation.tailrec /** A template trait for indexed sequences of type `IndexedSeq[A]` which optimizes @@ -200,7 +199,7 @@ trait IndexedSeqOptimized[+A, +Repr] extends Any with IndexedSeqLike[A, Repr] { override /*SeqLike*/ def indexWhere(p: A => Boolean, from: Int): Int = { - val start = from max 0 + val start = math.max(from, 0) negLength(start + segmentLength(!p(_), start)) } diff --git a/src/library/scala/collection/IterableLike.scala b/src/library/scala/collection/IterableLike.scala index ecf64624e8..419206c226 100644 --- a/src/library/scala/collection/IterableLike.scala +++ b/src/library/scala/collection/IterableLike.scala @@ -10,8 +10,7 @@ package scala package collection import generic._ -import immutable.{ List, Stream } -import scala.annotation.unchecked.uncheckedVariance +import immutable.Stream /** A template trait for iterable collections of type `Iterable[A]`. * $iterableInfo @@ -83,8 +82,8 @@ self => iterator.foldRight(z)(op) override /*TraversableLike*/ def reduceRight[B >: A](op: (A, B) => B): B = iterator.reduceRight(op) - - + + /** Returns this $coll as an iterable collection. * * A new collection will not be built; lazy collections will stay lazy. @@ -94,7 +93,7 @@ self => */ override /*TraversableLike*/ def toIterable: Iterable[A] = thisCollection - + /** Returns an Iterator over the elements in this $coll. Produces the same * result as `iterator`. * $willNotTerminateInf @@ -102,7 +101,7 @@ self => */ @deprecatedOverriding("toIterator should stay consistent with iterator for all Iterables: override iterator instead.", "2.11.0") override def toIterator: Iterator[A] = iterator - + override /*TraversableLike*/ def head: A = iterator.next() @@ -178,14 +177,14 @@ self => } /** Groups elements in fixed size blocks by passing a "sliding window" - * over them (as opposed to partitioning them, as is done in grouped.) - * "Sliding window" step is 1 by default. + * over them (as opposed to partitioning them, as is done in `grouped`.) + * The "sliding window" step is set to one. * @see [[scala.collection.Iterator]], method `sliding` * * @param size the number of elements per group * @return An iterator producing ${coll}s of size `size`, except the - * last and the only element will be truncated if there are - * fewer elements than size. + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. */ def sliding(size: Int): Iterator[Repr] = sliding(size, 1) @@ -197,8 +196,8 @@ self => * @param step the distance between the first elements of successive * groups * @return An iterator producing ${coll}s of size `size`, except the - * last and the only element will be truncated if there are - * fewer elements than size. + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. */ def sliding(size: Int, step: Int): Iterator[Repr] = for (xs <- iterator.sliding(size, step)) yield { diff --git a/src/library/scala/collection/IterableProxy.scala b/src/library/scala/collection/IterableProxy.scala index 97aa830c5a..5f4d69c411 100644 --- a/src/library/scala/collection/IterableProxy.scala +++ b/src/library/scala/collection/IterableProxy.scala @@ -16,5 +16,5 @@ package collection * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.3") trait IterableProxy[+A] extends Iterable[A] with IterableProxyLike[A, Iterable[A]] diff --git a/src/library/scala/collection/IterableProxyLike.scala b/src/library/scala/collection/IterableProxyLike.scala index 90e630ee28..f87089cba8 100644 --- a/src/library/scala/collection/IterableProxyLike.scala +++ b/src/library/scala/collection/IterableProxyLike.scala @@ -12,7 +12,6 @@ package scala package collection import generic._ -import mutable.Buffer // Methods could be printed by cat IterableLike.scala | egrep '^ (override )?def' @@ -23,7 +22,7 @@ import mutable.Buffer * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait IterableProxyLike[+A, +Repr <: IterableLike[A, Repr] with Iterable[A]] extends IterableLike[A, Repr] with TraversableProxyLike[A, Repr] { diff --git a/src/library/scala/collection/IterableViewLike.scala b/src/library/scala/collection/IterableViewLike.scala index b84d90c51b..c254ed7480 100644 --- a/src/library/scala/collection/IterableViewLike.scala +++ b/src/library/scala/collection/IterableViewLike.scala @@ -69,6 +69,10 @@ trait IterableViewLike[+A, trait Appended[B >: A] extends super.Appended[B] with Transformed[B] { def iterator = self.iterator ++ rest } + + trait Prepended[B >: A] extends super.Prepended[B] with Transformed[B] { + def iterator = fst.toIterator ++ self + } trait Filtered extends super.Filtered with Transformed[A] { def iterator = self.iterator filter pred @@ -110,6 +114,7 @@ trait IterableViewLike[+A, } with AbstractTransformed[(A1, B)] with ZippedAll[A1, B] protected override def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala index 03b9fbff26..809e851494 100644 --- a/src/library/scala/collection/Iterator.scala +++ b/src/library/scala/collection/Iterator.scala @@ -11,9 +11,8 @@ package collection import mutable.ArrayBuffer import scala.annotation.{tailrec, migration} +import scala.annotation.unchecked.{uncheckedVariance => uV} import immutable.Stream -import scala.collection.generic.CanBuildFrom -import scala.annotation.unchecked.{ uncheckedVariance => uV } /** The `Iterator` object provides various functions for creating specialized iterators. * @@ -162,30 +161,49 @@ object Iterator { def next = elem } - /** Avoid stack overflows when applying ++ to lots of iterators by - * flattening the unevaluated iterators out into a vector of closures. + /** Creates an iterator to which other iterators can be appended efficiently. + * Nested ConcatIterators are merged to avoid blowing the stack. */ - private[scala] final class ConcatIterator[+A](private[this] var current: Iterator[A], initial: Vector[() => Iterator[A]]) extends Iterator[A] { - @deprecated def this(initial: Vector[() => Iterator[A]]) = this(Iterator.empty, initial) // for binary compatibility - private[this] var queue: Vector[() => Iterator[A]] = initial - private[this] var currentHasNextChecked = false + private final class ConcatIterator[+A](private var current: Iterator[A @uV]) extends Iterator[A] { + private var tail: ConcatIteratorCell[A @uV] = null + private var last: ConcatIteratorCell[A @uV] = null + private var currentHasNextChecked = false + // Advance current to the next non-empty iterator // current is set to null when all iterators are exhausted @tailrec private[this] def advance(): Boolean = { - if (queue.isEmpty) { + if (tail eq null) { current = null + last = null false } else { - current = queue.head() - queue = queue.tail - if (current.hasNext) { + current = tail.headIterator + tail = tail.tail + merge() + if (currentHasNextChecked) true + else if (current.hasNext) { currentHasNextChecked = true true } else advance() } } + + // If the current iterator is a ConcatIterator, merge it into this one + @tailrec + private[this] def merge(): Unit = + if (current.isInstanceOf[ConcatIterator[_]]) { + val c = current.asInstanceOf[ConcatIterator[A]] + current = c.current + currentHasNextChecked = c.currentHasNextChecked + if (c.tail ne null) { + c.last.tail = tail + tail = c.tail + } + merge() + } + def hasNext = if (currentHasNextChecked) true else if (current eq null) false @@ -193,48 +211,73 @@ object Iterator { currentHasNextChecked = true true } else advance() + def next() = if (hasNext) { currentHasNextChecked = false current.next() } else Iterator.empty.next() - override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = - if(current eq null) new JoinIterator(Iterator.empty, that) - else new ConcatIterator(current, queue :+ (() => that.toIterator)) + override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = { + val c = new ConcatIteratorCell[B](that, null).asInstanceOf[ConcatIteratorCell[A]] + if(tail eq null) { + tail = c + last = c + } else { + last.tail = c + last = c + } + if(current eq null) current = Iterator.empty + this + } } - private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] { - private[this] var state = 0 // 0: lhs not checked, 1: lhs has next, 2: switched to rhs - private[this] lazy val rhs: Iterator[A] = that.toIterator - def hasNext = state match { - case 0 => - if (lhs.hasNext) { - state = 1 - true - } else { - state = 2 - rhs.hasNext - } - case 1 => true - case _ => rhs.hasNext + private[this] final class ConcatIteratorCell[A](head: => GenTraversableOnce[A], var tail: ConcatIteratorCell[A]) { + def headIterator: Iterator[A] = head.toIterator + } + + /** Creates a delegating iterator capped by a limit count. Negative limit means unbounded. + * Lazily skip to start on first evaluation. Avoids daisy-chained iterators due to slicing. + */ + private[scala] final class SliceIterator[A](val underlying: Iterator[A], start: Int, limit: Int) extends AbstractIterator[A] { + private var remaining = limit + private var dropping = start + @inline private def unbounded = remaining < 0 + private def skip(): Unit = + while (dropping > 0) { + if (underlying.hasNext) { + underlying.next() + dropping -= 1 + } else + dropping = 0 + } + def hasNext = { skip(); remaining != 0 && underlying.hasNext } + def next() = { + skip() + if (remaining > 0) { + remaining -= 1 + underlying.next() + } + else if (unbounded) underlying.next() + else empty.next() } - def next() = state match { - case 0 => - if (lhs.hasNext) lhs.next() - else { - state = 2 - rhs.next() - } - case 1 => - state = 0 - lhs.next() - case _ => - rhs.next() + override protected def sliceIterator(from: Int, until: Int): Iterator[A] = { + val lo = from max 0 + def adjustedBound = + if (unbounded) -1 + else 0 max (remaining - lo) + val rest = + if (until < 0) adjustedBound // respect current bound, if any + else if (until <= lo) 0 // empty + else if (unbounded) until - lo // now finite + else adjustedBound min (until - lo) // keep lesser bound + if (rest == 0) empty + else { + dropping += lo + remaining = rest + this + } } - - override def ++[B >: A](that: => GenTraversableOnce[B]) = - new ConcatIterator(this, Vector(() => that.toIterator)) } } @@ -347,11 +390,11 @@ trait Iterator[+A] extends TraversableOnce[A] { /** Selects first ''n'' values of this iterator. * * @param n the number of values to take - * @return an iterator producing only of the first `n` values of this iterator, or else the + * @return an iterator producing only the first `n` values of this iterator, or else the * whole iterator, if it produces fewer than `n` values. * @note Reuse: $consumesAndProducesIterator */ - def take(n: Int): Iterator[A] = slice(0, n) + def take(n: Int): Iterator[A] = sliceIterator(0, n max 0) /** Advances this iterator past the first ''n'' elements, or the length of the iterator, whichever is smaller. * @@ -372,29 +415,24 @@ trait Iterator[+A] extends TraversableOnce[A] { /** Creates an iterator returning an interval of the values produced by this iterator. * * @param from the index of the first element in this iterator which forms part of the slice. - * @param until the index of the first element following the slice. + * If negative, the slice starts at zero. + * @param until the index of the first element following the slice. If negative, the slice is empty. * @return an iterator which advances this iterator past the first `from` elements using `drop`, * and then takes `until - from` elements, using `take`. * @note Reuse: $consumesAndProducesIterator */ - def slice(from: Int, until: Int): Iterator[A] = { + def slice(from: Int, until: Int): Iterator[A] = sliceIterator(from, until max 0) + + /** Creates an optionally bounded slice, unbounded if `until` is negative. */ + protected def sliceIterator(from: Int, until: Int): Iterator[A] = { val lo = from max 0 - var toDrop = lo - while (toDrop > 0 && self.hasNext) { - self.next() - toDrop -= 1 - } + val rest = + if (until < 0) -1 // unbounded + else if (until <= lo) 0 // empty + else until - lo // finite - new AbstractIterator[A] { - private var remaining = until - lo - def hasNext = remaining > 0 && self.hasNext - def next(): A = - if (remaining > 0) { - remaining -= 1 - self.next() - } - else empty.next() - } + if (rest == 0) empty + else new Iterator.SliceIterator(this, lo, rest) } /** Creates a new iterator that maps all produced values of this iterator @@ -420,7 +458,7 @@ trait Iterator[+A] extends TraversableOnce[A] { * @usecase def ++(that: => Iterator[A]): Iterator[A] * @inheritdoc */ - def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new Iterator.JoinIterator(self, that) + def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new Iterator.ConcatIterator(self) ++ that /** Creates a new iterator by applying a function to all values produced by this iterator * and concatenating the results. @@ -522,13 +560,13 @@ trait Iterator[+A] extends TraversableOnce[A] { def collect[B](pf: PartialFunction[A, B]): Iterator[B] = new AbstractIterator[B] { // Manually buffer to avoid extra layer of wrapping with buffered private[this] var hd: A = _ - + // Little state machine to keep track of where we are // Seek = 0; Found = 1; Empty = -1 // Not in vals because scalac won't make them static (@inline def only works with -optimize) // BE REALLY CAREFUL TO KEEP COMMENTS AND NUMBERS IN SYNC! private[this] var status = 0/*Seek*/ - + def hasNext = { while (status == 0/*Seek*/) { if (self.hasNext) { @@ -698,13 +736,13 @@ trait Iterator[+A] extends TraversableOnce[A] { } def trailer: A = hd } - + val leading = new Leading - + val trailing = new AbstractIterator[A] { private[this] var myLeading = leading - /* Status flags meanings: - * -1 not yet accesssed + /* Status flag meanings: + * -1 not yet accessed * 0 single element waiting in leading * 1 defer to self */ @@ -736,7 +774,7 @@ trait Iterator[+A] extends TraversableOnce[A] { } else Iterator.empty.next() } - + override def toString = "unknown-if-empty iterator" } @@ -770,7 +808,7 @@ trait Iterator[+A] extends TraversableOnce[A] { status = 1 false } - def next() = + def next() = if (hasNext) { if (status == 1) self.next() else { @@ -953,8 +991,25 @@ trait Iterator[+A] extends TraversableOnce[A] { * or -1 if such an element does not exist until the end of the iterator is reached. * @note Reuse: $consumesIterator */ - def indexWhere(p: A => Boolean): Int = { + def indexWhere(p: A => Boolean): Int = indexWhere(p, 0) + + /** Returns the index of the first produced value satisfying a predicate, or -1, after or at + * some start index. + * $mayNotTerminateInf + * + * @param p the predicate to test values + * @param from the start index + * @return the index `>= from` of the first produced value satisfying `p`, + * or -1 if such an element does not exist until the end of the iterator is reached. + * @note Reuse: $consumesIterator + */ + def indexWhere(p: A => Boolean, from: Int): Int = { var i = 0 + while (i < from && hasNext) { + next() + i += 1 + } + while (hasNext) { if (p(next())) return i i += 1 @@ -971,8 +1026,26 @@ trait Iterator[+A] extends TraversableOnce[A] { * or -1 if such an element does not exist until the end of the iterator is reached. * @note Reuse: $consumesIterator */ - def indexOf[B >: A](elem: B): Int = { + def indexOf[B >: A](elem: B): Int = indexOf(elem, 0) + + /** Returns the index of the first occurrence of the specified object in this iterable object + * after or at some start index. + * $mayNotTerminateInf + * + * @param elem element to search for. + * @param from the start index + * @return the index `>= from` of the first occurrence of `elem` in the values produced by this + * iterator, or -1 if such an element does not exist until the end of the iterator is + * reached. + * @note Reuse: $consumesIterator + */ + def indexOf[B >: A](elem: B, from: Int): Int = { var i = 0 + while (i < from && hasNext) { + next() + i += 1 + } + while (hasNext) { if (next() == elem) return i i += 1 @@ -1018,7 +1091,7 @@ trait Iterator[+A] extends TraversableOnce[A] { extends AbstractIterator[Seq[B]] with Iterator[Seq[B]] { - require(size >= 1 && step >= 1, "size=%d and step=%d, but both must be positive".format(size, step)) + require(size >= 1 && step >= 1, f"size=$size%d and step=$step%d, but both must be positive") private[this] var buffer: ArrayBuffer[B] = ArrayBuffer() // the buffer private[this] var filled = false // whether the buffer is "hot" @@ -1026,30 +1099,30 @@ trait Iterator[+A] extends TraversableOnce[A] { private[this] var pad: Option[() => B] = None // what to pad short sequences with /** Public functions which can be used to configure the iterator before use. - * - * Pads the last segment if necessary so that all segments will - * have the same size. - * - * @param x The element that will be appended to the last segment, if necessary. - * @return The same iterator, and ''not'' a new iterator. - * @note This method mutates the iterator it is called on, which can be safely used afterwards. - * @note This method is mutually exclusive with `withPartial(true)`. - */ + * + * Pads the last segment if necessary so that all segments will + * have the same size. + * + * @param x The element that will be appended to the last segment, if necessary. + * @return The same iterator, and ''not'' a new iterator. + * @note This method mutates the iterator it is called on, which can be safely used afterwards. + * @note This method is mutually exclusive with `withPartial(true)`. + */ def withPadding(x: => B): this.type = { pad = Some(() => x) this } - /** Public functions which can be used to configure the iterator before use. - * - * Select whether the last segment may be returned with less than `size` - * elements. If not, some elements of the original iterator may not be - * returned at all. - * - * @param x `true` if partial segments may be returned, `false` otherwise. - * @return The same iterator, and ''not'' a new iterator. - * @note This method mutates the iterator it is called on, which can be safely used afterwards. - * @note This method is mutually exclusive with `withPadding`. - */ + /** Public functions which can be used to configure the iterator before use. + * + * Select whether the last segment may be returned with less than `size` + * elements. If not, some elements of the original iterator may not be + * returned at all. + * + * @param x `true` if partial segments may be returned, `false` otherwise. + * @return The same iterator, and ''not'' a new iterator. + * @note This method mutates the iterator it is called on, which can be safely used afterwards. + * @note This method is mutually exclusive with `withPadding`. + */ def withPartial(x: Boolean): this.type = { _partial = x if (_partial == true) // reset pad since otherwise it will take precedence @@ -1158,9 +1231,15 @@ trait Iterator[+A] extends TraversableOnce[A] { new GroupedIterator[B](self, size, size) /** Returns an iterator which presents a "sliding window" view of - * another iterator. The first argument is the window size, and - * the second is how far to advance the window on each iteration; - * defaults to `1`. Example usages: + * this iterator. The first argument is the window size, and + * the second argument `step` is how far to advance the window + * on each iteration. The `step` defaults to `1`. + * + * The default `GroupedIterator` can be configured to either + * pad a partial result to size `size` or suppress the partial + * result entirely. + * + * Example usages: * {{{ * // Returns List(List(1, 2, 3), List(2, 3, 4), List(3, 4, 5)) * (1 to 5).iterator.sliding(3).toList @@ -1174,6 +1253,11 @@ trait Iterator[+A] extends TraversableOnce[A] { * (1 to 5).iterator.sliding(4, 3).withPadding(it2.next).toList * }}} * + * @return An iterator producing `Seq[B]`s of size `size`, except the + * last element (which may be the only element) will be truncated + * if there are fewer than `size` elements remaining to be grouped. + * This behavior can be configured. + * * @note Reuse: $consumesAndProducesIterator */ def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B] = @@ -1287,7 +1371,6 @@ trait Iterator[+A] extends TraversableOnce[A] { * $willNotTerminateInf */ def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = { - require(start >= 0 && (start < xs.length || xs.length == 0), s"start $start out of range ${xs.length}") var i = start val end = start + math.min(len, xs.length - start) while (i < end && hasNext) { diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 7bfa60771f..93994d80bf 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -11,21 +11,21 @@ package collection import convert._ -/** A collection of implicit conversions supporting interoperability between - * Scala and Java collections. +/** A variety of implicit conversions supporting interoperability between + * Scala and Java collections. * - * The following conversions are supported: + * The following conversions are supported: *{{{ - * scala.collection.Iterable <=> java.lang.Iterable - * scala.collection.Iterable <=> java.util.Collection - * scala.collection.Iterator <=> java.util.{ Iterator, Enumeration } + * scala.collection.Iterable <=> java.lang.Iterable + * scala.collection.Iterable <=> java.util.Collection + * scala.collection.Iterator <=> java.util.{ Iterator, Enumeration } * scala.collection.mutable.Buffer <=> java.util.List - * scala.collection.mutable.Set <=> java.util.Set - * scala.collection.mutable.Map <=> java.util.{ Map, Dictionary } + * scala.collection.mutable.Set <=> java.util.Set + * scala.collection.mutable.Map <=> java.util.{ Map, Dictionary } * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap *}}} - * In all cases, converting from a source type to a target type and back - * again will return the original source object, eg. + * In all cases, converting from a source type to a target type and back + * again will return the original source object: * *{{{ * import scala.collection.JavaConversions._ @@ -45,8 +45,16 @@ import convert._ * java.util.Properties => scala.collection.mutable.Map[String, String] *}}} * + * The transparent conversions provided here are considered + * fragile because they can result in unexpected behavior and performance. + * + * Therefore, this API has been deprecated and `JavaConverters` should be + * used instead. `JavaConverters` provides the same conversions, but through + * extension methods. + * * @author Miles Sabin * @author Martin Odersky * @since 2.8 */ +@deprecated("use JavaConverters", since="2.12.0") object JavaConversions extends WrapAsScala with WrapAsJava diff --git a/src/library/scala/collection/JavaConverters.scala b/src/library/scala/collection/JavaConverters.scala index 86e86d4584..2337f0ef84 100644 --- a/src/library/scala/collection/JavaConverters.scala +++ b/src/library/scala/collection/JavaConverters.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -11,50 +11,62 @@ package collection import convert._ -// TODO: I cleaned all this documentation up in JavaConversions, but the -// documentation in here is basically the pre-cleaned-up version with minor -// additions. Would be nice to have in one place. - -/** A collection of decorators that allow converting between - * Scala and Java collections using `asScala` and `asJava` methods. - * - * The following conversions are supported via `asJava`, `asScala` +/** A variety of decorators that enable converting between + * Scala and Java collections using extension methods, `asScala` and `asJava`. * - * - `scala.collection.Iterable` <=> `java.lang.Iterable` - * - `scala.collection.Iterator` <=> `java.util.Iterator` - * - `scala.collection.mutable.Buffer` <=> `java.util.List` - * - `scala.collection.mutable.Set` <=> `java.util.Set` - * - `scala.collection.mutable.Map` <=> `java.util.Map` - * - `scala.collection.mutable.concurrent.Map` <=> `java.util.concurrent.ConcurrentMap` + * The extension methods return adapters for the corresponding API. * + * The following conversions are supported via `asScala` and `asJava`: + *{{{ + * scala.collection.Iterable <=> java.lang.Iterable + * scala.collection.Iterator <=> java.util.Iterator + * scala.collection.mutable.Buffer <=> java.util.List + * scala.collection.mutable.Set <=> java.util.Set + * scala.collection.mutable.Map <=> java.util.Map + * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap + *}}} + * The following conversions are supported via `asScala` and through + * specially-named extension methods to convert to Java collections, as shown: + *{{{ + * scala.collection.Iterable <=> java.util.Collection (via asJavaCollection) + * scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration) + * scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary) + *}}} + * In addition, the following one-way conversions are provided via `asJava`: + *{{{ + * scala.collection.Seq => java.util.List + * scala.collection.mutable.Seq => java.util.List + * scala.collection.Set => java.util.Set + * scala.collection.Map => java.util.Map + *}}} + * The following one way conversion is provided via `asScala`: + *{{{ + * java.util.Properties => scala.collection.mutable.Map + *}}} * In all cases, converting from a source type to a target type and back - * again will return the original source object, e.g. + * again will return the original source object. For example: * {{{ * import scala.collection.JavaConverters._ * - * val sl = new scala.collection.mutable.ListBuffer[Int] - * val jl : java.util.List[Int] = sl.asJava - * val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala - * assert(sl eq sl2) + * val source = new scala.collection.mutable.ListBuffer[Int] + * val target: java.util.List[Int] = source.asJava + * val other: scala.collection.mutable.Buffer[Int] = target.asScala + * assert(source eq other) * }}} - * The following conversions are also supported, but the - * direction from Scala to Java is done by the more specifically named methods: - * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`. - * - * - `scala.collection.Iterable` <=> `java.util.Collection` - * - `scala.collection.Iterator` <=> `java.util.Enumeration` - * - `scala.collection.mutable.Map` <=> `java.util.Dictionary` - * - * In addition, the following one way conversions are provided via `asJava`: + * Alternatively, the conversion methods have descriptive names and can be invoked explicitly. + * {{{ + * scala> val vs = java.util.Arrays.asList("hi", "bye") + * vs: java.util.List[String] = [hi, bye] * - * - `scala.collection.Seq` => `java.util.List` - * - `scala.collection.mutable.Seq` => `java.util.List` - * - `scala.collection.Set` => `java.util.Set` - * - `scala.collection.Map` => `java.util.Map` + * scala> val ss = asScalaIterator(vs.iterator) + * ss: Iterator[String] = non-empty iterator * - * The following one way conversion is provided via `asScala`: + * scala> .toList + * res0: List[String] = List(hi, bye) * - * - `java.util.Properties` => `scala.collection.mutable.Map` + * scala> val ss = asScalaBuffer(vs) + * ss: scala.collection.mutable.Buffer[String] = Buffer(hi, bye) + * }}} * * @since 2.8.1 */ diff --git a/src/library/scala/collection/LinearSeqOptimized.scala b/src/library/scala/collection/LinearSeqOptimized.scala index b7af8840a9..68b85dcfe5 100644 --- a/src/library/scala/collection/LinearSeqOptimized.scala +++ b/src/library/scala/collection/LinearSeqOptimized.scala @@ -9,8 +9,6 @@ package scala package collection -import mutable.ListBuffer -import immutable.List import scala.annotation.tailrec /** A template trait for linear sequences of type `LinearSeq[A]` which optimizes @@ -133,9 +131,9 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea else op(head, tail.foldRight(z)(op)) override /*TraversableLike*/ - def reduceLeft[B >: A](f: (B, A) => B): B = + def reduceLeft[B >: A](@deprecatedName('f) op: (B, A) => B): B = if (isEmpty) throw new UnsupportedOperationException("empty.reduceLeft") - else tail.foldLeft[B](head)(f) + else tail.foldLeft[B](head)(op) override /*IterableLike*/ def reduceRight[B >: A](op: (A, B) => B): B = @@ -293,7 +291,7 @@ trait LinearSeqOptimized[+A, +Repr <: LinearSeqOptimized[A, Repr]] extends Linea override /*SeqLike*/ def indexWhere(p: A => Boolean, from: Int): Int = { - var i = from + var i = math.max(from, 0) var these = this drop from while (these.nonEmpty) { if (p(these.head)) diff --git a/src/library/scala/collection/Map.scala b/src/library/scala/collection/Map.scala index 1e40fd8c24..c9a943f1f7 100644 --- a/src/library/scala/collection/Map.scala +++ b/src/library/scala/collection/Map.scala @@ -12,7 +12,7 @@ package collection import generic._ /** - * A map from keys of type `A` to values of type `B`. + * A map from keys of type `K` to values of type `V`. * * $mapNote * @@ -22,15 +22,15 @@ import generic._ * '''Note:''' If your additions and mutations return the same kind of map as the map * you are defining, you should inherit from `MapLike` as well. * - * @tparam A the type of the keys in this map. - * @tparam B the type of the values associated with keys. + * @tparam K the type of the keys in this map. + * @tparam V the type of the values associated with keys. * * @since 1.0 */ -trait Map[A, +B] extends Iterable[(A, B)] with GenMap[A, B] with MapLike[A, B, Map[A, B]] { - def empty: Map[A, B] = Map.empty +trait Map[K, +V] extends Iterable[(K, V)] with GenMap[K, V] with MapLike[K, V, Map[K, V]] { + def empty: Map[K, V] = Map.empty - override def seq: Map[A, B] = this + override def seq: Map[K, V] = this } /** $factoryInfo @@ -38,22 +38,22 @@ trait Map[A, +B] extends Iterable[(A, B)] with GenMap[A, B] with MapLike[A, B, M * @define coll map */ object Map extends MapFactory[Map] { - def empty[A, B]: immutable.Map[A, B] = immutable.Map.empty + def empty[K, V]: immutable.Map[K, V] = immutable.Map.empty /** $mapCanBuildFromInfo */ - implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B] + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Map[K, V]] = new MapCanBuildFrom[K, V] /** An abstract shell used by { mutable, immutable }.Map but not by collection.Map * because of variance issues. */ - abstract class WithDefault[A, +B](underlying: Map[A, B], d: A => B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + abstract class WithDefault[K, +V](underlying: Map[K, V], d: K => V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = underlying.size - def get(key: A) = underlying.get(key) // removed in 2.9: orElse Some(default(key)) + def get(key: K) = underlying.get(key) // removed in 2.9: orElse Some(default(key)) def iterator = underlying.iterator - override def default(key: A): B = d(key) + override def default(key: K): V = d(key) } } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -abstract class AbstractMap[A, +B] extends AbstractIterable[(A, B)] with Map[A, B] +abstract class AbstractMap[K, +V] extends AbstractIterable[(K, V)] with Map[K, V] diff --git a/src/library/scala/collection/MapLike.scala b/src/library/scala/collection/MapLike.scala index 99ed67325c..a087cb0f45 100644 --- a/src/library/scala/collection/MapLike.scala +++ b/src/library/scala/collection/MapLike.scala @@ -11,7 +11,7 @@ package collection import generic._ import mutable.{ Builder, MapBuilder } -import scala.annotation.{migration, bridge} +import scala.annotation.migration import parallel.ParMap /** A template trait for maps, which associate keys with values. @@ -28,10 +28,10 @@ import parallel.ParMap * To implement a concrete map, you need to provide implementations of the * following methods: * {{{ - * def get(key: A): Option[B] - * def iterator: Iterator[(A, B)] - * def + [B1 >: B](kv: (A, B1)): This - * def -(key: A): This + * def get(key: K): Option[V] + * def iterator: Iterator[(K, V)] + * def + [V1 >: V](kv: (K, V1)): This + * def -(key: K): This * }}} * If you wish that methods like `take`, `drop`, `filter` also return the same kind of map * you should also override: @@ -42,8 +42,8 @@ import parallel.ParMap * `size` for efficiency. * * @define mapTags - * @tparam A the type of the keys. - * @tparam B the type of associated values. + * @tparam K the type of the keys. + * @tparam V the type of associated values. * @tparam This the type of the map itself. * * @author Martin Odersky @@ -54,12 +54,12 @@ import parallel.ParMap * @define willNotTerminateInf * @define mayNotTerminateInf */ -trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] - extends PartialFunction[A, B] - with IterableLike[(A, B), This] - with GenMapLike[A, B, This] - with Subtractable[A, This] - with Parallelizable[(A, B), ParMap[A, B]] +trait MapLike[K, +V, +This <: MapLike[K, V, This] with Map[K, V]] + extends PartialFunction[K, V] + with IterableLike[(K, V), This] + with GenMapLike[K, V, This] + with Subtractable[K, This] + with Parallelizable[(K, V), ParMap[K, V]] { self => @@ -71,7 +71,7 @@ self => /** A common implementation of `newBuilder` for all maps in terms of `empty`. * Overridden for mutable maps in `mutable.MapLike`. */ - override protected[this] def newBuilder: Builder[(A, B), This] = new MapBuilder[A, B, This](empty) + override protected[this] def newBuilder: Builder[(K, V), This] = new MapBuilder[K, V, This](empty) /** Optionally returns the value associated with a key. * @@ -79,32 +79,32 @@ self => * @return an option value containing the value associated with `key` in this map, * or `None` if none exists. */ - def get(key: A): Option[B] + def get(key: K): Option[V] /** Creates a new iterator over all key/value pairs of this map * * @return the new iterator */ - def iterator: Iterator[(A, B)] + def iterator: Iterator[(K, V)] /** Adds a key/value pair to this map, returning a new map. * @param kv the key/value pair - * @tparam B1 the type of the value in the key/value pair. + * @tparam V1 the type of the value in the key/value pair. * @return a new map with the new binding added to this map * - * @usecase def + (kv: (A, B)): Map[A, B] + * @usecase def + (kv: (K, V)): Map[K, V] * @inheritdoc */ - def + [B1 >: B] (kv: (A, B1)): Map[A, B1] + def + [V1 >: V] (kv: (K, V1)): Map[K, V1] /** Removes a key from this map, returning a new map. * @param key the key to be removed * @return a new map without a binding for `key` * - * @usecase def - (key: A): Map[A, B] + * @usecase def - (key: K): Map[K, V] * @inheritdoc */ - def - (key: A): This + def - (key: K): This /** Tests whether the map is empty. * @@ -116,14 +116,14 @@ self => * @param key the key. * @param default a computation that yields a default value in case no binding for `key` is * found in the map. - * @tparam B1 the result type of the default computation. + * @tparam V1 the result type of the default computation. * @return the value associated with `key` if it exists, * otherwise the result of the `default` computation. * - * @usecase def getOrElse(key: A, default: => B): B + * @usecase def getOrElse(key: K, default: => V): V * @inheritdoc */ - def getOrElse[B1 >: B](key: A, default: => B1): B1 = get(key) match { + def getOrElse[V1 >: V](key: K, default: => V1): V1 = get(key) match { case Some(v) => v case None => default } @@ -137,7 +137,7 @@ self => * @return the value associated with the given key, or the result of the * map's `default` method, if none exists. */ - def apply(key: A): B = get(key) match { + def apply(key: K): V = get(key) match { case None => default(key) case Some(value) => value } @@ -147,7 +147,7 @@ self => * @param key the key * @return `true` if there is a binding for `key` in this map, `false` otherwise. */ - def contains(key: A): Boolean = get(key).isDefined + def contains(key: K): Boolean = get(key).isDefined /** Tests whether this map contains a binding for a key. This method, * which implements an abstract method of trait `PartialFunction`, @@ -156,29 +156,33 @@ self => * @param key the key * @return `true` if there is a binding for `key` in this map, `false` otherwise. */ - def isDefinedAt(key: A) = contains(key) + def isDefinedAt(key: K) = contains(key) + + override /*PartialFunction*/ + def applyOrElse[K1 <: K, V1 >: V](x: K1, default: K1 => V1): V1 = + getOrElse(x, default(x)) /** Collects all keys of this map in a set. * @return a set containing all keys of this map. */ - def keySet: Set[A] = new DefaultKeySet + def keySet: Set[K] = new DefaultKeySet /** The implementation class of the set returned by `keySet`. */ - protected class DefaultKeySet extends AbstractSet[A] with Set[A] with Serializable { - def contains(key : A) = self.contains(key) + protected class DefaultKeySet extends AbstractSet[K] with Set[K] with Serializable { + def contains(key : K) = self.contains(key) def iterator = keysIterator - def + (elem: A): Set[A] = (Set[A]() ++ this + elem).asInstanceOf[Set[A]] // !!! concrete overrides abstract problem - def - (elem: A): Set[A] = (Set[A]() ++ this - elem).asInstanceOf[Set[A]] // !!! concrete overrides abstract problem + def + (elem: K): Set[K] = (Set[K]() ++ this + elem).asInstanceOf[Set[K]] // !!! concrete overrides abstract problem + def - (elem: K): Set[K] = (Set[K]() ++ this - elem).asInstanceOf[Set[K]] // !!! concrete overrides abstract problem override def size = self.size - override def foreach[U](f: A => U) = self.keysIterator foreach f + override def foreach[U](f: K => U) = self.keysIterator foreach f } /** Creates an iterator for all keys. * * @return an iterator over all keys. */ - def keysIterator: Iterator[A] = new AbstractIterator[A] { + def keysIterator: Iterator[K] = new AbstractIterator[K] { val iter = self.iterator def hasNext = iter.hasNext def next() = iter.next()._1 @@ -188,29 +192,29 @@ self => * * @return the keys of this map as an iterable. */ - @migration("`keys` returns `Iterable[A]` rather than `Iterator[A]`.", "2.8.0") - def keys: Iterable[A] = keySet + @migration("`keys` returns `Iterable[K]` rather than `Iterator[K]`.", "2.8.0") + def keys: Iterable[K] = keySet /** Collects all values of this map in an iterable collection. * * @return the values of this map as an iterable. */ - @migration("`values` returns `Iterable[B]` rather than `Iterator[B]`.", "2.8.0") - def values: Iterable[B] = new DefaultValuesIterable + @migration("`values` returns `Iterable[V]` rather than `Iterator[V]`.", "2.8.0") + def values: Iterable[V] = new DefaultValuesIterable /** The implementation class of the iterable returned by `values`. */ - protected class DefaultValuesIterable extends AbstractIterable[B] with Iterable[B] with Serializable { + protected class DefaultValuesIterable extends AbstractIterable[V] with Iterable[V] with Serializable { def iterator = valuesIterator override def size = self.size - override def foreach[U](f: B => U) = self.valuesIterator foreach f + override def foreach[U](f: V => U) = self.valuesIterator foreach f } /** Creates an iterator for all values in this map. * * @return an iterator over all values that are associated with some key in this map. */ - def valuesIterator: Iterator[B] = new AbstractIterator[B] { + def valuesIterator: Iterator[V] = new AbstractIterator[V] { val iter = self.iterator def hasNext = iter.hasNext def next() = iter.next()._2 @@ -224,29 +228,33 @@ self => * @param key the given key value for which a binding is missing. * @throws NoSuchElementException */ - def default(key: A): B = + def default(key: K): V = throw new NoSuchElementException("key not found: " + key) - protected class FilteredKeys(p: A => Boolean) extends AbstractMap[A, B] with DefaultMap[A, B] { - override def foreach[U](f: ((A, B)) => U): Unit = for (kv <- self) if (p(kv._1)) f(kv) + protected class FilteredKeys(p: K => Boolean) extends AbstractMap[K, V] with DefaultMap[K, V] { + override def foreach[U](f: ((K, V)) => U): Unit = for (kv <- self) if (p(kv._1)) f(kv) def iterator = self.iterator.filter(kv => p(kv._1)) - override def contains(key: A) = self.contains(key) && p(key) - def get(key: A) = if (!p(key)) None else self.get(key) + override def contains(key: K) = p(key) && self.contains(key) + def get(key: K) = if (!p(key)) None else self.get(key) } /** Filters this map by retaining only keys satisfying a predicate. + * + * '''Note''': the predicate must accept any key of type `K`, not just those already + * present in the map, as the predicate is tested before the underlying map is queried. + * * @param p the predicate used to test keys * @return an immutable map consisting only of those key value pairs of this map where the key satisfies * the predicate `p`. The resulting map wraps the original map without copying any elements. */ - def filterKeys(p: A => Boolean): Map[A, B] = new FilteredKeys(p) + def filterKeys(p: K => Boolean): Map[K, V] = new FilteredKeys(p) - protected class MappedValues[C](f: B => C) extends AbstractMap[A, C] with DefaultMap[A, C] { - override def foreach[U](g: ((A, C)) => U): Unit = for ((k, v) <- self) g((k, f(v))) + protected class MappedValues[W](f: V => W) extends AbstractMap[K, W] with DefaultMap[K, W] { + override def foreach[U](g: ((K, W)) => U): Unit = for ((k, v) <- self) g((k, f(v))) def iterator = for ((k, v) <- self.iterator) yield (k, f(v)) override def size = self.size - override def contains(key: A) = self.contains(key) - def get(key: A) = self.get(key).map(f) + override def contains(key: K) = self.contains(key) + def get(key: K) = self.get(key).map(f) } /** Transforms this map by applying a function to every retrieved value. @@ -254,22 +262,22 @@ self => * @return a map view which maps every key of this map * to `f(this(key))`. The resulting map wraps the original map without copying any elements. */ - def mapValues[C](f: B => C): Map[A, C] = new MappedValues(f) + def mapValues[W](f: V => W): Map[K, W] = new MappedValues(f) // The following 5 operations (updated, two times +, two times ++) should really be - // generic, returning This[B]. We need better covariance support to express that though. + // generic, returning This[V]. We need better covariance support to express that though. // So right now we do the brute force approach of code duplication. /** Creates a new map obtained by updating this map with a given key/value pair. * @param key the key * @param value the value - * @tparam B1 the type of the added value + * @tparam V1 the type of the added value * @return A new map with the new key/value mapping added to this map. * - * @usecase def updated(key: A, value: B): Map[A, B] + * @usecase def updated(key: K, value: V): Map[K, V] * @inheritdoc */ - def updated [B1 >: B](key: A, value: B1): Map[A, B1] = this + ((key, value)) + def updated [V1 >: V](key: K, value: V1): Map[K, V1] = this + ((key, value)) /** Adds key/value pairs to this map, returning a new map. * @@ -279,27 +287,27 @@ self => * @param kv1 the first key/value pair * @param kv2 the second key/value pair * @param kvs the remaining key/value pairs - * @tparam B1 the type of the added values + * @tparam V1 the type of the added values * @return a new map with the given bindings added to this map * - * @usecase def + (kvs: (A, B)*): Map[A, B] + * @usecase def + (kvs: (K, V)*): Map[K, V] * @inheritdoc * @param kvs the key/value pairs */ - def + [B1 >: B] (kv1: (A, B1), kv2: (A, B1), kvs: (A, B1) *): Map[A, B1] = + def + [V1 >: V] (kv1: (K, V1), kv2: (K, V1), kvs: (K, V1) *): Map[K, V1] = this + kv1 + kv2 ++ kvs /** Adds all key/value pairs in a traversable collection to this map, returning a new map. * * @param xs the collection containing the added key/value pairs - * @tparam B1 the type of the added values + * @tparam V1 the type of the added values * @return a new map with the given bindings added to this map * - * @usecase def ++ (xs: Traversable[(A, B)]): Map[A, B] + * @usecase def ++ (xs: Traversable[(K, V)]): Map[K, V] * @inheritdoc */ - def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): Map[A, B1] = - ((repr: Map[A, B1]) /: xs.seq) (_ + _) + def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): Map[K, V1] = + ((repr: Map[K, V1]) /: xs.seq) (_ + _) /** Returns a new map obtained by removing all key/value pairs for which the predicate * `p` returns `true`. @@ -312,22 +320,31 @@ self => * @param p A predicate over key-value pairs * @return A new map containing elements not satisfying the predicate. */ - override def filterNot(p: ((A, B)) => Boolean): This = { + override def filterNot(p: ((K, V)) => Boolean): This = { var res: This = repr for (kv <- this) if (p(kv)) res = (res - kv._1).asInstanceOf[This] // !!! concrete overrides abstract problem res } - /* Overridden for efficiency. */ - override def toSeq: Seq[(A, B)] = toBuffer[(A, B)] - override def toBuffer[C >: (A, B)]: mutable.Buffer[C] = { - val result = new mutable.ArrayBuffer[C](size) - copyToBuffer(result) + override def toSeq: Seq[(K, V)] = { + if (isEmpty) Vector.empty[(K, V)] + else { + // Default appropriate for immutable collections; mutable collections override this + val vb = Vector.newBuilder[(K, V)] + foreach(vb += _) + vb.result + } + } + + override def toBuffer[E >: (K, V)]: mutable.Buffer[E] = { + val result = new mutable.ArrayBuffer[E](size) + // Faster to let the map iterate itself than to defer through copyToBuffer + foreach(result += _) result } - protected[this] override def parCombiner = ParMap.newCombiner[A, B] + protected[this] override def parCombiner = ParMap.newCombiner[K, V] /** Appends all bindings of this map to a string builder using start, end, and separator strings. * The written text begins with the string `start` and ends with the string diff --git a/src/library/scala/collection/MapProxy.scala b/src/library/scala/collection/MapProxy.scala index 26a7c710ee..2faf689973 100644 --- a/src/library/scala/collection/MapProxy.scala +++ b/src/library/scala/collection/MapProxy.scala @@ -17,5 +17,5 @@ package collection * @version 1.0, 21/07/2003 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.3") trait MapProxy[A, +B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]] diff --git a/src/library/scala/collection/MapProxyLike.scala b/src/library/scala/collection/MapProxyLike.scala index dd80a538e3..73a6935788 100644 --- a/src/library/scala/collection/MapProxyLike.scala +++ b/src/library/scala/collection/MapProxyLike.scala @@ -18,7 +18,7 @@ package collection * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait MapProxyLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] extends MapLike[A, B, This] with IterableProxyLike[(A, B), This] diff --git a/src/library/scala/collection/Parallelizable.scala b/src/library/scala/collection/Parallelizable.scala index b737752458..c131556388 100644 --- a/src/library/scala/collection/Parallelizable.scala +++ b/src/library/scala/collection/Parallelizable.scala @@ -12,7 +12,7 @@ package collection import parallel.Combiner /** This trait describes collections which can be turned into parallel collections - * by invoking the method `par`. Parallelizable collections may be parametrized with + * by invoking the method `par`. Parallelizable collections may be parameterized with * a target type different than their own. * * @tparam A the type of the elements in the collection diff --git a/src/library/scala/collection/SeqLike.scala b/src/library/scala/collection/SeqLike.scala index b775480532..3e025bc43f 100644 --- a/src/library/scala/collection/SeqLike.scala +++ b/src/library/scala/collection/SeqLike.scala @@ -9,11 +9,10 @@ package scala package collection -import mutable.{ ListBuffer, ArraySeq } import immutable.{ List, Range } import generic._ import parallel.ParSeq -import scala.math.{ min, max, Ordering } +import scala.math.Ordering /** A template trait for sequences of type `Seq[A]` * $seqInfo @@ -114,13 +113,12 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ } def indexWhere(p: A => Boolean, from: Int): Int = { - var i = from + var i = math.max(from, 0) val it = iterator.drop(from) while (it.hasNext) { if (p(it.next())) return i else i += 1 } - -1 } @@ -146,7 +144,7 @@ trait SeqLike[+A, +Repr] extends Any with IterableLike[A, Repr] with GenSeqLike[ * more than one way to generate the same subsequence, only one will be returned. * * For example, `"xyyy"` has three different ways to generate `"xy"` depending on - * whether the first, second, or third `"y"` is selected. However, since all are + * whether the first, second, or third `"y"` is selected. However, since all are * identical, only one will be chosen. Which of the three will be taken is an * implementation detail that is not defined. * diff --git a/src/library/scala/collection/SeqProxy.scala b/src/library/scala/collection/SeqProxy.scala index f728ba8585..f2b39c7b55 100644 --- a/src/library/scala/collection/SeqProxy.scala +++ b/src/library/scala/collection/SeqProxy.scala @@ -18,5 +18,5 @@ package collection * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait SeqProxy[+A] extends Seq[A] with SeqProxyLike[A, Seq[A]] diff --git a/src/library/scala/collection/SeqProxyLike.scala b/src/library/scala/collection/SeqProxyLike.scala index b01d227d10..b493c70796 100644 --- a/src/library/scala/collection/SeqProxyLike.scala +++ b/src/library/scala/collection/SeqProxyLike.scala @@ -23,7 +23,7 @@ import generic._ * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait SeqProxyLike[+A, +Repr <: SeqLike[A, Repr] with Seq[A]] extends SeqLike[A, Repr] with IterableProxyLike[A, Repr] { override def size = self.size override def toSeq: Seq[A] = self.toSeq diff --git a/src/library/scala/collection/SeqViewLike.scala b/src/library/scala/collection/SeqViewLike.scala index 3473c8aff1..1fbcb6531e 100644 --- a/src/library/scala/collection/SeqViewLike.scala +++ b/src/library/scala/collection/SeqViewLike.scala @@ -96,6 +96,14 @@ trait SeqViewLike[+A, if (idx < self.length) self(idx) else restSeq(idx - self.length) } + trait Prepended[B >: A] extends super.Prepended[B] with Transformed[B] { + protected[this] lazy val fstSeq = fst.toSeq + def length: Int = fstSeq.length + self.length + def apply(idx: Int): B = + if (idx < fstSeq.length) fstSeq(idx) + else self.apply(idx - fstSeq.length) + } + trait Filtered extends super.Filtered with Transformed[A] { protected[this] lazy val index = { var len = 0 @@ -179,21 +187,12 @@ trait SeqViewLike[+A, final override protected[this] def viewIdentifier = "P" } - trait Prepended[B >: A] extends Transformed[B] { - protected[this] val fst: B - override def iterator: Iterator[B] = Iterator.single(fst) ++ self.iterator - def length: Int = 1 + self.length - def apply(idx: Int): B = - if (idx == 0) fst - else self.apply(idx - 1) - final override protected[this] def viewIdentifier = "A" - } - /** Boilerplate method, to override in each subclass * This method could be eliminated if Scala had virtual classes */ protected override def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { protected[this] val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered @@ -212,7 +211,6 @@ trait SeqViewLike[+A, val patch = _patch val replaced = _replaced } with AbstractTransformed[B] with Patched[B] - protected def newPrepended[B >: A](elem: B): Transformed[B] = new { protected[this] val fst = elem } with AbstractTransformed[B] with Prepended[B] // see comment in IterableViewLike. protected override def newTaken(n: Int): Transformed[A] = newSliced(SliceInterval(0, n)) @@ -242,7 +240,7 @@ trait SeqViewLike[+A, } override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = - newPrepended(elem).asInstanceOf[That] + newPrepended(elem :: Nil).asInstanceOf[That] override def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = ++(Iterator.single(elem))(bf) diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala index f8ac1d754d..440452ce99 100644 --- a/src/library/scala/collection/SetLike.scala +++ b/src/library/scala/collection/SetLike.scala @@ -11,7 +11,7 @@ package collection import generic._ import mutable.{ Builder, SetBuilder } -import scala.annotation.{migration, bridge} +import scala.annotation.migration import parallel.ParSet /** A template trait for sets. @@ -77,11 +77,20 @@ self => protected[this] override def parCombiner = ParSet.newCombiner[A] - /* Overridden for efficiency. */ - override def toSeq: Seq[A] = toBuffer[A] + // Default collection type appropriate for immutable collections; mutable collections override this + override def toSeq: Seq[A] = { + if (isEmpty) Vector.empty[A] + else { + val vb = Vector.newBuilder[A] + foreach(vb += _) + vb.result + } + } + override def toBuffer[A1 >: A]: mutable.Buffer[A1] = { val result = new mutable.ArrayBuffer[A1](size) - copyToBuffer(result) + // Faster to let the map iterate itself than to defer through copyToBuffer + foreach(result += _) result } @@ -204,9 +213,9 @@ self => } } - /** An Iterator include all subsets containing exactly len elements. + /** An Iterator including all subsets containing exactly len elements. * If the elements in 'This' type is ordered, then the subsets will also be in the same order. - * ListSet(1,2,3).subsets => {1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}} + * ListSet(1,2,3).subsets => {{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}} * * @author Eastsun * @date 2010.12.6 diff --git a/src/library/scala/collection/SetProxy.scala b/src/library/scala/collection/SetProxy.scala index e17fb215b9..4a3fc17a78 100644 --- a/src/library/scala/collection/SetProxy.scala +++ b/src/library/scala/collection/SetProxy.scala @@ -17,5 +17,5 @@ package collection * @author Martin Odersky * @version 2.0, 01/01/2007 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.3") trait SetProxy[A] extends Set[A] with SetProxyLike[A, Set[A]] diff --git a/src/library/scala/collection/SetProxyLike.scala b/src/library/scala/collection/SetProxyLike.scala index 4cd215cd89..fa23fe5450 100644 --- a/src/library/scala/collection/SetProxyLike.scala +++ b/src/library/scala/collection/SetProxyLike.scala @@ -17,7 +17,7 @@ package collection * @author Martin Odersky * @version 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait SetProxyLike[A, +This <: SetLike[A, This] with Set[A]] extends SetLike[A, This] with IterableProxyLike[A, This] { def empty: This override def contains(elem: A): Boolean = self.contains(elem) diff --git a/src/library/scala/collection/SortedSet.scala b/src/library/scala/collection/SortedSet.scala index 43189d2e8c..0fa5ce0966 100644 --- a/src/library/scala/collection/SortedSet.scala +++ b/src/library/scala/collection/SortedSet.scala @@ -29,6 +29,6 @@ trait SortedSet[A] extends Set[A] with SortedSetLike[A, SortedSet[A]] { object SortedSet extends SortedSetFactory[SortedSet] { def empty[A](implicit ord: Ordering[A]): immutable.SortedSet[A] = immutable.SortedSet.empty[A](ord) def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = newCanBuildFrom[A] - // Force a declaration here so that BitSet's (which does not inherit from SortedSetFactory) can be more specific + // 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 } diff --git a/src/library/scala/collection/TraversableLike.scala b/src/library/scala/collection/TraversableLike.scala index bbbc33b3f5..c9482fe0a2 100644 --- a/src/library/scala/collection/TraversableLike.scala +++ b/src/library/scala/collection/TraversableLike.scala @@ -11,7 +11,7 @@ package collection import generic._ import mutable.{ Builder } -import scala.annotation.{tailrec, migration, bridge} +import scala.annotation.migration import scala.annotation.unchecked.{ uncheckedVariance => uV } import parallel.ParIterable import scala.language.higherKinds @@ -242,7 +242,7 @@ trait TraversableLike[+A, +Repr] extends Any b.result } - private def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { + private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Repr = { val b = newBuilder for (x <- this) if (p(x) != isFlipped) b += x @@ -605,13 +605,69 @@ trait TraversableLike[+A, +Repr] extends Any * applied to this $coll. By default the string prefix is the * simple name of the collection class $coll. */ - def stringPrefix : String = { - var string = repr.getClass.getName - val idx1 = string.lastIndexOf('.' : Int) - if (idx1 != -1) string = string.substring(idx1 + 1) - val idx2 = string.indexOf('$') - if (idx2 != -1) string = string.substring(0, idx2) - string + def stringPrefix: String = { + /* This method is written in a style that avoids calling `String.split()` + * as well as methods of java.lang.Character that require the Unicode + * database information. This is mostly important for Scala.js, so that + * using the collection library does automatically bring java.util.regex.* + * and the Unicode database in the generated code. + * + * This algorithm has the additional benefit that it won't allocate + * anything except the result String in the common case, where the class + * is not an inner class (i.e., when the result contains no '.'). + */ + val fqn = repr.getClass.getName + var pos: Int = fqn.length - 1 + + // Skip trailing $'s + while (pos != -1 && fqn.charAt(pos) == '$') { + pos -= 1 + } + if (pos == -1 || fqn.charAt(pos) == '.') { + return "" + } + + var result: String = "" + while (true) { + // Invariant: if we enter the loop, there is a non-empty part + + // Look for the beginning of the part, remembering where was the last non-digit + val partEnd = pos + 1 + while (pos != -1 && fqn.charAt(pos) <= '9' && fqn.charAt(pos) >= '0') { + pos -= 1 + } + val lastNonDigit = pos + while (pos != -1 && fqn.charAt(pos) != '$' && fqn.charAt(pos) != '.') { + pos -= 1 + } + val partStart = pos + 1 + + // A non-last part which contains only digits marks a method-local part -> drop the prefix + if (pos == lastNonDigit && partEnd != fqn.length) { + return result + } + + // Skip to the next part, and determine whether we are the end + while (pos != -1 && fqn.charAt(pos) == '$') { + pos -= 1 + } + val atEnd = pos == -1 || fqn.charAt(pos) == '.' + + // Handle the actual content of the part (we ignore parts that are likely synthetic) + def isPartLikelySynthetic = { + val firstChar = fqn.charAt(partStart) + (firstChar > 'Z' && firstChar < 0x7f) || (firstChar < 'A') + } + if (atEnd || !isPartLikelySynthetic) { + val part = fqn.substring(partStart, partEnd) + result = if (result.isEmpty) part else part + '.' + result + if (atEnd) + return result + } + } + + // dead code + result } /** Creates a non-strict view of this $coll. diff --git a/src/library/scala/collection/TraversableOnce.scala b/src/library/scala/collection/TraversableOnce.scala index 75c0d82922..b87fcd166e 100644 --- a/src/library/scala/collection/TraversableOnce.scala +++ b/src/library/scala/collection/TraversableOnce.scala @@ -9,7 +9,7 @@ package scala package collection -import mutable.{ Buffer, Builder, ListBuffer, ArrayBuffer } +import mutable.{ Buffer, Builder, ArrayBuffer } import generic.CanBuildFrom import scala.annotation.unchecked.{ uncheckedVariance => uV } import scala.language.{implicitConversions, higherKinds} diff --git a/src/library/scala/collection/TraversableProxy.scala b/src/library/scala/collection/TraversableProxy.scala index 9eec685d10..0c7219c5f9 100644 --- a/src/library/scala/collection/TraversableProxy.scala +++ b/src/library/scala/collection/TraversableProxy.scala @@ -21,5 +21,5 @@ package collection * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.3") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.3") trait TraversableProxy[+A] extends Traversable[A] with TraversableProxyLike[A, Traversable[A]] diff --git a/src/library/scala/collection/TraversableProxyLike.scala b/src/library/scala/collection/TraversableProxyLike.scala index fa470ea238..c8b641f88b 100644 --- a/src/library/scala/collection/TraversableProxyLike.scala +++ b/src/library/scala/collection/TraversableProxyLike.scala @@ -24,7 +24,7 @@ import scala.reflect.ClassTag * @version 2.8 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait TraversableProxyLike[+A, +Repr <: TraversableLike[A, Repr] with Traversable[A]] extends TraversableLike[A, Repr] with Proxy { def self: Repr diff --git a/src/library/scala/collection/TraversableViewLike.scala b/src/library/scala/collection/TraversableViewLike.scala index 5926c69ebf..0901d749c3 100644 --- a/src/library/scala/collection/TraversableViewLike.scala +++ b/src/library/scala/collection/TraversableViewLike.scala @@ -189,6 +189,15 @@ trait TraversableViewLike[+A, } final override protected[this] def viewIdentifier = "A" } + + trait Prepended[B >: A] extends Transformed[B] { + protected[this] val fst: GenTraversable[B] + def foreach[U](f: B => U) { + fst foreach f + self foreach f + } + final override protected[this] def viewIdentifier = "A" + } trait Filtered extends Transformed[A] { protected[this] val pred: A => Boolean @@ -222,11 +231,15 @@ trait TraversableViewLike[+A, final override protected[this] def viewIdentifier = "D" } - override def ++[B >: A, That](xs: GenTraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = { + override def ++[B >: A, That](xs: GenTraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = newAppended(xs.seq.toTraversable).asInstanceOf[That] -// was: if (bf.isInstanceOf[ByPassCanBuildFrom]) newAppended(that).asInstanceOf[That] -// else super.++[B, That](that)(bf) - } + + override def ++:[B >: A, That](xs: TraversableOnce[B])(implicit bf: CanBuildFrom[This, B, That]): That = + newPrepended(xs.seq.toTraversable).asInstanceOf[That] + + // Need second one because of optimization in TraversableLike + override def ++:[B >: A, That](xs: Traversable[B])(implicit bf: CanBuildFrom[This, B, That]): That = + newPrepended(xs).asInstanceOf[That] override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = { newMapped(f).asInstanceOf[That] @@ -253,6 +266,7 @@ trait TraversableViewLike[+A, */ protected def newForced[B](xs: => GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected def newAppended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected def newPrepended[B >: A](that: GenTraversable[B]): Transformed[B] = new { val fst = that } with AbstractTransformed[B] with Prepended[B] protected def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected def newFlatMapped[B](f: A => GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered diff --git a/src/library/scala/collection/concurrent/Map.scala b/src/library/scala/collection/concurrent/Map.scala index cfb567abe9..f27dfd57fc 100644 --- a/src/library/scala/collection/concurrent/Map.scala +++ b/src/library/scala/collection/concurrent/Map.scala @@ -86,4 +86,15 @@ trait Map[A, B] extends scala.collection.mutable.Map[A, B] { * @return `Some(v)` if the given key was previously mapped to some value `v`, or `None` otherwise */ def replace(k: A, v: B): Option[B] + + override def getOrElseUpdate(key: A, op: =>B): B = get(key) match { + case Some(v) => v + case None => + val v = op + putIfAbsent(key, v) match { + case Some(nv) => nv + case None => v + } + } + } diff --git a/src/library/scala/collection/concurrent/TrieMap.scala b/src/library/scala/collection/concurrent/TrieMap.scala index bcfea7a463..fe0b5c4f0e 100644 --- a/src/library/scala/collection/concurrent/TrieMap.scala +++ b/src/library/scala/collection/concurrent/TrieMap.scala @@ -11,13 +11,11 @@ package collection package concurrent import java.util.concurrent.atomic._ -import scala.collection.immutable.{ ListMap => ImmutableListMap } import scala.collection.parallel.mutable.ParTrieMap import scala.util.hashing.Hashing import scala.util.control.ControlThrowable import generic._ import scala.annotation.tailrec -import scala.annotation.switch private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen) extends INodeBase[K, V](g) { import INodeBase._ @@ -471,7 +469,7 @@ private[collection] final class CNode[K, V](val bitmap: Int, val array: Array[Ba val offset = if (array.length > 0) //util.Random.nextInt(array.length) /* <-- benchmarks show that this causes observable contention */ - scala.concurrent.forkjoin.ThreadLocalRandom.current.nextInt(0, array.length) + java.util.concurrent.ThreadLocalRandom.current.nextInt(0, array.length) else 0 while (i < array.length) { val pos = (i + offset) % array.length @@ -641,7 +639,8 @@ extends scala.collection.concurrent.Map[K, V] private var rootupdater = rtupd def hashing = hashingobj def equality = equalityobj - @volatile var root = r + @deprecated("this field will be made private", "2.12.0") + @volatile /*private*/ var root = r def this(hashf: Hashing[K], ef: Equiv[K]) = this( INode.newRootNode, @@ -685,11 +684,14 @@ extends scala.collection.concurrent.Map[K, V] } while (obj != TrieMapSerializationEnd) } - def CAS_ROOT(ov: AnyRef, nv: AnyRef) = rootupdater.compareAndSet(this, ov, nv) + @deprecated("this method will be made private", "2.12.0") + /*private*/ def CAS_ROOT(ov: AnyRef, nv: AnyRef) = rootupdater.compareAndSet(this, ov, nv) - def readRoot(abort: Boolean = false): INode[K, V] = RDCSS_READ_ROOT(abort) + @deprecated("this method will be made private", "2.12.0") + /*private[collection]*/ def readRoot(abort: Boolean = false): INode[K, V] = RDCSS_READ_ROOT(abort) - def RDCSS_READ_ROOT(abort: Boolean = false): INode[K, V] = { + @deprecated("this method will be made private", "2.12.0") + /*private[concurrent]*/ def RDCSS_READ_ROOT(abort: Boolean = false): INode[K, V] = { val r = /*READ*/root r match { case in: INode[K, V] => in @@ -884,7 +886,7 @@ extends scala.collection.concurrent.Map[K, V] * * If the specified mapping function throws an exception, * that exception is rethrown. - * + * * Note: This method will invoke op at most once. * However, `op` may be invoked without the result being added to the map if * a concurrent process is also trying to add a value corresponding to the @@ -930,6 +932,33 @@ extends scala.collection.concurrent.Map[K, V] if (nonReadOnly) readOnlySnapshot().iterator else new TrieMapIterator(0, this) + //////////////////////////////////////////////////////////////////////////// + // + // SI-10177 These methods need overrides as the inherited implementations + // call `.iterator` more than once, which doesn't guarantee a coherent + // view of the data if there is a concurrent writer + // Note that the we don't need overrides for keysIterator or valuesIterator + // TrieMapTest validates the behaviour. + override def values: Iterable[V] = { + if (nonReadOnly) readOnlySnapshot().values + else super.values + } + override def keySet: Set[K] = { + if (nonReadOnly) readOnlySnapshot().keySet + else super.keySet + } + override def filterKeys(p: K => Boolean): collection.Map[K, V] = { + if (nonReadOnly) readOnlySnapshot().filterKeys(p) + else super.filterKeys(p) + } + override def mapValues[W](f: V => W): collection.Map[K, W] = { + if (nonReadOnly) readOnlySnapshot().mapValues(f) + else super.mapValues(f) + } + // END extra overrides + /////////////////////////////////////////////////////////////////// + + private def cachedSize() = { val r = RDCSS_READ_ROOT() r.cachedSize(this) @@ -1083,6 +1112,7 @@ private[collection] class TrieMapIterator[K, V](var level: Int, private var ct: Seq(this) } + @deprecated("this method will be removed", "2.12.0") def printDebug() { println("ctrie iterator") println(stackpos.mkString(",")) @@ -1103,14 +1133,14 @@ private[concurrent] case object TrieMapSerializationEnd private[concurrent] object Debug { - import scala.collection._ + import JavaConverters._ lazy val logbuffer = new java.util.concurrent.ConcurrentLinkedQueue[AnyRef] def log(s: AnyRef) = logbuffer.add(s) def flush() { - for (s <- JavaConversions.asScalaIterator(logbuffer.iterator())) Console.out.println(s.toString) + for (s <- logbuffer.iterator().asScala) Console.out.println(s.toString) logbuffer.clear() } diff --git a/src/library/scala/collection/convert/AsJavaConverters.scala b/src/library/scala/collection/convert/AsJavaConverters.scala new file mode 100644 index 0000000000..c7c1fb9c74 --- /dev/null +++ b/src/library/scala/collection/convert/AsJavaConverters.scala @@ -0,0 +1,262 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package convert + +import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } + +/** Defines converter methods from Scala to Java collections. */ +trait AsJavaConverters { + import Wrappers._ + + /** + * Converts a Scala `Iterator` to a Java `Iterator`. + * + * The returned Java `Iterator` is backed by the provided Scala `Iterator` and any side-effects of + * using it via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Iterator` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaIterator]](java.util.Iterator)` then the original Java `Iterator` will + * be returned. + * + * @param i The Scala `Iterator` to be converted. + * @return A Java `Iterator` view of the argument. + */ + def asJavaIterator[A](i: Iterator[A]): ju.Iterator[A] = i match { + case null => null + case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] + case _ => IteratorWrapper(i) + } + + /** + * Converts a Scala `Iterator` to a Java `Enumeration`. + * + * The returned Java `Enumeration` is backed by the provided Scala `Iterator` and any side-effects + * of using it via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Iterator` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.enumerationAsScalaIterator]](java.util.Enumeration)` then the original Java + * `Enumeration` will be returned. + * + * @param i The Scala `Iterator` to be converted. + * @return A Java `Enumeration` view of the argument. + */ + def asJavaEnumeration[A](i: Iterator[A]): ju.Enumeration[A] = i match { + case null => null + case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]] + case _ => IteratorWrapper(i) + } + + /** + * Converts a Scala `Iterable` to a Java `Iterable`. + * + * The returned Java `Iterable` is backed by the provided Scala `Iterable` and any side-effects of + * using it via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Iterable` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.iterableAsScalaIterable]](java.lang.Iterable)` then the original Java + * `Iterable` will be returned. + * + * @param i The Scala `Iterable` to be converted. + * @return A Java `Iterable` view of the argument. + */ + def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match { + case null => null + case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] + case _ => IterableWrapper(i) + } + + /** + * Converts a Scala `Iterable` to an immutable Java `Collection`. + * + * If the Scala `Iterable` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.collectionAsScalaIterable]](java.util.Collection)` then the original Java + * `Collection` will be returned. + * + * @param i The Scala `Iterable` to be converted. + * @return A Java `Collection` view of the argument. + */ + def asJavaCollection[A](i: Iterable[A]): ju.Collection[A] = i match { + case null => null + case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] + case _ => new IterableWrapper(i) + } + + /** + * Converts a Scala mutable `Buffer` to a Java List. + * + * The returned Java List is backed by the provided Scala `Buffer` and any side-effects of using + * it via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Buffer` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be + * returned. + * + * @param b The Scala `Buffer` to be converted. + * @return A Java `List` view of the argument. + */ + def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = b match { + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableBufferWrapper(b) + } + + /** + * Converts a Scala mutable `Seq` to a Java `List`. + * + * The returned Java `List` is backed by the provided Scala `Seq` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Seq` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be + * returned. + * + * @param s The Scala `Seq` to be converted. + * @return A Java `List` view of the argument. + */ + def mutableSeqAsJavaList[A](s: mutable.Seq[A]): ju.List[A] = s match { + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableSeqWrapper(s) + } + + /** + * Converts a Scala `Seq` to a Java `List`. + * + * The returned Java `List` is backed by the provided Scala `Seq` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Seq` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaBuffer]](java.util.List)` then the original Java `List` will be + * returned. + * + * @param s The Scala `Seq` to be converted. + * @return A Java `List` view of the argument. + */ + def seqAsJavaList[A](s: Seq[A]): ju.List[A] = s match { + case null => null + case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] + case _ => new SeqWrapper(s) + } + + /** + * Converts a Scala mutable `Set` to a Java `Set`. + * + * The returned Java `Set` is backed by the provided Scala `Set` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Set` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaSet]](java.util.Set)` then the original Java `Set` will be returned. + * + * @param s The Scala mutable `Set` to be converted. + * @return A Java `Set` view of the argument. + */ + def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = s match { + case null => null + case JSetWrapper(wrapped) => wrapped + case _ => new MutableSetWrapper(s) + } + + /** + * Converts a Scala `Set` to a Java `Set`. + * + * The returned Java `Set` is backed by the provided Scala `Set` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Set` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asScalaSet]](java.util.Set)` then the original Java `Set` will be returned. + * + * @param s The Scala `Set` to be converted. + * @return A Java `Set` view of the argument. + */ + def setAsJavaSet[A](s: Set[A]): ju.Set[A] = s match { + case null => null + case JSetWrapper(wrapped) => wrapped + case _ => new SetWrapper(s) + } + + /** + * Converts a Scala mutable `Map` to a Java `Map`. + * + * The returned Java `Map` is backed by the provided Scala `Map` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Map` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mapAsScalaMap]](java.util.Map)` then the original Java `Map` will be + * returned. + * + * @param m The Scala mutable `Map` to be converted. + * @return A Java `Map` view of the argument. + */ + def mutableMapAsJavaMap[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = m match { + case null => null + case JMapWrapper(wrapped) => wrapped + case _ => new MutableMapWrapper(m) + } + + /** + * Converts a Scala mutable `Map` to a Java `Dictionary`. + * + * The returned Java `Dictionary` is backed by the provided Scala `Dictionary` and any + * side-effects of using it via the Java interface will be visible via the Scala interface and + * vice versa. + * + * If the Scala `Dictionary` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.dictionaryAsScalaMap]](java.util.Dictionary)` then the original Java + * `Dictionary` will be returned. + * + * @param m The Scala `Map` to be converted. + * @return A Java `Dictionary` view of the argument. + */ + def asJavaDictionary[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = m match { + case null => null + case JDictionaryWrapper(wrapped) => wrapped + case _ => new DictionaryWrapper(m) + } + + /** + * Converts a Scala `Map` to a Java `Map`. + * + * The returned Java `Map` is backed by the provided Scala `Map` and any side-effects of using it + * via the Java interface will be visible via the Scala interface and vice versa. + * + * If the Scala `Map` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mapAsScalaMap]](java.util.Map)` then the original Java `Map` will be + * returned. + * + * @param m The Scala `Map` to be converted. + * @return A Java `Map` view of the argument. + */ + def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match { + case null => null + case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]] + case _ => new MapWrapper(m) + } + + /** + * Converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. + * + * The returned Java `ConcurrentMap` is backed by the provided Scala `concurrent.Map` and any + * side-effects of using it via the Java interface will be visible via the Scala interface and + * vice versa. + * + * If the Scala `concurrent.Map` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mapAsScalaConcurrentMap]](java.util.concurrent.ConcurrentMap)` then the + * original Java `ConcurrentMap` will be returned. + * + * @param m The Scala `concurrent.Map` to be converted. + * @return A Java `ConcurrentMap` view of the argument. + */ + def mapAsJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match { + case null => null + case JConcurrentMapWrapper(wrapped) => wrapped + case _ => new ConcurrentMapWrapper(m) + } +} diff --git a/src/library/scala/collection/convert/AsScalaConverters.scala b/src/library/scala/collection/convert/AsScalaConverters.scala new file mode 100644 index 0000000000..f9e38797e1 --- /dev/null +++ b/src/library/scala/collection/convert/AsScalaConverters.scala @@ -0,0 +1,207 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package convert + +import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } + +/** Defines converter methods from Java to Scala collections. */ +trait AsScalaConverters { + import Wrappers._ + + /** + * Converts a Java `Iterator` to a Scala `Iterator`. + * + * The returned Scala `Iterator` is backed by the provided Java `Iterator` and any side-effects of + * using it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Iterator` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaIterator]](scala.collection.Iterator)` then the original Scala + * `Iterator` will be returned. + * + * @param i The Java `Iterator` to be converted. + * @return A Scala `Iterator` view of the argument. + */ + def asScalaIterator[A](i: ju.Iterator[A]): Iterator[A] = i match { + case null => null + case IteratorWrapper(wrapped) => wrapped + case _ => JIteratorWrapper(i) + } + + /** + * Converts a Java `Enumeration` to a Scala `Iterator`. + * + * The returned Scala `Iterator` is backed by the provided Java `Enumeration` and any side-effects + * of using it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Enumeration` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaEnumeration]](scala.collection.Iterator)` then the original Scala + * `Iterator` will be returned. + * + * @param i The Java `Enumeration` to be converted. + * @return A Scala `Iterator` view of the argument. + */ + def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = i match { + case null => null + case IteratorWrapper(wrapped) => wrapped + case _ => JEnumerationWrapper(i) + } + + /** + * Converts a Java `Iterable` to a Scala `Iterable`. + * + * The returned Scala `Iterable` is backed by the provided Java `Iterable` and any side-effects of + * using it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Iterable` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaIterable]](scala.collection.Iterable) then the original Scala + * `Iterable` will be returned. + * + * @param i The Java `Iterable` to be converted. + * @return A Scala `Iterable` view of the argument. + */ + def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = i match { + case null => null + case IterableWrapper(wrapped) => wrapped + case _ => JIterableWrapper(i) + } + + /** + * Converts a Java `Collection` to an Scala `Iterable`. + * + * If the Java `Collection` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaCollection]](scala.collection.Iterable)` then the original Scala + * `Iterable` will be returned. + * + * @param i The Java `Collection` to be converted. + * @return A Scala `Iterable` view of the argument. + */ + def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = i match { + case null => null + case IterableWrapper(wrapped) => wrapped + case _ => JCollectionWrapper(i) + } + + /** + * Converts a Java `List` to a Scala mutable `Buffer`. + * + * The returned Scala `Buffer` is backed by the provided Java `List` and any side-effects of using + * it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `List` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.bufferAsJavaList]](scala.collection.mutable.Buffer)` then the original Scala + * `Buffer` will be returned. + * + * @param l The Java `List` to be converted. + * @return A Scala mutable `Buffer` view of the argument. + */ + def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = l match { + case null => null + case MutableBufferWrapper(wrapped) => wrapped + case _ => new JListWrapper(l) + } + + /** + * Converts a Java `Set` to a Scala mutable `Set`. + * + * The returned Scala `Set` is backed by the provided Java `Set` and any side-effects of using it + * via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Set` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mutableSetAsJavaSet]](scala.collection.mutable.Set)` then the original Scala + * `Set` will be returned. + * + * @param s The Java `Set` to be converted. + * @return A Scala mutable `Set` view of the argument. + */ + def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = s match { + case null => null + case MutableSetWrapper(wrapped) => wrapped + case _ => new JSetWrapper(s) + } + + /** + * Converts a Java `Map` to a Scala mutable `Map`. + * + * The returned Scala `Map` is backed by the provided Java `Map` and any side-effects of using it + * via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Map` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mutableMapAsJavaMap]](scala.collection.mutable.Map)` then the original Scala + * `Map` will be returned. + * + * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), it is + * your responsibility to wrap all non-atomic operations with `underlying.synchronized`. + * This includes `get`, as `java.util.Map`'s API does not allow for an atomic `get` when `null` + * values may be present. + * + * @param m The Java `Map` to be converted. + * @return A Scala mutable `Map` view of the argument. + */ + def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = m match { + case null => null + case MutableMapWrapper(wrapped) => wrapped + case _ => new JMapWrapper(m) + } + + /** + * Converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`. + * + * The returned Scala `ConcurrentMap` is backed by the provided Java `ConcurrentMap` and any + * side-effects of using it via the Scala interface will be visible via the Java interface and + * vice versa. + * + * If the Java `ConcurrentMap` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.mapAsJavaConcurrentMap]](scala.collection.mutable.ConcurrentMap)` + * then the original Scala `ConcurrentMap` will be returned. + * + * @param m The Java `ConcurrentMap` to be converted. + * @return A Scala mutable `ConcurrentMap` view of the argument. + */ + def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match { + case null => null + case cmw: ConcurrentMapWrapper[_, _] => cmw.underlying + case _ => new JConcurrentMapWrapper(m) + } + + /** + * Converts a Java `Dictionary` to a Scala mutable `Map`. + * + * The returned Scala `Map` is backed by the provided Java `Dictionary` and any side-effects of + * using it via the Scala interface will be visible via the Java interface and vice versa. + * + * If the Java `Dictionary` was previously obtained from an implicit or explicit call of + * `[[JavaConverters.asJavaDictionary]](scala.collection.mutable.Map)` then the original + * Scala `Map` will be returned. + * + * @param p The Java `Dictionary` to be converted. + * @return A Scala mutable `Map` view of the argument. + */ + def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match { + case null => null + case DictionaryWrapper(wrapped) => wrapped + case _ => new JDictionaryWrapper(p) + } + + /** + * Converts a Java `Properties` to a Scala mutable `Map[String, String]`. + * + * The returned Scala `Map[String, String]` is backed by the provided Java `Properties` and any + * side-effects of using it via the Scala interface will be visible via the Java interface and + * vice versa. + * + * @param p The Java `Properties` to be converted. + * @return A Scala mutable `Map[String, String]` view of the argument. + */ + def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = p match { + case null => null + case _ => new JPropertiesWrapper(p) + } +} diff --git a/src/library/scala/collection/convert/DecorateAsJava.scala b/src/library/scala/collection/convert/DecorateAsJava.scala index e6aa5da067..83fffa5940 100644 --- a/src/library/scala/collection/convert/DecorateAsJava.scala +++ b/src/library/scala/collection/convert/DecorateAsJava.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -12,289 +12,97 @@ package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import Decorators._ -import WrapAsJava._ import scala.language.implicitConversions - -/** A collection of decorators that allow converting between - * Scala and Java collections using `asScala` and `asJava` methods. - * - * The following conversions are supported via `asJava`, `asScala` - * - * - `scala.collection.Iterable` <=> `java.lang.Iterable` - * - `scala.collection.Iterator` <=> `java.util.Iterator` - * - `scala.collection.mutable.Buffer` <=> `java.util.List` - * - `scala.collection.mutable.Set` <=> `java.util.Set` - * - `scala.collection.mutable.Map` <=> `java.util.Map` - * - `scala.collection.mutable.concurrent.Map` <=> `java.util.concurrent.ConcurrentMap` - * - * In all cases, converting from a source type to a target type and back - * again will return the original source object, e.g. - * {{{ - * import scala.collection.JavaConverters._ - * - * val sl = new scala.collection.mutable.ListBuffer[Int] - * val jl : java.util.List[Int] = sl.asJava - * val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala - * assert(sl eq sl2) - * }}} - * The following conversions are also supported, but the - * direction from Scala to Java is done by the more specifically named methods: - * `asJavaCollection`, `asJavaEnumeration`, `asJavaDictionary`. - * - * - `scala.collection.Iterable` <=> `java.util.Collection` - * - `scala.collection.Iterator` <=> `java.util.Enumeration` - * - `scala.collection.mutable.Map` <=> `java.util.Dictionary` - * - * In addition, the following one way conversions are provided via `asJava`: - * - * - `scala.collection.Seq` => `java.util.List` - * - `scala.collection.mutable.Seq` => `java.util.List` - * - `scala.collection.Set` => `java.util.Set` - * - `scala.collection.Map` => `java.util.Map` - * - * The following one way conversion is provided via `asScala`: - * - * - `java.util.Properties` => `scala.collection.mutable.Map` - * - * @since 2.8.1 - */ -trait DecorateAsJava { +/** Defines `asJava` extension methods for [[JavaConverters]]. */ +trait DecorateAsJava extends AsJavaConverters { /** - * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a - * Java `Iterator`. The returned Java `Iterator` is backed by the provided Scala - * `Iterator` and any side-effects of using it via the Java interface will - * be visible via the Scala interface and vice versa. - * - * If the Scala `Iterator` was previously obtained from an implicit or explicit - * call of `asIterator(java.util.Iterator)` then the original Java `Iterator` - * will be returned by the `asJava` method. - * - * @param i The `Iterator` to be converted. - * @return An object with an `asJava` method that returns a Java `Iterator` view of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a Java `Iterator`. + * @see [[asJavaIterator]] */ implicit def asJavaIteratorConverter[A](i : Iterator[A]): AsJava[ju.Iterator[A]] = new AsJava(asJavaIterator(i)) /** - * Adds an `asJavaEnumeration` method that implicitly converts a Scala - * `Iterator` to a Java `Enumeration`. The returned Java `Enumeration` is - * backed by the provided Scala `Iterator` and any side-effects of using - * it via the Java interface will be visible via the Scala interface and - * vice versa. - * - * If the Scala `Iterator` was previously obtained from an implicit or - * explicit call of `asIterator(java.util.Enumeration)` then the - * original Java `Enumeration` will be returned. - * - * @param i The `Iterator` to be converted. - * @return An object with an `asJavaEnumeration` method that returns a Java - * `Enumeration` view of the argument. + * Adds an `asJavaEnumeration` method that implicitly converts a Scala `Iterator` to a Java `Enumeration`. + * @see [[asJavaEnumeration]] */ implicit def asJavaEnumerationConverter[A](i : Iterator[A]): AsJavaEnumeration[A] = new AsJavaEnumeration(i) /** - * Adds an `asJava` method that implicitly converts a Scala `Iterable` to - * a Java `Iterable`. - * - * The returned Java `Iterable` is backed by the provided Scala `Iterable` - * and any side-effects of using it via the Java interface will be visible - * via the Scala interface and vice versa. - * - * If the Scala `Iterable` was previously obtained from an implicit or - * explicit call of `asIterable(java.lang.Iterable)` then the original - * Java `Iterable` will be returned. - * - * @param i The `Iterable` to be converted. - * @return An object with an `asJavaCollection` method that returns a Java - * `Iterable` view of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Iterable` to a Java `Iterable`. + * @see [[asJavaIterable]] */ implicit def asJavaIterableConverter[A](i : Iterable[A]): AsJava[jl.Iterable[A]] = new AsJava(asJavaIterable(i)) /** - * Adds an `asJavaCollection` method that implicitly converts a Scala - * `Iterable` to an immutable Java `Collection`. - * - * If the Scala `Iterable` was previously obtained from an implicit or - * explicit call of `asSizedIterable(java.util.Collection)` then the - * original Java `Collection` will be returned. - * - * @param i The `SizedIterable` to be converted. - * @return An object with an `asJava` method that returns a Java - * `Collection` view of the argument. + * Adds an `asJavaCollection` method that implicitly converts a Scala `Iterable` to an immutable Java `Collection`. + * @see [[asJavaCollection]] */ implicit def asJavaCollectionConverter[A](i : Iterable[A]): AsJavaCollection[A] = new AsJavaCollection(i) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer` - * to a Java `List`. - * - * The returned Java `List` is backed by the provided Scala `Buffer` and any - * side-effects of using it via the Java interface will be visible via the - * Scala interface and vice versa. - * - * If the Scala `Buffer` was previously obtained from an implicit or explicit - * call of `asBuffer(java.util.List)` then the original Java `List` will be - * returned. - * - * @param b The `Buffer` to be converted. - * @return An object with an `asJava` method that returns a Java `List` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer` to a Java `List`. + * @see [[bufferAsJavaList]] */ implicit def bufferAsJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] = new AsJava(bufferAsJavaList(b)) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `Seq` - * to a Java `List`. - * - * The returned Java `List` is backed by the provided Scala `Seq` and any - * side-effects of using it via the Java interface will be visible via the - * Scala interface and vice versa. - * - * If the Scala `Seq` was previously obtained from an implicit or explicit - * call of `asSeq(java.util.List)` then the original Java `List` will be - * returned. - * - * @param b The `Seq` to be converted. - * @return An object with an `asJava` method that returns a Java `List` - * view of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `Seq` to a Java `List`. + * @see [[mutableSeqAsJavaList]] */ implicit def mutableSeqAsJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] = new AsJava(mutableSeqAsJavaList(b)) /** - * Adds an `asJava` method that implicitly converts a Scala `Seq` to a - * Java `List`. - * - * The returned Java `List` is backed by the provided Scala `Seq` and any - * side-effects of using it via the Java interface will be visible via the - * Scala interface and vice versa. - * - * If the Scala `Seq` was previously obtained from an implicit or explicit - * call of `asSeq(java.util.List)` then the original Java `List` will be - * returned. - * - * @param b The `Seq` to be converted. - * @return An object with an `asJava` method that returns a Java `List` - * view of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Seq` to a Java `List`. + * @see [[seqAsJavaList]] */ implicit def seqAsJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] = new AsJava(seqAsJavaList(b)) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `Set`> - * to a Java `Set`. - * - * The returned Java `Set` is backed by the provided Scala `Set` and any - * side-effects of using it via the Java interface will be visible via - * the Scala interface and vice versa. - * - * If the Scala `Set` was previously obtained from an implicit or explicit - * call of `asSet(java.util.Set)` then the original Java `Set` will be - * returned. - * - * @param s The `Set` to be converted. - * @return An object with an `asJava` method that returns a Java `Set` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `Set` to a Java `Set`. + * @see [[mutableSetAsJavaSet]] */ implicit def mutableSetAsJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] = new AsJava(mutableSetAsJavaSet(s)) /** - * Adds an `asJava` method that implicitly converts a Scala `Set` to a - * Java `Set`. - * - * The returned Java `Set` is backed by the provided Scala `Set` and any - * side-effects of using it via the Java interface will be visible via - * the Scala interface and vice versa. - * - * If the Scala `Set` was previously obtained from an implicit or explicit - * call of `asSet(java.util.Set)` then the original Java `Set` will be - * returned. - * - * @param s The `Set` to be converted. - * @return An object with an `asJava` method that returns a Java `Set` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Set` to a Java `Set`. + * @see [[setAsJavaSet]] */ implicit def setAsJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] = new AsJava(setAsJavaSet(s)) /** - * Adds an `asJava` method that implicitly converts a Scala mutable `Map` - * to a Java `Map`. - * - * The returned Java `Map` is backed by the provided Scala `Map` and any - * side-effects of using it via the Java interface will be visible via the - * Scala interface and vice versa. - * - * If the Scala `Map` was previously obtained from an implicit or explicit - * call of `asMap(java.util.Map)` then the original Java `Map` will be - * returned. - * - * @param m The `Map` to be converted. - * @return An object with an `asJava` method that returns a Java `Map` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `Map` to a Java `Map`. + * @see [[mutableMapAsJavaMap]] */ implicit def mutableMapAsJavaMapConverter[A, B](m : mutable.Map[A, B]): AsJava[ju.Map[A, B]] = new AsJava(mutableMapAsJavaMap(m)) /** - * Adds an `asJavaDictionary` method that implicitly converts a Scala - * mutable `Map` to a Java `Dictionary`. - * - * The returned Java `Dictionary` is backed by the provided Scala - * `Dictionary` and any side-effects of using it via the Java interface - * will be visible via the Scala interface and vice versa. - * - * If the Scala `Dictionary` was previously obtained from an implicit or - * explicit call of `asMap(java.util.Dictionary)` then the original - * Java `Dictionary` will be returned. - * - * @param m The `Map` to be converted. - * @return An object with an `asJavaDictionary` method that returns a - * Java `Dictionary` view of the argument. + * Adds an `asJavaDictionary` method that implicitly converts a Scala mutable `Map` to a Java `Dictionary`. + * @see [[asJavaDictionary]] */ implicit def asJavaDictionaryConverter[A, B](m : mutable.Map[A, B]): AsJavaDictionary[A, B] = new AsJavaDictionary(m) /** - * Adds an `asJava` method that implicitly converts a Scala `Map` to - * a Java `Map`. - * - * The returned Java `Map` is backed by the provided Scala `Map` and any - * side-effects of using it via the Java interface will be visible via - * the Scala interface and vice versa. - * - * If the Scala `Map` was previously obtained from an implicit or explicit - * call of `asMap(java.util.Map)` then the original Java `Map` will be - * returned. - * - * @param m The `Map` to be converted. - * @return An object with an `asJava` method that returns a Java `Map` view - * of the argument. + * Adds an `asJava` method that implicitly converts a Scala `Map` to a Java `Map`. + * @see [[mapAsJavaMap]] */ implicit def mapAsJavaMapConverter[A, B](m : Map[A, B]): AsJava[ju.Map[A, B]] = new AsJava(mapAsJavaMap(m)) /** - * Adds an `asJava` method that implicitly converts a Scala mutable - * `concurrent.Map` to a Java `ConcurrentMap`. - * - * The returned Java `ConcurrentMap` is backed by the provided Scala - * `concurrent.Map` and any side-effects of using it via the Java interface - * will be visible via the Scala interface and vice versa. - * - * If the Scala `concurrent.Map` was previously obtained from an implicit or - * explicit call of `asConcurrentMap(java.util.concurrent.ConcurrentMap)` - * then the original Java `ConcurrentMap` will be returned. - * - * @param m The Scala `concurrent.Map` to be converted. - * @return An object with an `asJava` method that returns a Java - * `ConcurrentMap` view of the argument. + * Adds an `asJava` method that implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. + * @see [[mapAsJavaConcurrentMap]]. */ implicit def mapAsJavaConcurrentMapConverter[A, B](m: concurrent.Map[A, B]): AsJava[juc.ConcurrentMap[A, B]] = new AsJava(mapAsJavaConcurrentMap(m)) diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala index 5448f5f91c..f680aa5267 100644 --- a/src/library/scala/collection/convert/DecorateAsScala.scala +++ b/src/library/scala/collection/convert/DecorateAsScala.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2006-2013, LAMP/EPFL ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** @@ -12,185 +12,76 @@ package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import Decorators._ -import WrapAsScala._ import scala.language.implicitConversions -trait DecorateAsScala { +/** Defines `asScala` extension methods for [[JavaConverters]]. */ +trait DecorateAsScala extends AsScalaConverters { /** - * Adds an `asScala` method that implicitly converts a Java `Iterator` to - * a Scala `Iterator`. - * - * The returned Scala `Iterator` is backed by the provided Java `Iterator` - * and any side-effects of using it via the Scala interface will be visible - * via the Java interface and vice versa. - * - * If the Java `Iterator` was previously obtained from an implicit or - * explicit call of `asIterator(scala.collection.Iterator)` then the - * original Scala `Iterator` will be returned. - * - * @param i The `Iterator` to be converted. - * @return An object with an `asScala` method that returns a Scala - * `Iterator` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Iterator` to a Scala `Iterator`. + * @see [[asScalaIterator]] */ implicit def asScalaIteratorConverter[A](i : ju.Iterator[A]): AsScala[Iterator[A]] = new AsScala(asScalaIterator(i)) /** - * Adds an `asScala` method that implicitly converts a Java `Enumeration` - * to a Scala `Iterator`. - * - * The returned Scala `Iterator` is backed by the provided Java - * `Enumeration` and any side-effects of using it via the Scala interface - * will be visible via the Java interface and vice versa. - * - * If the Java `Enumeration` was previously obtained from an implicit or - * explicit call of `asEnumeration(scala.collection.Iterator)` then the - * original Scala `Iterator` will be returned. - * - * @param i The `Enumeration` to be converted. - * @return An object with an `asScala` method that returns a Scala - * `Iterator` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Enumeration` to a Scala `Iterator`. + * @see [[enumerationAsScalaIterator]] */ implicit def enumerationAsScalaIteratorConverter[A](i : ju.Enumeration[A]): AsScala[Iterator[A]] = new AsScala(enumerationAsScalaIterator(i)) /** - * Adds an `asScala` method that implicitly converts a Java `Iterable` to - * a Scala `Iterable`. - * - * The returned Scala `Iterable` is backed by the provided Java `Iterable` - * and any side-effects of using it via the Scala interface will be visible - * via the Java interface and vice versa. - * - * If the Java `Iterable` was previously obtained from an implicit or - * explicit call of `asIterable(scala.collection.Iterable)` then the original - * Scala `Iterable` will be returned. - * - * @param i The `Iterable` to be converted. - * @return An object with an `asScala` method that returns a Scala `Iterable` - * view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Iterable` to a Scala `Iterable`. + * @see [[iterableAsScalaIterable]] */ implicit def iterableAsScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] = new AsScala(iterableAsScalaIterable(i)) /** - * Adds an `asScala` method that implicitly converts a Java `Collection` to - * an Scala `Iterable`. - * - * If the Java `Collection` was previously obtained from an implicit or - * explicit call of `asCollection(scala.collection.SizedIterable)` then - * the original Scala `SizedIterable` will be returned. - * - * @param i The `Collection` to be converted. - * @return An object with an `asScala` method that returns a Scala - * `SizedIterable` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Collection` to an Scala `Iterable`. + * @see [[collectionAsScalaIterable]] */ implicit def collectionAsScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] = new AsScala(collectionAsScalaIterable(i)) /** - * Adds an `asScala` method that implicitly converts a Java `List` to a - * Scala mutable `Buffer`. - * - * The returned Scala `Buffer` is backed by the provided Java `List` and - * any side-effects of using it via the Scala interface will be visible via - * the Java interface and vice versa. - * - * If the Java `List` was previously obtained from an implicit or explicit - * call of `asList(scala.collection.mutable.Buffer)` then the original - * Scala `Buffer` will be returned. - * - * @param l The `List` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Buffer` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `List` to a Scala mutable `Buffer`. + * @see [[asScalaBuffer]] */ implicit def asScalaBufferConverter[A](l : ju.List[A]): AsScala[mutable.Buffer[A]] = new AsScala(asScalaBuffer(l)) /** - * Adds an `asScala` method that implicitly converts a Java `Set` to a - * Scala mutable `Set`. - * - * The returned Scala `Set` is backed by the provided Java `Set` and any - * side-effects of using it via the Scala interface will be visible via - * the Java interface and vice versa. - * - * If the Java `Set` was previously obtained from an implicit or explicit - * call of `asSet(scala.collection.mutable.Set)` then the original - * Scala `Set` will be returned. - * - * @param s The `Set` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Set` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Set` to a Scala mutable `Set`. + * @see [[asScalaSet]] */ implicit def asScalaSetConverter[A](s : ju.Set[A]): AsScala[mutable.Set[A]] = new AsScala(asScalaSet(s)) /** - * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala - * mutable `Map`. The returned Scala `Map` is backed by the provided Java - * `Map` and any side-effects of using it via the Scala interface will - * be visible via the Java interface and vice versa. - * - * If the Java `Map` was previously obtained from an implicit or explicit - * call of `asMap(scala.collection.mutable.Map)` then the original - * Scala `Map` will be returned. - * - * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), - * it is your responsibility to wrap all - * non-atomic operations with `underlying.synchronized`. - * This includes `get`, as `java.util.Map`'s API does not allow for an - * atomic `get` when `null` values may be present. - * - * @param m The `Map` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Map` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala mutable `Map`. + * @see [[mapAsScalaMap]] */ implicit def mapAsScalaMapConverter[A, B](m : ju.Map[A, B]): AsScala[mutable.Map[A, B]] = new AsScala(mapAsScalaMap(m)) /** - * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` - * to a Scala mutable `concurrent.Map`. The returned Scala `concurrent.Map` is - * backed by the provided Java `ConcurrentMap` and any side-effects of using - * it via the Scala interface will be visible via the Java interface and - * vice versa. - * - * If the Java `ConcurrentMap` was previously obtained from an implicit or - * explicit call of `mapAsScalaConcurrentMap(scala.collection.mutable.ConcurrentMap)` - * then the original Scala `concurrent.Map` will be returned. - * - * @param m The `ConcurrentMap` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `concurrent.Map` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` to a Scala mutable `concurrent.Map`. + * @see [[mapAsScalaConcurrentMap]] */ implicit def mapAsScalaConcurrentMapConverter[A, B](m: juc.ConcurrentMap[A, B]): AsScala[concurrent.Map[A, B]] = new AsScala(mapAsScalaConcurrentMap(m)) /** - * Adds an `asScala` method that implicitly converts a Java `Dictionary` - * to a Scala mutable `Map[String, String]`. The returned Scala - * `Map[String, String]` is backed by the provided Java `Dictionary` and - * any side-effects of using it via the Scala interface will be visible via - * the Java interface and vice versa. - * - * @param p The `Dictionary` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Map[String, String]` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Dictionary` to a Scala mutable `Map`. + * @see [[dictionaryAsScalaMap]] */ implicit def dictionaryAsScalaMapConverter[A, B](p: ju.Dictionary[A, B]): AsScala[mutable.Map[A, B]] = new AsScala(dictionaryAsScalaMap(p)) /** - * Adds an `asScala` method that implicitly converts a Java `Properties` - * to a Scala mutable `Map[String, String]`. The returned Scala - * `Map[String, String]` is backed by the provided Java `Properties` and - * any side-effects of using it via the Scala interface will be visible via - * the Java interface and vice versa. - * - * @param p The `Properties` to be converted. - * @return An object with an `asScala` method that returns a Scala mutable - * `Map[String, String]` view of the argument. + * Adds an `asScala` method that implicitly converts a Java `Properties` to a Scala mutable `Map[String, String]`. + * @see [[propertiesAsScalaMap]] */ implicit def propertiesAsScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] = new AsScala(propertiesAsScalaMap(p)) diff --git a/src/library/scala/collection/convert/Decorators.scala b/src/library/scala/collection/convert/Decorators.scala index d232fa04e1..3e45a02254 100644 --- a/src/library/scala/collection/convert/Decorators.scala +++ b/src/library/scala/collection/convert/Decorators.scala @@ -12,7 +12,7 @@ package convert import java.{ util => ju } -private[collection] trait Decorators { +private[collection] object Decorators { /** Generic class containing the `asJava` converter method */ class AsJava[A](op: => A) { /** Converts a Scala collection to the corresponding Java collection */ @@ -28,20 +28,18 @@ private[collection] trait Decorators { /** Generic class containing the `asJavaCollection` converter method */ class AsJavaCollection[A](i: Iterable[A]) { /** Converts a Scala `Iterable` to a Java `Collection` */ - def asJavaCollection: ju.Collection[A] = JavaConversions.asJavaCollection(i) + def asJavaCollection: ju.Collection[A] = JavaConverters.asJavaCollection(i) } /** Generic class containing the `asJavaEnumeration` converter method */ class AsJavaEnumeration[A](i: Iterator[A]) { /** Converts a Scala `Iterator` to a Java `Enumeration` */ - def asJavaEnumeration: ju.Enumeration[A] = JavaConversions.asJavaEnumeration(i) + def asJavaEnumeration: ju.Enumeration[A] = JavaConverters.asJavaEnumeration(i) } /** Generic class containing the `asJavaDictionary` converter method */ class AsJavaDictionary[A, B](m : mutable.Map[A, B]) { /** Converts a Scala `Map` to a Java `Dictionary` */ - def asJavaDictionary: ju.Dictionary[A, B] = JavaConversions.asJavaDictionary(m) + def asJavaDictionary: ju.Dictionary[A, B] = JavaConverters.asJavaDictionary(m) } } - -private[collection] object Decorators extends Decorators diff --git a/src/library/scala/collection/convert/ImplicitConversions.scala b/src/library/scala/collection/convert/ImplicitConversions.scala new file mode 100644 index 0000000000..35e6ce1616 --- /dev/null +++ b/src/library/scala/collection/convert/ImplicitConversions.scala @@ -0,0 +1,171 @@ +/* __ *\ +** ________ ___ / / ___ Scala API ** +** / __/ __// _ | / / / _ | (c) 2006-2016, LAMP/EPFL ** +** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** +** /____/\___/_/ |_/____/_/ | | ** +** |/ ** +\* */ + +package scala +package collection +package convert + +import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } +import scala.language.implicitConversions + +import JavaConverters._ + +/** Defines implicit converter methods from Java to Scala collections. */ +trait ToScalaImplicits { + /** Implicitly converts a Java `Iterator` to a Scala `Iterator`. + * @see [[AsScalaConverters.asScalaIterator]] + */ + implicit def `iterator asScala`[A](it: ju.Iterator[A]): Iterator[A] = asScalaIterator(it) + + /** Implicitly converts a Java `Enumeration` to a Scala `Iterator`. + * @see [[AsScalaConverters.enumerationAsScalaIterator]] + */ + implicit def `enumeration AsScalaIterator`[A](i: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(i) + + /** Implicitly converts a Java `Iterable` to a Scala `Iterable`. + * @see [[AsScalaConverters.iterableAsScalaIterable]] + */ + implicit def `iterable AsScalaIterable`[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i) + + /** Implicitly converts a Java `Collection` to an Scala `Iterable`. + * @see [[AsScalaConverters.collectionAsScalaIterable]] + */ + implicit def `collection AsScalaIterable`[A](i: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(i) + + /** Implicitly converts a Java `List` to a Scala mutable `Buffer`. + * @see [[AsScalaConverters.asScalaBuffer]] + */ + implicit def `list asScalaBuffer`[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l) + + /** Implicitly converts a Java `Set` to a Scala mutable `Set`. + * @see [[AsScalaConverters.asScalaSet]] + */ + implicit def `set asScala`[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s) + + /** Implicitly converts a Java `Map` to a Scala mutable `Map`. + * @see [[AsScalaConverters.mapAsScalaMap]] + */ + implicit def `map AsScala`[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m) + + /** Implicitly converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`. + * @see [[AsScalaConverters.mapAsScalaConcurrentMap]] + */ + implicit def `map AsScalaConcurrentMap`[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m) + + /** Implicitly converts a Java `Dictionary` to a Scala mutable `Map`. + * @see [[AsScalaConverters.dictionaryAsScalaMap]] + */ + implicit def `dictionary AsScalaMap`[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(p) + + /** Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`. + * @see [[AsScalaConverters.propertiesAsScalaMap]] + */ + implicit def `properties AsScalaMap`(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) +} + +/** Defines implicit conversions from Scala to Java collections. */ +trait ToJavaImplicits { + /** Implicitly converts a Scala `Iterator` to a Java `Iterator`. + * @see [[AsJavaConverters.asJavaIterator]] + */ + implicit def `iterator asJava`[A](it: Iterator[A]): ju.Iterator[A] = asJavaIterator(it) + + /** Implicitly converts a Scala `Iterator` to a Java `Enumeration`. + * @see [[AsJavaConverters.asJavaEnumeration]] + */ + implicit def `enumeration asJava`[A](it: Iterator[A]): ju.Enumeration[A] = asJavaEnumeration(it) + + /** Implicitly converts a Scala `Iterable` to a Java `Iterable`. + * @see [[AsJavaConverters.asJavaIterable]] + */ + implicit def `iterable asJava`[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i) + + /** Implicitly converts a Scala `Iterable` to an immutable Java `Collection`. + * @see [[AsJavaConverters.asJavaCollection]] + */ + implicit def `collection asJava`[A](it: Iterable[A]): ju.Collection[A] = asJavaCollection(it) + + /** Implicitly converts a Scala mutable `Buffer` to a Java `List`. + * @see [[AsJavaConverters.bufferAsJavaList]] + */ + implicit def `buffer AsJavaList`[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b) + + /** Implicitly converts a Scala mutable `Seq` to a Java `List`. + * @see [[AsJavaConverters.mutableSeqAsJavaList]] + */ + implicit def `mutableSeq AsJavaList`[A](seq: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(seq) + + /** Implicitly converts a Scala `Seq` to a Java `List`. + * @see [[AsJavaConverters.seqAsJavaList]] + */ + implicit def `seq AsJavaList`[A](seq: Seq[A]): ju.List[A] = seqAsJavaList(seq) + + /** Implicitly converts a Scala mutable `Set` to a Java `Set`. + * @see [[AsJavaConverters.mutableSetAsJavaSet]] + */ + implicit def `mutableSet AsJavaSet`[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s) + + /** Implicitly converts a Scala `Set` to a Java `Set`. + * @see [[AsJavaConverters.setAsJavaSet]] + */ + implicit def `set AsJavaSet`[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s) + + /** Implicitly converts a Scala mutable `Map` to a Java `Map`. + * @see [[AsJavaConverters.mutableMapAsJavaMap]] + */ + implicit def `mutableMap AsJavaMap`[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap(m) + + /** Implicitly converts a Scala mutable `Map` to a Java `Dictionary`. + * @see [[AsJavaConverters.asJavaDictionary]] + */ + implicit def `dictionary asJava`[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = asJavaDictionary(m) + + /** Implicitly converts a Scala `Map` to a Java `Map`. + * @see [[AsJavaConverters.mapAsJavaMap]] + */ + implicit def `map AsJavaMap`[A, B](m: Map[A, B]): ju.Map[A, B] = mapAsJavaMap(m) + + /** Implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`. + * @see [[AsJavaConverters.mapAsJavaConcurrentMap]] + */ + implicit def `map AsJavaConcurrentMap`[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = mapAsJavaConcurrentMap(m) +} + +/** + * Convenience for miscellaneous implicit conversions from Scala to Java collections API. + * + * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead. + * Implicit conversions may cause unexpected issues, see [[ImplicitConversions]]. + */ +object ImplicitConversionsToJava extends ToJavaImplicits + +/** + * Convenience for miscellaneous implicit conversions from Java to Scala collections API. + * + * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead. + * Implicit conversions may cause unexpected issues, see [[ImplicitConversions]]. + */ +object ImplicitConversionsToScala extends ToScalaImplicits + +/** + * Convenience for miscellaneous implicit conversions between Java and Scala collections API. + * + * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead. + * Implicit conversions may cause unexpected issues. Example: + * + * {{{ + * import collection.convert.ImplicitConversions._ + * case class StringBox(s: String) + * val m = Map(StringBox("one") -> "uno") + * m.get("one") + * }}} + * + * The above example returns `null` instead of producing a type error at compile-time. The map is + * implicitly converted to a `java.util.Map` which provides a method `get(x: AnyRef)`. + */ +object ImplicitConversions extends ToScalaImplicits with ToJavaImplicits diff --git a/src/library/scala/collection/convert/WrapAsJava.scala b/src/library/scala/collection/convert/WrapAsJava.scala index 9916fe9843..e3a064b79d 100644 --- a/src/library/scala/collection/convert/WrapAsJava.scala +++ b/src/library/scala/collection/convert/WrapAsJava.scala @@ -13,7 +13,27 @@ package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import scala.language.implicitConversions -trait WrapAsJava { +@deprecated("use JavaConverters or consider ToJavaImplicits", since="2.12.0") +trait WrapAsJava extends LowPriorityWrapAsJava { + // provide higher-priority implicits with names that don't exist in JavaConverters for the case + // when importing both JavaConverters._ and JavaConversions._. otherwise implicit conversions + // would not apply, see https://github.com/scala/scala/pull/5109#issuecomment-212417789 + implicit def `deprecated asJavaIterator`[A](it: Iterator[A]): ju.Iterator[A] = asJavaIterator(it) + implicit def `deprecated asJavaEnumeration`[A](it: Iterator[A]): ju.Enumeration[A] = asJavaEnumeration(it) + implicit def `deprecated asJavaIterable`[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i) + implicit def `deprecated asJavaCollection`[A](it: Iterable[A]): ju.Collection[A] = asJavaCollection(it) + implicit def `deprecated bufferAsJavaList`[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b) + implicit def `deprecated mutableSeqAsJavaList`[A](seq: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(seq) + implicit def `deprecated seqAsJavaList`[A](seq: Seq[A]): ju.List[A] = seqAsJavaList(seq) + implicit def `deprecated mutableSetAsJavaSet`[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s) + implicit def `deprecated setAsJavaSet`[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s) + implicit def `deprecated mutableMapAsJavaMap`[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = mutableMapAsJavaMap(m) + implicit def `deprecated asJavaDictionary`[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = asJavaDictionary(m) + implicit def `deprecated mapAsJavaMap`[A, B](m: Map[A, B]): ju.Map[A, B] = mapAsJavaMap(m) + implicit def `deprecated mapAsJavaConcurrentMap`[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = mapAsJavaConcurrentMap(m) +} + +private[convert] trait LowPriorityWrapAsJava { import Wrappers._ /** @@ -30,8 +50,9 @@ trait WrapAsJava { * @return A Java Iterator view of the argument. */ implicit def asJavaIterator[A](it: Iterator[A]): ju.Iterator[A] = it match { - case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] - case _ => IteratorWrapper(it) + case null => null + case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] + case _ => IteratorWrapper(it) } /** @@ -48,8 +69,9 @@ trait WrapAsJava { * @return A Java Enumeration view of the argument. */ implicit def asJavaEnumeration[A](it: Iterator[A]): ju.Enumeration[A] = it match { + case null => null case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]] - case _ => IteratorWrapper(it) + case _ => IteratorWrapper(it) } /** @@ -66,8 +88,9 @@ trait WrapAsJava { * @return A Java Iterable view of the argument. */ implicit def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match { - case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] - case _ => IterableWrapper(i) + case null => null + case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] + case _ => IterableWrapper(i) } /** @@ -82,8 +105,9 @@ trait WrapAsJava { * @return A Java Collection view of the argument. */ implicit def asJavaCollection[A](it: Iterable[A]): ju.Collection[A] = it match { - case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] - case _ => new IterableWrapper(it) + case null => null + case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] + case _ => new IterableWrapper(it) } /** @@ -100,8 +124,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = b match { - case JListWrapper(wrapped) => wrapped - case _ => new MutableBufferWrapper(b) + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableBufferWrapper(b) } /** @@ -118,8 +143,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def mutableSeqAsJavaList[A](seq: mutable.Seq[A]): ju.List[A] = seq match { - case JListWrapper(wrapped) => wrapped - case _ => new MutableSeqWrapper(seq) + case null => null + case JListWrapper(wrapped) => wrapped + case _ => new MutableSeqWrapper(seq) } /** @@ -136,8 +162,9 @@ trait WrapAsJava { * @return A Java List view of the argument. */ implicit def seqAsJavaList[A](seq: Seq[A]): ju.List[A] = seq match { - case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] - case _ => new SeqWrapper(seq) + case null => null + case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] + case _ => new SeqWrapper(seq) } /** @@ -154,8 +181,9 @@ trait WrapAsJava { * @return A Java Set view of the argument. */ implicit def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = s match { + case null => null case JSetWrapper(wrapped) => wrapped - case _ => new MutableSetWrapper(s) + case _ => new MutableSetWrapper(s) } /** @@ -172,8 +200,9 @@ trait WrapAsJava { * @return A Java Set view of the argument. */ implicit def setAsJavaSet[A](s: Set[A]): ju.Set[A] = s match { + case null => null case JSetWrapper(wrapped) => wrapped - case _ => new SetWrapper(s) + case _ => new SetWrapper(s) } /** @@ -190,9 +219,9 @@ trait WrapAsJava { * @return A Java Map view of the argument. */ implicit def mutableMapAsJavaMap[A, B](m: mutable.Map[A, B]): ju.Map[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped + case null => null case JMapWrapper(wrapped) => wrapped - case _ => new MutableMapWrapper(m) + case _ => new MutableMapWrapper(m) } /** @@ -210,9 +239,9 @@ trait WrapAsJava { * @return A Java `Dictionary` view of the argument. */ implicit def asJavaDictionary[A, B](m: mutable.Map[A, B]): ju.Dictionary[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped - case JDictionaryWrapper(wrapped) => wrapped - case _ => new DictionaryWrapper(m) + case null => null + case JDictionaryWrapper(wrapped) => wrapped + case _ => new DictionaryWrapper(m) } /** @@ -230,9 +259,9 @@ trait WrapAsJava { * @return A Java `Map` view of the argument. */ implicit def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match { - //case JConcurrentMapWrapper(wrapped) => wrapped + case null => null case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]] - case _ => new MapWrapper(m) + case _ => new MapWrapper(m) } /** @@ -251,9 +280,11 @@ trait WrapAsJava { * @return A Java `ConcurrentMap` view of the argument. */ implicit def mapAsJavaConcurrentMap[A, B](m: concurrent.Map[A, B]): juc.ConcurrentMap[A, B] = m match { + case null => null case JConcurrentMapWrapper(wrapped) => wrapped - case _ => new ConcurrentMapWrapper(m) + case _ => new ConcurrentMapWrapper(m) } } -object WrapAsJava extends WrapAsJava { } +@deprecated("use JavaConverters or consider ImplicitConversionsToJava", since="2.12.0") +object WrapAsJava extends WrapAsJava diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala index ab151a6778..fbaafde798 100644 --- a/src/library/scala/collection/convert/WrapAsScala.scala +++ b/src/library/scala/collection/convert/WrapAsScala.scala @@ -13,8 +13,26 @@ package convert import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import scala.language.implicitConversions -trait WrapAsScala { +@deprecated("use JavaConverters or consider ToScalaImplicits", since="2.12.0") +trait WrapAsScala extends LowPriorityWrapAsScala { + // provide higher-priority implicits with names that don't exist in JavaConverters for the case + // when importing both JavaConverters._ and JavaConversions._. otherwise implicit conversions + // would not apply, see https://github.com/scala/scala/pull/5109#issuecomment-212417789 + implicit def `deprecated asScalaIterator`[A](it: ju.Iterator[A]): Iterator[A] = asScalaIterator(it) + implicit def `deprecated enumerationAsScalaIterator`[A](i: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(i) + implicit def `deprecated iterableAsScalaIterable`[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i) + implicit def `deprecated collectionAsScalaIterable`[A](i: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(i) + implicit def `deprecated asScalaBuffer`[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l) + implicit def `deprecated asScalaSet`[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s) + implicit def `deprecated mapAsScalaMap`[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m) + implicit def `deprecated mapAsScalaConcurrentMap`[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m) + implicit def `deprecated dictionaryAsScalaMap`[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(p) + implicit def `deprecated propertiesAsScalaMap`(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p) +} + +private[convert] trait LowPriorityWrapAsScala { import Wrappers._ + /** * Implicitly converts a Java `Iterator` to a Scala `Iterator`. * @@ -30,8 +48,9 @@ trait WrapAsScala { * @return A Scala `Iterator` view of the argument. */ implicit def asScalaIterator[A](it: ju.Iterator[A]): Iterator[A] = it match { + case null => null case IteratorWrapper(wrapped) => wrapped - case _ => JIteratorWrapper(it) + case _ => JIteratorWrapper(it) } /** @@ -48,8 +67,9 @@ trait WrapAsScala { * @return A Scala Iterator view of the argument. */ implicit def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = i match { + case null => null case IteratorWrapper(wrapped) => wrapped - case _ => JEnumerationWrapper(i) + case _ => JEnumerationWrapper(i) } /** @@ -67,8 +87,9 @@ trait WrapAsScala { * @return A Scala Iterable view of the argument. */ implicit def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = i match { + case null => null case IterableWrapper(wrapped) => wrapped - case _ => JIterableWrapper(i) + case _ => JIterableWrapper(i) } /** @@ -82,8 +103,9 @@ trait WrapAsScala { * @return A Scala Iterable view of the argument. */ implicit def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = i match { + case null => null case IterableWrapper(wrapped) => wrapped - case _ => JCollectionWrapper(i) + case _ => JCollectionWrapper(i) } /** @@ -101,8 +123,9 @@ trait WrapAsScala { * @return A Scala mutable `Buffer` view of the argument. */ implicit def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = l match { - case MutableBufferWrapper(wrapped) => wrapped - case _ =>new JListWrapper(l) + case null => null + case MutableBufferWrapper(wrapped) => wrapped + case _ => new JListWrapper(l) } /** @@ -119,8 +142,9 @@ trait WrapAsScala { * @return A Scala mutable Set view of the argument. */ implicit def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = s match { + case null => null case MutableSetWrapper(wrapped) => wrapped - case _ =>new JSetWrapper(s) + case _ => new JSetWrapper(s) } /** @@ -133,20 +157,20 @@ trait WrapAsScala { * If the Java `Map` was previously obtained from an implicit or * explicit call of `mapAsScalaMap(scala.collection.mutable.Map)` then * the original Scala Map will be returned. - * + * * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), - * it is your responsibility to wrap all + * it is your responsibility to wrap all * non-atomic operations with `underlying.synchronized`. * This includes `get`, as `java.util.Map`'s API does not allow for an * atomic `get` when `null` values may be present. - * + * * @param m The Map to be converted. * @return A Scala mutable Map view of the argument. */ implicit def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = m match { - //case ConcurrentMapWrapper(wrapped) => wrapped + case null => null case MutableMapWrapper(wrapped) => wrapped - case _ => new JMapWrapper(m) + case _ => new JMapWrapper(m) } /** @@ -163,24 +187,26 @@ trait WrapAsScala { * @return A Scala mutable ConcurrentMap view of the argument. */ implicit def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = m match { - case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying - case _ => new JConcurrentMapWrapper(m) + case null => null + case cmw: ConcurrentMapWrapper[_, _] => cmw.underlying + case _ => new JConcurrentMapWrapper(m) } /** * Implicitly converts a Java `Dictionary` to a Scala mutable - * `Map[String, String]`. + * `Map`. * - * The returned Scala `Map[String, String]` is backed by the provided Java + * The returned Scala `Map` is backed by the provided Java * `Dictionary` and any side-effects of using it via the Scala interface * will be visible via the Java interface and vice versa. * * @param p The Dictionary to be converted. - * @return A Scala mutable Map[String, String] view of the argument. + * @return A Scala mutable Map view of the argument. */ implicit def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match { + case null => null case DictionaryWrapper(wrapped) => wrapped - case _ => new JDictionaryWrapper(p) + case _ => new JDictionaryWrapper(p) } /** @@ -194,8 +220,10 @@ trait WrapAsScala { * @return A Scala mutable Map[String, String] view of the argument. */ implicit def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = p match { - case _ => new JPropertiesWrapper(p) + case null => null + case _ => new JPropertiesWrapper(p) } } -object WrapAsScala extends WrapAsScala { } +@deprecated("use JavaConverters or consider ImplicitConversionsToScala", since="2.12.0") +object WrapAsScala extends WrapAsScala diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala index e829a0215b..9f7e3e8174 100644 --- a/src/library/scala/collection/convert/Wrappers.scala +++ b/src/library/scala/collection/convert/Wrappers.scala @@ -14,10 +14,7 @@ import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc } import WrapAsScala._ import WrapAsJava._ -/** Don't put the implementations in the same scope as the implicits - * which utilize them, or they will stow away into every scope which - * extends one of those implementations. See SI-5580. - */ +/** Adapters for Java/Scala collections API. */ private[collection] trait Wrappers { trait IterableWrapperTrait[A] extends ju.AbstractCollection[A] { val underlying: Iterable[A] @@ -31,7 +28,7 @@ private[collection] trait Wrappers { def next() = underlying.next() def hasMoreElements = underlying.hasNext def nextElement() = underlying.next() - def remove() = throw new UnsupportedOperationException + override def remove() = throw new UnsupportedOperationException } class ToIteratorWrapper[A](underlying : Iterator[A]) { @@ -102,9 +99,9 @@ private[collection] trait Wrappers { override def clone(): JListWrapper[A] = JListWrapper(new ju.ArrayList[A](underlying)) } - // Note various overrides to avoid performance gotchas. - class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] { - self => + @SerialVersionUID(1L) + class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] with Serializable { self => + // Note various overrides to avoid performance gotchas. override def contains(o: Object): Boolean = { try { underlying.contains(o.asInstanceOf[A]) } catch { case cce: ClassCastException => false } @@ -116,7 +113,7 @@ private[collection] trait Wrappers { var prev: Option[A] = None def hasNext = ui.hasNext def next = { val e = ui.next(); prev = Some(e); e } - def remove = prev match { + override def remove() = prev match { case Some(e) => underlying match { case ms: mutable.Set[a] => @@ -165,7 +162,8 @@ private[collection] trait Wrappers { new JSetWrapper[A](new ju.LinkedHashSet[A](underlying)) } - class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] { self => + @SerialVersionUID(1L) + class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] with Serializable { self => override def size = underlying.size override def get(key: AnyRef): B = try { @@ -202,7 +200,7 @@ private[collection] trait Wrappers { } } - def remove() { + override def remove() { prev match { case Some(k) => underlying match { @@ -295,24 +293,24 @@ private[collection] trait Wrappers { class ConcurrentMapWrapper[A, B](override val underlying: concurrent.Map[A, B]) extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { - def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { + override def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { case Some(v) => v case None => null.asInstanceOf[B] } - def remove(k: AnyRef, v: AnyRef) = try { + override def remove(k: AnyRef, v: AnyRef) = try { underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B]) } catch { case ex: ClassCastException => false } - def replace(k: A, v: B): B = underlying.replace(k, v) match { + override def replace(k: A, v: B): B = underlying.replace(k, v) match { case Some(v) => v case None => null.asInstanceOf[B] } - def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) + override def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) } /** Wraps a concurrent Java map as a Scala one. Single-element concurrent diff --git a/src/library/scala/collection/convert/package.scala b/src/library/scala/collection/convert/package.scala index 13970f9a3e..810d112cd5 100644 --- a/src/library/scala/collection/convert/package.scala +++ b/src/library/scala/collection/convert/package.scala @@ -10,10 +10,17 @@ package scala package collection package object convert { + @deprecated("use JavaConverters", since="2.12.0") val decorateAsJava = new DecorateAsJava { } + @deprecated("use JavaConverters", since="2.12.0") val decorateAsScala = new DecorateAsScala { } - val decorateAll = new DecorateAsJava with DecorateAsScala { } + @deprecated("use JavaConverters", since="2.12.0") + val decorateAll = JavaConverters + + @deprecated("use JavaConverters or consider ImplicitConversionsToJava", since="2.12.0") val wrapAsJava = new WrapAsJava { } + @deprecated("use JavaConverters or consider ImplicitConversionsToScala", since="2.12.0") val wrapAsScala = new WrapAsScala { } + @deprecated("use JavaConverters or consider ImplicitConversions", since="2.12.0") val wrapAll = new WrapAsJava with WrapAsScala { } } diff --git a/src/library/scala/collection/generic/BitOperations.scala b/src/library/scala/collection/generic/BitOperations.scala index d430ece2f5..2f460eee1f 100644 --- a/src/library/scala/collection/generic/BitOperations.scala +++ b/src/library/scala/collection/generic/BitOperations.scala @@ -26,16 +26,7 @@ private[collection] object BitOperations { def complement(i: Int) = (-1) ^ i def bits(num: Int) = 31 to 0 by -1 map (i => (num >>> i & 1) != 0) def bitString(num: Int, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep - - def highestOneBit(j: Int) = { - var i = j - i |= (i >> 1) - i |= (i >> 2) - i |= (i >> 4) - i |= (i >> 8) - i |= (i >> 16) - i - (i >>> 1) - } + def highestOneBit(j: Int) = java.lang.Integer.highestOneBit(j) } object Int extends Int @@ -49,17 +40,7 @@ private[collection] object BitOperations { def complement(i: Long) = (-1L) ^ i def bits(num: Long) = 63L to 0L by -1L map (i => (num >>> i & 1L) != 0L) def bitString(num: Long, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep - - def highestOneBit(j: Long) = { - var i = j - i |= (i >> 1) - i |= (i >> 2) - i |= (i >> 4) - i |= (i >> 8) - i |= (i >> 16) - i |= (i >> 32) - i - (i >>> 1) - } + def highestOneBit(j: Long) = java.lang.Long.highestOneBit(j) } object Long extends Long } diff --git a/src/library/scala/collection/generic/GenSetFactory.scala b/src/library/scala/collection/generic/GenSetFactory.scala index 800f66eb53..65404a4991 100644 --- a/src/library/scala/collection/generic/GenSetFactory.scala +++ b/src/library/scala/collection/generic/GenSetFactory.scala @@ -40,7 +40,11 @@ abstract class GenSetFactory[CC[X] <: GenSet[X] with GenSetLike[X, CC[X]]] /** $setCanBuildFromInfo */ def setCanBuildFrom[A] = new CanBuildFrom[CC[_], A, CC[A]] { - def apply(from: CC[_]) = newBuilder[A] + def apply(from: CC[_]) = from match { + // When building from an existing Set, try to preserve its type: + case from: Set[_] => from.genericBuilder.asInstanceOf[Builder[A, CC[A]]] + case _ => newBuilder[A] + } def apply() = newBuilder[A] } } diff --git a/src/library/scala/collection/generic/GenTraversableFactory.scala b/src/library/scala/collection/generic/GenTraversableFactory.scala index 2092c0c5f5..7c2aa5615c 100644 --- a/src/library/scala/collection/generic/GenTraversableFactory.scala +++ b/src/library/scala/collection/generic/GenTraversableFactory.scala @@ -229,7 +229,7 @@ extends GenericCompanion[CC] { /** Produces a $coll containing repeated applications of a function to a start value. * * @param start the start value of the $coll - * @param len the number of elements contained inthe $coll + * @param len the number of elements contained in the $coll * @param f the function that's repeatedly applied * @return a $coll with `len` values in the sequence `start, f(start), f(f(start)), ...` */ diff --git a/src/library/scala/collection/generic/GenericParTemplate.scala b/src/library/scala/collection/generic/GenericParTemplate.scala index b9b7043270..44a778a953 100644 --- a/src/library/scala/collection/generic/GenericParTemplate.scala +++ b/src/library/scala/collection/generic/GenericParTemplate.scala @@ -13,7 +13,6 @@ package generic import scala.collection.parallel.Combiner import scala.collection.parallel.ParIterable import scala.collection.parallel.ParMap -import scala.collection.parallel.TaskSupport import scala.annotation.unchecked.uncheckedVariance import scala.language.higherKinds diff --git a/src/library/scala/collection/generic/IterableForwarder.scala b/src/library/scala/collection/generic/IterableForwarder.scala index 7387dbe667..7f6eb6e131 100644 --- a/src/library/scala/collection/generic/IterableForwarder.scala +++ b/src/library/scala/collection/generic/IterableForwarder.scala @@ -26,7 +26,7 @@ import scala.collection._ * @version 2.8 * @since 2.8 */ -@deprecated("Forwarding is inherently unreliable since it is not automated and methods can be forgotten.", "2.11.0") +@deprecated("forwarding is inherently unreliable since it is not automated and methods can be forgotten", "2.11.0") trait IterableForwarder[+A] extends Iterable[A] with TraversableForwarder[A] { /** The iterable object to which calls are forwarded */ diff --git a/src/library/scala/collection/generic/MapFactory.scala b/src/library/scala/collection/generic/MapFactory.scala index b9f3d4b010..255d695303 100644 --- a/src/library/scala/collection/generic/MapFactory.scala +++ b/src/library/scala/collection/generic/MapFactory.scala @@ -10,8 +10,6 @@ package scala package collection package generic - -import mutable.{Builder, MapBuilder} import scala.language.higherKinds /** A template for companion objects of `Map` and subclasses thereof. diff --git a/src/library/scala/collection/generic/MutableSortedMapFactory.scala b/src/library/scala/collection/generic/MutableSortedMapFactory.scala new file mode 100644 index 0000000000..b6fa933ca8 --- /dev/null +++ b/src/library/scala/collection/generic/MutableSortedMapFactory.scala @@ -0,0 +1,24 @@ +package scala +package collection +package generic + +import scala.language.higherKinds + +/** + * A template for companion objects of `SortedMap` and subclasses thereof. + * + * @tparam CC the type of the collection. + * + * @author Rui Gonçalves + * @since 2.12 + * @version 2.12 + * + * @define Coll `mutable.SortedMap` + * @define coll mutable sorted map + * @define factoryInfo + * This object provides a set of operations needed to create sorted maps of type `$Coll`. + * @define sortedMapCanBuildFromInfo + * The standard `CanBuildFrom` instance for sorted maps + */ +abstract class MutableSortedMapFactory[CC[A, B] <: mutable.SortedMap[A, B] with SortedMapLike[A, B, CC[A, B]]] + extends SortedMapFactory[CC] diff --git a/src/library/scala/collection/generic/ParFactory.scala b/src/library/scala/collection/generic/ParFactory.scala index 4486cea419..901e9fc239 100644 --- a/src/library/scala/collection/generic/ParFactory.scala +++ b/src/library/scala/collection/generic/ParFactory.scala @@ -11,7 +11,6 @@ package collection package generic import scala.collection.parallel.ParIterable -import scala.collection.parallel.Combiner import scala.language.higherKinds /** A template class for companion objects of `ParIterable` and subclasses diff --git a/src/library/scala/collection/generic/ParSetFactory.scala b/src/library/scala/collection/generic/ParSetFactory.scala index 4320635ae6..1341ddcb38 100644 --- a/src/library/scala/collection/generic/ParSetFactory.scala +++ b/src/library/scala/collection/generic/ParSetFactory.scala @@ -10,7 +10,6 @@ package scala package collection package generic -import scala.collection.mutable.Builder import scala.collection.parallel.Combiner import scala.collection.parallel.ParSet import scala.collection.parallel.ParSetLike diff --git a/src/library/scala/collection/generic/SeqForwarder.scala b/src/library/scala/collection/generic/SeqForwarder.scala index e21e2ea016..cee93d2ddb 100644 --- a/src/library/scala/collection/generic/SeqForwarder.scala +++ b/src/library/scala/collection/generic/SeqForwarder.scala @@ -25,7 +25,7 @@ import scala.collection.immutable.Range * @version 2.8 * @since 2.8 */ -@deprecated("Forwarding is inherently unreliable since it is not automated and new methods can be forgotten.", "2.11.0") +@deprecated("forwarding is inherently unreliable since it is not automated and new methods can be forgotten", "2.11.0") trait SeqForwarder[+A] extends Seq[A] with IterableForwarder[A] { protected override def underlying: Seq[A] diff --git a/src/library/scala/collection/generic/SetFactory.scala b/src/library/scala/collection/generic/SetFactory.scala index fcd8d00c18..5e50844cc9 100644 --- a/src/library/scala/collection/generic/SetFactory.scala +++ b/src/library/scala/collection/generic/SetFactory.scala @@ -12,7 +12,6 @@ package scala package collection package generic -import mutable.Builder import scala.language.higherKinds abstract class SetFactory[CC[X] <: Set[X] with SetLike[X, CC[X]]] diff --git a/src/library/scala/collection/generic/TraversableForwarder.scala b/src/library/scala/collection/generic/TraversableForwarder.scala index 359ea402b6..b94507d6ef 100644 --- a/src/library/scala/collection/generic/TraversableForwarder.scala +++ b/src/library/scala/collection/generic/TraversableForwarder.scala @@ -27,7 +27,7 @@ import scala.reflect.ClassTag * @version 2.8 * @since 2.8 */ -@deprecated("Forwarding is inherently unreliable since it is not automated and new methods can be forgotten.", "2.11.0") +@deprecated("forwarding is inherently unreliable since it is not automated and new methods can be forgotten", "2.11.0") trait TraversableForwarder[+A] extends Traversable[A] { /** The traversable object to which calls are forwarded. */ protected def underlying: Traversable[A] diff --git a/src/library/scala/collection/generic/package.scala b/src/library/scala/collection/generic/package.scala index 1beb4a8599..015c3455db 100644 --- a/src/library/scala/collection/generic/package.scala +++ b/src/library/scala/collection/generic/package.scala @@ -1,6 +1,5 @@ package scala package collection -import generic.CanBuildFrom import scala.language.higherKinds diff --git a/src/library/scala/collection/immutable/BitSet.scala b/src/library/scala/collection/immutable/BitSet.scala index 70543aa3a6..ecf3326c7f 100644 --- a/src/library/scala/collection/immutable/BitSet.scala +++ b/src/library/scala/collection/immutable/BitSet.scala @@ -14,7 +14,7 @@ package immutable import generic._ import BitSetLike.{LogWL, updateArray} -import mutable.{ Builder, SetBuilder } +import mutable.Builder /** A class for immutable bitsets. * $bitsetinfo @@ -68,6 +68,8 @@ object BitSet extends BitSetFactory[BitSet] { /** The empty bitset */ val empty: BitSet = new BitSet1(0L) + private def createSmall(a: Long, b: Long): BitSet = if (b == 0L) new BitSet1(a) else new BitSet2(a, b) + /** A builder that takes advantage of mutable BitSets. */ def newBuilder: Builder[Int, BitSet] = new Builder[Int, BitSet] { private[this] val b = new mutable.BitSet @@ -84,7 +86,7 @@ object BitSet extends BitSetFactory[BitSet] { val len = elems.length if (len == 0) empty else if (len == 1) new BitSet1(elems(0)) - else if (len == 2) new BitSet2(elems(0), elems(1)) + else if (len == 2) createSmall(elems(0), elems(1)) else { val a = new Array[Long](len) Array.copy(elems, 0, a, 0, len) @@ -99,17 +101,24 @@ object BitSet extends BitSetFactory[BitSet] { val len = elems.length if (len == 0) empty else if (len == 1) new BitSet1(elems(0)) - else if (len == 2) new BitSet2(elems(0), elems(1)) + else if (len == 2) createSmall(elems(0), elems(1)) else new BitSetN(elems) } + @SerialVersionUID(2260107458435649300L) class BitSet1(val elems: Long) extends BitSet { protected def nwords = 1 protected def word(idx: Int) = if (idx == 0) elems else 0L protected def updateWord(idx: Int, w: Long): BitSet = if (idx == 0) new BitSet1(w) - else if (idx == 1) new BitSet2(elems, w) + else if (idx == 1) createSmall(elems, w) else fromBitMaskNoCopy(updateArray(Array(elems), idx, w)) + override def head: Int = + if (elems == 0L) throw new NoSuchElementException("Empty BitSet") + else java.lang.Long.numberOfTrailingZeros(elems) + override def tail: BitSet = + if (elems == 0L) throw new NoSuchElementException("Empty BitSet") + else new BitSet1(elems - java.lang.Long.lowestOneBit(elems)) } class BitSet2(val elems0: Long, elems1: Long) extends BitSet { @@ -117,8 +126,20 @@ object BitSet extends BitSetFactory[BitSet] { protected def word(idx: Int) = if (idx == 0) elems0 else if (idx == 1) elems1 else 0L protected def updateWord(idx: Int, w: Long): BitSet = if (idx == 0) new BitSet2(w, elems1) - else if (idx == 1) new BitSet2(elems0, w) + else if (idx == 1) createSmall(elems0, w) else fromBitMaskNoCopy(updateArray(Array(elems0, elems1), idx, w)) + override def head: Int = + if (elems0 == 0L) { + if (elems1 == 0) throw new NoSuchElementException("Empty BitSet") + 64 + java.lang.Long.numberOfTrailingZeros(elems1) + } + else java.lang.Long.numberOfTrailingZeros(elems0) + override def tail: BitSet = + if (elems0 == 0L) { + if (elems1 == 0L) throw new NoSuchElementException("Empty BitSet") + createSmall(elems0, elems1 - java.lang.Long.lowestOneBit(elems1)) + } + else new BitSet2(elems0 - java.lang.Long.lowestOneBit(elems0), elems1) } /** The implementing class for bit sets with elements >= 128 (exceeding @@ -131,5 +152,15 @@ object BitSet extends BitSetFactory[BitSet] { protected def nwords = elems.length protected def word(idx: Int) = if (idx < nwords) elems(idx) else 0L protected def updateWord(idx: Int, w: Long): BitSet = fromBitMaskNoCopy(updateArray(elems, idx, w)) + override def tail: BitSet = { + val n = nwords + var i = 0 + while (i < n) { + val wi = word(i) + if (wi != 0L) return fromBitMaskNoCopy(updateArray(elems, i, wi - java.lang.Long.lowestOneBit(wi))) + i += 1 + } + throw new NoSuchElementException("Empty BitSet") + } } } diff --git a/src/library/scala/collection/immutable/HashMap.scala b/src/library/scala/collection/immutable/HashMap.scala index 3e482f1369..627f723cb0 100644 --- a/src/library/scala/collection/immutable/HashMap.scala +++ b/src/library/scala/collection/immutable/HashMap.scala @@ -33,8 +33,7 @@ import parallel.immutable.ParHashMap * @define willNotTerminateInf */ @SerialVersionUID(2L) -@deprecatedInheritance("The implementation details of immutable hash maps make inheriting from them unwise.", "2.11.0") -class HashMap[A, +B] extends AbstractMap[A, B] +sealed class HashMap[A, +B] extends AbstractMap[A, B] with Map[A, B] with MapLike[A, B, HashMap[A, B]] with Serializable @@ -53,6 +52,9 @@ class HashMap[A, +B] extends AbstractMap[A, B] def get(key: A): Option[B] = get0(key, computeHash(key), 0) + override final def contains(key: A): Boolean = + contains0(key, computeHash(key), 0) + override def updated [B1 >: B] (key: A, value: B1): HashMap[A, B1] = updated0(key, computeHash(key), 0, value, null, null) @@ -65,6 +67,8 @@ class HashMap[A, +B] extends AbstractMap[A, B] def - (key: A): HashMap[A, B] = removed0(key, computeHash(key), 0) + override def tail: HashMap[A, B] = this - head._1 + override def filter(p: ((A, B)) => Boolean) = { val buffer = new Array[HashMap[A, B]](bufferSize(size)) nullToEmpty(filter0(p, false, 0, buffer, 0)) @@ -91,7 +95,7 @@ class HashMap[A, +B] extends AbstractMap[A, B] import HashMap.{Merger, MergeFunction, liftMerger} private[collection] def get0(key: A, hash: Int, level: Int): Option[B] = None - + protected def contains0(key: A, hash: Int, level: Int): Boolean = false private[collection] def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = new HashMap.HashMap1(key, hash, value, kv) @@ -156,7 +160,10 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), HashMap[A, B]] = new MapCanBuildFrom[A, B] def empty[A, B]: HashMap[A, B] = EmptyHashMap.asInstanceOf[HashMap[A, B]] - private object EmptyHashMap extends HashMap[Any, Nothing] { } + private object EmptyHashMap extends HashMap[Any, Nothing] { + override def head: (Any, Nothing) = throw new NoSuchElementException("Empty Map") + override def tail: HashMap[Any, Nothing] = throw new NoSuchElementException("Empty Map") + } // utility method to create a HashTrieMap from two leaf HashMaps (HashMap1 or HashMapCollision1) with non-colliding hash code) private def makeHashTrieMap[A, B](hash0:Int, elem0:HashMap[A, B], hash1:Int, elem1:HashMap[A, B], level:Int, size:Int) : HashTrieMap[A, B] = { @@ -181,6 +188,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + @deprecatedInheritance("This class will be made final in a future release.", "2.12.2") class HashMap1[A,+B](private[collection] val key: A, private[collection] val hash: Int, private[collection] val value: (B @uV), private[collection] var kv: (A,B @uV)) extends HashMap[A,B] { override def size = 1 @@ -191,6 +199,8 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def get0(key: A, hash: Int, level: Int): Option[B] = if (hash == this.hash && key == this.key) Some(value) else None + override protected def contains0(key: A, hash: Int, level: Int): Boolean = + hash == this.hash && key == this.key private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = if (hash == this.hash && key == this.key ) { if (merger eq null) { @@ -235,6 +245,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def get0(key: A, hash: Int, level: Int): Option[B] = if (hash == this.hash) kvs.get(key) else None + override protected def contains0(key: A, hash: Int, level: Int): Boolean = + hash == this.hash && kvs.contains(key) + private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = if (hash == this.hash) { if ((merger eq null) || !kvs.contains(key)) new HashMapCollision1(hash, kvs.updated(key, value)) @@ -290,6 +303,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { } } + @deprecatedInheritance("This class will be made final in a future release.", "2.12.2") class HashTrieMap[A, +B]( private[collection] val bitmap: Int, private[collection] val elems: Array[HashMap[A, B @uV]], @@ -302,21 +316,41 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def size = size0 override def get0(key: A, hash: Int, level: Int): Option[B] = { + // Note: this code is duplicated with `contains0` + val index = (hash >>> level) & 0x1f + if (bitmap == - 1) { + elems(index).get0(key, hash, level + 5) + } else { + val mask = (1 << index) + if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask - 1)) + elems(offset).get0(key, hash, level + 5) + } else { + None + } + } + } + + override protected def contains0(key: A, hash: Int, level: Int): Boolean = { + // Note: this code is duplicated from `get0` val index = (hash >>> level) & 0x1f - val mask = (1 << index) if (bitmap == - 1) { - elems(index & 0x1f).get0(key, hash, level + 5) - } else if ((bitmap & mask) != 0) { - val offset = Integer.bitCount(bitmap & (mask-1)) - elems(offset).get0(key, hash, level + 5) - } else - None + elems(index).contains0(key, hash, level + 5) + } else { + val mask = (1 << index) + if ((bitmap & mask) != 0) { + val offset = Integer.bitCount(bitmap & (mask - 1)) + elems(offset).contains0(key, hash, level + 5) + } else { + false + } + } } private[collection] override def updated0[B1 >: B](key: A, hash: Int, level: Int, value: B1, kv: (A, B1), merger: Merger[A, B1]): HashMap[A, B1] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) - val offset = Integer.bitCount(bitmap & (mask-1)) + val offset = Integer.bitCount(bitmap & (mask - 1)) if ((bitmap & mask) != 0) { val sub = elems(offset) val subNew = sub.updated0(key, hash, level + 5, value, kv, merger) @@ -338,7 +372,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int { override def removed0(key: A, hash: Int, level: Int): HashMap[A, B] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) - val offset = Integer.bitCount(bitmap & (mask-1)) + val offset = Integer.bitCount(bitmap & (mask - 1)) if ((bitmap & mask) != 0) { val sub = elems(offset) val subNew = sub.removed0(key, hash, level + 5) diff --git a/src/library/scala/collection/immutable/HashSet.scala b/src/library/scala/collection/immutable/HashSet.scala index 050e90b49b..fc937e3a22 100644 --- a/src/library/scala/collection/immutable/HashSet.scala +++ b/src/library/scala/collection/immutable/HashSet.scala @@ -31,8 +31,7 @@ import scala.annotation.tailrec * @define coll immutable hash set */ @SerialVersionUID(2L) -@deprecatedInheritance("The implementation details of immutable hash sets make inheriting from them unwise.", "2.11.0") -class HashSet[A] extends AbstractSet[A] +sealed class HashSet[A] extends AbstractSet[A] with Set[A] with GenericSetTemplate[A, HashSet] with SetLike[A, HashSet[A]] @@ -162,6 +161,8 @@ class HashSet[A] extends AbstractSet[A] def - (e: A): HashSet[A] = nullToEmpty(removed0(e, computeHash(e), 0)) + override def tail: HashSet[A] = this - head + override def filter(p: A => Boolean) = { val buffer = new Array[HashSet[A]](bufferSize(size)) nullToEmpty(filter0(p, false, 0, buffer, 0)) @@ -187,7 +188,7 @@ class HashSet[A] extends AbstractSet[A] protected def get0(key: A, hash: Int, level: Int): Boolean = false - def updated0(key: A, hash: Int, level: Int): HashSet[A] = + private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = new HashSet.HashSet1(key, hash) protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = this @@ -213,7 +214,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { /** $setCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HashSet[A]] = setCanBuildFrom[A] - private object EmptyHashSet extends HashSet[Any] { } + private object EmptyHashSet extends HashSet[Any] { + override def head: Any = throw new NoSuchElementException("Empty Set") + override def tail: HashSet[Any] = throw new NoSuchElementException("Empty Set") + } private[collection] def emptyInstance: HashSet[Any] = EmptyHashSet // utility method to create a HashTrieSet from two leaf HashSets (HashSet1 or HashSetCollision1) with non-colliding hash code) @@ -250,10 +254,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { class HashSet1[A](private[HashSet] val key: A, private[HashSet] val hash: Int) extends LeafHashSet[A] { override def size = 1 - override def get0(key: A, hash: Int, level: Int): Boolean = + override protected def get0(key: A, hash: Int, level: Int): Boolean = (hash == this.hash && key == this.key) - override def subsetOf0(that: HashSet[A], level: Int) = { + override protected def subsetOf0(that: HashSet[A], level: Int) = { // check if that contains this.key // we use get0 with our key and hash at the correct level instead of calling contains, // which would not work since that might not be a top-level HashSet @@ -261,7 +265,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { that.get0(key, hash, level) } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash && key == this.key) this else { if (hash != this.hash) { @@ -306,7 +310,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { override private[immutable] def diff0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = if (that.get0(key, hash, level)) null else this - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash && key == this.key) null else this override protected def filter0(p: A => Boolean, negate: Boolean, level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = @@ -320,10 +324,10 @@ object HashSet extends ImmutableSetFactory[HashSet] { override def size = ks.size - override def get0(key: A, hash: Int, level: Int): Boolean = + override protected def get0(key: A, hash: Int, level: Int): Boolean = if (hash == this.hash) ks.contains(key) else false - override def subsetOf0(that: HashSet[A], level: Int) = { + override protected def subsetOf0(that: HashSet[A], level: Int) = { // we have to check each element // we use get0 with our hash at the correct level instead of calling contains, // which would not work since that might not be a top-level HashSet @@ -331,11 +335,11 @@ object HashSet extends ImmutableSetFactory[HashSet] { ks.forall(key => that.get0(key, hash, level)) } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) new HashSetCollision1(hash, ks + key) else makeHashTrieSet(this.hash, this, hash, new HashSet1(key, hash), level) - override def union0(that: LeafHashSet[A], level: Int): HashSet[A] = that match { + override private[immutable] def union0(that: LeafHashSet[A], level: Int): HashSet[A] = that match { case that if that.hash != this.hash => // different hash code, so there is no need to investigate further. // Just create a branch node containing the two. @@ -368,7 +372,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { + override private[immutable] def union0(that: HashSet[A], level: Int, buffer: Array[HashSet[A]], offset0: Int): HashSet[A] = that match { case that: LeafHashSet[A] => // switch to the simpler Tree/Leaf implementation this.union0(that, level) @@ -425,7 +429,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = if (hash == this.hash) { val ks1 = ks - key ks1.size match { @@ -522,7 +526,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { override def size = size0 - override def get0(key: A, hash: Int, level: Int): Boolean = { + override protected def get0(key: A, hash: Int, level: Int): Boolean = { val index = (hash >>> level) & 0x1f val mask = (1 << index) if (bitmap == - 1) { @@ -534,7 +538,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { false } - override def updated0(key: A, hash: Int, level: Int): HashSet[A] = { + override private[collection] def updated0(key: A, hash: Int, level: Int): HashSet[A] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) val offset = Integer.bitCount(bitmap & (mask-1)) @@ -836,7 +840,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { case _ => this } - override def removed0(key: A, hash: Int, level: Int): HashSet[A] = { + override protected def removed0(key: A, hash: Int, level: Int): HashSet[A] = { val index = (hash >>> level) & 0x1f val mask = (1 << index) val offset = Integer.bitCount(bitmap & (mask-1)) @@ -873,7 +877,7 @@ object HashSet extends ImmutableSetFactory[HashSet] { } } - override def subsetOf0(that: HashSet[A], level: Int): Boolean = if (that eq this) true else that match { + override protected def subsetOf0(that: HashSet[A], level: Int): Boolean = if (that eq this) true else that match { case that: HashTrieSet[A] if this.size0 <= that.size0 => // create local mutable copies of members var abm = this.bitmap diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala index 8e8bf953f3..550b987cb6 100644 --- a/src/library/scala/collection/immutable/List.scala +++ b/src/library/scala/collection/immutable/List.scala @@ -13,7 +13,7 @@ package immutable import generic._ import mutable.{Builder, ListBuffer} import scala.annotation.tailrec -import java.io._ +import java.io.{ObjectOutputStream, ObjectInputStream} /** A class for immutable linked lists representing ordered collections * of elements of type `A`. @@ -25,6 +25,8 @@ import java.io._ * This class is optimal for last-in-first-out (LIFO), stack-like access patterns. If you need another access * pattern, for example, random access or FIFO, consider using a collection more suited to this than `List`. * + * $usesMutableState + * * ==Performance== * '''Time:''' `List` has `O(1)` prepend and head/tail access. Most other operations are `O(n)` on the number of elements in the list. * This includes the index-based lookup of elements, `length`, `append` and `reverse`. @@ -86,11 +88,9 @@ sealed abstract class List[+A] extends AbstractSeq[A] with Product with GenericTraversableTemplate[A, List] with LinearSeqOptimized[A, List[A]] - with Serializable { + with scala.Serializable { override def companion: GenericCompanion[List] = List - import scala.collection.{Iterable, Traversable, Seq, IndexedSeq} - def isEmpty: Boolean def head: A def tail: List[A] @@ -276,8 +276,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] } (b.toList, these) } - - @noinline // TODO - fix optimizer bug that requires noinline (see SI-8334) + final override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That = { if (bf eq List.ReusableCBF) { if (this eq Nil) Nil.asInstanceOf[That] else { @@ -295,8 +294,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] } else super.map(f) } - - @noinline // TODO - fix optimizer bug that requires noinline for map; applied here to be safe (see SI-8334) + final override def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[List[A], B, That]): That = { if (bf eq List.ReusableCBF) { if (this eq Nil) Nil.asInstanceOf[That] else { @@ -325,8 +323,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] } else super.collect(pf) } - - @noinline // TODO - fix optimizer bug that requires noinline for map; applied here to be safe (see SI-8334) + final override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That = { if (bf eq List.ReusableCBF) { if (this eq Nil) Nil.asInstanceOf[That] else { @@ -414,7 +411,7 @@ sealed abstract class List[+A] extends AbstractSeq[A] else new Stream.Cons(head, tail.toStream) // Create a proxy for Java serialization that allows us to avoid mutation - // during de-serialization. This is the Serialization Proxy Pattern. + // during deserialization. This is the Serialization Proxy Pattern. protected final def writeReplace(): AnyRef = new List.SerializationProxy(this) } @@ -466,7 +463,7 @@ object List extends SeqFactory[List] { override def empty[A]: List[A] = Nil override def apply[A](xs: A*): List[A] = xs.toList - + private[collection] val partialNotApplied = new Function1[Any, Any] { def apply(x: Any): Any = this } @SerialVersionUID(1L) @@ -482,7 +479,7 @@ object List extends SeqFactory[List] { out.writeObject(ListSerializeEnd) } - // Java serialization calls this before readResolve during de-serialization. + // Java serialization calls this before readResolve during deserialization. // Read the whole list and store it in `orig`. private def readObject(in: ObjectInputStream) { in.defaultReadObject() diff --git a/src/library/scala/collection/immutable/ListMap.scala b/src/library/scala/collection/immutable/ListMap.scala index 1eedf93269..589f8bbba9 100644 --- a/src/library/scala/collection/immutable/ListMap.scala +++ b/src/library/scala/collection/immutable/ListMap.scala @@ -6,202 +6,161 @@ ** |/ ** \* */ - - package scala package collection package immutable import generic._ -import scala.annotation.{tailrec, bridge} - -/** $factoryInfo - * @since 1 - * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#list_maps "Scala's Collection Library overview"]] - * section on `List Maps` for more information. - * - * @define Coll immutable.ListMap - * @define coll immutable list map - */ +import scala.annotation.tailrec + +/** + * $factoryInfo + * + * Note that each element insertion takes O(n) time, which means that creating a list map with + * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of + * elements. + * + * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#list_maps "Scala's Collection Library overview"]] + * section on `List Maps` for more information. + * @since 1 + * @define Coll ListMap + * @define coll list map + */ object ListMap extends ImmutableMapFactory[ListMap] { - /** $mapCanBuildFromInfo */ + + /** + * $mapCanBuildFromInfo + */ implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), ListMap[A, B]] = new MapCanBuildFrom[A, B] + def empty[A, B]: ListMap[A, B] = EmptyListMap.asInstanceOf[ListMap[A, B]] - private object EmptyListMap extends ListMap[Any, Nothing] { } + @SerialVersionUID(-8256686706655863282L) + private object EmptyListMap extends ListMap[Any, Nothing] } -/** This class implements immutable maps using a list-based data structure, which preserves insertion order. - * Instances of `ListMap` represent empty maps; they can be either created by - * calling the constructor directly, or by applying the function `ListMap.empty`. - * - * @tparam A the type of the keys in this list map. - * @tparam B the type of the values associated with the keys. - * - * @author Matthias Zenger - * @author Martin Odersky - * @version 2.0, 01/01/2007 - * @since 1 - * @define Coll immutable.ListMap - * @define coll immutable list map - * @define mayNotTerminateInf - * @define willNotTerminateInf - */ +/** + * This class implements immutable maps using a list-based data structure. List map iterators and + * traversal methods visit key-value pairs in the order whey were first inserted. + * + * Entries are stored internally in reversed insertion order, which means the newest key is at the + * head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and `init` + * are O(1). Other operations, such as inserting or removing entries, are also O(n), which makes + * this collection suitable only for a small number of elements. + * + * Instances of `ListMap` represent empty maps; they can be either created by calling the + * constructor directly, or by applying the function `ListMap.empty`. + * + * @tparam A the type of the keys contained in this list map + * @tparam B the type of the values associated with the keys + * + * @author Matthias Zenger + * @author Martin Odersky + * @version 2.0, 01/01/2007 + * @since 1 + * @define Coll ListMap + * @define coll list map + * @define mayNotTerminateInf + * @define willNotTerminateInf + */ @SerialVersionUID(301002838095710379L) -@deprecatedInheritance("The semantics of immutable collections makes inheriting from ListMap error-prone.", "2.11.0") -class ListMap[A, +B] -extends AbstractMap[A, B] - with Map[A, B] - with MapLike[A, B, ListMap[A, B]] - with Serializable { +sealed class ListMap[A, +B] extends AbstractMap[A, B] + with Map[A, B] + with MapLike[A, B, ListMap[A, B]] + with Serializable { override def empty = ListMap.empty - /** Returns the number of mappings in this map. - * - * @return number of mappings in this map. - */ override def size: Int = 0 + override def isEmpty: Boolean = true - /** Checks if this map maps `key` to a value and return the - * value if it exists. - * - * @param key the key of the mapping of interest - * @return the value of the mapping, if it exists - */ def get(key: A): Option[B] = None - /** This method allows one to create a new map with an additional mapping - * from `key` to `value`. If the map contains already a mapping for `key`, - * it will be overridden by this function. - * - * @param key the key element of the updated entry. - * @param value the value element of the updated entry. - */ - override def updated [B1 >: B] (key: A, value: B1): ListMap[A, B1] = - new Node[B1](key, value) - - /** Add a key/value pair to this map. - * @param kv the key/value pair - * @return A new map with the new binding added to this map - */ - def + [B1 >: B] (kv: (A, B1)): ListMap[A, B1] = updated(kv._1, kv._2) - - /** Adds two or more elements to this collection and returns - * either the collection itself (if it is mutable), or a new collection - * with the added elements. - * - * @param elem1 the first element to add. - * @param elem2 the second element to add. - * @param elems the remaining elements to add. - */ - override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): ListMap[A, B1] = - this + elem1 + elem2 ++ elems - - /** Adds a number of elements provided by a traversable object - * and returns a new collection with the added elements. - * - * @param xs the traversable object. - */ + override def updated[B1 >: B](key: A, value: B1): ListMap[A, B1] = new Node[B1](key, value) + + def +[B1 >: B](kv: (A, B1)): ListMap[A, B1] = new Node[B1](kv._1, kv._2) + def -(key: A): ListMap[A, B] = this + override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): ListMap[A, B1] = - ((repr: ListMap[A, B1]) /: xs.seq) (_ + _) - - /** This creates a new mapping without the given `key`. - * If the map does not contain a mapping for the given key, the - * method returns the same map. - * - * @param key a map without a mapping for the given key. - */ - def - (key: A): ListMap[A, B] = this - - /** Returns an iterator over key-value pairs. - */ - def iterator: Iterator[(A,B)] = - new AbstractIterator[(A,B)] { - var self: ListMap[A,B] = ListMap.this - def hasNext = !self.isEmpty - def next(): (A,B) = - if (!hasNext) throw new NoSuchElementException("next on empty iterator") - else { val res = (self.key, self.value); self = self.next; res } - }.toList.reverseIterator - - protected def key: A = throw new NoSuchElementException("empty map") - protected def value: B = throw new NoSuchElementException("empty map") - protected def next: ListMap[A, B] = throw new NoSuchElementException("empty map") - - /** This class represents an entry in the `ListMap`. - */ + if (xs.isEmpty) this + else ((repr: ListMap[A, B1]) /: xs) (_ + _) + + def iterator: Iterator[(A, B)] = { + def reverseList = { + var curr: ListMap[A, B] = this + var res: List[(A, B)] = Nil + while (!curr.isEmpty) { + res = (curr.key, curr.value) :: res + curr = curr.next + } + res + } + reverseList.iterator + } + + protected def key: A = throw new NoSuchElementException("key of empty map") + protected def value: B = throw new NoSuchElementException("value of empty map") + protected def next: ListMap[A, B] = throw new NoSuchElementException("next of empty map") + + override def stringPrefix = "ListMap" + + /** + * Represents an entry in the `ListMap`. + */ @SerialVersionUID(-6453056603889598734L) protected class Node[B1 >: B](override protected val key: A, override protected val value: B1) extends ListMap[A, B1] with Serializable { - /** Returns the number of mappings in this map. - * - * @return number of mappings. - */ - override def size: Int = size0(this, 0) - - // to allow tail recursion and prevent stack overflows - @tailrec private def size0(cur: ListMap[A, B1], acc: Int): Int = if (cur.isEmpty) acc else size0(cur.next, acc + 1) - - /** Is this an empty map? - * - * @return true, iff the map is empty. - */ - override def isEmpty: Boolean = false - /** Retrieves the value which is associated with the given key. This - * method throws an exception if there is no mapping from the given - * key to a value. - * - * @param k the key - * @return the value associated with the given key. - */ - override def apply(k: A): B1 = apply0(this, k) + override def size: Int = sizeInternal(this, 0) + @tailrec private[this] def sizeInternal(cur: ListMap[A, B1], acc: Int): Int = + if (cur.isEmpty) acc + else sizeInternal(cur.next, acc + 1) - @tailrec private def apply0(cur: ListMap[A, B1], k: A): B1 = - if (cur.isEmpty) throw new NoSuchElementException("key not found: "+k) + override def isEmpty: Boolean = false + + override def apply(k: A): B1 = applyInternal(this, k) + + @tailrec private[this] def applyInternal(cur: ListMap[A, B1], k: A): B1 = + if (cur.isEmpty) throw new NoSuchElementException("key not found: " + k) else if (k == cur.key) cur.value - else apply0(cur.next, k) - - /** Checks if this map maps `key` to a value and return the - * value if it exists. - * - * @param k the key of the mapping of interest - * @return the value of the mapping, if it exists - */ - override def get(k: A): Option[B1] = get0(this, k) - - @tailrec private def get0(cur: ListMap[A, B1], k: A): Option[B1] = - if (k == cur.key) Some(cur.value) - else if (cur.next.nonEmpty) get0(cur.next, k) else None - - /** This method allows one to create a new map with an additional mapping - * from `key` to `value`. If the map contains already a mapping for `key`, - * it will be overridden by this function. - */ - override def updated [B2 >: B1](k: A, v: B2): ListMap[A, B2] = { + else applyInternal(cur.next, k) + + override def get(k: A): Option[B1] = getInternal(this, k) + + @tailrec private[this] def getInternal(cur: ListMap[A, B1], k: A): Option[B1] = + if (cur.isEmpty) None + else if (k == cur.key) Some(cur.value) + else getInternal(cur.next, k) + + override def contains(k: A): Boolean = containsInternal(this, k) + + @tailrec private[this] def containsInternal(cur: ListMap[A, B1], k: A): Boolean = + if(cur.isEmpty) false + else if (k == cur.key) true + else containsInternal(cur.next, k) + + override def updated[B2 >: B1](k: A, v: B2): ListMap[A, B2] = { val m = this - k new m.Node[B2](k, v) } - /** Creates a new mapping without the given `key`. - * If the map does not contain a mapping for the given key, the - * method returns the same map. - */ - override def - (k: A): ListMap[A, B1] = remove0(k, this, Nil) - - @tailrec private def remove0(k: A, cur: ListMap[A, B1], acc: List[ListMap[A, B1]]): ListMap[A, B1] = - if (cur.isEmpty) - acc.last - else if (k == cur.key) - (cur.next /: acc) { - case (t, h) => val tt = t; new tt.Node(h.key, h.value) // SI-7459 - } - else - remove0(k, cur.next, cur::acc) + override def +[B2 >: B1](kv: (A, B2)): ListMap[A, B2] = { + val m = this - kv._1 + new m.Node[B2](kv._1, kv._2) + } + + override def -(k: A): ListMap[A, B1] = removeInternal(k, this, Nil) + + @tailrec private[this] def removeInternal(k: A, cur: ListMap[A, B1], acc: List[ListMap[A, B1]]): ListMap[A, B1] = + if (cur.isEmpty) acc.last + else if (k == cur.key) (cur.next /: acc) { case (t, h) => new t.Node(h.key, h.value) } + else removeInternal(k, cur.next, cur :: acc) override protected def next: ListMap[A, B1] = ListMap.this + + override def last: (A, B1) = (key, value) + override def init: ListMap[A, B1] = next } } diff --git a/src/library/scala/collection/immutable/ListSet.scala b/src/library/scala/collection/immutable/ListSet.scala index adc975479a..d9795e9161 100644 --- a/src/library/scala/collection/immutable/ListSet.scala +++ b/src/library/scala/collection/immutable/ListSet.scala @@ -11,174 +11,126 @@ package collection package immutable import generic._ -import scala.annotation.{tailrec, bridge} -import mutable.{ ListBuffer, Builder } - -/** $factoryInfo - * @define Coll immutable.ListSet - * @define coll immutable list set - * @since 1 - */ +import scala.annotation.tailrec + +/** + * $factoryInfo + * + * Note that each element insertion takes O(n) time, which means that creating a list set with + * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of + * elements. + * + * @since 1 + * @define Coll ListSet + * @define coll list set + */ object ListSet extends ImmutableSetFactory[ListSet] { - /** setCanBuildFromInfo */ - implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] = setCanBuildFrom[A] - override def newBuilder[A]: Builder[A, ListSet[A]] = new ListSetBuilder[A] + /** + * $setCanBuildFromInfo + */ + implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, ListSet[A]] = + setCanBuildFrom[A] - private object EmptyListSet extends ListSet[Any] { } + @SerialVersionUID(5010379588739277132L) + private object EmptyListSet extends ListSet[Any] private[collection] def emptyInstance: ListSet[Any] = EmptyListSet - - /** A custom builder because forgetfully adding elements one at - * a time to a list backed set puts the "squared" in N^2. There is a - * temporary space cost, but it's improbable a list backed set could - * become large enough for this to matter given its pricy element lookup. - */ - class ListSetBuilder[Elem](initial: ListSet[Elem]) extends Builder[Elem, ListSet[Elem]] { - def this() = this(empty[Elem]) - protected val elems = (new mutable.ListBuffer[Elem] ++= initial).reverse - protected val seen = new mutable.HashSet[Elem] ++= initial - - def +=(x: Elem): this.type = { - if (!seen(x)) { - elems += x - seen += x - } - this - } - def clear() = { elems.clear() ; seen.clear() } - def result() = elems.foldLeft(empty[Elem])(_ unchecked_+ _) - } } -/** This class implements immutable sets using a list-based data - * structure. Instances of `ListSet` represent - * empty sets; they can be either created by calling the constructor - * directly, or by applying the function `ListSet.empty`. - * - * @tparam A the type of the elements contained in this list set. - * - * @author Matthias Zenger - * @version 1.0, 09/07/2003 - * @since 1 - * @define Coll immutable.ListSet - * @define coll immutable list set - * @define mayNotTerminateInf - * @define willNotTerminateInf - */ -@deprecatedInheritance("The semantics of immutable collections makes inheriting from ListSet error-prone.", "2.11.0") -class ListSet[A] extends AbstractSet[A] - with Set[A] - with GenericSetTemplate[A, ListSet] - with SetLike[A, ListSet[A]] - with Serializable{ self => +/** + * This class implements immutable sets using a list-based data structure. List set iterators and + * traversal methods visit elements in the order whey were first inserted. + * + * Elements are stored internally in reversed insertion order, which means the newest element is at + * the head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and + * `init` are O(1). Other operations, such as inserting or removing entries, are also O(n), which + * makes this collection suitable only for a small number of elements. + * + * Instances of `ListSet` represent empty sets; they can be either created by calling the + * constructor directly, or by applying the function `ListSet.empty`. + * + * @tparam A the type of the elements contained in this list set + * + * @author Matthias Zenger + * @version 1.0, 09/07/2003 + * @since 1 + * @define Coll ListSet + * @define coll list set + * @define mayNotTerminateInf + * @define willNotTerminateInf + */ +@SerialVersionUID(-8417059026623606218L) +sealed class ListSet[A] extends AbstractSet[A] + with Set[A] + with GenericSetTemplate[A, ListSet] + with SetLike[A, ListSet[A]] + with Serializable { + override def companion: GenericCompanion[ListSet] = ListSet - /** Returns the number of elements in this set. - * - * @return number of set elements. - */ override def size: Int = 0 override def isEmpty: Boolean = true - /** Checks if this set contains element `elem`. - * - * @param elem the element to check for membership. - * @return `'''true'''`, iff `elem` is contained in this set. - */ def contains(elem: A): Boolean = false - /** This method creates a new set with an additional element. - */ - def + (elem: A): ListSet[A] = new Node(elem) - - /** `-` can be used to remove a single element. - */ - def - (elem: A): ListSet[A] = this + def +(elem: A): ListSet[A] = new Node(elem) + def -(elem: A): ListSet[A] = this - /** If we are bulk adding elements and desire a runtime measured in - * sub-interstellar time units, we better find a way to avoid traversing - * the collection on each element. That's what the custom builder does, - * so we take the easy way out and add ourselves and the argument to - * a new builder. - */ override def ++(xs: GenTraversableOnce[A]): ListSet[A] = if (xs.isEmpty) this - else (new ListSet.ListSetBuilder(this) ++= xs.seq).result() - - private[ListSet] def unchecked_+(e: A): ListSet[A] = new Node(e) - private[ListSet] def unchecked_outer: ListSet[A] = - throw new NoSuchElementException("Empty ListSet has no outer pointer") - - /** Creates a new iterator over all elements contained in this set. - * - * @throws java.util.NoSuchElementException - * @return the new iterator - */ - def iterator: Iterator[A] = new AbstractIterator[A] { - var that: ListSet[A] = self - def hasNext = that.nonEmpty - def next: A = - if (hasNext) { - val res = that.head - that = that.tail - res + else (repr /: xs) (_ + _) + + def iterator: Iterator[A] = { + def reverseList = { + var curr: ListSet[A] = this + var res: List[A] = Nil + while (!curr.isEmpty) { + res = curr.elem :: res + curr = curr.next } - else Iterator.empty.next() + res + } + reverseList.iterator } - /** - * @throws java.util.NoSuchElementException - */ - override def head: A = throw new NoSuchElementException("Set has no elements") + protected def elem: A = throw new NoSuchElementException("elem of empty set") + protected def next: ListSet[A] = throw new NoSuchElementException("next of empty set") - /** - * @throws java.util.NoSuchElementException - */ - override def tail: ListSet[A] = throw new NoSuchElementException("Next of an empty set") + override def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]] override def stringPrefix = "ListSet" - /** Represents an entry in the `ListSet`. - */ - protected class Node(override val head: A) extends ListSet[A] with Serializable { - override private[ListSet] def unchecked_outer = self + /** + * Represents an entry in the `ListSet`. + */ + @SerialVersionUID(-787710309854855049L) + protected class Node(override protected val elem: A) extends ListSet[A] with Serializable { - /** Returns the number of elements in this set. - * - * @return number of set elements. - */ override def size = sizeInternal(this, 0) - @tailrec private def sizeInternal(n: ListSet[A], acc: Int): Int = + + @tailrec private[this] def sizeInternal(n: ListSet[A], acc: Int): Int = if (n.isEmpty) acc - else sizeInternal(n.unchecked_outer, acc + 1) + else sizeInternal(n.next, acc + 1) - /** Checks if this set is empty. - * - * @return true, iff there is no element in the set. - */ override def isEmpty: Boolean = false - /** Checks if this set contains element `elem`. - * - * @param e the element to check for membership. - * @return `'''true'''`, iff `elem` is contained in this set. - */ override def contains(e: A) = containsInternal(this, e) - @tailrec private def containsInternal(n: ListSet[A], e: A): Boolean = - !n.isEmpty && (n.head == e || containsInternal(n.unchecked_outer, e)) - /** This method creates a new set with an additional element. - */ + @tailrec private[this] def containsInternal(n: ListSet[A], e: A): Boolean = + !n.isEmpty && (n.elem == e || containsInternal(n.next, e)) + override def +(e: A): ListSet[A] = if (contains(e)) this else new Node(e) - /** `-` can be used to remove a single element from a set. - */ - override def -(e: A): ListSet[A] = if (e == head) self else { - val tail = self - e; new tail.Node(head) - } + override def -(e: A): ListSet[A] = removeInternal(e, this, Nil) + + @tailrec private[this] def removeInternal(k: A, cur: ListSet[A], acc: List[ListSet[A]]): ListSet[A] = + if (cur.isEmpty) acc.last + else if (k == cur.elem) (cur.next /: acc) { case (t, h) => new t.Node(h.elem) } + else removeInternal(k, cur.next, cur :: acc) - override def tail: ListSet[A] = self + override protected def next: ListSet[A] = ListSet.this + + override def last: A = elem + override def init: ListSet[A] = next } - - override def toSet[B >: A]: Set[B] = this.asInstanceOf[ListSet[B]] } diff --git a/src/library/scala/collection/immutable/Map.scala b/src/library/scala/collection/immutable/Map.scala index 2c5b444c70..4107b6414d 100644 --- a/src/library/scala/collection/immutable/Map.scala +++ b/src/library/scala/collection/immutable/Map.scala @@ -18,30 +18,30 @@ import generic._ * functionality for the abstract methods in `Map`: * * {{{ - * def get(key: A): Option[B] - * def iterator: Iterator[(A, B)] - * def + [B1 >: B](kv: (A, B1)): Map[A, B1] - * def -(key: A): Map[A, B] + * def get(key: K): Option[V] + * def iterator: Iterator[(K, V)] + * def + [V1 >: V](kv: (K, V1)): Map[K, V1] + * def -(key: K): Map[K, V] * }}} * * @since 1 */ -trait Map[A, +B] extends Iterable[(A, B)] -// with GenMap[A, B] - with scala.collection.Map[A, B] - with MapLike[A, B, Map[A, B]] { self => +trait Map[K, +V] extends Iterable[(K, V)] +// with GenMap[K, V] + with scala.collection.Map[K, V] + with MapLike[K, V, Map[K, V]] { self => - override def empty: Map[A, B] = Map.empty + override def empty: Map[K, V] = Map.empty /** Returns this $coll as an immutable map. * * A new map will not be built; lazy collections will stay lazy. */ @deprecatedOverriding("Immutable maps should do nothing on toMap except return themselves cast as a map.", "2.11.0") - override def toMap[T, U](implicit ev: (A, B) <:< (T, U)): immutable.Map[T, U] = + override def toMap[T, U](implicit ev: (K, V) <:< (T, U)): immutable.Map[T, U] = self.asInstanceOf[immutable.Map[T, U]] - override def seq: Map[A, B] = this + override def seq: Map[K, V] = this /** The same map with a given default function. * Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefault`. @@ -51,7 +51,7 @@ trait Map[A, +B] extends Iterable[(A, B)] * @param d the function mapping keys to values, used for non-present keys * @return a wrapper of the map with a default value */ - def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1] = new Map.WithDefault[A, B1](this, d) + def withDefault[V1 >: V](d: K => V1): immutable.Map[K, V1] = new Map.WithDefault[K, V1](this, d) /** The same map with a given default value. * Note: `get`, `contains`, `iterator`, `keys`, etc are not affected by `withDefaultValue`. @@ -61,15 +61,15 @@ trait Map[A, +B] extends Iterable[(A, B)] * @param d default value used for non-present keys * @return a wrapper of the map with a default value */ - def withDefaultValue[B1 >: B](d: B1): immutable.Map[A, B1] = new Map.WithDefault[A, B1](this, x => d) + def withDefaultValue[V1 >: V](d: V1): immutable.Map[K, V1] = new Map.WithDefault[K, V1](this, x => d) /** Add a key/value pair to this map. * @param key the key * @param value the value * @return A new map with the new binding added to this map */ - override def updated [B1 >: B](key: A, value: B1): Map[A, B1] - def + [B1 >: B](kv: (A, B1)): Map[A, B1] + override def updated [V1 >: V](key: K, value: V1): Map[K, V1] + def + [V1 >: V](kv: (K, V1)): Map[K, V1] } /** $factoryInfo @@ -79,116 +79,138 @@ trait Map[A, +B] extends Iterable[(A, B)] object Map extends ImmutableMapFactory[Map] { /** $mapCanBuildFromInfo */ - implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B] + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Map[K, V]] = new MapCanBuildFrom[K, V] - def empty[A, B]: Map[A, B] = EmptyMap.asInstanceOf[Map[A, B]] + def empty[K, V]: Map[K, V] = EmptyMap.asInstanceOf[Map[K, V]] - class WithDefault[A, +B](underlying: Map[A, B], d: A => B) extends scala.collection.Map.WithDefault[A, B](underlying, d) with Map[A, B] { + class WithDefault[K, +V](underlying: Map[K, V], d: K => V) extends scala.collection.Map.WithDefault[K, V](underlying, d) with Map[K, V] { override def empty = new WithDefault(underlying.empty, d) - override def updated[B1 >: B](key: A, value: B1): WithDefault[A, B1] = new WithDefault[A, B1](underlying.updated[B1](key, value), d) - override def + [B1 >: B](kv: (A, B1)): WithDefault[A, B1] = updated(kv._1, kv._2) - override def - (key: A): WithDefault[A, B] = new WithDefault(underlying - key, d) - override def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1] = new WithDefault[A, B1](underlying, d) - override def withDefaultValue[B1 >: B](d: B1): immutable.Map[A, B1] = new WithDefault[A, B1](underlying, x => d) + override def updated[V1 >: V](key: K, value: V1): WithDefault[K, V1] = new WithDefault[K, V1](underlying.updated[V1](key, value), d) + override def + [V1 >: V](kv: (K, V1)): WithDefault[K, V1] = updated(kv._1, kv._2) + override def - (key: K): WithDefault[K, V] = new WithDefault(underlying - key, d) + override def withDefault[V1 >: V](d: K => V1): immutable.Map[K, V1] = new WithDefault[K, V1](underlying, d) + override def withDefaultValue[V1 >: V](d: V1): immutable.Map[K, V1] = new WithDefault[K, V1](underlying, x => d) } private object EmptyMap extends AbstractMap[Any, Nothing] with Map[Any, Nothing] with Serializable { override def size: Int = 0 + override def apply(key: Any) = throw new NoSuchElementException("key not found: " + key) + override def contains(key: Any) = false def get(key: Any): Option[Nothing] = None def iterator: Iterator[(Any, Nothing)] = Iterator.empty - override def updated [B1] (key: Any, value: B1): Map[Any, B1] = new Map1(key, value) - def + [B1](kv: (Any, B1)): Map[Any, B1] = updated(kv._1, kv._2) + override def updated [V1] (key: Any, value: V1): Map[Any, V1] = new Map1(key, value) + def + [V1](kv: (Any, V1)): Map[Any, V1] = updated(kv._1, kv._2) def - (key: Any): Map[Any, Nothing] = this } - class Map1[A, +B](key1: A, value1: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + class Map1[K, +V](key1: K, value1: V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = 1 - def get(key: A): Option[B] = + override def apply(key: K) = if (key == key1) value1 else throw new NoSuchElementException("key not found: " + key) + override def contains(key: K) = key == key1 + def get(key: K): Option[V] = if (key == key1) Some(value1) else None def iterator = Iterator((key1, value1)) - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = + override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] = if (key == key1) new Map1(key1, value) else new Map2(key1, value1, key, value) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) - def - (key: A): Map[A, B] = + def + [V1 >: V](kv: (K, V1)): Map[K, V1] = updated(kv._1, kv._2) + def - (key: K): Map[K, V] = if (key == key1) Map.empty else this - override def foreach[U](f: ((A, B)) => U): Unit = { + override def foreach[U](f: ((K, V)) => U): Unit = { f((key1, value1)) } } - class Map2[A, +B](key1: A, value1: B, key2: A, value2: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + class Map2[K, +V](key1: K, value1: V, key2: K, value2: V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = 2 - def get(key: A): Option[B] = + override def apply(key: K) = + if (key == key1) value1 + else if (key == key2) value2 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: K) = (key == key1) || (key == key2) + def get(key: K): Option[V] = if (key == key1) Some(value1) else if (key == key2) Some(value2) else None def iterator = Iterator((key1, value1), (key2, value2)) - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = + override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] = if (key == key1) new Map2(key1, value, key2, value2) else if (key == key2) new Map2(key1, value1, key2, value) else new Map3(key1, value1, key2, value2, key, value) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) - def - (key: A): Map[A, B] = + def + [V1 >: V](kv: (K, V1)): Map[K, V1] = updated(kv._1, kv._2) + def - (key: K): Map[K, V] = if (key == key1) new Map1(key2, value2) else if (key == key2) new Map1(key1, value1) else this - override def foreach[U](f: ((A, B)) => U): Unit = { + override def foreach[U](f: ((K, V)) => U): Unit = { f((key1, value1)); f((key2, value2)) } } - class Map3[A, +B](key1: A, value1: B, key2: A, value2: B, key3: A, value3: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + class Map3[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = 3 - def get(key: A): Option[B] = + override def apply(key: K) = + if (key == key1) value1 + else if (key == key2) value2 + else if (key == key3) value3 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: K) = (key == key1) || (key == key2) || (key == key3) + def get(key: K): Option[V] = if (key == key1) Some(value1) else if (key == key2) Some(value2) else if (key == key3) Some(value3) else None def iterator = Iterator((key1, value1), (key2, value2), (key3, value3)) - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = + override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] = if (key == key1) new Map3(key1, value, key2, value2, key3, value3) else if (key == key2) new Map3(key1, value1, key2, value, key3, value3) else if (key == key3) new Map3(key1, value1, key2, value2, key3, value) else new Map4(key1, value1, key2, value2, key3, value3, key, value) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) - def - (key: A): Map[A, B] = + def + [V1 >: V](kv: (K, V1)): Map[K, V1] = updated(kv._1, kv._2) + def - (key: K): Map[K, V] = if (key == key1) new Map2(key2, value2, key3, value3) else if (key == key2) new Map2(key1, value1, key3, value3) else if (key == key3) new Map2(key1, value1, key2, value2) else this - override def foreach[U](f: ((A, B)) => U): Unit = { + override def foreach[U](f: ((K, V)) => U): Unit = { f((key1, value1)); f((key2, value2)); f((key3, value3)) } } - class Map4[A, +B](key1: A, value1: B, key2: A, value2: B, key3: A, value3: B, key4: A, value4: B) extends AbstractMap[A, B] with Map[A, B] with Serializable { + class Map4[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V, key4: K, value4: V) extends AbstractMap[K, V] with Map[K, V] with Serializable { override def size = 4 - def get(key: A): Option[B] = + override def apply(key: K) = + if (key == key1) value1 + else if (key == key2) value2 + else if (key == key3) value3 + else if (key == key4) value4 + else throw new NoSuchElementException("key not found: " + key) + override def contains(key: K) = (key == key1) || (key == key2) || (key == key3) || (key == key4) + def get(key: K): Option[V] = if (key == key1) Some(value1) else if (key == key2) Some(value2) else if (key == key3) Some(value3) else if (key == key4) Some(value4) else None def iterator = Iterator((key1, value1), (key2, value2), (key3, value3), (key4, value4)) - override def updated [B1 >: B] (key: A, value: B1): Map[A, B1] = + override def updated [V1 >: V] (key: K, value: V1): Map[K, V1] = if (key == key1) new Map4(key1, value, key2, value2, key3, value3, key4, value4) else if (key == key2) new Map4(key1, value1, key2, value, key3, value3, key4, value4) else if (key == key3) new Map4(key1, value1, key2, value2, key3, value, key4, value4) else if (key == key4) new Map4(key1, value1, key2, value2, key3, value3, key4, value) - else new HashMap + ((key1, value1), (key2, value2), (key3, value3), (key4, value4), (key, value)) - def + [B1 >: B](kv: (A, B1)): Map[A, B1] = updated(kv._1, kv._2) - def - (key: A): Map[A, B] = + else (new HashMap).updated(key1,value1).updated(key2, value2).updated(key3, value3).updated(key4, value4).updated(key, value) + def + [V1 >: V](kv: (K, V1)): Map[K, V1] = updated(kv._1, kv._2) + def - (key: K): Map[K, V] = if (key == key1) new Map3(key2, value2, key3, value3, key4, value4) else if (key == key2) new Map3(key1, value1, key3, value3, key4, value4) else if (key == key3) new Map3(key1, value1, key2, value2, key4, value4) else if (key == key4) new Map3(key1, value1, key2, value2, key3, value3) else this - override def foreach[U](f: ((A, B)) => U): Unit = { + override def foreach[U](f: ((K, V)) => U): Unit = { f((key1, value1)); f((key2, value2)); f((key3, value3)); f((key4, value4)) } } } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -abstract class AbstractMap[A, +B] extends scala.collection.AbstractMap[A, B] with Map[A, B] +abstract class AbstractMap[K, +V] extends scala.collection.AbstractMap[K, V] with Map[K, V] diff --git a/src/library/scala/collection/immutable/MapLike.scala b/src/library/scala/collection/immutable/MapLike.scala index bd5b9c9faf..5867383b52 100644 --- a/src/library/scala/collection/immutable/MapLike.scala +++ b/src/library/scala/collection/immutable/MapLike.scala @@ -14,16 +14,16 @@ import generic._ import parallel.immutable.ParMap /** - * A generic template for immutable maps from keys of type `A` - * to values of type `B`. + * A generic template for immutable maps from keys of type `K` + * to values of type `V`. * To implement a concrete map, you need to provide implementations of the * following methods (where `This` is the type of the actual map implementation): * * {{{ - * def get(key: A): Option[B] - * def iterator: Iterator[(A, B)] - * def + [B1 >: B](kv: (A, B)): Map[A, B1] - * def - (key: A): This + * def get(key: K): Option[V] + * def iterator: Iterator[(K, V)] + * def + [V1 >: V](kv: (K, V)): Map[K, V1] + * def - (key: K): This * }}} * * If you wish that transformer methods like `take`, `drop`, `filter` return the @@ -36,8 +36,8 @@ import parallel.immutable.ParMap * It is also good idea to override methods `foreach` and * `size` for efficiency. * - * @tparam A the type of the keys contained in this collection. - * @tparam B the type of the values associated with the keys. + * @tparam K the type of the keys contained in this collection. + * @tparam V the type of the values associated with the keys. * @tparam This The type of the actual map implementation. * * @author Martin Odersky @@ -46,26 +46,26 @@ import parallel.immutable.ParMap * @define Coll immutable.Map * @define coll immutable map */ -trait MapLike[A, +B, +This <: MapLike[A, B, This] with Map[A, B]] - extends scala.collection.MapLike[A, B, This] - with Parallelizable[(A, B), ParMap[A, B]] +trait MapLike[K, +V, +This <: MapLike[K, V, This] with Map[K, V]] + extends scala.collection.MapLike[K, V, This] + with Parallelizable[(K, V), ParMap[K, V]] { self => - protected[this] override def parCombiner = ParMap.newCombiner[A, B] + protected[this] override def parCombiner = ParMap.newCombiner[K, V] /** A new immutable map containing updating this map with a given key/value mapping. * @param key the key * @param value the value * @return A new map with the new key/value mapping */ - override def updated [B1 >: B](key: A, value: B1): immutable.Map[A, B1] = this + ((key, value)) + override def updated [V1 >: V](key: K, value: V1): immutable.Map[K, V1] = this + ((key, value)) /** Add a key/value pair to this map, returning a new map. * @param kv the key/value pair. * @return A new map with the new binding added to this map. */ - def + [B1 >: B] (kv: (A, B1)): immutable.Map[A, B1] + def + [V1 >: V] (kv: (K, V1)): immutable.Map[K, V1] /** Adds two or more elements to this collection and returns * a new collection. @@ -75,7 +75,7 @@ self => * @param elems the remaining elements to add. * @return A new map with the new bindings added to this map. */ - override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): immutable.Map[A, B1] = + override def + [V1 >: V] (elem1: (K, V1), elem2: (K, V1), elems: (K, V1) *): immutable.Map[K, V1] = this + elem1 + elem2 ++ elems /** Adds a number of elements provided by a traversable object @@ -84,40 +84,40 @@ self => * @param xs the traversable object consisting of key-value pairs. * @return a new immutable map with the bindings of this map and those from `xs`. */ - override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): immutable.Map[A, B1] = - ((repr: immutable.Map[A, B1]) /: xs.seq) (_ + _) + override def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): immutable.Map[K, V1] = + ((repr: immutable.Map[K, V1]) /: xs.seq) (_ + _) /** Filters this map by retaining only keys satisfying a predicate. * @param p the predicate used to test keys * @return an immutable map consisting only of those key value pairs of this map where the key satisfies * the predicate `p`. The resulting map wraps the original map without copying any elements. */ - override def filterKeys(p: A => Boolean): Map[A, B] = new FilteredKeys(p) with DefaultMap[A, B] + override def filterKeys(p: K => Boolean): Map[K, V] = new FilteredKeys(p) with DefaultMap[K, V] /** Transforms this map by applying a function to every retrieved value. * @param f the function used to transform values of this map. * @return a map view which maps every key of this map * to `f(this(key))`. The resulting map wraps the original map without copying any elements. */ - override def mapValues[C](f: B => C): Map[A, C] = new MappedValues(f) with DefaultMap[A, C] + override def mapValues[W](f: V => W): Map[K, W] = new MappedValues(f) with DefaultMap[K, W] /** Collects all keys of this map in a set. * @return a set containing all keys of this map. */ - override def keySet: immutable.Set[A] = new ImmutableDefaultKeySet + override def keySet: immutable.Set[K] = new ImmutableDefaultKeySet - protected class ImmutableDefaultKeySet extends super.DefaultKeySet with immutable.Set[A] { - override def + (elem: A): immutable.Set[A] = + protected class ImmutableDefaultKeySet extends super.DefaultKeySet with immutable.Set[K] { + override def + (elem: K): immutable.Set[K] = if (this(elem)) this - else immutable.Set[A]() ++ this + elem - override def - (elem: A): immutable.Set[A] = - if (this(elem)) immutable.Set[A]() ++ this - elem + else immutable.Set[K]() ++ this + elem + override def - (elem: K): immutable.Set[K] = + if (this(elem)) immutable.Set[K]() ++ this - elem else this // ImmutableDefaultKeySet is only protected, so we won't warn on override. // Someone could override in a way that makes widening not okay // (e.g. by overriding +, though the version in this class is fine) - override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set[B]] + override def toSet[B >: K]: Set[B] = this.asInstanceOf[Set[B]] } /** This function transforms all the values of mappings contained @@ -126,10 +126,9 @@ self => * @param f A function over keys and values * @return the updated map */ - def transform[C, That](f: (A, B) => C)(implicit bf: CanBuildFrom[This, (A, C), That]): That = { + def transform[W, That](f: (K, V) => W)(implicit bf: CanBuildFrom[This, (K, W), That]): That = { val b = bf(repr) for ((key, value) <- this) b += ((key, f(key, value))) b.result() } } - diff --git a/src/library/scala/collection/immutable/MapProxy.scala b/src/library/scala/collection/immutable/MapProxy.scala index d126b9e7a6..0d1c17d4b3 100644 --- a/src/library/scala/collection/immutable/MapProxy.scala +++ b/src/library/scala/collection/immutable/MapProxy.scala @@ -23,7 +23,7 @@ package immutable * @version 2.0, 31/12/2006 * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait MapProxy[A, +B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]] { override def repr = this private def newProxy[B1 >: B](newSelf: Map[A, B1]): MapProxy[A, B1] = diff --git a/src/library/scala/collection/immutable/NumericRange.scala b/src/library/scala/collection/immutable/NumericRange.scala index 59b8a40c64..f1b831bf75 100644 --- a/src/library/scala/collection/immutable/NumericRange.scala +++ b/src/library/scala/collection/immutable/NumericRange.scala @@ -10,8 +10,6 @@ package scala package collection package immutable -import mutable.{ Builder, ListBuffer } - // TODO: Now the specialization exists there is no clear reason to have // separate classes for Range/NumericRange. Investigate and consolidate. @@ -121,7 +119,7 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { // (Integral <: Ordering). This can happen for custom Integral types. // - The Ordering is the default Ordering of a well-known Integral type. if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) { - if (num.signum(step) > 0) start + if (num.signum(step) > 0) head else last } else super.min(ord) @@ -129,7 +127,7 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { // See comment for fast path in min(). if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) { if (num.signum(step) > 0) last - else start + else head } else super.max(ord) // Motivated by the desire for Double ranges with BigDecimal precision, @@ -168,6 +166,12 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { override def isEmpty = underlyingRange.isEmpty override def apply(idx: Int): A = fm(underlyingRange(idx)) override def containsTyped(el: A) = underlyingRange exists (x => fm(x) == el) + + override def toString = { + def simpleOf(x: Any): String = x.getClass.getName.split("\\.").last + val stepped = simpleOf(underlyingRange.step) + s"${super.toString} (using $underlyingRange of $stepped)" + } } } @@ -198,7 +202,7 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { // Either numRangeElements or (head + last) must be even, so divide the even one before multiplying val a = head.toLong val b = last.toLong - val ans = + val ans = if ((numRangeElements & 1) == 0) (numRangeElements / 2) * (a + b) else numRangeElements * { // Sum is even, but we might overflow it, so divide in pieces and add back remainder @@ -257,9 +261,11 @@ extends AbstractSeq[T] with IndexedSeq[T] with Serializable { super.equals(other) } - override def toString() = { - val endStr = if (length > Range.MAX_PRINT) ", ... )" else ")" - take(Range.MAX_PRINT).mkString("NumericRange(", ", ", endStr) + override def toString = { + val empty = if (isEmpty) "empty " else "" + val preposition = if (isInclusive) "to" else "until" + val stepped = if (step == 1) "" else s" by $step" + s"${empty}NumericRange $start $preposition $end$stepped" } } diff --git a/src/library/scala/collection/immutable/PagedSeq.scala b/src/library/scala/collection/immutable/PagedSeq.scala index 982c10687c..01854b1797 100644 --- a/src/library/scala/collection/immutable/PagedSeq.scala +++ b/src/library/scala/collection/immutable/PagedSeq.scala @@ -12,8 +12,7 @@ package scala package collection package immutable -import java.io._ -import scala.util.matching.Regex +import java.io.{File, FileReader, Reader} import scala.reflect.ClassTag /** The `PagedSeq` object defines a lazy implementations of @@ -23,7 +22,7 @@ import scala.reflect.ClassTag * `fromIterator` and `fromIterable` provide generalised instances of `PagedSeq` * @since 2.7 */ -@deprecated("This object will be moved to the scala-parser-combinators module", "2.11.8") +@deprecated("this object will be moved to the scala-parser-combinators module", "2.11.8") object PagedSeq { final val UndeterminedEnd = Int.MaxValue @@ -127,7 +126,7 @@ import PagedSeq._ * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecated("This class will be moved to the scala-parser-combinators module", "2.11.8") +@deprecated("this class will be moved to the scala-parser-combinators module", "2.11.8") class PagedSeq[T: ClassTag] protected( more: (Array[T], Int, Int) => Int, first1: Page[T], diff --git a/src/library/scala/collection/immutable/Queue.scala b/src/library/scala/collection/immutable/Queue.scala index 16cdc6d080..5081b39bdc 100644 --- a/src/library/scala/collection/immutable/Queue.scala +++ b/src/library/scala/collection/immutable/Queue.scala @@ -12,7 +12,6 @@ package immutable import generic._ import mutable.{ Builder, ListBuffer } -import scala.annotation.tailrec /** `Queue` objects implement data structures that allow to * insert and retrieve elements in a first-in-first-out (FIFO) manner. @@ -38,8 +37,7 @@ import scala.annotation.tailrec */ @SerialVersionUID(-7622936493364270175L) -@deprecatedInheritance("The implementation details of immutable queues make inheriting from them unwise.", "2.11.0") -class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) +sealed class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) extends AbstractSeq[A] with LinearSeq[A] with GenericTraversableTemplate[A, Queue] @@ -86,6 +84,14 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) else if (in.nonEmpty) new Queue(Nil, in.reverse.tail) else throw new NoSuchElementException("tail on empty queue") + /* This is made to avoid inefficient implementation of iterator. */ + override def forall(p: A => Boolean): Boolean = + in.forall(p) && out.forall(p) + + /* This is made to avoid inefficient implementation of iterator. */ + override def exists(p: A => Boolean): Boolean = + in.exists(p) || out.exists(p) + /** Returns the length of the queue. */ override def length = in.length + out.length @@ -100,6 +106,15 @@ class Queue[+A] protected(protected val in: List[A], protected val out: List[A]) case _ => super.:+(elem)(bf) } + override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Queue[A], B, That]): That = { + if (bf eq Queue.ReusableCBF) { + val thatQueue = that.asInstanceOf[Queue[B]] + new Queue[B](thatQueue.in ++ (thatQueue.out reverse_::: this.in), this.out).asInstanceOf[That] + } else { + super.++(that)(bf) + } + } + /** Creates a new queue with element added at the end * of the old queue. * diff --git a/src/library/scala/collection/immutable/Range.scala b/src/library/scala/collection/immutable/Range.scala index ca6720da19..82203b3d1a 100644 --- a/src/library/scala/collection/immutable/Range.scala +++ b/src/library/scala/collection/immutable/Range.scala @@ -33,7 +33,7 @@ import scala.collection.parallel.immutable.ParRange * `init`) are also permitted on overfull ranges. * * @param start the start of this range. - * @param end the end of the range. For exclusive ranges, e.g. + * @param end the end of the range. For exclusive ranges, e.g. * `Range(0,3)` or `(0 until 3)`, this is one * step past the last one in the range. For inclusive * ranges, e.g. `Range.inclusive(0,3)` or `(0 to 3)`, @@ -57,8 +57,7 @@ import scala.collection.parallel.immutable.ParRange * and its complexity is O(1). */ @SerialVersionUID(7618862778670199309L) -@deprecatedInheritance("The implementation details of Range makes inheriting from it unwise.", "2.11.0") -class Range(val start: Int, val end: Int, val step: Int) +sealed class Range(val start: Int, val end: Int, val step: Int) extends scala.collection.AbstractSeq[Int] with IndexedSeq[Int] with scala.collection.CustomParallelizable[Int, ParRange] @@ -81,8 +80,8 @@ extends scala.collection.AbstractSeq[Int] || (start < end && step < 0) || (start == end && !isInclusive) ) - @deprecated("This method will be made private, use `length` instead.", "2.11") - final val numRangeElements: Int = { + + private val numRangeElements: Int = { if (step == 0) throw new IllegalArgumentException("step cannot be 0.") else if (isEmpty) 0 else { @@ -91,21 +90,17 @@ extends scala.collection.AbstractSeq[Int] else len.toInt } } - @deprecated("This method will be made private, use `last` instead.", "2.11") - final val lastElement = - if (isEmpty) start - step - else step match { - case 1 => if (isInclusive) end else end-1 - case -1 => if (isInclusive) end else end+1 - case _ => - val remainder = (gap % step).toInt - if (remainder != 0) end - remainder - else if (isInclusive) end - else end - step - } - - @deprecated("This method will be made private.", "2.11") - final val terminalElement = lastElement + step + + // This field has a sensible value only for non-empty ranges + private val lastElement = step match { + case 1 => if (isInclusive) end else end-1 + case -1 => if (isInclusive) end else end+1 + case _ => + val remainder = (gap % step).toInt + if (remainder != 0) end - remainder + else if (isInclusive) end + else end - step + } /** The last element of this range. This method will return the correct value * even if there are too many elements to iterate over. @@ -199,6 +194,23 @@ extends scala.collection.AbstractSeq[Int] } ) + /** Creates a new range containing the elements starting at `from` up to but not including `until`. + * + * $doesNotUseBuilders + * + * @param from the element at which to start + * @param until the element at which to end (not included in the range) + * @return a new range consisting of a contiguous interval of values in the old range + */ + override def slice(from: Int, until: Int): Range = + if (from <= 0) take(until) + else if (until >= numRangeElements && numRangeElements >= 0) drop(from) + else { + val fromValue = locationAfterN(from) + if (from >= until) newEmptyRange(fromValue) + else new Range.Inclusive(fromValue, locationAfterN(until-1), step) + } + /** Creates a new range containing all the elements of this range except the last one. * * $doesNotUseBuilders @@ -380,22 +392,20 @@ extends scala.collection.AbstractSeq[Int] case _ => super.equals(other) } - /** Note: hashCode can't be overridden without breaking Seq's - * equals contract. - */ - override def toString() = { - val endStr = - if (numRangeElements > Range.MAX_PRINT || (!isEmpty && numRangeElements < 0)) ", ... )" else ")" - take(Range.MAX_PRINT).mkString("Range(", ", ", endStr) + /* Note: hashCode can't be overridden without breaking Seq's equals contract. */ + + override def toString = { + val preposition = if (isInclusive) "to" else "until" + val stepped = if (step == 1) "" else s" by $step" + val prefix = if (isEmpty) "empty " else if (!isExact) "inexact " else "" + s"${prefix}Range $start $preposition $end$stepped" } } /** A companion object for the `Range` class. */ object Range { - private[immutable] val MAX_PRINT = 512 // some arbitrary value - /** Counts the number of range elements. * @pre step != 0 * If the size of the range exceeds Int.MaxValue, the @@ -427,7 +437,7 @@ object Range { def count(start: Int, end: Int, step: Int): Int = count(start, end, step, isInclusive = false) - class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) { + final class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) { // override def par = new ParRange(this) override def isInclusive = true override protected def copy(start: Int, end: Int, step: Int): Range = new Inclusive(start, end, step) @@ -496,8 +506,9 @@ object Range { // As there is no appealing default step size for not-really-integral ranges, // we offer a partially constructed object. - class Partial[T, U](f: T => U) { + class Partial[T, U](private val f: T => U) extends AnyVal { def by(x: T): U = f(x) + override def toString = "Range requires step" } // Illustrating genericity with Int Range, which should have the same behavior diff --git a/src/library/scala/collection/immutable/Set.scala b/src/library/scala/collection/immutable/Set.scala index 031e5248c1..0f16f97cb0 100644 --- a/src/library/scala/collection/immutable/Set.scala +++ b/src/library/scala/collection/immutable/Set.scala @@ -65,6 +65,7 @@ object Set extends ImmutableSetFactory[Set] { implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A] /** An optimized representation for immutable empty sets */ + @SerialVersionUID(-2443710944435909512L) private object EmptySet extends AbstractSet[Any] with Set[Any] with Serializable { override def size: Int = 0 def contains(elem: Any): Boolean = false @@ -103,10 +104,11 @@ object Set extends ImmutableSetFactory[Set] { if (p(elem1)) Some(elem1) else None } + override def head: A = elem1 + override def tail: Set[A] = Set.empty // Why is Set1 non-final? Need to fix that! @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set1[B]] - } /** An optimized representation for immutable sets of size 2 */ @@ -138,6 +140,8 @@ object Set extends ImmutableSetFactory[Set] { else if (p(elem2)) Some(elem2) else None } + override def head: A = elem1 + override def tail: Set[A] = new Set1(elem2) // Why is Set2 non-final? Need to fix that! @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set2[B]] @@ -174,6 +178,8 @@ object Set extends ImmutableSetFactory[Set] { else if (p(elem3)) Some(elem3) else None } + override def head: A = elem1 + override def tail: Set[A] = new Set2(elem2, elem3) // Why is Set3 non-final? Need to fix that! @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set3[B]] @@ -187,7 +193,7 @@ object Set extends ImmutableSetFactory[Set] { elem == elem1 || elem == elem2 || elem == elem3 || elem == elem4 def + (elem: A): Set[A] = if (contains(elem)) this - else new HashSet[A] + (elem1, elem2, elem3, elem4, elem) + else new HashSet[A] + elem1 + elem2 + elem3 + elem4 + elem def - (elem: A): Set[A] = if (elem == elem1) new Set3(elem2, elem3, elem4) else if (elem == elem2) new Set3(elem1, elem3, elem4) @@ -212,6 +218,8 @@ object Set extends ImmutableSetFactory[Set] { else if (p(elem4)) Some(elem4) else None } + override def head: A = elem1 + override def tail: Set[A] = new Set3(elem2, elem3, elem4) // Why is Set4 non-final? Need to fix that! @deprecatedOverriding("This immutable set should do nothing on toSet but cast itself to a Set with a wider element type.", "2.11.8") override def toSet[B >: A]: Set[B] = this.asInstanceOf[Set4[B]] diff --git a/src/library/scala/collection/immutable/SetProxy.scala b/src/library/scala/collection/immutable/SetProxy.scala index d505185e1d..b421b48597 100644 --- a/src/library/scala/collection/immutable/SetProxy.scala +++ b/src/library/scala/collection/immutable/SetProxy.scala @@ -12,8 +12,7 @@ package scala package collection package immutable -/** This is a simple wrapper class for <a href="Set.html" - * target="contentFrame">`scala.collection.immutable.Set`</a>. +/** This is a simple wrapper class for [[scala.collection.immutable.Set]]. * * It is most useful for assembling customized set abstractions * dynamically using object composition and forwarding. @@ -22,7 +21,7 @@ package immutable * * @since 2.8 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") trait SetProxy[A] extends Set[A] with SetProxyLike[A, Set[A]] { override def repr = this private def newProxy[B >: A](newSelf: Set[B]): SetProxy[B] = diff --git a/src/library/scala/collection/immutable/SortedMap.scala b/src/library/scala/collection/immutable/SortedMap.scala index 682788e18e..0f3bd2e195 100644 --- a/src/library/scala/collection/immutable/SortedMap.scala +++ b/src/library/scala/collection/immutable/SortedMap.scala @@ -14,7 +14,6 @@ package immutable import generic._ import mutable.Builder -import scala.annotation.unchecked.uncheckedVariance /** A map whose keys are sorted. * diff --git a/src/library/scala/collection/immutable/SortedSet.scala b/src/library/scala/collection/immutable/SortedSet.scala index 4a8859a7ab..75b2b1f4dc 100644 --- a/src/library/scala/collection/immutable/SortedSet.scala +++ b/src/library/scala/collection/immutable/SortedSet.scala @@ -13,7 +13,6 @@ package collection package immutable import generic._ -import mutable.Builder /** A subtrait of `collection.SortedSet` which represents sorted sets * which cannot be mutated. @@ -38,6 +37,6 @@ object SortedSet extends ImmutableSortedSetFactory[SortedSet] { /** $sortedSetCanBuildFromInfo */ def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = newCanBuildFrom[A] def empty[A](implicit ord: Ordering[A]): SortedSet[A] = TreeSet.empty[A] - // Force a declaration here so that BitSet's (which does not inherit from SortedSetFactory) can be more specific + // 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 } diff --git a/src/library/scala/collection/immutable/Stack.scala b/src/library/scala/collection/immutable/Stack.scala index 1c28093b2c..02bdadb5dd 100644 --- a/src/library/scala/collection/immutable/Stack.scala +++ b/src/library/scala/collection/immutable/Stack.scala @@ -46,7 +46,7 @@ object Stack extends SeqFactory[Stack] { * @define willNotTerminateInf */ @SerialVersionUID(1976480595012942526L) -@deprecated("Stack is an inelegant and potentially poorly-performing wrapper around List. Use List instead: stack push x becomes x :: list; stack.pop is list.tail.", "2.11.0") +@deprecated("Stack is an inelegant and potentially poorly-performing wrapper around List. Use List instead: stack push x becomes x :: list; stack.pop is list.tail.", "2.11.0") class Stack[+A] protected (protected val elems: List[A]) extends AbstractSeq[A] with LinearSeq[A] diff --git a/src/library/scala/collection/immutable/Stream.scala b/src/library/scala/collection/immutable/Stream.scala index d3be809255..8f26de153a 100644 --- a/src/library/scala/collection/immutable/Stream.scala +++ b/src/library/scala/collection/immutable/Stream.scala @@ -11,7 +11,7 @@ package collection package immutable import generic._ -import mutable.{Builder, StringBuilder, LazyBuilder, ListBuffer} +import mutable.{Builder, StringBuilder, LazyBuilder} import scala.annotation.tailrec import Stream.cons import scala.language.implicitConversions @@ -23,7 +23,7 @@ import scala.language.implicitConversions * import scala.math.BigInt * object Main extends App { * - * val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 } + * lazy val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map { n => n._1 + n._2 } * * fibs take 5 foreach println * } @@ -46,7 +46,7 @@ import scala.language.implicitConversions * import scala.math.BigInt * object Main extends App { * - * val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip( + * lazy val fibs: Stream[BigInt] = BigInt(0) #:: BigInt(1) #:: fibs.zip( * fibs.tail).map(n => { * println("Adding %d and %d".format(n._1, n._2)) * n._1 + n._2 @@ -162,7 +162,7 @@ import scala.language.implicitConversions * // The first time we try to access the tail we're going to need more * // information which will require us to recurse, which will require us to * // recurse, which... - * val sov: Stream[Vector[Int]] = Vector(0) #:: sov.zip(sov.tail).map { n => n._1 ++ n._2 } + * lazy val sov: Stream[Vector[Int]] = Vector(0) #:: sov.zip(sov.tail).map { n => n._1 ++ n._2 } * }}} * * The definition of `fibs` above creates a larger number of objects than @@ -198,16 +198,13 @@ import scala.language.implicitConversions * @define orderDependentFold * @define willTerminateInf Note: lazily evaluated; will terminate for infinite-sized collections. */ -@deprecatedInheritance("This class will be sealed.", "2.11.0") -abstract class Stream[+A] extends AbstractSeq[A] +sealed abstract class Stream[+A] extends AbstractSeq[A] with LinearSeq[A] with GenericTraversableTemplate[A, Stream] with LinearSeqOptimized[A, Stream[A]] - with Serializable { -self => - override def companion: GenericCompanion[Stream] = Stream + with Serializable { self => - import scala.collection.{Traversable, Iterable, Seq, IndexedSeq} + override def companion: GenericCompanion[Stream] = Stream /** Indicates whether or not the `Stream` is empty. * @@ -360,7 +357,7 @@ self => * `List(BigInt(12)) ++ fibs`. * * @tparam B The element type of the returned collection.'''That''' - * @param that The [[scala.collection.GenTraversableOnce]] the be concatenated + * @param that The [[scala.collection.GenTraversableOnce]] to be concatenated * to this `Stream`. * @return A new collection containing the result of concatenating `this` with * `that`. @@ -499,80 +496,19 @@ self => ) else super.flatMap(f)(bf) - /** Returns all the elements of this `Stream` that satisfy the predicate `p` - * in a new `Stream` - i.e., it is still a lazy data structure. The order of - * the elements is preserved - * - * @param p the predicate used to filter the stream. - * @return the elements of this stream satisfying `p`. - * - * @example {{{ - * $naturalsEx - * naturalsFrom(1) filter { _ % 5 == 0 } take 10 mkString(", ") - * // produces "5, 10, 15, 20, 25, 30, 35, 40, 45, 50" - * }}} - */ - override def filter(p: A => Boolean): Stream[A] = { + override private[scala] def filterImpl(p: A => Boolean, isFlipped: Boolean): Stream[A] = { // optimization: drop leading prefix of elems for which f returns false // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise var rest = this - while (!rest.isEmpty && !p(rest.head)) rest = rest.tail + while (!rest.isEmpty && p(rest.head) == isFlipped) rest = rest.tail // private utility func to avoid `this` on stack (would be needed for the lazy arg) - if (rest.nonEmpty) Stream.filteredTail(rest, p) + if (rest.nonEmpty) Stream.filteredTail(rest, p, isFlipped) else Stream.Empty } - override final def withFilter(p: A => Boolean): StreamWithFilter = new StreamWithFilter(p) - - /** A lazier implementation of WithFilter than TraversableLike's. - */ - final class StreamWithFilter(p: A => Boolean) extends WithFilter(p) { - - override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { - def tailMap(coll: Stream[A]): Stream[B] = { - var head: A = null.asInstanceOf[A] - var tail: Stream[A] = coll - while (true) { - if (tail.isEmpty) - return Stream.Empty - head = tail.head - tail = tail.tail - if (p(head)) - return cons(f(head), tailMap(tail)) - } - throw new RuntimeException() - } - - if (isStreamBuilder(bf)) asThat(tailMap(Stream.this)) - else super.map(f)(bf) - } - - override def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = { - def tailFlatMap(coll: Stream[A]): Stream[B] = { - var head: A = null.asInstanceOf[A] - var tail: Stream[A] = coll - while (true) { - if (tail.isEmpty) - return Stream.Empty - head = tail.head - tail = tail.tail - if (p(head)) - return f(head).toStream append tailFlatMap(tail) - } - throw new RuntimeException() - } - - if (isStreamBuilder(bf)) asThat(tailFlatMap(Stream.this)) - else super.flatMap(f)(bf) - } - - override def foreach[U](f: A => U) = - for (x <- self) - if (p(x)) f(x) - - override def withFilter(q: A => Boolean): StreamWithFilter = - new StreamWithFilter(x => p(x) && q(x)) - } + /** A FilterMonadic which allows GC of the head of stream during processing */ + @noinline // Workaround SI-9137, see https://github.com/scala/scala/pull/4284#issuecomment-73180791 + override final def withFilter(p: A => Boolean): FilterMonadic[A, Stream[A]] = new Stream.StreamWithFilter(this, p) /** A lazier Iterator than LinearSeqLike's. */ override def iterator: Iterator[A] = new StreamIterator(self) @@ -1093,6 +1029,8 @@ self => */ override def stringPrefix = "Stream" + override def equals(that: Any): Boolean = + if (this eq that.asInstanceOf[AnyRef]) true else super.equals(that) } /** A specialized, extra-lazy implementation of a stream iterator, so it can @@ -1152,14 +1090,12 @@ object Stream extends SeqFactory[Stream] { /** Creates a new builder for a stream */ def newBuilder[A]: Builder[A, Stream[A]] = new StreamBuilder[A] - import scala.collection.{Iterable, Seq, IndexedSeq} - /** A builder for streams * @note This builder is lazy only in the sense that it does not go downs the spine * of traversables that are added as a whole. If more laziness can be achieved, * this builder should be bypassed. */ - class StreamBuilder[A] extends scala.collection.mutable.LazyBuilder[A, Stream[A]] { + class StreamBuilder[A] extends LazyBuilder[A, Stream[A]] { def result: Stream[A] = parts.toStream flatMap (_.toStream) } @@ -1183,11 +1119,11 @@ object Stream extends SeqFactory[Stream] { /** Construct a stream consisting of a given first element followed by elements * from a lazily evaluated Stream. */ - def #::(hd: A): Stream[A] = cons(hd, tl) + def #::[B >: A](hd: B): Stream[B] = cons(hd, tl) /** Construct a stream consisting of the concatenation of the given stream and * a lazily evaluated Stream. */ - def #:::(prefix: Stream[A]): Stream[A] = prefix append tl + def #:::[B >: A](prefix: Stream[B]): Stream[B] = prefix append tl } /** A wrapper method that adds `#::` for cons and `#:::` for concat as operations @@ -1237,6 +1173,27 @@ object Stream extends SeqFactory[Stream] { tlVal } + + override /*LinearSeqOptimized*/ + def sameElements[B >: A](that: GenIterable[B]): Boolean = { + @tailrec def consEq(a: Cons[_], b: Cons[_]): Boolean = { + if (a.head != b.head) false + else { + a.tail match { + case at: Cons[_] => + b.tail match { + case bt: Cons[_] => (at eq bt) || consEq(at, bt) + case _ => false + } + case _ => b.tail.isEmpty + } + } + } + that match { + case that: Cons[_] => consEq(this, that) + case _ => super.sameElements(that) + } + } } /** An infinite stream that repeatedly applies a given function to a start value. @@ -1295,13 +1252,36 @@ object Stream extends SeqFactory[Stream] { else cons(start, range(start + step, end, step)) } - private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean) = { - cons(stream.head, stream.tail filter p) + private[immutable] def filteredTail[A](stream: Stream[A], p: A => Boolean, isFlipped: Boolean) = { + cons(stream.head, stream.tail.filterImpl(p, isFlipped)) } private[immutable] def collectedTail[A, B, That](head: B, stream: Stream[A], pf: PartialFunction[A, B], bf: CanBuildFrom[Stream[A], B, That]) = { cons(head, stream.tail.collect(pf)(bf).asInstanceOf[Stream[B]]) } -} + /** An implementation of `FilterMonadic` allowing GC of the filtered-out elements of + * the `Stream` as it is processed. + * + * Because this is not an inner class of `Stream` with a reference to the original + * head, it is now possible for GC to collect any leading and filtered-out elements + * which do not satisfy the filter, while the tail is still processing (see SI-8990). + */ + private[immutable] final class StreamWithFilter[A](sl: => Stream[A], p: A => Boolean) extends FilterMonadic[A, Stream[A]] { + private var s = sl // set to null to allow GC after filtered + private lazy val filtered = { val f = s filter p; s = null; f } // don't set to null if throw during filter + + def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Stream[A], B, That]): That = + filtered map f + + def flatMap[B, That](f: A => scala.collection.GenTraversableOnce[B])(implicit bf: CanBuildFrom[Stream[A], B, That]): That = + filtered flatMap f + def foreach[U](f: A => U): Unit = + filtered foreach f + + def withFilter(q: A => Boolean): FilterMonadic[A, Stream[A]] = + new StreamWithFilter[A](filtered, q) + } + +} diff --git a/src/library/scala/collection/immutable/StreamViewLike.scala b/src/library/scala/collection/immutable/StreamViewLike.scala index c2eb85815d..4d7eaeff2a 100644 --- a/src/library/scala/collection/immutable/StreamViewLike.scala +++ b/src/library/scala/collection/immutable/StreamViewLike.scala @@ -53,6 +53,7 @@ extends SeqView[A, Coll] /** boilerplate */ protected override def newForced[B](xs: => scala.collection.GenSeq[B]): Transformed[B] = new { val forced = xs } with AbstractTransformed[B] with Forced[B] protected override def newAppended[B >: A](that: scala.collection.GenTraversable[B]): Transformed[B] = new { val rest = that } with AbstractTransformed[B] with Appended[B] + protected override def newPrepended[B >: A](that: scala.collection.GenTraversable[B]): Transformed[B] = new { protected[this] val fst = that } with AbstractTransformed[B] with Prepended[B] protected override def newMapped[B](f: A => B): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with Mapped[B] protected override def newFlatMapped[B](f: A => scala.collection.GenTraversableOnce[B]): Transformed[B] = new { val mapping = f } with AbstractTransformed[B] with FlatMapped[B] protected override def newFiltered(p: A => Boolean): Transformed[A] = new { val pred = p } with AbstractTransformed[A] with Filtered @@ -67,7 +68,6 @@ extends SeqView[A, Coll] protected override def newPatched[B >: A](_from: Int, _patch: scala.collection.GenSeq[B], _replaced: Int): Transformed[B] = { new { val from = _from; val patch = _patch; val replaced = _replaced } with AbstractTransformed[B] with Patched[B] } - protected override def newPrepended[B >: A](elem: B): Transformed[B] = new { protected[this] val fst = elem } with AbstractTransformed[B] with Prepended[B] override def stringPrefix = "StreamView" } diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala index 232d67df4f..fce0f073aa 100644 --- a/src/library/scala/collection/immutable/StringLike.scala +++ b/src/library/scala/collection/immutable/StringLike.scala @@ -10,7 +10,7 @@ package scala package collection package immutable -import mutable.{ ArrayBuilder, Builder } +import mutable.Builder import scala.util.matching.Regex import scala.math.ScalaNumber import scala.reflect.ClassTag @@ -100,11 +100,13 @@ self => /** Return all lines in this string in an iterator, including trailing * line end characters. * - * The number of strings returned is one greater than the number of line - * end characters in this string. For an empty string, a single empty - * line is returned. A line end character is one of - * - `LF` - line feed (`0x0A` hex) - * - `FF` - form feed (`0x0C` hex) + * This method is analogous to `s.split(EOL).toIterator`, + * except that any existing line endings are preserved in the result strings, + * and the empty string yields an empty iterator. + * + * A line end character is one of + * - `LF` - line feed (`0x0A`) + * - `FF` - form feed (`0x0C`) */ def linesWithSeparators: Iterator[String] = new AbstractIterator[String] { val str = self.toString @@ -121,17 +123,17 @@ self => } /** Return all lines in this string in an iterator, excluding trailing line - * end characters, i.e., apply `.stripLineEnd` to all lines + * end characters; i.e., apply `.stripLineEnd` to all lines * returned by `linesWithSeparators`. */ def lines: Iterator[String] = linesWithSeparators map (line => new WrappedString(line).stripLineEnd) /** Return all lines in this string in an iterator, excluding trailing line - * end characters, i.e., apply `.stripLineEnd` to all lines + * end characters; i.e., apply `.stripLineEnd` to all lines * returned by `linesWithSeparators`. */ - @deprecated("Use `lines` instead.","2.11.0") + @deprecated("use `lines` instead","2.11.0") def linesIterator: Iterator[String] = linesWithSeparators map (line => new WrappedString(line).stripLineEnd) @@ -163,20 +165,14 @@ self => if (toString.endsWith(suffix)) toString.substring(0, toString.length() - suffix.length) else toString - /** Replace all literal occurrences of `literal` with the string `replacement`. - * This is equivalent to [[java.lang.String#replaceAll]] except that both arguments - * are appropriately quoted to avoid being interpreted as metacharacters. + /** Replace all literal occurrences of `literal` with the literal string `replacement`. + * This method is equivalent to [[java.lang.String#replace]]. * * @param literal the string which should be replaced everywhere it occurs * @param replacement the replacement string * @return the resulting string */ - def replaceAllLiterally(literal: String, replacement: String): String = { - val arg1 = Regex.quote(literal) - val arg2 = Regex.quoteReplacement(replacement) - - toString.replaceAll(arg1, arg2) - } + def replaceAllLiterally(literal: String, replacement: String): String = toString.replace(literal, replacement) /** For every line in this string: * @@ -202,35 +198,64 @@ self => */ def stripMargin: String = stripMargin('|') - private def escape(ch: Char): String = "\\Q" + ch + "\\E" - - def split(separator: Char): Array[String] = { - val thisString = toString - var pos = thisString.indexOf(separator) - - if (pos != -1) { - val res = new ArrayBuilder.ofRef[String] - - var prev = 0 - do { - res += thisString.substring(prev, pos) - prev = pos + 1 - pos = thisString.indexOf(separator, prev) - } while (pos != -1) - - if (prev != thisString.length) - res += thisString.substring(prev, thisString.length) - - val initialResult = res.result() - pos = initialResult.length - while (pos > 0 && initialResult(pos - 1).isEmpty) pos = pos - 1 - if (pos != initialResult.length) { - val trimmed = new Array[String](pos) - Array.copy(initialResult, 0, trimmed, 0, pos) - trimmed - } else initialResult - } else Array[String](thisString) - } + private def escape(ch: Char): String = if ( + (ch >= 'a') && (ch <= 'z') || + (ch >= 'A') && (ch <= 'Z') || + (ch >= '0' && ch <= '9')) ch.toString + else "\\" + ch + + /** Split this string around the separator character + * + * If this string is the empty string, returns an array of strings + * that contains a single empty string. + * + * If this string is not the empty string, returns an array containing + * the substrings terminated by the start of the string, the end of the + * string or the separator character, excluding empty trailing substrings + * + * If the separator character is a surrogate character, only split on + * matching surrogate characters if they are not part of a surrogate pair + * + * The behaviour follows, and is implemented in terms of <a href="http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split%28java.lang.String%29">String.split(re: String)</a> + * + * + * @example {{{ + * "a.b".split('.') //returns Array("a", "b") + * + * //splitting the empty string always returns the array with a single + * //empty string + * "".split('.') //returns Array("") + * + * //only trailing empty substrings are removed + * "a.".split('.') //returns Array("a") + * ".a.".split('.') //returns Array("", "a") + * "..a..".split('.') //returns Array("", "", "a") + * + * //all parts are empty and trailing + * ".".split('.') //returns Array() + * "..".split('.') //returns Array() + * + * //surrogate pairs + * val high = 0xD852.toChar + * val low = 0xDF62.toChar + * val highstring = high.toString + * val lowstring = low.toString + * + * //well-formed surrogate pairs are not split + * val highlow = highstring + lowstring + * highlow.split(high) //returns Array(highlow) + * + * //bare surrogate characters are split + * val bare = "_" + highstring + "_" + * bare.split(high) //returns Array("_", "_") + * + * }}} + * + * @param separator the character used as a delimiter + */ + def split(separator: Char): Array[String] = + toString.split(escape(separator)) + @throws(classOf[java.util.regex.PatternSyntaxException]) def split(separators: Array[Char]): Array[String] = { @@ -256,31 +281,39 @@ self => def r(groupNames: String*): Regex = new Regex(toString, groupNames: _*) /** - * @throws java.lang.IllegalArgumentException - If the string does not contain a parsable boolean. + * @throws java.lang.IllegalArgumentException If the string does not contain a parsable `Boolean`. */ def toBoolean: Boolean = parseBoolean(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable byte. + * Parse as a `Byte` (string must contain only decimal digits and optional leading `-`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Byte`. */ def toByte: Byte = java.lang.Byte.parseByte(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable short. + * Parse as a `Short` (string must contain only decimal digits and optional leading `-`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Short`. */ def toShort: Short = java.lang.Short.parseShort(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable int. + * Parse as an `Int` (string must contain only decimal digits and optional leading `-`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Int`. */ def toInt: Int = java.lang.Integer.parseInt(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable long. + * Parse as a `Long` (string must contain only decimal digits and optional leading `-`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Long`. */ def toLong: Long = java.lang.Long.parseLong(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable float. + * Parse as a `Float` (surrounding whitespace is removed with a `trim`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Float`. + * @throws java.lang.NullPointerException If the string is null. */ def toFloat: Float = java.lang.Float.parseFloat(toString) /** - * @throws java.lang.NumberFormatException - If the string does not contain a parsable double. + * Parse as a `Double` (surrounding whitespace is removed with a `trim`). + * @throws java.lang.NumberFormatException If the string does not contain a parsable `Double`. + * @throws java.lang.NullPointerException If the string is null. */ def toDouble: Double = java.lang.Double.parseDouble(toString) @@ -306,8 +339,7 @@ self => * holes. * * The interpretation of the formatting patterns is described in - * <a href="" target="contentFrame" class="java/util/Formatter"> - * `java.util.Formatter`</a>, with the addition that + * [[java.util.Formatter]], with the addition that * classes deriving from `ScalaNumber` (such as [[scala.BigInt]] and * [[scala.BigDecimal]]) are unwrapped to pass a type which `Formatter` * understands. @@ -322,8 +354,7 @@ self => * which influences formatting as in `java.lang.String`'s format. * * The interpretation of the formatting patterns is described in - * <a href="" target="contentFrame" class="java/util/Formatter"> - * `java.util.Formatter`</a>, with the addition that + * [[java.util.Formatter]], with the addition that * classes deriving from `ScalaNumber` (such as `scala.BigInt` and * `scala.BigDecimal`) are unwrapped to pass a type which `Formatter` * understands. diff --git a/src/library/scala/collection/immutable/Traversable.scala b/src/library/scala/collection/immutable/Traversable.scala index 5fc0607a00..3d4ba95a16 100644 --- a/src/library/scala/collection/immutable/Traversable.scala +++ b/src/library/scala/collection/immutable/Traversable.scala @@ -18,6 +18,17 @@ import mutable.Builder /** A trait for traversable collections that are guaranteed immutable. * $traversableInfo * @define mutability immutable + * + * @define usesMutableState + * + * Note: Despite being an immutable collection, the implementation uses mutable state internally during + * construction. These state changes are invisible in single-threaded code but can lead to race conditions + * in some multi-threaded scenarios. The state of a new collection instance may not have been "published" + * (in the sense of the Java Memory Model specification), so that an unsynchronized non-volatile read from + * another thread may observe the object in an invalid state (see + * [[https://issues.scala-lang.org/browse/SI-7838 SI-7838]] for details). Note that such a read is not + * guaranteed to ''ever'' see the written object at all, and should therefore not be used, regardless + * of this issue. The easiest workaround is to exchange values between threads through a volatile var. */ trait Traversable[+A] extends scala.collection.Traversable[A] // with GenTraversable[A] diff --git a/src/library/scala/collection/immutable/TreeMap.scala b/src/library/scala/collection/immutable/TreeMap.scala index b845b76026..2d1bf0f6b1 100644 --- a/src/library/scala/collection/immutable/TreeMap.scala +++ b/src/library/scala/collection/immutable/TreeMap.scala @@ -44,8 +44,7 @@ object TreeMap extends ImmutableSortedMapFactory[TreeMap] { * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecatedInheritance("The implementation details of immutable tree maps make inheriting from them unwise.", "2.11.0") -class TreeMap[A, +B] private (tree: RB.Tree[A, B])(implicit val ordering: Ordering[A]) +final class TreeMap[A, +B] private (tree: RB.Tree[A, B])(implicit val ordering: Ordering[A]) extends SortedMap[A, B] with SortedMapLike[A, B, TreeMap[A, B]] with MapLike[A, B, TreeMap[A, B]] diff --git a/src/library/scala/collection/immutable/TreeSet.scala b/src/library/scala/collection/immutable/TreeSet.scala index 2800030d67..2cdf3b3521 100644 --- a/src/library/scala/collection/immutable/TreeSet.scala +++ b/src/library/scala/collection/immutable/TreeSet.scala @@ -49,8 +49,7 @@ object TreeSet extends ImmutableSortedSetFactory[TreeSet] { * @define willNotTerminateInf */ @SerialVersionUID(-5685982407650748405L) -@deprecatedInheritance("The implementation details of immutable tree sets make inheriting from them unwise.", "2.11.0") -class TreeSet[A] private (tree: RB.Tree[A, Unit])(implicit val ordering: Ordering[A]) +final class TreeSet[A] private (tree: RB.Tree[A, Unit])(implicit val ordering: Ordering[A]) extends SortedSet[A] with SortedSetLike[A, TreeSet[A]] with Serializable { if (ordering eq null) diff --git a/src/library/scala/collection/immutable/Vector.scala b/src/library/scala/collection/immutable/Vector.scala index 5a9734a99e..1093084b9d 100644 --- a/src/library/scala/collection/immutable/Vector.scala +++ b/src/library/scala/collection/immutable/Vector.scala @@ -11,9 +11,8 @@ package collection package immutable import scala.annotation.unchecked.uncheckedVariance -import scala.compat.Platform import scala.collection.generic._ -import scala.collection.mutable.Builder +import scala.collection.mutable.{Builder, ReusableBuilder} import scala.collection.parallel.immutable.ParVector /** Companion object to the Vector class @@ -24,7 +23,7 @@ object Vector extends IndexedSeqFactory[Vector] { ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] private[immutable] val NIL = new Vector[Nothing](0, 0, 0) override def empty[A]: Vector[A] = NIL - + // Constants governing concat strategy for performance private final val Log2ConcatFaster = 5 private final val TinyAppendFaster = 2 @@ -40,6 +39,8 @@ object Vector extends IndexedSeqFactory[Vector] { * endian bit-mapped vector trie with a branching factor of 32. Locality is very good, but not * contiguous, which is good for very large sequences. * + * $usesMutableState + * * @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#vectors "Scala's Collection Library overview"]] * section on `Vectors` for more information. * @@ -59,6 +60,7 @@ object Vector extends IndexedSeqFactory[Vector] { * @define mayNotTerminateInf * @define willNotTerminateInf */ +@SerialVersionUID(-1334388273712300479L) final class Vector[+A] private[immutable] (private[collection] val startIndex: Int, private[collection] val endIndex: Int, focus: Int) extends AbstractSeq[A] with IndexedSeq[A] @@ -69,12 +71,7 @@ extends AbstractSeq[A] with CustomParallelizable[A, ParVector[A]] { self => -override def companion: GenericCompanion[Vector] = Vector - - //assert(startIndex >= 0, startIndex+"<0") - //assert(startIndex <= endIndex, startIndex+">"+endIndex) - //assert(focus >= 0, focus+"<0") - //assert(focus <= endIndex, focus+">"+endIndex) + override def companion: GenericCompanion[Vector] = Vector private[immutable] var dirty = false @@ -98,8 +95,6 @@ override def companion: GenericCompanion[Vector] = Vector s } - - // can still be improved override /*SeqLike*/ def reverseIterator: Iterator[A] = new AbstractIterator[A] { private var i = self.length @@ -111,22 +106,18 @@ override def companion: GenericCompanion[Vector] = Vector } else Iterator.empty.next() } - // TODO: reverse - - // TODO: check performance of foreach/map etc. should override or not? // Ideally, clients will inline calls to map all the way down, including the iterator/builder methods. // In principle, escape analysis could even remove the iterator/builder allocations and do it // with local variables exclusively. But we're not quite there yet ... def apply(index: Int): A = { val idx = checkRangeConvert(index) - //println("get elem: "+index + "/"+idx + "(focus:" +focus+" xor:"+(idx^focus)+" depth:"+depth+")") getElem(idx, idx ^ focus) } private def checkRangeConvert(index: Int) = { val idx = index + startIndex - if (0 <= index && idx < endIndex) + if (index >= 0 && idx < endIndex) idx else throw new IndexOutOfBoundsException(index.toString) @@ -135,7 +126,7 @@ override def companion: GenericCompanion[Vector] = Vector // If we have a default builder, there are faster ways to perform some operations @inline private[this] def isDefaultCBF[A, B, That](bf: CanBuildFrom[Vector[A], B, That]): Boolean = (bf eq IndexedSeq.ReusableCBF) || (bf eq collection.immutable.Seq.ReusableCBF) || (bf eq collection.Seq.ReusableCBF) - + // SeqLike api override def updated[B >: A, That](index: Int, elem: B)(implicit bf: CanBuildFrom[Vector[A], B, That]): That = @@ -189,31 +180,36 @@ override def companion: GenericCompanion[Vector] = Vector Vector.empty } - override /*IterableLike*/ def head: A = { + override /*IterableLike*/ + def head: A = { if (isEmpty) throw new UnsupportedOperationException("empty.head") apply(0) } - override /*TraversableLike*/ def tail: Vector[A] = { + override /*TraversableLike*/ + def tail: Vector[A] = { if (isEmpty) throw new UnsupportedOperationException("empty.tail") drop(1) } - override /*TraversableLike*/ def last: A = { + override /*TraversableLike*/ + def last: A = { if (isEmpty) throw new UnsupportedOperationException("empty.last") - apply(length-1) + apply(length - 1) } - override /*TraversableLike*/ def init: Vector[A] = { + override /*TraversableLike*/ + def init: Vector[A] = { if (isEmpty) throw new UnsupportedOperationException("empty.init") dropRight(1) } - override /*IterableLike*/ def slice(from: Int, until: Int): Vector[A] = + override /*IterableLike*/ + def slice(from: Int, until: Int): Vector[A] = take(until).drop(from) - override /*IterableLike*/ def splitAt(n: Int): (Vector[A], Vector[A]) = (take(n), drop(n)) - + override /*IterableLike*/ + def splitAt(n: Int): (Vector[A], Vector[A]) = (take(n), drop(n)) // concat (suboptimal but avoids worst performance gotchas) override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Vector[A], B, That]): That = { @@ -225,11 +221,11 @@ override def companion: GenericCompanion[Vector] = Vector val again = if (!that.isTraversableAgain) that.toVector else that.seq again.size match { // Often it's better to append small numbers of elements (or prepend if RHS is a vector) - case n if n <= TinyAppendFaster || n < (this.size >> Log2ConcatFaster) => + case n if n <= TinyAppendFaster || n < (this.size >>> Log2ConcatFaster) => var v: Vector[B] = this for (x <- again) v = v :+ x v.asInstanceOf[That] - case n if this.size < (n >> Log2ConcatFaster) && again.isInstanceOf[Vector[_]] => + case n if this.size < (n >>> Log2ConcatFaster) && again.isInstanceOf[Vector[_]] => var v = again.asInstanceOf[Vector[B]] val ri = this.reverseIterator while (ri.hasNext) v = ri.next +: v @@ -241,8 +237,6 @@ override def companion: GenericCompanion[Vector] = Vector else super.++(that.seq) } - - // semi-private api private[immutable] def updateAt[B >: A](index: Int, elem: B): Vector[B] = { @@ -251,11 +245,10 @@ override def companion: GenericCompanion[Vector] = Vector s.initFrom(this) s.dirty = dirty s.gotoPosWritable(focus, idx, focus ^ idx) // if dirty commit changes; go to new pos and prepare for writing - s.display0(idx & 0x1f) = elem.asInstanceOf[AnyRef] + s.display0(idx & 31) = elem.asInstanceOf[AnyRef] s } - private def gotoPosWritable(oldIndex: Int, newIndex: Int, xor: Int) = if (dirty) { gotoPosWritable1(oldIndex, newIndex, xor) } else { @@ -270,7 +263,7 @@ override def companion: GenericCompanion[Vector] = Vector dirty = true } - private[immutable] def appendFront[B>:A](value: B): Vector[B] = { + private[immutable] def appendFront[B >: A](value: B): Vector[B] = { if (endIndex != startIndex) { val blockIndex = (startIndex - 1) & ~31 val lo = (startIndex - 1) & 31 @@ -284,61 +277,46 @@ override def companion: GenericCompanion[Vector] = Vector s } else { - val freeSpace = ((1<<5*(depth)) - endIndex) // free space at the right given the current tree-structure depth - val shift = freeSpace & ~((1<<5*(depth-1))-1) // number of elements by which we'll shift right (only move at top level) - val shiftBlocks = freeSpace >>> 5*(depth-1) // number of top-level blocks + val freeSpace = (1 << (5 * depth)) - endIndex // free space at the right given the current tree-structure depth + val shift = freeSpace & ~((1 << (5 * (depth - 1))) - 1) // number of elements by which we'll shift right (only move at top level) + val shiftBlocks = freeSpace >>> (5 * (depth - 1)) // number of top-level blocks - //println("----- appendFront " + value + " at " + (startIndex - 1) + " reached block start") if (shift != 0) { // case A: we can shift right on the top level - debug() - //println("shifting right by " + shiftBlocks + " at level " + (depth-1) + " (had "+freeSpace+" free space)") - if (depth > 1) { val newBlockIndex = blockIndex + shift val newFocus = focus + shift + val s = new Vector(startIndex - 1 + shift, endIndex + shift, newBlockIndex) s.initFrom(this) s.dirty = dirty s.shiftTopLevel(0, shiftBlocks) // shift right by n blocks - s.debug() s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) // maybe create pos; prepare for writing s.display0(lo) = value.asInstanceOf[AnyRef] - //assert(depth == s.depth) s } else { val newBlockIndex = blockIndex + 32 val newFocus = focus - //assert(newBlockIndex == 0) - //assert(newFocus == 0) - val s = new Vector(startIndex - 1 + shift, endIndex + shift, newBlockIndex) s.initFrom(this) s.dirty = dirty s.shiftTopLevel(0, shiftBlocks) // shift right by n elements s.gotoPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) // prepare for writing - s.display0(shift-1) = value.asInstanceOf[AnyRef] - s.debug() + s.display0(shift - 1) = value.asInstanceOf[AnyRef] s } } else if (blockIndex < 0) { // case B: we need to move the whole structure - val move = (1 << 5*(depth+1)) - (1 << 5*(depth)) - //println("moving right by " + move + " at level " + (depth-1) + " (had "+freeSpace+" free space)") - + val move = (1 << (5 * (depth + 1))) - (1 << (5 * depth)) val newBlockIndex = blockIndex + move val newFocus = focus + move - val s = new Vector(startIndex - 1 + move, endIndex + move, newBlockIndex) s.initFrom(this) s.dirty = dirty - s.debug() s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) // could optimize: we know it will create a whole branch s.display0(lo) = value.asInstanceOf[AnyRef] - s.debug() - //assert(s.depth == depth+1) s } else { val newBlockIndex = blockIndex @@ -349,31 +327,26 @@ override def companion: GenericCompanion[Vector] = Vector s.dirty = dirty s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) s.display0(lo) = value.asInstanceOf[AnyRef] - //assert(s.depth == depth) s } - } } else { // empty vector, just insert single element at the back val elems = new Array[AnyRef](32) elems(31) = value.asInstanceOf[AnyRef] - val s = new Vector(31,32,0) + val s = new Vector(31, 32, 0) s.depth = 1 s.display0 = elems s } } - private[immutable] def appendBack[B>:A](value: B): Vector[B] = { -// //println("------- append " + value) -// debug() + private[immutable] def appendBack[B >: A](value: B): Vector[B] = { if (endIndex != startIndex) { val blockIndex = endIndex & ~31 val lo = endIndex & 31 if (endIndex != blockIndex) { - //println("will make writable block (from "+focus+") at: " + blockIndex) val s = new Vector(startIndex, endIndex + 1, blockIndex) s.initFrom(this) s.dirty = dirty @@ -381,41 +354,31 @@ override def companion: GenericCompanion[Vector] = Vector s.display0(lo) = value.asInstanceOf[AnyRef] s } else { - val shift = startIndex & ~((1<<5*(depth-1))-1) - val shiftBlocks = startIndex >>> 5*(depth-1) - - //println("----- appendBack " + value + " at " + endIndex + " reached block end") + val shift = startIndex & ~((1 << (5 * (depth - 1))) - 1) + val shiftBlocks = startIndex >>> (5 * (depth - 1)) if (shift != 0) { - debug() - //println("shifting left by " + shiftBlocks + " at level " + (depth-1) + " (had "+startIndex+" free space)") if (depth > 1) { val newBlockIndex = blockIndex - shift val newFocus = focus - shift + val s = new Vector(startIndex - shift, endIndex + 1 - shift, newBlockIndex) s.initFrom(this) s.dirty = dirty s.shiftTopLevel(shiftBlocks, 0) // shift left by n blocks - s.debug() s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) s.display0(lo) = value.asInstanceOf[AnyRef] - s.debug() - //assert(depth == s.depth) s } else { val newBlockIndex = blockIndex - 32 val newFocus = focus - //assert(newBlockIndex == 0) - //assert(newFocus == 0) - val s = new Vector(startIndex - shift, endIndex + 1 - shift, newBlockIndex) s.initFrom(this) s.dirty = dirty s.shiftTopLevel(shiftBlocks, 0) // shift right by n elements s.gotoPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) s.display0(32 - shift) = value.asInstanceOf[AnyRef] - s.debug() s } } else { @@ -427,18 +390,13 @@ override def companion: GenericCompanion[Vector] = Vector s.dirty = dirty s.gotoFreshPosWritable(newFocus, newBlockIndex, newFocus ^ newBlockIndex) s.display0(lo) = value.asInstanceOf[AnyRef] - //assert(s.depth == depth+1) might or might not create new level! - if (s.depth == depth+1) { - //println("creating new level " + s.depth + " (had "+0+" free space)") - s.debug() - } s } } } else { val elems = new Array[AnyRef](32) elems(0) = value.asInstanceOf[AnyRef] - val s = new Vector(0,1,0) + val s = new Vector(0, 1, 0) s.depth = 1 s.display0 = elems s @@ -449,39 +407,39 @@ override def companion: GenericCompanion[Vector] = Vector // low-level implementation (needs cleanup, maybe move to util class) private def shiftTopLevel(oldLeft: Int, newLeft: Int) = (depth - 1) match { - case 0 => - display0 = copyRange(display0, oldLeft, newLeft) - case 1 => - display1 = copyRange(display1, oldLeft, newLeft) - case 2 => - display2 = copyRange(display2, oldLeft, newLeft) - case 3 => - display3 = copyRange(display3, oldLeft, newLeft) - case 4 => - display4 = copyRange(display4, oldLeft, newLeft) - case 5 => - display5 = copyRange(display5, oldLeft, newLeft) + case 0 => display0 = copyRange(display0, oldLeft, newLeft) + case 1 => display1 = copyRange(display1, oldLeft, newLeft) + case 2 => display2 = copyRange(display2, oldLeft, newLeft) + case 3 => display3 = copyRange(display3, oldLeft, newLeft) + case 4 => display4 = copyRange(display4, oldLeft, newLeft) + case 5 => display5 = copyRange(display5, oldLeft, newLeft) } private def zeroLeft(array: Array[AnyRef], index: Int): Unit = { - var i = 0; while (i < index) { array(i) = null; i+=1 } + var i = 0 + while (i < index) { + array(i) = null + i += 1 + } } private def zeroRight(array: Array[AnyRef], index: Int): Unit = { - var i = index; while (i < array.length) { array(i) = null; i+=1 } + var i = index + while (i < array.length) { + array(i) = null + i += 1 + } } private def copyLeft(array: Array[AnyRef], right: Int): Array[AnyRef] = { -// if (array eq null) -// println("OUCH!!! " + right + "/" + depth + "/"+startIndex + "/" + endIndex + "/" + focus) - val a2 = new Array[AnyRef](array.length) - Platform.arraycopy(array, 0, a2, 0, right) - a2 + val copy = new Array[AnyRef](array.length) + java.lang.System.arraycopy(array, 0, copy, 0, right) + copy } private def copyRight(array: Array[AnyRef], left: Int): Array[AnyRef] = { - val a2 = new Array[AnyRef](array.length) - Platform.arraycopy(array, left, a2, left, a2.length - left) - a2 + val copy = new Array[AnyRef](array.length) + java.lang.System.arraycopy(array, left, copy, left, copy.length - left) + copy } private def preClean(depth: Int) = { @@ -513,38 +471,33 @@ override def companion: GenericCompanion[Vector] = Vector // requires structure is at index cutIndex and writable at level 0 private def cleanLeftEdge(cutIndex: Int) = { - if (cutIndex < (1 << 5)) { + if (cutIndex < (1 << 5)) { zeroLeft(display0, cutIndex) - } else - if (cutIndex < (1 << 10)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5)) - } else - if (cutIndex < (1 << 15)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5) & 0x1f) - display2 = copyRight(display2, (cutIndex >>> 10)) - } else - if (cutIndex < (1 << 20)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5) & 0x1f) - display2 = copyRight(display2, (cutIndex >>> 10) & 0x1f) - display3 = copyRight(display3, (cutIndex >>> 15)) - } else - if (cutIndex < (1 << 25)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5) & 0x1f) - display2 = copyRight(display2, (cutIndex >>> 10) & 0x1f) - display3 = copyRight(display3, (cutIndex >>> 15) & 0x1f) - display4 = copyRight(display4, (cutIndex >>> 20)) - } else - if (cutIndex < (1 << 30)) { - zeroLeft(display0, cutIndex & 0x1f) - display1 = copyRight(display1, (cutIndex >>> 5) & 0x1f) - display2 = copyRight(display2, (cutIndex >>> 10) & 0x1f) - display3 = copyRight(display3, (cutIndex >>> 15) & 0x1f) - display4 = copyRight(display4, (cutIndex >>> 20) & 0x1f) - display5 = copyRight(display5, (cutIndex >>> 25)) + } else if (cutIndex < (1 << 10)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, cutIndex >>> 5) + } else if (cutIndex < (1 << 15)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, (cutIndex >>> 5) & 31) + display2 = copyRight(display2, cutIndex >>> 10) + } else if (cutIndex < (1 << 20)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, (cutIndex >>> 5) & 31) + display2 = copyRight(display2, (cutIndex >>> 10) & 31) + display3 = copyRight(display3, cutIndex >>> 15) + } else if (cutIndex < (1 << 25)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, (cutIndex >>> 5) & 31) + display2 = copyRight(display2, (cutIndex >>> 10) & 31) + display3 = copyRight(display3, (cutIndex >>> 15) & 31) + display4 = copyRight(display4, cutIndex >>> 20) + } else if (cutIndex < (1 << 30)) { + zeroLeft(display0, cutIndex & 31) + display1 = copyRight(display1, (cutIndex >>> 5) & 31) + display2 = copyRight(display2, (cutIndex >>> 10) & 31) + display3 = copyRight(display3, (cutIndex >>> 15) & 31) + display4 = copyRight(display4, (cutIndex >>> 20) & 31) + display5 = copyRight(display5, cutIndex >>> 25) } else { throw new IllegalArgumentException() } @@ -552,49 +505,43 @@ override def companion: GenericCompanion[Vector] = Vector // requires structure is writable and at index cutIndex private def cleanRightEdge(cutIndex: Int) = { - // we're actually sitting one block left if cutIndex lies on a block boundary // this means that we'll end up erasing the whole block!! - if (cutIndex <= (1 << 5)) { + if (cutIndex <= (1 << 5)) { zeroRight(display0, cutIndex) - } else - if (cutIndex <= (1 << 10)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (cutIndex >>> 5)) - } else - if (cutIndex <= (1 << 15)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (((cutIndex-1) >>> 5) & 0x1f) + 1) - display2 = copyLeft(display2, (cutIndex >>> 10)) - } else - if (cutIndex <= (1 << 20)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (((cutIndex-1) >>> 5) & 0x1f) + 1) - display2 = copyLeft(display2, (((cutIndex-1) >>> 10) & 0x1f) + 1) - display3 = copyLeft(display3, (cutIndex >>> 15)) - } else - if (cutIndex <= (1 << 25)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (((cutIndex-1) >>> 5) & 0x1f) + 1) - display2 = copyLeft(display2, (((cutIndex-1) >>> 10) & 0x1f) + 1) - display3 = copyLeft(display3, (((cutIndex-1) >>> 15) & 0x1f) + 1) - display4 = copyLeft(display4, (cutIndex >>> 20)) - } else - if (cutIndex <= (1 << 30)) { - zeroRight(display0, ((cutIndex-1) & 0x1f) + 1) - display1 = copyLeft(display1, (((cutIndex-1) >>> 5) & 0x1f) + 1) - display2 = copyLeft(display2, (((cutIndex-1) >>> 10) & 0x1f) + 1) - display3 = copyLeft(display3, (((cutIndex-1) >>> 15) & 0x1f) + 1) - display4 = copyLeft(display4, (((cutIndex-1) >>> 20) & 0x1f) + 1) - display5 = copyLeft(display5, (cutIndex >>> 25)) + } else if (cutIndex <= (1 << 10)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, cutIndex >>> 5) + } else if (cutIndex <= (1 << 15)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, (((cutIndex - 1) >>> 5) & 31) + 1) + display2 = copyLeft(display2, cutIndex >>> 10) + } else if (cutIndex <= (1 << 20)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, (((cutIndex - 1) >>> 5) & 31) + 1) + display2 = copyLeft(display2, (((cutIndex - 1) >>> 10) & 31) + 1) + display3 = copyLeft(display3, cutIndex >>> 15) + } else if (cutIndex <= (1 << 25)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, (((cutIndex - 1) >>> 5) & 31) + 1) + display2 = copyLeft(display2, (((cutIndex - 1) >>> 10) & 31) + 1) + display3 = copyLeft(display3, (((cutIndex - 1) >>> 15) & 31) + 1) + display4 = copyLeft(display4, cutIndex >>> 20) + } else if (cutIndex <= (1 << 30)) { + zeroRight(display0, ((cutIndex - 1) & 31) + 1) + display1 = copyLeft(display1, (((cutIndex - 1) >>> 5) & 31) + 1) + display2 = copyLeft(display2, (((cutIndex - 1) >>> 10) & 31) + 1) + display3 = copyLeft(display3, (((cutIndex - 1) >>> 15) & 31) + 1) + display4 = copyLeft(display4, (((cutIndex - 1) >>> 20) & 31) + 1) + display5 = copyLeft(display5, cutIndex >>> 25) } else { throw new IllegalArgumentException() } } private def requiredDepth(xor: Int) = { - if (xor < (1 << 5)) 1 + if (xor < (1 << 5)) 1 else if (xor < (1 << 10)) 2 else if (xor < (1 << 15)) 3 else if (xor < (1 << 20)) 4 @@ -607,24 +554,11 @@ override def companion: GenericCompanion[Vector] = Vector val blockIndex = cutIndex & ~31 val xor = cutIndex ^ (endIndex - 1) val d = requiredDepth(xor) - val shift = (cutIndex & ~((1 << (5*d))-1)) - - //println("cut front at " + cutIndex + ".." + endIndex + " (xor: "+xor+" shift: " + shift + " d: " + d +")") - -/* - val s = new Vector(cutIndex-shift, endIndex-shift, blockIndex-shift) - s.initFrom(this) - if (s.depth > 1) - s.gotoPos(blockIndex, focus ^ blockIndex) - s.depth = d - s.stabilize(blockIndex-shift) - s.cleanLeftEdge(cutIndex-shift) - s -*/ + val shift = cutIndex & ~((1 << (5 * d)) - 1) // need to init with full display iff going to cutIndex requires swapping block at level >= d - val s = new Vector(cutIndex-shift, endIndex-shift, blockIndex-shift) + val s = new Vector(cutIndex - shift, endIndex - shift, blockIndex - shift) s.initFrom(this) s.dirty = dirty s.gotoPosWritable(focus, blockIndex, focus ^ blockIndex) @@ -637,25 +571,18 @@ override def companion: GenericCompanion[Vector] = Vector val blockIndex = (cutIndex - 1) & ~31 val xor = startIndex ^ (cutIndex - 1) val d = requiredDepth(xor) - val shift = (startIndex & ~((1 << (5*d))-1)) - -/* - println("cut back at " + startIndex + ".." + cutIndex + " (xor: "+xor+" d: " + d +")") - if (cutIndex == blockIndex + 32) - println("OUCH!!!") -*/ - val s = new Vector(startIndex-shift, cutIndex-shift, blockIndex-shift) + val shift = startIndex & ~((1 << (5 * d)) - 1) + + val s = new Vector(startIndex - shift, cutIndex - shift, blockIndex - shift) s.initFrom(this) s.dirty = dirty s.gotoPosWritable(focus, blockIndex, focus ^ blockIndex) s.preClean(d) - s.cleanRightEdge(cutIndex-shift) + s.cleanRightEdge(cutIndex - shift) s } - } - class VectorIterator[+A](_startIndex: Int, endIndex: Int) extends AbstractIterator[A] with Iterator[A] @@ -678,7 +605,7 @@ extends AbstractIterator[A] if (lo == endLo) { if (blockIndex + lo < endIndex) { - val newBlockIndex = blockIndex+32 + val newBlockIndex = blockIndex + 32 gotoNextBlockStart(newBlockIndex, blockIndex ^ newBlockIndex) blockIndex = newBlockIndex @@ -704,8 +631,8 @@ extends AbstractIterator[A] } } - -final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A @uncheckedVariance] { +/** A class to build instances of `Vector`. This builder is reusable. */ +final class VectorBuilder[A]() extends ReusableBuilder[A, Vector[A]] with VectorPointer[A @uncheckedVariance] { // possible alternative: start with display0 = null, blockIndex = -32, lo = 32 // to avoid allocating initial array if the result will be empty anyways @@ -716,9 +643,9 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A private var blockIndex = 0 private var lo = 0 - def += (elem: A): this.type = { + def +=(elem: A): this.type = { if (lo >= display0.length) { - val newBlockIndex = blockIndex+32 + val newBlockIndex = blockIndex + 32 gotoNextBlockStartWritable(newBlockIndex, blockIndex ^ newBlockIndex) blockIndex = newBlockIndex lo = 0 @@ -728,8 +655,7 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A this } - override def ++=(xs: TraversableOnce[A]): this.type = - super.++=(xs) + override def ++=(xs: TraversableOnce[A]): this.type = super.++=(xs) def result: Vector[A] = { val size = blockIndex + lo @@ -749,10 +675,8 @@ final class VectorBuilder[A]() extends Builder[A,Vector[A]] with VectorPointer[A } } - - private[immutable] trait VectorPointer[T] { - private[immutable] var depth: Int = _ + private[immutable] var depth: Int = _ private[immutable] var display0: Array[AnyRef] = _ private[immutable] var display1: Array[AnyRef] = _ private[immutable] var display2: Array[AnyRef] = _ @@ -797,98 +721,102 @@ private[immutable] trait VectorPointer[T] { } } - // requires structure is at pos oldIndex = xor ^ index private[immutable] final def getElem(index: Int, xor: Int): T = { - if (xor < (1 << 5)) { // level = 0 - display0(index & 31).asInstanceOf[T] - } else - if (xor < (1 << 10)) { // level = 1 - display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else - if (xor < (1 << 15)) { // level = 2 - display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]]((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else - if (xor < (1 << 20)) { // level = 3 - display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]]((index >> 10) & 31).asInstanceOf[Array[AnyRef]]((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else - if (xor < (1 << 25)) { // level = 4 - display4((index >> 20) & 31).asInstanceOf[Array[AnyRef]]((index >> 15) & 31).asInstanceOf[Array[AnyRef]]((index >> 10) & 31).asInstanceOf[Array[AnyRef]]((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else - if (xor < (1 << 30)) { // level = 5 - display5((index >> 25) & 31).asInstanceOf[Array[AnyRef]]((index >> 20) & 31).asInstanceOf[Array[AnyRef]]((index >> 15) & 31).asInstanceOf[Array[AnyRef]]((index >> 10) & 31).asInstanceOf[Array[AnyRef]]((index >> 5) & 31).asInstanceOf[Array[AnyRef]](index & 31).asInstanceOf[T] - } else { // level = 6 + if (xor < (1 << 5)) { // level = 0 + (display0 + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 10)) { // level = 1 + (display1 + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 15)) { // level = 2 + (display2 + ((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 20)) { // level = 3 + (display3 + ((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 25)) { // level = 4 + (display4 + ((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else if (xor < (1 << 30)) { // level = 5 + (display5 + ((index >>> 25) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + ((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + (index & 31).asInstanceOf[T]) + } else { // level = 6 throw new IllegalArgumentException() } } - // go to specific position // requires structure is at pos oldIndex = xor ^ index, // ensures structure is at pos index private[immutable] final def gotoPos(index: Int, xor: Int): Unit = { - if (xor < (1 << 5)) { // level = 0 (could maybe removed) - } else - if (xor < (1 << 10)) { // level = 1 - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 15)) { // level = 2 - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 20)) { // level = 3 - display2 = display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 25)) { // level = 4 - display3 = display4((index >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 30)) { // level = 5 - display4 = display5((index >> 25) & 31).asInstanceOf[Array[AnyRef]] - display3 = display4((index >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else { // level = 6 + if (xor < (1 << 5)) { // level = 0 + // we're already at the block start pos + } else if (xor < (1 << 10)) { // level = 1 + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 15)) { // level = 2 + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 20)) { // level = 3 + display2 = display3((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 25)) { // level = 4 + display3 = display4((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 30)) { // level = 5 + display4 = display5((index >>> 25) & 31).asInstanceOf[Array[AnyRef]] + display3 = display4((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else { // level = 6 throw new IllegalArgumentException() } } - - // USED BY ITERATOR // xor: oldIndex ^ index private[immutable] final def gotoNextBlockStart(index: Int, xor: Int): Unit = { // goto block start pos - if (xor < (1 << 10)) { // level = 1 - display0 = display1((index >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 15)) { // level = 2 - display1 = display2((index >> 10) & 31).asInstanceOf[Array[AnyRef]] + if (xor < (1 << 10)) { // level = 1 + display0 = display1((index >>> 5) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 15)) { // level = 2 + display1 = display2((index >>> 10) & 31).asInstanceOf[Array[AnyRef]] display0 = display1(0).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 20)) { // level = 3 - display2 = display3((index >> 15) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 20)) { // level = 3 + display2 = display3((index >>> 15) & 31).asInstanceOf[Array[AnyRef]] display1 = display2(0).asInstanceOf[Array[AnyRef]] display0 = display1(0).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 25)) { // level = 4 - display3 = display4((index >> 20) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 25)) { // level = 4 + display3 = display4((index >>> 20) & 31).asInstanceOf[Array[AnyRef]] display2 = display3(0).asInstanceOf[Array[AnyRef]] display1 = display2(0).asInstanceOf[Array[AnyRef]] display0 = display1(0).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 30)) { // level = 5 - display4 = display5((index >> 25) & 31).asInstanceOf[Array[AnyRef]] + } else if (xor < (1 << 30)) { // level = 5 + display4 = display5((index >>> 25) & 31).asInstanceOf[Array[AnyRef]] display3 = display4(0).asInstanceOf[Array[AnyRef]] display2 = display3(0).asInstanceOf[Array[AnyRef]] display1 = display2(0).asInstanceOf[Array[AnyRef]] display0 = display1(0).asInstanceOf[Array[AnyRef]] - } else { // level = 6 + } else { // level = 6 throw new IllegalArgumentException() } } @@ -897,73 +825,65 @@ private[immutable] trait VectorPointer[T] { // xor: oldIndex ^ index private[immutable] final def gotoNextBlockStartWritable(index: Int, xor: Int): Unit = { // goto block start pos - if (xor < (1 << 10)) { // level = 1 - if (depth == 1) { display1 = new Array(32); display1(0) = display0; depth+=1} + if (xor < (1 << 10)) { // level = 1 + if (depth == 1) { display1 = new Array(32); display1(0) = display0; depth += 1 } display0 = new Array(32) - display1((index >> 5) & 31) = display0 - } else - if (xor < (1 << 15)) { // level = 2 - if (depth == 2) { display2 = new Array(32); display2(0) = display1; depth+=1} + display1((index >>> 5) & 31) = display0 + } else if (xor < (1 << 15)) { // level = 2 + if (depth == 2) { display2 = new Array(32); display2(0) = display1; depth += 1 } display0 = new Array(32) display1 = new Array(32) - display1((index >> 5) & 31) = display0 - display2((index >> 10) & 31) = display1 - } else - if (xor < (1 << 20)) { // level = 3 - if (depth == 3) { display3 = new Array(32); display3(0) = display2; depth+=1} + display1((index >>> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + } else if (xor < (1 << 20)) { // level = 3 + if (depth == 3) { display3 = new Array(32); display3(0) = display2; depth += 1 } display0 = new Array(32) display1 = new Array(32) display2 = new Array(32) - display1((index >> 5) & 31) = display0 - display2((index >> 10) & 31) = display1 - display3((index >> 15) & 31) = display2 - } else - if (xor < (1 << 25)) { // level = 4 - if (depth == 4) { display4 = new Array(32); display4(0) = display3; depth+=1} + display1((index >>> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + display3((index >>> 15) & 31) = display2 + } else if (xor < (1 << 25)) { // level = 4 + if (depth == 4) { display4 = new Array(32); display4(0) = display3; depth += 1 } display0 = new Array(32) display1 = new Array(32) display2 = new Array(32) display3 = new Array(32) - display1((index >> 5) & 31) = display0 - display2((index >> 10) & 31) = display1 - display3((index >> 15) & 31) = display2 - display4((index >> 20) & 31) = display3 - } else - if (xor < (1 << 30)) { // level = 5 - if (depth == 5) { display5 = new Array(32); display5(0) = display4; depth+=1} + display1((index >>> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + display3((index >>> 15) & 31) = display2 + display4((index >>> 20) & 31) = display3 + } else if (xor < (1 << 30)) { // level = 5 + if (depth == 5) { display5 = new Array(32); display5(0) = display4; depth += 1 } display0 = new Array(32) display1 = new Array(32) display2 = new Array(32) display3 = new Array(32) display4 = new Array(32) - display1((index >> 5) & 31) = display0 - display2((index >> 10) & 31) = display1 - display3((index >> 15) & 31) = display2 - display4((index >> 20) & 31) = display3 - display5((index >> 25) & 31) = display4 - } else { // level = 6 + display1((index >>> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + display3((index >>> 15) & 31) = display2 + display4((index >>> 20) & 31) = display3 + display5((index >>> 25) & 31) = display4 + } else { // level = 6 throw new IllegalArgumentException() } } - - // STUFF BELOW USED BY APPEND / UPDATE - private[immutable] final def copyOf(a: Array[AnyRef]) = { - val b = new Array[AnyRef](a.length) - Platform.arraycopy(a, 0, b, 0, a.length) - b + private[immutable] final def copyOf(a: Array[AnyRef]): Array[AnyRef] = { + val copy = new Array[AnyRef](a.length) + java.lang.System.arraycopy(a, 0, copy, 0, a.length) + copy } - private[immutable] final def nullSlotAndCopy(array: Array[AnyRef], index: Int) = { - //println("copy and null") + private[immutable] final def nullSlotAndCopy(array: Array[AnyRef], index: Int): Array[AnyRef] = { val x = array(index) array(index) = null copyOf(x.asInstanceOf[Array[AnyRef]]) } - // make sure there is no aliasing // requires structure is at pos index // ensures structure is clean and at pos index and writable at all levels except 0 @@ -975,40 +895,39 @@ private[immutable] trait VectorPointer[T] { display3 = copyOf(display3) display2 = copyOf(display2) display1 = copyOf(display1) - display5((index >> 25) & 31) = display4 - display4((index >> 20) & 31) = display3 - display3((index >> 15) & 31) = display2 - display2((index >> 10) & 31) = display1 - display1((index >> 5) & 31) = display0 + display5((index >>> 25) & 31) = display4 + display4((index >>> 20) & 31) = display3 + display3((index >>> 15) & 31) = display2 + display2((index >>> 10) & 31) = display1 + display1((index >>> 5) & 31) = display0 case 4 => display4 = copyOf(display4) display3 = copyOf(display3) display2 = copyOf(display2) display1 = copyOf(display1) - display4((index >> 20) & 31) = display3 - display3((index >> 15) & 31) = display2 - display2((index >> 10) & 31) = display1 - display1((index >> 5) & 31) = display0 + display4((index >>> 20) & 31) = display3 + display3((index >>> 15) & 31) = display2 + display2((index >>> 10) & 31) = display1 + display1((index >>> 5) & 31) = display0 case 3 => display3 = copyOf(display3) display2 = copyOf(display2) display1 = copyOf(display1) - display3((index >> 15) & 31) = display2 - display2((index >> 10) & 31) = display1 - display1((index >> 5) & 31) = display0 + display3((index >>> 15) & 31) = display2 + display2((index >>> 10) & 31) = display1 + display1((index >>> 5) & 31) = display0 case 2 => display2 = copyOf(display2) display1 = copyOf(display1) - display2((index >> 10) & 31) = display1 - display1((index >> 5) & 31) = display0 + display2((index >>> 10) & 31) = display1 + display1((index >>> 5) & 31) = display0 case 1 => display1 = copyOf(display1) - display1((index >> 5) & 31) = display0 + display1((index >>> 5) & 31) = display0 case 0 => } - /// USED IN UPDATE AND APPEND BACK // prepare for writing at an existing position @@ -1018,29 +937,29 @@ private[immutable] trait VectorPointer[T] { private[immutable] final def gotoPosWritable0(newIndex: Int, xor: Int): Unit = (depth - 1) match { case 5 => display5 = copyOf(display5) - display4 = nullSlotAndCopy(display5, (newIndex >> 25) & 31).asInstanceOf[Array[AnyRef]] - display3 = nullSlotAndCopy(display4, (newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display4 = nullSlotAndCopy(display5, (newIndex >>> 25) & 31) + display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31) + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 4 => display4 = copyOf(display4) - display3 = nullSlotAndCopy(display4, (newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31) + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 3 => display3 = copyOf(display3) - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 2 => display2 = copyOf(display2) - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 1 => display1 = copyOf(display1) - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) case 0 => display0 = copyOf(display0) } @@ -1049,64 +968,59 @@ private[immutable] trait VectorPointer[T] { // requires structure is dirty and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 private[immutable] final def gotoPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = { - if (xor < (1 << 5)) { // level = 0 + if (xor < (1 << 5)) { // level = 0 display0 = copyOf(display0) - } else - if (xor < (1 << 10)) { // level = 1 + } else if (xor < (1 << 10)) { // level = 1 display1 = copyOf(display1) - display1((oldIndex >> 5) & 31) = display0 - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31) - } else - if (xor < (1 << 15)) { // level = 2 + display1((oldIndex >>> 5) & 31) = display0 + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else if (xor < (1 << 15)) { // level = 2 display1 = copyOf(display1) display2 = copyOf(display2) - display1((oldIndex >> 5) & 31) = display0 - display2((oldIndex >> 10) & 31) = display1 - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 20)) { // level = 3 + display1((oldIndex >>> 5) & 31) = display0 + display2((oldIndex >>> 10) & 31) = display1 + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else if (xor < (1 << 20)) { // level = 3 display1 = copyOf(display1) display2 = copyOf(display2) display3 = copyOf(display3) - display1((oldIndex >> 5) & 31) = display0 - display2((oldIndex >> 10) & 31) = display1 - display3((oldIndex >> 15) & 31) = display2 - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 25)) { // level = 4 + display1((oldIndex >>> 5) & 31) = display0 + display2((oldIndex >>> 10) & 31) = display1 + display3((oldIndex >>> 15) & 31) = display2 + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else if (xor < (1 << 25)) { // level = 4 display1 = copyOf(display1) display2 = copyOf(display2) display3 = copyOf(display3) display4 = copyOf(display4) - display1((oldIndex >> 5) & 31) = display0 - display2((oldIndex >> 10) & 31) = display1 - display3((oldIndex >> 15) & 31) = display2 - display4((oldIndex >> 20) & 31) = display3 - display3 = nullSlotAndCopy(display4, (newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else - if (xor < (1 << 30)) { // level = 5 + display1((oldIndex >>> 5) & 31) = display0 + display2((oldIndex >>> 10) & 31) = display1 + display3((oldIndex >>> 15) & 31) = display2 + display4((oldIndex >>> 20) & 31) = display3 + display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31) + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else if (xor < (1 << 30)) { // level = 5 display1 = copyOf(display1) display2 = copyOf(display2) display3 = copyOf(display3) display4 = copyOf(display4) display5 = copyOf(display5) - display1((oldIndex >> 5) & 31) = display0 - display2((oldIndex >> 10) & 31) = display1 - display3((oldIndex >> 15) & 31) = display2 - display4((oldIndex >> 20) & 31) = display3 - display5((oldIndex >> 25) & 31) = display4 - display4 = nullSlotAndCopy(display5, (newIndex >> 25) & 31).asInstanceOf[Array[AnyRef]] - display3 = nullSlotAndCopy(display4, (newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] - display2 = nullSlotAndCopy(display3, (newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] - display1 = nullSlotAndCopy(display2, (newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] - display0 = nullSlotAndCopy(display1, (newIndex >> 5) & 31).asInstanceOf[Array[AnyRef]] - } else { // level = 6 + display1((oldIndex >>> 5) & 31) = display0 + display2((oldIndex >>> 10) & 31) = display1 + display3((oldIndex >>> 15) & 31) = display2 + display4((oldIndex >>> 20) & 31) = display3 + display5((oldIndex >>> 25) & 31) = display4 + display4 = nullSlotAndCopy(display5, (newIndex >>> 25) & 31) + display3 = nullSlotAndCopy(display4, (newIndex >>> 20) & 31) + display2 = nullSlotAndCopy(display3, (newIndex >>> 15) & 31) + display1 = nullSlotAndCopy(display2, (newIndex >>> 10) & 31) + display0 = nullSlotAndCopy(display1, (newIndex >>> 5) & 31) + } else { // level = 6 throw new IllegalArgumentException() } } @@ -1116,117 +1030,83 @@ private[immutable] trait VectorPointer[T] { private[immutable] final def copyRange(array: Array[AnyRef], oldLeft: Int, newLeft: Int) = { val elems = new Array[AnyRef](32) - Platform.arraycopy(array, oldLeft, elems, newLeft, 32 - math.max(newLeft,oldLeft)) + java.lang.System.arraycopy(array, oldLeft, elems, newLeft, 32 - math.max(newLeft, oldLeft)) elems } - - // USED IN APPEND // create a new block at the bottom level (and possibly nodes on its path) and prepares for writing // requires structure is clean and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 private[immutable] final def gotoFreshPosWritable0(oldIndex: Int, newIndex: Int, xor: Int): Unit = { // goto block start pos - if (xor < (1 << 5)) { // level = 0 - //println("XXX clean with low xor") - } else - if (xor < (1 << 10)) { // level = 1 + if (xor < (1 << 5)) { // level = 0 + // we're already at the block start + } else if (xor < (1 << 10)) { // level = 1 if (depth == 1) { display1 = new Array(32) - display1((oldIndex >> 5) & 31) = display0 - depth +=1 + display1((oldIndex >>> 5) & 31) = display0 + depth += 1 } display0 = new Array(32) - } else - if (xor < (1 << 15)) { // level = 2 + } else if (xor < (1 << 15)) { // level = 2 if (depth == 2) { display2 = new Array(32) - display2((oldIndex >> 10) & 31) = display1 - depth +=1 + display2((oldIndex >>> 10) & 31) = display1 + depth += 1 } - display1 = display2((newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((newIndex >>> 10) & 31).asInstanceOf[Array[AnyRef]] if (display1 == null) display1 = new Array(32) display0 = new Array(32) - } else - if (xor < (1 << 20)) { // level = 3 + } else if (xor < (1 << 20)) { // level = 3 if (depth == 3) { display3 = new Array(32) - display3((oldIndex >> 15) & 31) = display2 - depth +=1 + display3((oldIndex >>> 15) & 31) = display2 + depth += 1 } - display2 = display3((newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((newIndex >>> 15) & 31).asInstanceOf[Array[AnyRef]] if (display2 == null) display2 = new Array(32) - display1 = display2((newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((newIndex >>> 10) & 31).asInstanceOf[Array[AnyRef]] if (display1 == null) display1 = new Array(32) display0 = new Array(32) - } else - if (xor < (1 << 25)) { // level = 4 + } else if (xor < (1 << 25)) { // level = 4 if (depth == 4) { display4 = new Array(32) - display4((oldIndex >> 20) & 31) = display3 - depth +=1 + display4((oldIndex >>> 20) & 31) = display3 + depth += 1 } - display3 = display4((newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] + display3 = display4((newIndex >>> 20) & 31).asInstanceOf[Array[AnyRef]] if (display3 == null) display3 = new Array(32) - display2 = display3((newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((newIndex >>> 15) & 31).asInstanceOf[Array[AnyRef]] if (display2 == null) display2 = new Array(32) - display1 = display2((newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((newIndex >>> 10) & 31).asInstanceOf[Array[AnyRef]] if (display1 == null) display1 = new Array(32) display0 = new Array(32) - } else - if (xor < (1 << 30)) { // level = 5 + } else if (xor < (1 << 30)) { // level = 5 if (depth == 5) { display5 = new Array(32) - display5((oldIndex >> 25) & 31) = display4 - depth +=1 + display5((oldIndex >>> 25) & 31) = display4 + depth += 1 } - display4 = display5((newIndex >> 25) & 31).asInstanceOf[Array[AnyRef]] + display4 = display5((newIndex >>> 25) & 31).asInstanceOf[Array[AnyRef]] if (display4 == null) display4 = new Array(32) - display3 = display4((newIndex >> 20) & 31).asInstanceOf[Array[AnyRef]] + display3 = display4((newIndex >>> 20) & 31).asInstanceOf[Array[AnyRef]] if (display3 == null) display3 = new Array(32) - display2 = display3((newIndex >> 15) & 31).asInstanceOf[Array[AnyRef]] + display2 = display3((newIndex >>> 15) & 31).asInstanceOf[Array[AnyRef]] if (display2 == null) display2 = new Array(32) - display1 = display2((newIndex >> 10) & 31).asInstanceOf[Array[AnyRef]] + display1 = display2((newIndex >>> 10) & 31).asInstanceOf[Array[AnyRef]] if (display1 == null) display1 = new Array(32) display0 = new Array(32) - } else { // level = 6 + } else { // level = 6 throw new IllegalArgumentException() } } - // requires structure is dirty and at pos oldIndex, // ensures structure is dirty and at pos newIndex and writable at level 0 private[immutable] final def gotoFreshPosWritable1(oldIndex: Int, newIndex: Int, xor: Int): Unit = { stabilize(oldIndex) gotoFreshPosWritable0(oldIndex, newIndex, xor) } - - - - - // DEBUG STUFF - - private[immutable] def debug(): Unit = { - return -/* - //println("DISPLAY 5: " + display5 + " ---> " + (if (display5 ne null) display5.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 4: " + display4 + " ---> " + (if (display4 ne null) display4.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 3: " + display3 + " ---> " + (if (display3 ne null) display3.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 2: " + display2 + " ---> " + (if (display2 ne null) display2.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 1: " + display1 + " ---> " + (if (display1 ne null) display1.map(x=> if (x eq null) "." else x + "->" +x.asInstanceOf[Array[AnyRef]].mkString("")).mkString(" ") else "null")) - //println("DISPLAY 0: " + display0 + " ---> " + (if (display0 ne null) display0.map(x=> if (x eq null) "." else x.toString).mkString(" ") else "null")) -*/ - //println("DISPLAY 5: " + (if (display5 ne null) display5.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 4: " + (if (display4 ne null) display4.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 3: " + (if (display3 ne null) display3.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 2: " + (if (display2 ne null) display2.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 1: " + (if (display1 ne null) display1.map(x=> if (x eq null) "." else x.asInstanceOf[Array[AnyRef]].deepMkString("[","","]")).mkString(" ") else "null")) - //println("DISPLAY 0: " + (if (display0 ne null) display0.map(x=> if (x eq null) "." else x.toString).mkString(" ") else "null")) - } - - } - diff --git a/src/library/scala/collection/immutable/WrappedString.scala b/src/library/scala/collection/immutable/WrappedString.scala index 7592316650..8726bd2ed9 100644 --- a/src/library/scala/collection/immutable/WrappedString.scala +++ b/src/library/scala/collection/immutable/WrappedString.scala @@ -29,8 +29,7 @@ import mutable.{Builder, StringBuilder} * @define Coll `WrappedString` * @define coll wrapped string */ -@deprecatedInheritance("Inherit from StringLike instead of WrappedString.", "2.11.0") -class WrappedString(val self: String) extends AbstractSeq[Char] with IndexedSeq[Char] with StringLike[WrappedString] { +final class WrappedString(val self: String) extends AbstractSeq[Char] with IndexedSeq[Char] with StringLike[WrappedString] { override protected[this] def thisCollection: WrappedString = this override protected[this] def toCollection(repr: WrappedString): WrappedString = repr 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..23d386f729 100644 --- a/src/library/scala/collection/mutable/ArrayBuffer.scala +++ b/src/library/scala/collection/mutable/ArrayBuffer.scala @@ -67,7 +67,7 @@ class ArrayBuffer[A](override protected val initialSize: Int) override def sizeHint(len: Int) { if (len > size && len >= 1) { val newarray = new Array[AnyRef](len) - scala.compat.Platform.arraycopy(array, 0, newarray, 0, size0) + java.lang.System.arraycopy(array, 0, newarray, 0, size0) array = newarray } } @@ -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 f4ca27dcba..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,9 +99,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -119,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 @@ -167,9 +164,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -187,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 @@ -235,9 +229,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -255,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 @@ -303,9 +294,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -323,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 @@ -371,9 +359,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -391,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 @@ -439,9 +424,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -459,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 @@ -507,9 +489,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -527,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 @@ -575,9 +554,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -595,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] = _ @@ -642,9 +619,7 @@ object ArrayBuilder { super.++=(xs) } - def clear() { - size = 0 - } + def clear() { size = 0 } def result() = { if (capacity != 0 && capacity == size) { @@ -662,68 +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) { - capacity = 0 - 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..0f83fd92c1 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,29 @@ 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 slice(from: Int, until: Int): Array[T] = { + val lo = math.max(from, 0) + val hi = math.min(math.max(until, 0), repr.length) + val size = math.max(hi - lo, 0) + val result = java.lang.reflect.Array.newInstance(elementClass, size) + if (size > 0) { + Array.copy(repr, lo, result, 0, size) + } + result.asInstanceOf[Array[T]] } 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 +101,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 +114,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 +142,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,10 +176,8 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza } (a1, a2, a3) } - def seq = thisCollection - } /** @@ -187,15 +192,15 @@ 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) def update(index: Int, elem: T) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `byte`s. */ -final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { + /** A subclass of `ArrayOps` for arrays containing `Byte`s. */ + final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[Byte] with ArrayLike[Byte, Array[Byte]] { override protected[this] def thisCollection: WrappedArray[Byte] = new WrappedArray.ofByte(repr) override protected[this] def toCollection(repr: Array[Byte]): WrappedArray[Byte] = new WrappedArray.ofByte(repr) @@ -206,8 +211,8 @@ final class ofByte(override val repr: Array[Byte]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Byte) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `short`s. */ -final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { + /** A subclass of `ArrayOps` for arrays containing `Short`s. */ + final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOps[Short] with ArrayLike[Short, Array[Short]] { override protected[this] def thisCollection: WrappedArray[Short] = new WrappedArray.ofShort(repr) override protected[this] def toCollection(repr: Array[Short]): WrappedArray[Short] = new WrappedArray.ofShort(repr) @@ -218,8 +223,8 @@ final class ofShort(override val repr: Array[Short]) extends AnyVal with ArrayOp def update(index: Int, elem: Short) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `char`s. */ -final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { + /** A subclass of `ArrayOps` for arrays containing `Char`s. */ + final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[Char] with ArrayLike[Char, Array[Char]] { override protected[this] def thisCollection: WrappedArray[Char] = new WrappedArray.ofChar(repr) override protected[this] def toCollection(repr: Array[Char]): WrappedArray[Char] = new WrappedArray.ofChar(repr) @@ -230,8 +235,8 @@ final class ofChar(override val repr: Array[Char]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Char) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `int`s. */ -final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { + /** A subclass of `ArrayOps` for arrays containing `Int`s. */ + final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[Int] with ArrayLike[Int, Array[Int]] { override protected[this] def thisCollection: WrappedArray[Int] = new WrappedArray.ofInt(repr) override protected[this] def toCollection(repr: Array[Int]): WrappedArray[Int] = new WrappedArray.ofInt(repr) @@ -242,8 +247,8 @@ final class ofInt(override val repr: Array[Int]) extends AnyVal with ArrayOps[In def update(index: Int, elem: Int) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `long`s. */ -final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { + /** A subclass of `ArrayOps` for arrays containing `Long`s. */ + final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[Long] with ArrayLike[Long, Array[Long]] { override protected[this] def thisCollection: WrappedArray[Long] = new WrappedArray.ofLong(repr) override protected[this] def toCollection(repr: Array[Long]): WrappedArray[Long] = new WrappedArray.ofLong(repr) @@ -254,8 +259,8 @@ final class ofLong(override val repr: Array[Long]) extends AnyVal with ArrayOps[ def update(index: Int, elem: Long) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `float`s. */ -final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { + /** A subclass of `ArrayOps` for arrays containing `Float`s. */ + final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOps[Float] with ArrayLike[Float, Array[Float]] { override protected[this] def thisCollection: WrappedArray[Float] = new WrappedArray.ofFloat(repr) override protected[this] def toCollection(repr: Array[Float]): WrappedArray[Float] = new WrappedArray.ofFloat(repr) @@ -266,8 +271,8 @@ final class ofFloat(override val repr: Array[Float]) extends AnyVal with ArrayOp def update(index: Int, elem: Float) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `double`s. */ -final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { + /** A subclass of `ArrayOps` for arrays containing `Double`s. */ + final class ofDouble(override val repr: Array[Double]) extends AnyVal with ArrayOps[Double] with ArrayLike[Double, Array[Double]] { override protected[this] def thisCollection: WrappedArray[Double] = new WrappedArray.ofDouble(repr) override protected[this] def toCollection(repr: Array[Double]): WrappedArray[Double] = new WrappedArray.ofDouble(repr) @@ -278,8 +283,8 @@ final class ofDouble(override val repr: Array[Double]) extends AnyVal with Array def update(index: Int, elem: Double) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays containing `boolean`s. */ -final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { + /** A subclass of `ArrayOps` for arrays containing `Boolean`s. */ + final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with ArrayOps[Boolean] with ArrayLike[Boolean, Array[Boolean]] { override protected[this] def thisCollection: WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) override protected[this] def toCollection(repr: Array[Boolean]): WrappedArray[Boolean] = new WrappedArray.ofBoolean(repr) @@ -290,8 +295,8 @@ final class ofBoolean(override val repr: Array[Boolean]) extends AnyVal with Arr def update(index: Int, elem: Boolean) { repr(index) = elem } } - /** A class of `ArrayOps` for arrays of `Unit` types. */ -final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { + /** A subclass of `ArrayOps` for arrays of `Unit` types. */ + final class ofUnit(override val repr: Array[Unit]) extends AnyVal with ArrayOps[Unit] with ArrayLike[Unit, Array[Unit]] { override protected[this] def thisCollection: WrappedArray[Unit] = new WrappedArray.ofUnit(repr) override protected[this] def toCollection(repr: Array[Unit]): WrappedArray[Unit] = new WrappedArray.ofUnit(repr) 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..e74ee65dda 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 } @@ -164,7 +164,7 @@ class BitSet(protected final var elems: Array[Long]) extends AbstractSet[Int] */ @deprecated("If this BitSet contains a value that is 128 or greater, the result of this method is an 'immutable' " + "BitSet that shares state with this mutable BitSet. Thus, if the mutable BitSet is modified, it will violate the " + - "immutability of the result.", "2.11.6") + "immutability of the result.", "2.12.0") def toImmutable = immutable.BitSet.fromBitMaskNoCopy(elems) override def clone(): BitSet = { diff --git a/src/library/scala/collection/mutable/BufferLike.scala b/src/library/scala/collection/mutable/BufferLike.scala index 3c57387c03..c78d59297b 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) } @@ -184,7 +187,7 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]] * * @param cmd the message to send. */ - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") def <<(cmd: Message[A]): Unit = cmd match { case Include(Start, x) => prepend(x) case Include(End, x) => append(x) @@ -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..60f0e29746 100644 --- a/src/library/scala/collection/mutable/BufferProxy.scala +++ b/src/library/scala/collection/mutable/BufferProxy.scala @@ -26,7 +26,7 @@ import script._ * @define Coll `BufferProxy` * @define coll buffer proxy */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait BufferProxy[A] extends Buffer[A] with Proxy { def self: Buffer[A] @@ -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. @@ -132,7 +130,7 @@ trait BufferProxy[A] extends Buffer[A] with Proxy { * * @param cmd the message to send. */ - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") override def <<(cmd: Message[A]) { self << cmd } /** Return a clone of this buffer. diff --git a/src/library/scala/collection/mutable/Builder.scala b/src/library/scala/collection/mutable/Builder.scala index 75560580cc..528f78bd98 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 @@ -55,18 +65,18 @@ trait Builder[-Elem, +To] extends Growable[Elem] { /** Gives a hint that one expects the `result` of this builder * to have the same size as the given collection, plus some delta. This will * provide a hint only if the collection is known to have a cheap - * `size` method. Currently this is assumed to be the case if and only if - * the collection is of type `IndexedSeqLike`. - * Some builder classes - * will optimize their representation based on the hint. However, + * `size` method, which is determined by calling `sizeHint`. + * + * Some builder classes will optimize their representation based on the hint. However, * builder implementations are still required to work correctly even if the hint is * wrong, i.e. a different number of elements is added. * * @param coll the collection which serves as a hint for the result's size. */ def sizeHint(coll: TraversableLike[_, _]) { - if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) { - sizeHint(coll.size) + coll.sizeHintIfCheap match { + case -1 => + case n => sizeHint(n) } } @@ -84,8 +94,9 @@ trait Builder[-Elem, +To] extends Growable[Elem] { * @param delta a correction to add to the `coll.size` to produce the size hint. */ def sizeHint(coll: TraversableLike[_, _], delta: Int) { - if (coll.isInstanceOf[collection.IndexedSeqLike[_,_]]) { - sizeHint(coll.size + delta) + coll.sizeHintIfCheap match { + case -1 => + case n => sizeHint(n + delta) } } @@ -102,8 +113,10 @@ trait Builder[-Elem, +To] extends Growable[Elem] { * than collection's size are reduced. */ def sizeHintBounded(size: Int, boundingColl: TraversableLike[_, _]) { - if (boundingColl.isInstanceOf[collection.IndexedSeqLike[_,_]]) - sizeHint(size min boundingColl.size) + boundingColl.sizeHintIfCheap match { + case -1 => + case n => sizeHint(size min n) + } } /** Creates a new builder by applying a transformation function to @@ -112,6 +125,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/DefaultMapModel.scala b/src/library/scala/collection/mutable/DefaultMapModel.scala index 0088620540..7f832c0766 100644 --- a/src/library/scala/collection/mutable/DefaultMapModel.scala +++ b/src/library/scala/collection/mutable/DefaultMapModel.scala @@ -19,7 +19,7 @@ package mutable * @version 1.0, 08/07/2003 * @since 1 */ -@deprecated("This trait will be removed.", "2.11.0") +@deprecated("this trait will be removed", "2.11.0") trait DefaultMapModel[A, B] extends Map[A, B] { type Entry = DefaultEntry[A, B] diff --git a/src/library/scala/collection/mutable/DoubleLinkedList.scala b/src/library/scala/collection/mutable/DoubleLinkedList.scala index fd95e74fbc..537cebd903 100644 --- a/src/library/scala/collection/mutable/DoubleLinkedList.scala +++ b/src/library/scala/collection/mutable/DoubleLinkedList.scala @@ -41,7 +41,7 @@ import generic._ * @define mayNotTerminateInf * @define willNotTerminateInf */ -@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") +@deprecated("low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features", "2.11.0") @SerialVersionUID(-8144992287952814767L) class DoubleLinkedList[A]() extends AbstractSeq[A] with LinearSeq[A] @@ -78,7 +78,7 @@ class DoubleLinkedList[A]() extends AbstractSeq[A] * @define coll double linked list * @define Coll `DoubleLinkedList` */ -@deprecated("Low-level linked lists are deprecated.", "2.11.0") +@deprecated("low-level linked lists are deprecated", "2.11.0") object DoubleLinkedList extends SeqFactory[DoubleLinkedList] { /** $genericCanBuildFromInfo */ implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, DoubleLinkedList[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] diff --git a/src/library/scala/collection/mutable/DoubleLinkedListLike.scala b/src/library/scala/collection/mutable/DoubleLinkedListLike.scala index aafe34f50a..e85ef05319 100644 --- a/src/library/scala/collection/mutable/DoubleLinkedListLike.scala +++ b/src/library/scala/collection/mutable/DoubleLinkedListLike.scala @@ -56,7 +56,7 @@ import scala.annotation.migration * @define Coll `DoubleLinkedList` * @define coll double linked list */ -@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") +@deprecated("low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features", "2.11.0") trait DoubleLinkedListLike[A, This <: Seq[A] with DoubleLinkedListLike[A, This]] extends SeqLike[A, This] with LinkedListLike[A, This] { self => /** A reference to the node in the linked list preceding the current node. */ diff --git a/src/library/scala/collection/mutable/FlatHashTable.scala b/src/library/scala/collection/mutable/FlatHashTable.scala index 8c4115b1dd..0d8799282f 100644 --- a/src/library/scala/collection/mutable/FlatHashTable.scala +++ b/src/library/scala/collection/mutable/FlatHashTable.scala @@ -47,9 +47,7 @@ trait FlatHashTable[A] extends FlatHashTable.HashUtils[A] { @transient protected var seedvalue: Int = tableSizeSeed - import HashTable.powerOfTwo - - protected def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) + protected def capacity(expectedSize: Int) = HashTable.nextPositivePowerOfTwo(expectedSize) /** The initial size of the hash table. */ 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/HashMap.scala b/src/library/scala/collection/mutable/HashMap.scala index 11ff1f0893..de61ebb796 100644 --- a/src/library/scala/collection/mutable/HashMap.scala +++ b/src/library/scala/collection/mutable/HashMap.scala @@ -73,10 +73,18 @@ extends AbstractMap[A, B] } override def getOrElseUpdate(key: A, defaultValue: => B): B = { - val i = index(elemHashCode(key)) + val hash = elemHashCode(key) + val i = index(hash) val entry = findEntry(key, i) if (entry != null) entry.value - else addEntry(createNewEntry(key, defaultValue), i) + else { + val table0 = table + val default = defaultValue + // Avoid recomputing index if the `defaultValue()` hasn't triggered + // a table resize. + val newEntryIndex = if (table0 eq table) i else index(hash) + addEntry(createNewEntry(key, default), newEntryIndex) + } } /* inlined HashTable.findEntry0 to preserve its visibility */ diff --git a/src/library/scala/collection/mutable/HashTable.scala b/src/library/scala/collection/mutable/HashTable.scala index 4873aa3c3e..01ec1defad 100644 --- a/src/library/scala/collection/mutable/HashTable.scala +++ b/src/library/scala/collection/mutable/HashTable.scala @@ -367,7 +367,11 @@ trait HashTable[A, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashU * Note: we take the most significant bits of the hashcode, not the lower ones * this is of crucial importance when populating the table in parallel */ - protected final def index(hcode: Int): Int = if (table.length == 1) 0 else improve(hcode, seedvalue) >>> numberOfLeadingZeros(table.length - 1) + protected final def index(hcode: Int): Int = { + val ones = table.length - 1 + val exponent = Integer.numberOfLeadingZeros(ones) + (improve(hcode, seedvalue) >>> exponent) & ones + } protected def initWithContents(c: HashTable.Contents[A, Entry]) = { if (c != null) { @@ -395,13 +399,13 @@ private[collection] object HashTable { /** The load factor for the hash table (in 0.001 step). */ private[collection] final def defaultLoadFactor: Int = 750 // corresponds to 75% - private[collection] final def loadFactorDenum = 1000 + private[collection] final def loadFactorDenum = 1000 // should be loadFactorDenom, but changing that isn't binary compatible private[collection] final def newThreshold(_loadFactor: Int, size: Int) = ((size.toLong * _loadFactor) / loadFactorDenum).toInt private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = ((thr.toLong * loadFactorDenum) / _loadFactor).toInt - private[collection] final def capacity(expectedSize: Int) = if (expectedSize == 0) 1 else powerOfTwo(expectedSize) + private[collection] final def capacity(expectedSize: Int) = nextPositivePowerOfTwo(expectedSize) trait HashUtils[KeyType] { protected final def sizeMapBucketBitSize = 5 @@ -429,16 +433,7 @@ private[collection] object HashTable { /** * Returns a power of two >= `target`. */ - private[collection] def powerOfTwo(target: Int): Int = { - /* See http://bits.stephan-brumme.com/roundUpToNextPowerOfTwo.html */ - var c = target - 1 - c |= c >>> 1 - c |= c >>> 2 - c |= c >>> 4 - c |= c >>> 8 - c |= c >>> 16 - c + 1 - } + private[collection] def nextPositivePowerOfTwo(target: Int): Int = 1 << -numberOfLeadingZeros(target - 1) class Contents[A, Entry >: Null <: HashEntry[A, Entry]]( val loadFactor: Int, diff --git a/src/library/scala/collection/mutable/History.scala b/src/library/scala/collection/mutable/History.scala index 19148c0ac2..13e2f32225 100644 --- a/src/library/scala/collection/mutable/History.scala +++ b/src/library/scala/collection/mutable/History.scala @@ -1,6 +1,6 @@ /* __ *\ ** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/tPFL ** +** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** diff --git a/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala b/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala index 9ece8b1335..7ab4dd2d9d 100644 --- a/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala +++ b/src/library/scala/collection/mutable/ImmutableMapAdaptor.scala @@ -25,7 +25,7 @@ import scala.annotation.migration * @version 2.0, 01/01/2007 * @since 1 */ -@deprecated("Adaptors are inherently unreliable and prone to performance problems.", "2.11.0") +@deprecated("adaptors are inherently unreliable and prone to performance problems", "2.11.0") class ImmutableMapAdaptor[A, B](protected var imap: immutable.Map[A, B]) extends AbstractMap[A, B] with Map[A, B] diff --git a/src/library/scala/collection/mutable/ImmutableSetAdaptor.scala b/src/library/scala/collection/mutable/ImmutableSetAdaptor.scala index d7eec70b15..aa21c4cc11 100644 --- a/src/library/scala/collection/mutable/ImmutableSetAdaptor.scala +++ b/src/library/scala/collection/mutable/ImmutableSetAdaptor.scala @@ -20,7 +20,7 @@ package mutable * @version 1.0, 21/07/2003 * @since 1 */ -@deprecated("Adaptors are inherently unreliable and prone to performance problems.", "2.11.0") +@deprecated("adaptors are inherently unreliable and prone to performance problems", "2.11.0") class ImmutableSetAdaptor[A](protected var set: immutable.Set[A]) extends AbstractSet[A] with Set[A] 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/LinkedList.scala b/src/library/scala/collection/mutable/LinkedList.scala index b3500367af..5d03cd4410 100644 --- a/src/library/scala/collection/mutable/LinkedList.scala +++ b/src/library/scala/collection/mutable/LinkedList.scala @@ -76,7 +76,7 @@ import generic._ * }}} */ @SerialVersionUID(-7308240733518833071L) -@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") +@deprecated("low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features", "2.11.0") class LinkedList[A]() extends AbstractSeq[A] with LinearSeq[A] with GenericTraversableTemplate[A, LinkedList] @@ -114,7 +114,7 @@ class LinkedList[A]() extends AbstractSeq[A] * @define Coll `LinkedList` * @define coll linked list */ -@deprecated("Low-level linked lists are deprecated.", "2.11.0") +@deprecated("low-level linked lists are deprecated", "2.11.0") object LinkedList extends SeqFactory[LinkedList] { override def empty[A]: LinkedList[A] = new LinkedList[A] implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, LinkedList[A]] = ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] diff --git a/src/library/scala/collection/mutable/LinkedListLike.scala b/src/library/scala/collection/mutable/LinkedListLike.scala index d0748b8a9f..27c4466c99 100644 --- a/src/library/scala/collection/mutable/LinkedListLike.scala +++ b/src/library/scala/collection/mutable/LinkedListLike.scala @@ -55,7 +55,7 @@ import scala.annotation.tailrec * * }}} */ -@deprecated("Low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features.", "2.11.0") +@deprecated("low-level linked lists are deprecated due to idiosyncrasies in interface and incomplete features", "2.11.0") trait LinkedListLike[A, This <: Seq[A] with LinkedListLike[A, This]] extends SeqLike[A, This] { self => var elem: A = _ diff --git a/src/library/scala/collection/mutable/ListBuffer.scala b/src/library/scala/collection/mutable/ListBuffer.scala index f9bab40a1e..aa79e972d5 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 { @@ -120,6 +119,10 @@ final class ListBuffer[A] // Don't use the inherited size, which forwards to a List and is O(n). override def size = length + // Override with efficient implementations using the extra size information available to ListBuffer. + override def isEmpty: Boolean = len == 0 + override def nonEmpty: Boolean = len > 0 + // Implementations of abstract methods in Buffer override def apply(n: Int): A = @@ -262,13 +265,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 +301,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 @@ -382,6 +390,25 @@ final class ListBuffer[A] this } + /** Selects the last element. + * + * Runs in constant time. + * + * @return the last element of this buffer. + * @throws NoSuchElementException if this buffer is empty. + */ + override def last: A = + if (last0 eq null) throw new NoSuchElementException("last of empty ListBuffer") + else last0.head + + /** Optionally selects the last element. + * + * Runs in constant time. + * + * @return `Some` of the last element of this buffer if the buffer is nonempty, `None` if it is empty. + */ + override def lastOption: Option[A] = if (last0 eq null) None else Some(last0.head) + /** Returns an iterator over this `ListBuffer`. The iterator will reflect * changes made to the underlying `ListBuffer` beyond the next element; * the next element's value is cached so that `hasNext` and `next` are @@ -408,9 +435,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 +450,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/Map.scala b/src/library/scala/collection/mutable/Map.scala index 2ac3cb65b5..460a8b8f77 100644 --- a/src/library/scala/collection/mutable/Map.scala +++ b/src/library/scala/collection/mutable/Map.scala @@ -20,15 +20,15 @@ import generic._ * @since 1.0 * @author Matthias Zenger */ -trait Map[A, B] - extends Iterable[(A, B)] -// with GenMap[A, B] - with scala.collection.Map[A, B] - with MapLike[A, B, Map[A, B]] { +trait Map[K, V] + extends Iterable[(K, V)] +// with GenMap[K, V] + with scala.collection.Map[K, V] + with MapLike[K, V, Map[K, V]] { - override def empty: Map[A, B] = Map.empty + override def empty: Map[K, V] = Map.empty - override def seq: Map[A, B] = this + override def seq: Map[K, V] = this /** The same map with a given default function. * @@ -37,7 +37,7 @@ trait Map[A, B] * @param d the function mapping keys to values, used for non-present keys * @return a wrapper of the map with a default value */ - def withDefault(d: A => B): mutable.Map[A, B] = new Map.WithDefault[A, B](this, d) + def withDefault(d: K => V): mutable.Map[K, V] = new Map.WithDefault[K, V](this, d) /** The same map with a given default value. * @@ -46,7 +46,7 @@ trait Map[A, B] * @param d default value used for non-present keys * @return a wrapper of the map with a default value */ - def withDefaultValue(d: B): mutable.Map[A, B] = new Map.WithDefault[A, B](this, x => d) + def withDefaultValue(d: V): mutable.Map[K, V] = new Map.WithDefault[K, V](this, x => d) } /** $factoryInfo @@ -56,25 +56,25 @@ trait Map[A, B] */ object Map extends MutableMapFactory[Map] { /** $canBuildFromInfo */ - implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), Map[A, B]] = new MapCanBuildFrom[A, B] + implicit def canBuildFrom[K, V]: CanBuildFrom[Coll, (K, V), Map[K, V]] = new MapCanBuildFrom[K, V] - def empty[A, B]: Map[A, B] = new HashMap[A, B] + def empty[K, V]: Map[K, V] = new HashMap[K, V] - class WithDefault[A, B](underlying: Map[A, B], d: A => B) extends scala.collection.Map.WithDefault(underlying, d) with Map[A, B] { - override def += (kv: (A, B)) = {underlying += kv; this} - def -= (key: A) = {underlying -= key; this} + class WithDefault[K, V](underlying: Map[K, V], d: K => V) extends scala.collection.Map.WithDefault(underlying, d) with Map[K, V] { + override def += (kv: (K, V)) = {underlying += kv; this} + def -= (key: K) = {underlying -= key; this} override def empty = new WithDefault(underlying.empty, d) - override def updated[B1 >: B](key: A, value: B1): WithDefault[A, B1] = new WithDefault[A, B1](underlying.updated[B1](key, value), d) - override def + [B1 >: B](kv: (A, B1)): WithDefault[A, B1] = updated(kv._1, kv._2) - override def - (key: A): WithDefault[A, B] = new WithDefault(underlying - key, d) + override def updated[V1 >: V](key: K, value: V1): WithDefault[K, V1] = new WithDefault[K, V1](underlying.updated[V1](key, value), d) + override def + [V1 >: V](kv: (K, V1)): WithDefault[K, V1] = updated(kv._1, kv._2) + override def - (key: K): WithDefault[K, V] = new WithDefault(underlying - key, d) /** If these methods aren't overridden to thread through the underlying map, * successive calls to withDefault* have no effect. */ - override def withDefault(d: A => B): mutable.Map[A, B] = new WithDefault[A, B](underlying, d) - override def withDefaultValue(d: B): mutable.Map[A, B] = new WithDefault[A, B](underlying, x => d) + override def withDefault(d: K => V): mutable.Map[K, V] = new WithDefault[K, V](underlying, d) + override def withDefaultValue(d: V): mutable.Map[K, V] = new WithDefault[K, V](underlying, x => d) } } /** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */ -abstract class AbstractMap[A, B] extends scala.collection.AbstractMap[A, B] with Map[A, B] +abstract class AbstractMap[K, V] extends scala.collection.AbstractMap[K, V] with Map[K, V] 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..238b6d1be1 100644 --- a/src/library/scala/collection/mutable/MapLike.scala +++ b/src/library/scala/collection/mutable/MapLike.scala @@ -31,10 +31,10 @@ import scala.collection.parallel.mutable.ParMap * To implement a concrete mutable map, you need to provide * implementations of the following methods: * {{{ - * def get(key: A): Option[B] - * def iterator: Iterator[(A, B)] - * def += (kv: (A, B)): This - * def -= (key: A): This + * def get(key: K): Option[V] + * def iterator: Iterator[(K, V)] + * def += (kv: (K, V)): This + * def -= (key: K): This * }}} * If you wish that methods like `take`, `drop`, `filter` also return the same kind of map * you should also override: @@ -44,13 +44,13 @@ import scala.collection.parallel.mutable.ParMap * It is also good idea to override methods `foreach` and * `size` for efficiency. */ -trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] - extends scala.collection.MapLike[A, B, This] - with Builder[(A, B), This] - with Growable[(A, B)] - with Shrinkable[A] +trait MapLike[K, V, +This <: MapLike[K, V, This] with Map[K, V]] + extends scala.collection.MapLike[K, V, This] + with Builder[(K, V), This] + with Growable[(K, V)] + with Shrinkable[K] with Cloneable[This] - with Parallelizable[(A, B), ParMap[A, B]] + with Parallelizable[(K, V), ParMap[K, V]] { self => /** A common implementation of `newBuilder` for all mutable maps @@ -58,9 +58,21 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * * Overrides `MapLike` implementation for better efficiency. */ - override protected[this] def newBuilder: Builder[(A, B), This] = empty + override protected[this] def newBuilder: Builder[(K, V), This] = empty + + protected[this] override def parCombiner = ParMap.newCombiner[K, V] + + /** 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[(K, V)] = { + // ArrayBuffer for efficiency, preallocated to the right size. + val result = new ArrayBuffer[(K, V)](size) + foreach(result += _) + result + } - protected[this] override def parCombiner = ParMap.newCombiner[A, B] /** Adds a new key/value pair to this map and optionally returns previously bound value. * If the map already contains a @@ -72,7 +84,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * before the `put` operation was executed, or `None` if `key` * was not defined in the map before. */ - def put(key: A, value: B): Option[B] = { + def put(key: K, value: V): Option[V] = { val r = get(key) update(key, value) r @@ -85,7 +97,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param key The key to update * @param value The new value */ - def update(key: A, value: B) { this += ((key, value)) } + def update(key: K, value: V) { this += ((key, value)) } /** Adds a new key/value pair to this map. * If the map already contains a @@ -93,7 +105,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param kv the key/value pair. * @return the map itself */ - def += (kv: (A, B)): this.type + def += (kv: (K, V)): this.type /** Creates a new map consisting of all key/value pairs of the current map * plus a new pair of a given key and value. @@ -103,7 +115,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return A fresh immutable map with the binding from `key` to * `value` added to this map. */ - override def updated[B1 >: B](key: A, value: B1): Map[A, B1] = this + ((key, value)) + override def updated[V1 >: V](key: K, value: V1): Map[K, V1] = this + ((key, value)) /** Creates a new map containing a new key/value mapping and all the key/value mappings * of this map. @@ -114,7 +126,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return a new map containing mappings of this map and the mapping `kv`. */ @migration("`+` creates a new map. Use `+=` to add an element to this map and return that map itself.", "2.8.0") - def + [B1 >: B] (kv: (A, B1)): Map[A, B1] = clone().asInstanceOf[Map[A, B1]] += kv + def + [V1 >: V] (kv: (K, V1)): Map[K, V1] = clone().asInstanceOf[Map[K, V1]] += kv /** Creates a new map containing two or more key/value mappings and all the key/value * mappings of this map. @@ -127,8 +139,8 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return a new map containing mappings of this map and two or more specified mappings. */ @migration("`+` creates a new map. Use `+=` to add an element to this map and return that map itself.", "2.8.0") - override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): Map[A, B1] = - clone().asInstanceOf[Map[A, B1]] += elem1 += elem2 ++= elems + override def + [V1 >: V] (elem1: (K, V1), elem2: (K, V1), elems: (K, V1) *): Map[K, V1] = + clone().asInstanceOf[Map[K, V1]] += elem1 += elem2 ++= elems /** Creates a new map containing the key/value mappings provided by the specified traversable object * and all the key/value mappings of this map. @@ -139,8 +151,8 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return a new map containing mappings of this map and those provided by `xs`. */ @migration("`++` creates a new map. Use `++=` to add an element to this map and return that map itself.", "2.8.0") - override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): Map[A, B1] = - clone().asInstanceOf[Map[A, B1]] ++= xs.seq + override def ++[V1 >: V](xs: GenTraversableOnce[(K, V1)]): Map[K, V1] = + clone().asInstanceOf[Map[K, V1]] ++= xs.seq /** Removes a key from this map, returning the value associated previously * with that key as an option. @@ -148,7 +160,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return an option value containing the value associated previously with `key`, * or `None` if `key` was not defined in the map before. */ - def remove(key: A): Option[B] = { + def remove(key: K): Option[V] = { val r = get(key) this -= key r @@ -158,7 +170,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param key the key to be removed * @return the map itself. */ - def -= (key: A): this.type + def -= (key: K): this.type /** Creates a new map with all the key/value mappings of this map except the key/value mapping * with the specified key. @@ -167,7 +179,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return a new map with all the mappings of this map except that with a key `key`. */ @migration("`-` creates a new map. Use `-=` to remove an element from this map and return that map itself.", "2.8.0") - override def -(key: A): This = clone() -= key + override def -(key: K): This = clone() -= key /** Removes all bindings from the map. After this operation has completed, * the map will be empty. @@ -188,7 +200,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @return the value associated with key (either previously or as a result * of executing the method). */ - def getOrElseUpdate(key: A, op: => B): B = + def getOrElseUpdate(key: K, op: => V): V = get(key) match { case Some(v) => v case None => val d = op; this(key) = d; d @@ -201,7 +213,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * @param f the transformation to apply * @return the map itself. */ - def transform(f: (A, B) => B): this.type = { + def transform(f: (K, V) => V): this.type = { this.iterator foreach { case (key, value) => update(key, f(key, value)) } @@ -213,7 +225,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * * @param p The test predicate */ - def retain(p: (A, B) => Boolean): this.type = { + def retain(p: (K, V) => Boolean): this.type = { for ((k, v) <- this.toList) // SI-7269 toList avoids ConcurrentModificationException if (!p(k, v)) this -= k @@ -237,7 +249,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * with a key equal to `elem1`, `elem2` or any of `elems`. */ @migration("`-` creates a new map. Use `-=` to remove an element from this map and return that map itself.", "2.8.0") - override def -(elem1: A, elem2: A, elems: A*): This = + override def -(elem1: K, elem2: K, elems: K*): This = clone() -= elem1 -= elem2 --= elems /** Creates a new map with all the key/value mappings of this map except mappings with keys @@ -248,5 +260,5 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]] * with a key equal to a key from `xs`. */ @migration("`--` creates a new map. Use `--=` to remove an element from this map and return that map itself.", "2.8.0") - override def --(xs: GenTraversableOnce[A]): This = clone() --= xs.seq + override def --(xs: GenTraversableOnce[K]): This = clone() --= xs.seq } diff --git a/src/library/scala/collection/mutable/MapProxy.scala b/src/library/scala/collection/mutable/MapProxy.scala index 552cd9769b..63b14d328a 100644 --- a/src/library/scala/collection/mutable/MapProxy.scala +++ b/src/library/scala/collection/mutable/MapProxy.scala @@ -20,7 +20,7 @@ package mutable * @version 2.0, 31/12/2006 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait MapProxy[A, B] extends Map[A, B] with MapProxyLike[A, B, Map[A, B]] { private def newProxy[B1 >: B](newSelf: Map[A, B1]): MapProxy[A, B1] = new MapProxy[A, B1] { val self = newSelf } 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/ObservableBuffer.scala b/src/library/scala/collection/mutable/ObservableBuffer.scala index 9c3247f83b..53d26f4c6f 100644 --- a/src/library/scala/collection/mutable/ObservableBuffer.scala +++ b/src/library/scala/collection/mutable/ObservableBuffer.scala @@ -23,9 +23,8 @@ import script._ * @version 1.0, 08/07/2003 * @since 1 */ -@deprecated("Observables are deprecated because scripting is deprecated.", "2.11.0") -trait ObservableBuffer[A] extends Buffer[A] with Publisher[Message[A] with Undoable] -{ +@deprecated("observables are deprecated because scripting is deprecated", "2.11.0") +trait ObservableBuffer[A] extends Buffer[A] with Publisher[Message[A] with Undoable] { type Pub <: ObservableBuffer[A] abstract override def +=(element: A): this.type = { diff --git a/src/library/scala/collection/mutable/ObservableMap.scala b/src/library/scala/collection/mutable/ObservableMap.scala index 7509b72568..421302b700 100644 --- a/src/library/scala/collection/mutable/ObservableMap.scala +++ b/src/library/scala/collection/mutable/ObservableMap.scala @@ -25,9 +25,8 @@ import script._ * @version 2.0, 31/12/2006 * @since 1 */ -@deprecated("Observables are deprecated because scripting is deprecated.", "2.11.0") -trait ObservableMap[A, B] extends Map[A, B] with Publisher[Message[(A, B)] with Undoable] -{ +@deprecated("observables are deprecated because scripting is deprecated", "2.11.0") +trait ObservableMap[A, B] extends Map[A, B] with Publisher[Message[(A, B)] with Undoable] { type Pub <: ObservableMap[A, B] diff --git a/src/library/scala/collection/mutable/ObservableSet.scala b/src/library/scala/collection/mutable/ObservableSet.scala index 19b4a5e39f..eb55a1f822 100644 --- a/src/library/scala/collection/mutable/ObservableSet.scala +++ b/src/library/scala/collection/mutable/ObservableSet.scala @@ -23,9 +23,8 @@ import script._ * @version 1.0, 08/07/2003 * @since 1 */ -@deprecated("Observables are deprecated because scripting is deprecated.", "2.11.0") -trait ObservableSet[A] extends Set[A] with Publisher[Message[A] with Undoable] -{ +@deprecated("observables are deprecated because scripting is deprecated", "2.11.0") +trait ObservableSet[A] extends Set[A] with Publisher[Message[A] with Undoable] { type Pub <: ObservableSet[A] diff --git a/src/library/scala/collection/mutable/OpenHashMap.scala b/src/library/scala/collection/mutable/OpenHashMap.scala index c86357efad..b2e9ee27b9 100644 --- a/src/library/scala/collection/mutable/OpenHashMap.scala +++ b/src/library/scala/collection/mutable/OpenHashMap.scala @@ -21,12 +21,16 @@ object OpenHashMap { def apply[K, V](elems : (K, V)*) = new OpenHashMap[K, V] ++= elems def empty[K, V] = new OpenHashMap[K, V] - final private class OpenEntry[Key, Value](val key: Key, - val hash: Int, + /** A hash table entry. + * + * The entry is occupied if and only if its `value` is a `Some`; + * deleted if and only if its `value` is `None`. + * If its `key` is not the default value of type `Key`, the entry is occupied. + * If the entry is occupied, `hash` contains the hash value of `key`. + */ + final private class OpenEntry[Key, Value](var key: Key, + var hash: Int, var value: Option[Value]) - extends HashEntry[Key, OpenEntry[Key, Value]] - - private[mutable] def nextPositivePowerOfTwo(i : Int) = 1 << (32 - Integer.numberOfLeadingZeros(i - 1)) } /** A mutable hash map based on an open hashing scheme. The precise scheme is @@ -61,10 +65,17 @@ extends AbstractMap[Key, Value] override def empty: OpenHashMap[Key, Value] = OpenHashMap.empty[Key, Value] - private[this] val actualInitialSize = OpenHashMap.nextPositivePowerOfTwo(initialSize) + private[this] val actualInitialSize = HashTable.nextPositivePowerOfTwo(initialSize) private var mask = actualInitialSize - 1 - private var table : Array[Entry] = new Array[Entry](actualInitialSize) + + /** The hash table. + * + * The table's entries are initialized to `null`, indication of an empty slot. + * A slot is either deleted or occupied if and only if the entry is non-`null`. + */ + private[this] var table = new Array[Entry](actualInitialSize) + private var _size = 0 private var deleted = 0 @@ -91,39 +102,41 @@ extends AbstractMap[Key, Value] table = new Array[Entry](newSize) mask = newSize - 1 oldTable.foreach( entry => - if (entry != null && entry.value != None) addEntry(entry)) + if (entry != null && entry.value != None) + table(findIndex(entry.key, entry.hash)) = entry ) deleted = 0 } /** Return the index of the first slot in the hash table (in probe order) - * that either is empty, or is or was last occupied by the given key. - */ - private[this] def findIndex(key: Key) : Int = findIndex(key, hashOf(key)) - - /** Return the index of the first slot in the hash table (in probe order) - * that either is empty, or is or was last occupied by the given key. - * - * This method is an optimization for when the hash value is in hand. + * that is, in order of preference, either occupied by the given key, deleted, or empty. * * @param hash hash value for `key` */ private[this] def findIndex(key: Key, hash: Int): Int = { var index = hash & mask var j = 0 - while(table(index) != null && - !(table(index).hash == hash && - table(index).key == key)){ + + /** Index of the first slot containing a deleted entry, or -1 if none found yet. */ + var firstDeletedIndex = -1 + + var entry = table(index) + while (entry != null) { + if (entry.hash == hash && entry.key == key && entry.value != None) + return index + + if (firstDeletedIndex == -1 && entry.value == None) + firstDeletedIndex = index + j += 1 index = (index + j) & mask + entry = table(index) } - index - } - private[this] def addEntry(entry: Entry) = - if (entry != null) table(findIndex(entry.key, entry.hash)) = entry + if (firstDeletedIndex == -1) index else firstDeletedIndex + } override def update(key: Key, value: Value) { - put(key, hashOf(key), value) + put(key, value) } @deprecatedOverriding("+= should not be overridden in order to maintain consistency with put.", "2.11.0") @@ -147,6 +160,8 @@ extends AbstractMap[Key, Value] } else { val res = entry.value if (entry.value == None) { + entry.key = key + entry.hash = hash size += 1 deleted -= 1 modCount += 1 @@ -156,13 +171,22 @@ extends AbstractMap[Key, Value] } } + /** Delete the hash table slot contained in the given entry. */ + @inline + private[this] def deleteSlot(entry: Entry) = { + entry.key = null.asInstanceOf[Key] + entry.hash = 0 + entry.value = None + + size -= 1 + deleted += 1 + } + override def remove(key : Key): Option[Value] = { - val index = findIndex(key) - if (table(index) != null && table(index).value != None){ - val res = table(index).value - table(index).value = None - size -= 1 - deleted += 1 + val entry = table(findIndex(key, hashOf(key))) + if (entry != null && entry.value != None) { + val res = entry.value + deleteSlot(entry) res } else None } @@ -243,7 +267,7 @@ extends AbstractMap[Key, Value] } override def retain(f : (Key, Value) => Boolean) = { - foreachUndeletedEntry(entry => if (!f(entry.key, entry.value.get)) {entry.value = None; size -= 1; deleted += 1} ) + foreachUndeletedEntry(entry => if (!f(entry.key, entry.value.get)) deleteSlot(entry)) this } diff --git a/src/library/scala/collection/mutable/PriorityQueue.scala b/src/library/scala/collection/mutable/PriorityQueue.scala index 2562f60355..ed43ef6db9 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] @@ -67,7 +66,7 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) def p_swap(a: Int, b: Int) = super.swap(a, b) } - protected[this] override def newBuilder = new PriorityQueue[A] + protected[this] override def newBuilder = PriorityQueue.newBuilder[A] private val resarr = new ResizableArrayAccess[A] @@ -90,14 +89,15 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) } } - protected def fixDown(as: Array[AnyRef], m: Int, n: Int): Unit = { + protected def fixDown(as: Array[AnyRef], m: Int, n: Int): Boolean = { + // returns true if any swaps were done (used in heapify) var k: Int = m while (n >= 2 * k) { var j = 2 * k if (j < n && toA(as(j)) < toA(as(j + 1))) j += 1 if (toA(as(k)) >= toA(as(j))) - return + return k != m else { val h = as(k) as(k) = as(j) @@ -105,6 +105,7 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) k = j } } + k != m } /** Inserts a single element into the priority queue. @@ -120,6 +121,66 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) this } + override def ++=(xs: TraversableOnce[A]): this.type = { + val from = resarr.p_size0 + for (x <- xs) unsafeAdd(x) + heapify(from) + this + } + + private def unsafeAdd(elem: A): Unit = { + // like += but skips fixUp, which breaks the ordering invariant + // a series of unsafeAdds MUST be followed by heapify + resarr.p_ensureSize(resarr.p_size0 + 1) + resarr.p_array(resarr.p_size0) = elem.asInstanceOf[AnyRef] + resarr.p_size0 += 1 + } + + private def heapify(from: Int): Unit = { + // elements at indices 1..from-1 were already in heap order before any adds + // elements at indices from..n are newly added, their order must be fixed + val n = length + + if (from <= 2) { + // no pre-existing order to maintain, do the textbook heapify algorithm + for (i <- n/2 to 1 by -1) fixDown(resarr.p_array, i, n) + } + else if (n - from < 4) { + // for very small adds, doing the simplest fix is faster + for (i <- from to n) fixUp(resarr.p_array, i) + } + else { + var min = from/2 // tracks the minimum element in the queue + val queue = scala.collection.mutable.Queue[Int](min) + + // do fixDown on the parents of all the new elements + // except the parent of the first new element, which is in the queue + // (that parent is treated specially because it might be the root) + for (i <- n/2 until min by -1) { + if (fixDown(resarr.p_array, i, n)) { + // there was a swap, so also need to fixDown i's parent + val parent = i/2 + if (parent < min) { // make sure same parent isn't added twice + min = parent + queue += parent + } + } + } + + while (queue.nonEmpty) { + val i = queue.dequeue() + if (fixDown(resarr.p_array, i, n)) { + val parent = i/2 + if (parent < min && parent > 0) { + // the "parent > 0" is to avoid adding the parent of the root + min = parent + queue += parent + } + } + } + } + } + /** Adds all elements provided by a `TraversableOnce` object * into the priority queue. * @@ -143,9 +204,11 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) def dequeue(): A = if (resarr.p_size0 > 1) { resarr.p_size0 = resarr.p_size0 - 1 - resarr.p_swap(1, resarr.p_size0) + val result = resarr.p_array(1) + resarr.p_array(1) = resarr.p_array(resarr.p_size0) + resarr.p_array(resarr.p_size0) = null // erase reference from array fixDown(resarr.p_array, 1, resarr.p_size0 - 1) - toA(resarr.p_array(resarr.p_size0)) + toA(result) } else throw new NoSuchElementException("no element to remove from heap") @@ -187,27 +250,34 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) } } - /** Returns the reverse of this queue. The priority queue that gets - * returned will have an inversed ordering - if for some elements - * `x` and `y` the original queue's ordering - * had `compare` returning an integer ''w'', the new one will return ''-w'', - * assuming the original ordering abides its contract. + /** Returns the reverse of this priority queue. The new priority queue has + * the same elements as the original, but the opposite ordering. * - * Note that the order of the elements will be reversed unless the - * `compare` method returns 0. In this case, such elements - * will be subsequent, but their corresponding subinterval may be inappropriately - * reversed. However, due to the compare-equals contract, they will also be equal. + * For example, the element with the highest priority in `pq` has the lowest + * priority in `pq.reverse`, and vice versa. * - * @return A reversed priority queue. + * Ties are handled arbitrarily. Elements with equal priority may or + * may not be reversed with respect to each other. + * + * @return the 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) - }) - for (i <- 1 until resarr.length) revq += resarr(i) + val revq = new PriorityQueue[A]()(ord.reverse) + // copy the existing data into the new array backwards + // this won't put it exactly into the correct order, + // but will require less fixing than copying it in + // the original order + val n = resarr.p_size0 + revq.resarr.p_ensureSize(n) + revq.resarr.p_size0 = n + val from = resarr.p_array + val to = revq.resarr.p_array + for (i <- 1 until n) to(i) = from(n-i) + revq.heapify(1) revq } + /** Returns an iterator which yields all the elements in the reverse order * than that returned by the method `iterator`. * @@ -257,12 +327,198 @@ class PriorityQueue[A](implicit val ord: Ordering[A]) * * @return a priority queue with the same elements. */ - override def clone(): PriorityQueue[A] = new PriorityQueue[A] ++= this.iterator + override def clone(): PriorityQueue[A] = { + val pq = new PriorityQueue[A] + val n = resarr.p_size0 + pq.resarr.p_ensureSize(n) + java.lang.System.arraycopy(resarr.p_array, 1, pq.resarr.p_array, 1, n-1) + pq.resarr.p_size0 = n + pq + } } object PriorityQueue extends OrderedTraversableFactory[PriorityQueue] { - def newBuilder[A](implicit ord: Ordering[A]) = new PriorityQueue[A] + def newBuilder[A](implicit ord: Ordering[A]): Builder[A, PriorityQueue[A]] = { + new Builder[A, PriorityQueue[A]] { + val pq = new PriorityQueue[A] + def +=(elem: A): this.type = { pq.unsafeAdd(elem); this } + def result(): PriorityQueue[A] = { pq.heapify(1); pq } + def clear(): Unit = pq.clear() + } + } + 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/Queue.scala b/src/library/scala/collection/mutable/Queue.scala index ad60173b64..fd5fe9aecc 100644 --- a/src/library/scala/collection/mutable/Queue.scala +++ b/src/library/scala/collection/mutable/Queue.scala @@ -143,7 +143,7 @@ extends MutableList[A] /** Return the proper suffix of this list which starts with the first element that satisfies `p`. * That element is unlinked from the list. If no element satisfies `p`, return None. */ - @deprecated("extractFirst inappropriately exposes implementation details. Use dequeue or dequeueAll.", "2.11.0") + @deprecated("extractFirst inappropriately exposes implementation details. Use dequeue or dequeueAll.", "2.11.0") def extractFirst(start: LinkedList[A], p: A => Boolean): Option[LinkedList[A]] = { if (isEmpty) None else { diff --git a/src/library/scala/collection/mutable/QueueProxy.scala b/src/library/scala/collection/mutable/QueueProxy.scala index 22ff3306d5..e780cc2cf0 100644 --- a/src/library/scala/collection/mutable/QueueProxy.scala +++ b/src/library/scala/collection/mutable/QueueProxy.scala @@ -21,7 +21,7 @@ package mutable * @version 1.1, 03/05/2004 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait QueueProxy[A] extends Queue[A] with Proxy { def self: Queue[A] 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..50d3513784 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) } //########################################################################## @@ -101,7 +101,7 @@ trait ResizableArray[A] extends IndexedSeq[A] if (newSize > Int.MaxValue) newSize = Int.MaxValue val newArray: Array[AnyRef] = new Array(newSize.toInt) - scala.compat.Platform.arraycopy(array, 0, newArray, 0, size0) + java.lang.System.arraycopy(array, 0, newArray, 0, size0) array = newArray } } diff --git a/src/library/scala/collection/mutable/ReusableBuilder.scala b/src/library/scala/collection/mutable/ReusableBuilder.scala new file mode 100644 index 0000000000..dee2cd6393 --- /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..0797a83154 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 @@ -213,7 +224,7 @@ trait SetLike[A, +This <: SetLike[A, This] with Set[A]] * @throws UnsupportedOperationException * if the message was not understood. */ - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") def <<(cmd: Message[A]): Unit = cmd match { case Include(_, x) => this += x case Remove(_, x) => this -= x diff --git a/src/library/scala/collection/mutable/SetProxy.scala b/src/library/scala/collection/mutable/SetProxy.scala index 74279507ff..43b6aa57af 100644 --- a/src/library/scala/collection/mutable/SetProxy.scala +++ b/src/library/scala/collection/mutable/SetProxy.scala @@ -18,7 +18,7 @@ package mutable * @version 1.1, 09/05/2004 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait SetProxy[A] extends Set[A] with SetProxyLike[A, Set[A]] { override def repr = this override def empty = new SetProxy[A] { val self = SetProxy.this.self.empty } 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/Stack.scala b/src/library/scala/collection/mutable/Stack.scala index 1a92f23b7b..28d50af1f9 100644 --- a/src/library/scala/collection/mutable/Stack.scala +++ b/src/library/scala/collection/mutable/Stack.scala @@ -54,6 +54,7 @@ object Stack extends SeqFactory[Stack] { * @define mayNotTerminateInf * @define willNotTerminateInf */ +@deprecated("Stack is an inelegant and potentially poorly-performing wrapper around List. Use a List assigned to a var instead.", "2.12.0") class Stack[A] private (var elems: List[A]) extends AbstractSeq[A] with Seq[A] diff --git a/src/library/scala/collection/mutable/StackProxy.scala b/src/library/scala/collection/mutable/StackProxy.scala index 81e63b05d2..ac52bbba21 100644 --- a/src/library/scala/collection/mutable/StackProxy.scala +++ b/src/library/scala/collection/mutable/StackProxy.scala @@ -19,7 +19,7 @@ package mutable * @version 1.0, 10/05/2004 * @since 1 */ -@deprecated("Proxying is deprecated due to lack of use and compiler-level support.", "2.11.0") +@deprecated("proxying is deprecated due to lack of use and compiler-level support", "2.11.0") trait StackProxy[A] extends Stack[A] with Proxy { def self: Stack[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/SynchronizedBuffer.scala b/src/library/scala/collection/mutable/SynchronizedBuffer.scala index 8c646b0ce5..9c27f8b003 100644 --- a/src/library/scala/collection/mutable/SynchronizedBuffer.scala +++ b/src/library/scala/collection/mutable/SynchronizedBuffer.scala @@ -25,7 +25,7 @@ import script._ * @define Coll `SynchronizedBuffer` * @define coll synchronized buffer */ -@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentLinkedQueue as an alternative.", "2.11.0") +@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentLinkedQueue as an alternative.", "2.11.0") trait SynchronizedBuffer[A] extends Buffer[A] { import scala.collection.Traversable @@ -162,7 +162,7 @@ trait SynchronizedBuffer[A] extends Buffer[A] { super.clear() } - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") override def <<(cmd: Message[A]): Unit = synchronized { super.<<(cmd) } diff --git a/src/library/scala/collection/mutable/SynchronizedMap.scala b/src/library/scala/collection/mutable/SynchronizedMap.scala index 9876296ebe..8618798dbd 100644 --- a/src/library/scala/collection/mutable/SynchronizedMap.scala +++ b/src/library/scala/collection/mutable/SynchronizedMap.scala @@ -24,7 +24,7 @@ import scala.annotation.migration * @define Coll `SynchronizedMap` * @define coll synchronized map */ -@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentHashMap as an alternative.", "2.11.0") +@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentHashMap as an alternative.", "2.11.0") trait SynchronizedMap[A, B] extends Map[A, B] { abstract override def get(key: A): Option[B] = synchronized { super.get(key) } @@ -54,7 +54,7 @@ trait SynchronizedMap[A, B] extends Map[A, B] { override def contains(key: A): Boolean = synchronized {super.contains(key) } override def isDefinedAt(key: A) = synchronized { super.isDefinedAt(key) } - // @deprecated("See Map.+ for explanation") override def +(kv: (A, B)): this.type = synchronized[this.type] { super.+(kv) } + // @deprecated("see Map.+ for explanation") override def +(kv: (A, B)): this.type = synchronized[this.type] { super.+(kv) } // can't override -, -- same type! // @deprecated override def -(key: A): Self = synchronized { super.-(key) } diff --git a/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala b/src/library/scala/collection/mutable/SynchronizedPriorityQueue.scala 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/SynchronizedQueue.scala b/src/library/scala/collection/mutable/SynchronizedQueue.scala index 48e40ab27f..ee44f07df2 100644 --- a/src/library/scala/collection/mutable/SynchronizedQueue.scala +++ b/src/library/scala/collection/mutable/SynchronizedQueue.scala @@ -25,7 +25,7 @@ package mutable * @define Coll `SynchronizedQueue` * @define coll synchronized queue */ -@deprecated("Synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentLinkedQueue as an alternative.", "2.11.0") +@deprecated("Synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.ConcurrentLinkedQueue as an alternative.", "2.11.0") class SynchronizedQueue[A] extends Queue[A] { /** Checks if the queue is empty. * diff --git a/src/library/scala/collection/mutable/SynchronizedSet.scala b/src/library/scala/collection/mutable/SynchronizedSet.scala index dd842f26ce..399630eb3c 100644 --- a/src/library/scala/collection/mutable/SynchronizedSet.scala +++ b/src/library/scala/collection/mutable/SynchronizedSet.scala @@ -24,7 +24,7 @@ import script._ * @define Coll `SynchronizedSet` * @define coll synchronized set */ -@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentHashMap[A,Unit] as an alternative.", "2.11.0") +@deprecated("Synchronization via traits is deprecated as it is inherently unreliable. Consider java.util.concurrent.ConcurrentHashMap[A,Unit] as an alternative.", "2.11.0") trait SynchronizedSet[A] extends Set[A] { abstract override def size: Int = synchronized { super.size @@ -94,7 +94,7 @@ trait SynchronizedSet[A] extends Set[A] { super.toString } - @deprecated("Scripting is deprecated.", "2.11.0") + @deprecated("scripting is deprecated", "2.11.0") override def <<(cmd: Message[A]): Unit = synchronized { super.<<(cmd) } diff --git a/src/library/scala/collection/mutable/SynchronizedStack.scala b/src/library/scala/collection/mutable/SynchronizedStack.scala index bbb6f5a9bb..2954a1f768 100644 --- a/src/library/scala/collection/mutable/SynchronizedStack.scala +++ b/src/library/scala/collection/mutable/SynchronizedStack.scala @@ -25,9 +25,8 @@ package mutable * @define Coll `SynchronizedStack` * @define coll synchronized stack */ -@deprecated("Synchronization via selective overriding of methods is inherently unreliable. Consider java.util.concurrent.LinkedBlockingDequeue instead.", "2.11.0") +@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..14ae7c9c8c --- /dev/null +++ b/src/library/scala/collection/mutable/TreeMap.scala @@ -0,0 +1,188 @@ +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 valuesIterator: Iterator[B] = RB.valuesIterator(tree, from, until) + override def keysIterator: Iterator[A] = RB.keysIterator(tree, from, until) + + 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..0b5ebe7e9a 100644 --- a/src/library/scala/collection/mutable/WrappedArray.scala +++ b/src/library/scala/collection/mutable/WrappedArray.scala @@ -13,9 +13,12 @@ package collection package mutable import scala.reflect.ClassTag -import scala.runtime.ScalaRunTime._ +import scala.runtime.BoxedUnit import scala.collection.generic._ import scala.collection.parallel.mutable.ParArray +import scala.util.hashing.MurmurHash3 + +import java.util.Arrays /** * A class representing `Array[T]`. @@ -46,7 +49,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 +66,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,10 +125,15 @@ 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 } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofRef[_] => Arrays.equals(array.asInstanceOf[Array[AnyRef]], that.array.asInstanceOf[Array[AnyRef]]) + case _ => super.equals(that) + } } final class ofByte(val array: Array[Byte]) extends WrappedArray[Byte] with Serializable { @@ -133,6 +141,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Byte = array(index) def update(index: Int, elem: Byte) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedBytesHash(array) + override def equals(that: Any) = that match { + case that: ofByte => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofShort(val array: Array[Short]) extends WrappedArray[Short] with Serializable { @@ -140,6 +153,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Short = array(index) def update(index: Int, elem: Short) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofShort => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofChar(val array: Array[Char]) extends WrappedArray[Char] with Serializable { @@ -147,6 +165,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Char = array(index) def update(index: Int, elem: Char) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofChar => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofInt(val array: Array[Int]) extends WrappedArray[Int] with Serializable { @@ -154,6 +177,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Int = array(index) def update(index: Int, elem: Int) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofInt => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofLong(val array: Array[Long]) extends WrappedArray[Long] with Serializable { @@ -161,6 +189,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Long = array(index) def update(index: Int, elem: Long) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofLong => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofFloat(val array: Array[Float]) extends WrappedArray[Float] with Serializable { @@ -168,6 +201,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Float = array(index) def update(index: Int, elem: Float) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofFloat => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofDouble(val array: Array[Double]) extends WrappedArray[Double] with Serializable { @@ -175,6 +213,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Double = array(index) def update(index: Int, elem: Double) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofDouble => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofBoolean(val array: Array[Boolean]) extends WrappedArray[Boolean] with Serializable { @@ -182,6 +225,11 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Boolean = array(index) def update(index: Int, elem: Boolean) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofBoolean => Arrays.equals(array, that.array) + case _ => super.equals(that) + } } final class ofUnit(val array: Array[Unit]) extends WrappedArray[Unit] with Serializable { @@ -189,5 +237,10 @@ object WrappedArray { def length: Int = array.length def apply(index: Int): Unit = array(index) def update(index: Int, elem: Unit) { array(index) = elem } + override def hashCode = MurmurHash3.wrappedArrayHash(array) + override def equals(that: Any) = that match { + case that: ofUnit => array.length == that.array.length + case _ => super.equals(that) + } } } diff --git a/src/library/scala/collection/mutable/WrappedArrayBuilder.scala b/src/library/scala/collection/mutable/WrappedArrayBuilder.scala index 5781ec91be..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,9 +74,7 @@ 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) { diff --git a/src/library/scala/collection/package.scala b/src/library/scala/collection/package.scala index 856f901b77..6df254c0e0 100644 --- a/src/library/scala/collection/package.scala +++ b/src/library/scala/collection/package.scala @@ -76,13 +76,9 @@ package scala * The concrete parallel collections also have specific performance characteristics which are * described in [[http://docs.scala-lang.org/overviews/parallel-collections/concrete-parallel-collections.html#performance-characteristics the parallel collections guide]] * - * === Converting between Java Collections === + * === Converting to and from Java Collections === * - * The [[scala.collection.JavaConversions]] object provides implicit defs that - * will allow mostly seamless integration between APIs using Java Collections - * and the Scala collections library. - * - * Alternatively the [[scala.collection.JavaConverters]] object provides a collection + * The [[scala.collection.JavaConverters]] object provides a collection * of decorators that allow converting between Scala and Java collections using `asScala` * and `asJava` methods. */ diff --git a/src/library/scala/collection/parallel/ParIterableLike.scala b/src/library/scala/collection/parallel/ParIterableLike.scala index 8c9b959569..2e60089df5 100644 --- a/src/library/scala/collection/parallel/ParIterableLike.scala +++ b/src/library/scala/collection/parallel/ParIterableLike.scala @@ -9,6 +9,8 @@ package scala package collection.parallel +import scala.language.{ higherKinds, implicitConversions } + import scala.collection.mutable.Builder import scala.collection.mutable.ArrayBuffer import scala.collection.IterableLike @@ -21,13 +23,9 @@ import scala.collection.GenIterable import scala.collection.GenTraversableOnce import scala.collection.GenTraversable import immutable.HashMapCombiner -import scala.reflect.{ClassTag, classTag} - -import java.util.concurrent.atomic.AtomicBoolean +import scala.reflect.ClassTag import scala.annotation.unchecked.uncheckedVariance -import scala.annotation.unchecked.uncheckedStable -import scala.language.{ higherKinds, implicitConversions } import scala.collection.parallel.ParallelCollectionImplicits._ @@ -195,7 +193,7 @@ self: ParIterableLike[T, Repr, Sequential] => * import scala.collection.parallel._ * val pc = mutable.ParArray(1, 2, 3) * pc.tasksupport = new ForkJoinTaskSupport( - * new scala.concurrent.forkjoin.ForkJoinPool(2)) + * new java.util.concurrent.ForkJoinPool(2)) * }}} * * @see [[scala.collection.parallel.TaskSupport]] @@ -844,7 +842,7 @@ self: ParIterableLike[T, Repr, Sequential] => tasksupport.executeAndWaitResult(new ToParMap(combinerFactory(cbf), splitter)(ev) mapResult { _.resultWithTaskSupport }) } - @deprecated("Use .seq.view instead", "2.11.0") + @deprecated("use .seq.view instead", "2.11.0") def view = seq.view override def toArray[U >: T: ClassTag]: Array[U] = { @@ -1284,7 +1282,7 @@ self: ParIterableLike[T, Repr, Sequential] => extends Transformer[Combiner[(U, S), That], Zip[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zip2combiner[U, S, That](othpit, pbf()) - protected[this] def newSubtask(p: IterableSplitter[T]) = unsupported + protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling val sizes = pits.map(_.remaining) @@ -1300,7 +1298,7 @@ self: ParIterableLike[T, Repr, Sequential] => extends Transformer[Combiner[(U, S), That], ZipAll[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zipAll2combiner[U, S, That](othpit, thiselem, thatelem, pbf()) - protected[this] def newSubtask(p: IterableSplitter[T]) = unsupported + protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException override def split = if (pit.remaining <= len) { val pits = pit.splitWithSignalling val sizes = pits.map(_.remaining) @@ -1322,7 +1320,7 @@ self: ParIterableLike[T, Repr, Sequential] => extends Accessor[Unit, CopyToArray[U, This]] { @volatile var result: Unit = () def leaf(prev: Option[Unit]) = pit.copyToArray(array, from, len) - protected[this] def newSubtask(p: IterableSplitter[T]) = unsupported + protected[this] def newSubtask(p: IterableSplitter[T]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(0)(_ + _.remaining); if untilp < len) yield { @@ -1379,7 +1377,7 @@ self: ParIterableLike[T, Repr, Sequential] => val half = howmany / 2 ScanNode(mergeTrees(trees, from, half), mergeTrees(trees, from + half, howmany - half)) } else trees(from) - protected[this] def newSubtask(pit: IterableSplitter[T]) = unsupported + protected[this] def newSubtask(pit: IterableSplitter[T]) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(from)(_ + _.remaining)) yield { @@ -1416,7 +1414,7 @@ self: ParIterableLike[T, Repr, Sequential] => new FromScanTree(left, z, op, cbf), new FromScanTree(right, z, op, cbf) ) - case _ => unsupportedop("Cannot be split further") + case _ => throw new UnsupportedOperationException("Cannot be split further") } def shouldSplitFurther = tree match { case ScanNode(_, _) => true diff --git a/src/library/scala/collection/parallel/ParMap.scala b/src/library/scala/collection/parallel/ParMap.scala index 9f92e6c1e8..70afe5174b 100644 --- a/src/library/scala/collection/parallel/ParMap.scala +++ b/src/library/scala/collection/parallel/ParMap.scala @@ -11,7 +11,6 @@ package collection.parallel import scala.collection.Map import scala.collection.GenMap -import scala.collection.mutable.Builder import scala.collection.generic.ParMapFactory import scala.collection.generic.GenericParMapTemplate import scala.collection.generic.GenericParMapCompanion diff --git a/src/library/scala/collection/parallel/ParMapLike.scala b/src/library/scala/collection/parallel/ParMapLike.scala index 0a671fb085..a3ac388587 100644 --- a/src/library/scala/collection/parallel/ParMapLike.scala +++ b/src/library/scala/collection/parallel/ParMapLike.scala @@ -12,10 +12,8 @@ package collection.parallel import scala.collection.MapLike import scala.collection.GenMapLike import scala.collection.Map -import scala.collection.mutable.Builder + import scala.annotation.unchecked.uncheckedVariance -import scala.collection.generic.IdleSignalling -import scala.collection.generic.Signalling /** A template trait for mutable parallel maps. This trait is to be mixed in * with concrete parallel maps to override the representation type. diff --git a/src/library/scala/collection/parallel/ParSeqLike.scala b/src/library/scala/collection/parallel/ParSeqLike.scala index 0b6fec364e..60fa1858e7 100644 --- a/src/library/scala/collection/parallel/ParSeqLike.scala +++ b/src/library/scala/collection/parallel/ParSeqLike.scala @@ -9,11 +9,10 @@ package scala package collection.parallel -import scala.collection.{ Parallel, SeqLike, GenSeqLike, GenSeq, GenIterable, Iterator } +import scala.collection.{ SeqLike, GenSeq, GenIterable, Iterator } import scala.collection.generic.DefaultSignalling import scala.collection.generic.AtomicIndexFlag import scala.collection.generic.CanBuildFrom -import scala.collection.generic.CanCombineFrom import scala.collection.generic.VolatileAbort import scala.collection.parallel.ParallelCollectionImplicits._ @@ -365,7 +364,7 @@ self => pit.setIndexFlagIfLesser(from) } } - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(from)(_ + _.remaining)) yield new IndexWhere(pred, untilp, p) @@ -386,7 +385,7 @@ self => pit.setIndexFlagIfGreater(pos) } } - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(pos)(_ + _.remaining)) yield new LastIndexWhere(pred, untilp, p) @@ -420,7 +419,7 @@ self => result = pit.sameElements(otherpit) if (!result) pit.abort() } - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val fp = pit.remaining / 2 val sp = pit.remaining - fp @@ -434,7 +433,7 @@ self => extends Transformer[Combiner[U, That], Updated[U, That]] { @volatile var result: Combiner[U, That] = null def leaf(prev: Option[Combiner[U, That]]) = result = pit.updated2combiner(pos, elem, pbf()) - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val pits = pit.splitWithSignalling for ((p, untilp) <- pits zip pits.scanLeft(0)(_ + _.remaining)) yield new Updated(pos - untilp, elem, pbf, p) @@ -447,7 +446,7 @@ self => extends Transformer[Combiner[(U, S), That], Zip[U, S, That]] { @volatile var result: Result = null def leaf(prev: Option[Result]) = result = pit.zip2combiner[U, S, That](otherpit, cf()) - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val fp = len / 2 val sp = len - len / 2 @@ -468,7 +467,7 @@ self => result = pit.corresponds(corr)(otherpit) if (!result) pit.abort() } - protected[this] def newSubtask(p: SuperParIterator) = unsupported + protected[this] def newSubtask(p: SuperParIterator) = throw new UnsupportedOperationException override def split = { val fp = pit.remaining / 2 val sp = pit.remaining - fp diff --git a/src/library/scala/collection/parallel/RemainsIterator.scala b/src/library/scala/collection/parallel/RemainsIterator.scala index 5f2ceac0e0..63d63d9ef3 100644 --- a/src/library/scala/collection/parallel/RemainsIterator.scala +++ b/src/library/scala/collection/parallel/RemainsIterator.scala @@ -9,13 +9,10 @@ package scala package collection.parallel -import scala.collection.Parallel import scala.collection.generic.Signalling import scala.collection.generic.DelegatedSignalling import scala.collection.generic.IdleSignalling -import scala.collection.generic.CanCombineFrom import scala.collection.mutable.Builder -import scala.collection.Iterator.empty import scala.collection.GenTraversableOnce import scala.collection.parallel.immutable.repetition @@ -456,6 +453,15 @@ self => } it } + /** Drop implemented as simple eager consumption. */ + override def drop(n: Int): IterableSplitter[T] = { + var i = 0 + while (i < n && hasNext) { + next() + i += 1 + } + this + } override def take(n: Int): IterableSplitter[T] = newTaken(n) override def slice(from1: Int, until1: Int): IterableSplitter[T] = newSliceInternal(newTaken(until1), from1) diff --git a/src/library/scala/collection/parallel/TaskSupport.scala b/src/library/scala/collection/parallel/TaskSupport.scala index 9064018d46..4d633253ce 100644 --- a/src/library/scala/collection/parallel/TaskSupport.scala +++ b/src/library/scala/collection/parallel/TaskSupport.scala @@ -10,13 +10,13 @@ package scala package collection.parallel import java.util.concurrent.ThreadPoolExecutor -import scala.concurrent.forkjoin.ForkJoinPool +import java.util.concurrent.ForkJoinPool import scala.concurrent.ExecutionContext /** A trait implementing the scheduling of a parallel collection operation. * * Parallel collections are modular in the way operations are scheduled. Each - * parallel collection is parametrized with a task support object which is + * parallel collection is parameterized with a task support object which is * responsible for scheduling and load-balancing tasks to processors. * * A task support object can be changed in a parallel collection after it has @@ -41,7 +41,7 @@ import scala.concurrent.ExecutionContext * import scala.collection.parallel._ * val pc = mutable.ParArray(1, 2, 3) * pc.tasksupport = new ForkJoinTaskSupport( - * new scala.concurrent.forkjoin.ForkJoinPool(2)) + * new java.util.concurrent.ForkJoinPool(2)) * }}} * * @see [[http://docs.scala-lang.org/overviews/parallel-collections/configuration.html Configuring Parallel Collections]] section @@ -60,7 +60,7 @@ extends TaskSupport with AdaptiveWorkStealingForkJoinTasks * * @see [[scala.collection.parallel.TaskSupport]] for more information. */ -@deprecated("Use `ForkJoinTaskSupport` instead.", "2.11.0") +@deprecated("use `ForkJoinTaskSupport` instead", "2.11.0") class ThreadPoolTaskSupport(val environment: ThreadPoolExecutor = ThreadPoolTasks.defaultThreadPool) extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks @@ -71,7 +71,7 @@ extends TaskSupport with AdaptiveWorkStealingThreadPoolTasks * forkjoin based task support or a thread pool executor one, depending on * what the execution context uses. * - * By default, parallel collections are parametrized with this task support + * By default, parallel collections are parameterized with this task support * object, so parallel collections share the same execution context backend * as the rest of the `scala.concurrent` package. * diff --git a/src/library/scala/collection/parallel/Tasks.scala b/src/library/scala/collection/parallel/Tasks.scala index fcf0dff846..f472c6be5c 100644 --- a/src/library/scala/collection/parallel/Tasks.scala +++ b/src/library/scala/collection/parallel/Tasks.scala @@ -10,7 +10,7 @@ package scala package collection.parallel import java.util.concurrent.ThreadPoolExecutor -import scala.concurrent.forkjoin._ +import java.util.concurrent.{ForkJoinPool, RecursiveAction, ForkJoinWorkerThread} import scala.concurrent.ExecutionContext import scala.util.control.Breaks._ import scala.annotation.unchecked.uncheckedVariance @@ -66,13 +66,10 @@ trait Task[R, +Tp] { } private[parallel] def mergeThrowables(that: Task[_, _]) { - // TODO: As soon as we target Java >= 7, use Throwable#addSuppressed - // to pass additional Throwables to the caller, e. g. - // if (this.throwable != null && that.throwable != null) - // this.throwable.addSuppressed(that.throwable) - // For now, we just use whatever Throwable comes across “first”. - if (this.throwable == null && that.throwable != null) - this.throwable = that.throwable + if (this.throwable != null && that.throwable != null) + this.throwable.addSuppressed(that.throwable) + else if (this.throwable == null && that.throwable != null) + this.throwable = that.throwable } // override in concrete task implementations to signal abort to other tasks @@ -211,7 +208,7 @@ trait AdaptiveWorkStealingTasks extends Tasks { /** An implementation of tasks objects based on the Java thread pooling API. */ -@deprecated("Use `ForkJoinTasks` instead.", "2.11.0") +@deprecated("use `ForkJoinTasks` instead", "2.11.0") trait ThreadPoolTasks extends Tasks { import java.util.concurrent._ @@ -320,7 +317,7 @@ trait ThreadPoolTasks extends Tasks { } -@deprecated("Use `ForkJoinTasks` instead.", "2.11.0") +@deprecated("use `ForkJoinTasks` instead", "2.11.0") object ThreadPoolTasks { import java.util.concurrent._ @@ -448,7 +445,7 @@ trait AdaptiveWorkStealingForkJoinTasks extends ForkJoinTasks with AdaptiveWorkS def newWrappedTask[R, Tp](b: Task[R, Tp]) = new WrappedTask[R, Tp](b) } -@deprecated("Use `AdaptiveWorkStealingForkJoinTasks` instead.", "2.11.0") +@deprecated("use `AdaptiveWorkStealingForkJoinTasks` instead", "2.11.0") trait AdaptiveWorkStealingThreadPoolTasks extends ThreadPoolTasks with AdaptiveWorkStealingTasks { class WrappedTask[R, Tp](val body: Task[R, Tp]) @@ -526,7 +523,7 @@ private[parallel] final class FutureTasks(executor: ExecutionContext) extends Ta } /** This tasks implementation uses execution contexts to spawn a parallel computation. - * + * * As an optimization, it internally checks whether the execution context is the * standard implementation based on fork/join pools, and if it is, creates a * `ForkJoinTaskSupport` that shares the same pool to forward its request to it. @@ -540,7 +537,7 @@ trait ExecutionContextTasks extends Tasks { val environment: ExecutionContext /** A driver serves as a target for this proxy `Tasks` object. - * + * * If the execution context has the standard implementation and uses fork/join pools, * the driver is `ForkJoinTaskSupport` with the same pool, as an optimization. * Otherwise, the driver will be a Scala `Future`-based implementation. diff --git a/src/library/scala/collection/parallel/immutable/ParHashSet.scala b/src/library/scala/collection/parallel/immutable/ParHashSet.scala index 65a632470e..3a1ec7fff8 100644 --- a/src/library/scala/collection/parallel/immutable/ParHashSet.scala +++ b/src/library/scala/collection/parallel/immutable/ParHashSet.scala @@ -197,7 +197,7 @@ extends scala.collection.parallel.BucketCombiner[T, ParHashSet[T], Any, HashSetC while (i < chunksz) { val v = chunkarr(i).asInstanceOf[T] val hc = trie.computeHash(v) - trie = trie.updated0(v, hc, rootbits) + trie = trie.updated0(v, hc, rootbits) // internal API, private[collection] i += 1 } i = 0 diff --git a/src/library/scala/collection/parallel/immutable/ParMap.scala b/src/library/scala/collection/parallel/immutable/ParMap.scala index 2956c2a883..65bb2e12c5 100644 --- a/src/library/scala/collection/parallel/immutable/ParMap.scala +++ b/src/library/scala/collection/parallel/immutable/ParMap.scala @@ -16,7 +16,6 @@ import scala.collection.generic.GenericParMapCompanion import scala.collection.generic.CanCombineFrom import scala.collection.parallel.ParMapLike import scala.collection.parallel.Combiner -import scala.collection.GenMapLike /** A template trait for immutable parallel maps. * diff --git a/src/library/scala/collection/parallel/immutable/ParRange.scala b/src/library/scala/collection/parallel/immutable/ParRange.scala index ec90de3a7d..de2b53a6c0 100644 --- a/src/library/scala/collection/parallel/immutable/ParRange.scala +++ b/src/library/scala/collection/parallel/immutable/ParRange.scala @@ -12,7 +12,6 @@ package collection.parallel.immutable import scala.collection.immutable.Range import scala.collection.parallel.Combiner import scala.collection.parallel.SeqSplitter -import scala.collection.generic.CanCombineFrom import scala.collection.Iterator /** Parallel ranges. @@ -108,6 +107,7 @@ self => } } + override def toString = s"Par$range" } object ParRange { diff --git a/src/library/scala/collection/parallel/immutable/package.scala b/src/library/scala/collection/parallel/immutable/package.scala index 8fd84eaf4d..3cafdba5f7 100644 --- a/src/library/scala/collection/parallel/immutable/package.scala +++ b/src/library/scala/collection/parallel/immutable/package.scala @@ -20,7 +20,12 @@ package immutable { self => def apply(idx: Int) = if (0 <= idx && idx < length) elem else throw new IndexOutOfBoundsException("" + idx) - override def seq = throw new UnsupportedOperationException + override def seq: collection.immutable.Seq[T] = new collection.AbstractSeq[T] with collection.immutable.Seq[T] { + override def length: Int = self.length + override def apply(idx: Int): T = self.apply(idx) + override def iterator: Iterator[T] = Iterator.continually(elem).take(length) + override def par: ParSeq[T] = self + } def update(idx: Int, elem: T) = throw new UnsupportedOperationException class ParIterator(var i: Int = 0, val until: Int = length, elem: T = self.elem) extends SeqSplitter[T] { diff --git a/src/library/scala/collection/parallel/mutable/LazyCombiner.scala b/src/library/scala/collection/parallel/mutable/LazyCombiner.scala index 5ab2bb81c6..cc25b5b4b2 100644 --- a/src/library/scala/collection/parallel/mutable/LazyCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/LazyCombiner.scala @@ -30,7 +30,6 @@ trait LazyCombiner[Elem, +To, Buff <: Growable[Elem] with Sizing] extends Combin def result: To = allocateAndCopy def clear() = { chain.clear() } def combine[N <: Elem, NewTo >: To](other: Combiner[N, NewTo]): Combiner[N, NewTo] = if (this ne other) { - import language.existentials // FIXME: See SI-7750 if (other.isInstanceOf[LazyCombiner[_, _, _]]) { val that = other.asInstanceOf[LazyCombiner[Elem, To, Buff]] newLazyCombiner(chain ++= that.chain) diff --git a/src/library/scala/collection/parallel/mutable/ParArray.scala b/src/library/scala/collection/parallel/mutable/ParArray.scala index d0d022db4b..8a2cf2716a 100644 --- a/src/library/scala/collection/parallel/mutable/ParArray.scala +++ b/src/library/scala/collection/parallel/mutable/ParArray.scala @@ -18,7 +18,6 @@ import scala.collection.generic.GenericParCompanion import scala.collection.generic.CanCombineFrom import scala.collection.generic.CanBuildFrom import scala.collection.generic.ParFactory -import scala.collection.generic.Sizing import scala.collection.parallel.Combiner import scala.collection.parallel.SeqSplitter import scala.collection.parallel.ParSeqLike diff --git a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala index a1dc37cec9..2faf223b99 100644 --- a/src/library/scala/collection/parallel/mutable/ParTrieMap.scala +++ b/src/library/scala/collection/parallel/mutable/ParTrieMap.scala @@ -152,18 +152,9 @@ extends TrieMapIterator[K, V](lev, ct, mustInit) /** Only used within the `ParTrieMap`. */ private[mutable] trait ParTrieMapCombiner[K, V] extends Combiner[(K, V), ParTrieMap[K, V]] { - def combine[N <: (K, V), NewTo >: ParTrieMap[K, V]](other: Combiner[N, NewTo]): Combiner[N, NewTo] = if (this eq other) this else { - throw new UnsupportedOperationException("This shouldn't have been called in the first place.") - - val thiz = this.asInstanceOf[ParTrieMap[K, V]] - val that = other.asInstanceOf[ParTrieMap[K, V]] - val result = new ParTrieMap[K, V] - - result ++= thiz.iterator - result ++= that.iterator - - result - } + def combine[N <: (K, V), NewTo >: ParTrieMap[K, V]](other: Combiner[N, NewTo]): Combiner[N, NewTo] = + if (this eq other) this + else throw new UnsupportedOperationException("This shouldn't have been called in the first place.") override def canBeShared = true } diff --git a/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala b/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala index 79322c85b1..6883457fef 100644 --- a/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/ResizableParArrayCombiner.scala @@ -9,18 +9,10 @@ package scala package collection.parallel.mutable - - -import scala.collection.generic.Sizing import scala.collection.mutable.ArraySeq import scala.collection.mutable.ArrayBuffer -import scala.collection.parallel.TaskSupport -import scala.collection.parallel.unsupportedop -import scala.collection.parallel.Combiner import scala.collection.parallel.Task - - /** An array combiner that uses a chain of arraybuffers to store elements. */ trait ResizableParArrayCombiner[T] extends LazyCombiner[T, ParArray[T], ExposedArrayBuffer[T]] { diff --git a/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala b/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala index d1379cde11..e71e61f2f1 100644 --- a/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala +++ b/src/library/scala/collection/parallel/mutable/UnrolledParArrayCombiner.scala @@ -9,23 +9,11 @@ package scala package collection.parallel.mutable -import scala.collection.generic.Sizing import scala.collection.mutable.ArraySeq -import scala.collection.mutable.ArrayBuffer -import scala.collection.mutable.UnrolledBuffer +import scala.collection.mutable.DoublingUnrolledBuffer import scala.collection.mutable.UnrolledBuffer.Unrolled -import scala.collection.parallel.TaskSupport -import scala.collection.parallel.unsupportedop import scala.collection.parallel.Combiner import scala.collection.parallel.Task -import scala.reflect.ClassTag - -// Todo -- revisit whether inheritance is the best way to achieve this functionality -private[mutable] 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 Unrolled[T](0, new Array[T](4), null, this) -} - /** An array combiner that uses doubling unrolled buffers to store elements. */ trait UnrolledParArrayCombiner[T] @@ -62,7 +50,7 @@ extends Combiner[T, ParArray[T]] { case that: UnrolledParArrayCombiner[t] => buff concat that.buff this - case _ => unsupportedop("Cannot combine with combiner of different type.") + case _ => throw new UnsupportedOperationException("Cannot combine with combiner of different type.") } def size = buff.size diff --git a/src/library/scala/collection/parallel/package.scala b/src/library/scala/collection/parallel/package.scala index d77dcb0658..eaa87b675a 100644 --- a/src/library/scala/collection/parallel/package.scala +++ b/src/library/scala/collection/parallel/package.scala @@ -35,15 +35,7 @@ package object parallel { else sz } - private[parallel] def unsupported = throw new UnsupportedOperationException - - private[parallel] def unsupportedop(msg: String) = throw new UnsupportedOperationException(msg) - - private[parallel] def outofbounds(idx: Int) = throw new IndexOutOfBoundsException(idx.toString) - - private[parallel] def getTaskSupport: TaskSupport = new ExecutionContextTaskSupport - - val defaultTaskSupport: TaskSupport = getTaskSupport + val defaultTaskSupport: TaskSupport = new ExecutionContextTaskSupport def setTaskSupport[Coll](c: Coll, t: TaskSupport): Coll = { c match { @@ -98,7 +90,7 @@ package parallel { } } } - + trait FactoryOps[From, Elem, To] { trait Otherwise[R] { def otherwise(notbody: => R): R @@ -122,9 +114,9 @@ package parallel { def ifParSeq[R](isbody: ParSeq[T] => R): Otherwise[R] } - @deprecated("This trait will be removed.", "2.11.0") + @deprecated("this trait will be removed", "2.11.0") trait ThrowableOps { - @deprecated("This method will be removed.", "2.11.0") + @deprecated("this method will be removed", "2.11.0") def alongWith(that: Throwable): Throwable } @@ -143,7 +135,7 @@ package parallel { } /** Composite throwable - thrown when multiple exceptions are thrown at the same time. */ - @deprecated("This class will be removed.", "2.11.0") + @deprecated("this class will be removed.", "2.11.0") final case class CompositeThrowable(throwables: Set[Throwable]) extends Exception( "Multiple exceptions thrown during a parallel computation: " + throwables.map(t => t + "\n" + t.getStackTrace.take(10).++("...").mkString("\n")).mkString("\n\n") diff --git a/src/library/scala/collection/script/Location.scala b/src/library/scala/collection/script/Location.scala index bed74bf9ca..8a0b10c331 100644 --- a/src/library/scala/collection/script/Location.scala +++ b/src/library/scala/collection/script/Location.scala @@ -18,17 +18,17 @@ package script * @since 2.8 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") sealed abstract class Location -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case object Start extends Location -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case object End extends Location -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case object NoLo extends Location -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Index(n: Int) extends Location diff --git a/src/library/scala/collection/script/Message.scala b/src/library/scala/collection/script/Message.scala index 3fc2a0ec7e..a6ba9d9523 100644 --- a/src/library/scala/collection/script/Message.scala +++ b/src/library/scala/collection/script/Message.scala @@ -21,7 +21,7 @@ import mutable.ArrayBuffer * @version 1.0, 08/07/2003 * @since 2.8 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") trait Message[+A] /** This observable update refers to inclusion operations that add new elements @@ -30,7 +30,7 @@ trait Message[+A] * @author Matthias Zenger * @version 1.0, 08/07/2003 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Include[+A](location: Location, elem: A) extends Message[A] { def this(elem: A) = this(NoLo, elem) } @@ -41,7 +41,7 @@ case class Include[+A](location: Location, elem: A) extends Message[A] { * @author Matthias Zenger * @version 1.0, 08/07/2003 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Update[+A](location: Location, elem: A) extends Message[A] { def this(elem: A) = this(NoLo, elem) } @@ -52,7 +52,7 @@ case class Update[+A](location: Location, elem: A) extends Message[A] { * @author Matthias Zenger * @version 1.0, 08/07/2003 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Remove[+A](location: Location, elem: A) extends Message[A] { def this(elem: A) = this(NoLo, elem) } @@ -62,7 +62,7 @@ case class Remove[+A](location: Location, elem: A) extends Message[A] { * @author Matthias Zenger * @version 1.0, 08/07/2003 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") case class Reset[+A]() extends Message[A] /** Objects of this class represent compound messages consisting @@ -71,7 +71,7 @@ case class Reset[+A]() extends Message[A] * @author Matthias Zenger * @version 1.0, 10/05/2004 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") class Script[A] extends ArrayBuffer[Message[A]] with Message[A] { override def toString(): String = { diff --git a/src/library/scala/collection/script/Scriptable.scala b/src/library/scala/collection/script/Scriptable.scala index 4db75ddd3e..8965286b0d 100644 --- a/src/library/scala/collection/script/Scriptable.scala +++ b/src/library/scala/collection/script/Scriptable.scala @@ -17,7 +17,7 @@ package script * @version 1.0, 09/05/2004 * @since 2.8 */ -@deprecated("Scripting is deprecated.", "2.11.0") +@deprecated("scripting is deprecated", "2.11.0") trait Scriptable[A] { /** Send a message to this scriptable object. */ |