Skip to content

Commit 70956e5

Browse files
committed
Merge pull request scala#2119 from JamesIry/master_SI-6642
SI-6642 Adds iteratorFrom, keysIteratorFrom, and valuesIteratorFrom
2 parents bafebe1 + 07ba1f8 commit 70956e5

File tree

13 files changed

+411
-97
lines changed

13 files changed

+411
-97
lines changed

src/library/scala/Enumeration.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ abstract class Enumeration (initial: Int) extends Serializable {
254254
def contains(v: Value) = nnIds contains (v.id - bottomId)
255255
def + (value: Value) = new ValueSet(nnIds + (value.id - bottomId))
256256
def - (value: Value) = new ValueSet(nnIds - (value.id - bottomId))
257-
def iterator = nnIds.iterator map (id => thisenum.apply(id + bottomId))
257+
def iterator = nnIds.iterator map (id => thisenum.apply(bottomId + id))
258+
override def keysIteratorFrom(start: Value) = nnIds keysIteratorFrom start.id map (id => thisenum.apply(bottomId + id))
258259
override def stringPrefix = thisenum + ".ValueSet"
259260
/** Creates a bit mask for the zero-adjusted ids in this set as a
260261
* new array of longs */

src/library/scala/collection/BitSetLike.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,10 @@ trait BitSetLike[+This <: BitSetLike[This] with SortedSet[Int]] extends SortedSe
9898
fromBitMaskNoCopy(a)
9999
}
100100

101-
def iterator: Iterator[Int] = new AbstractIterator[Int] {
102-
private var current = 0
101+
def iterator: Iterator[Int] = iteratorFrom(0)
102+
103+
override def keysIteratorFrom(start: Int) = new AbstractIterator[Int] {
104+
private var current = start
103105
private val end = nwords * WordLength
104106
def hasNext: Boolean = {
105107
while (current < end && !self.contains(current)) current += 1

src/library/scala/collection/SortedMapLike.scala

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ self =>
4242
val map = self.rangeImpl(from, until)
4343
new map.DefaultKeySortedSet
4444
}
45+
override def keysIteratorFrom(start: A) = self.keysIteratorFrom(start)
4546
}
4647

4748
/** Add a key/value pair to this map.
@@ -76,11 +77,17 @@ self =>
7677
override def filterKeys(p: A => Boolean): SortedMap[A, B] = new FilteredKeys(p) with SortedMap.Default[A, B] {
7778
implicit def ordering: Ordering[A] = self.ordering
7879
override def rangeImpl(from : Option[A], until : Option[A]): SortedMap[A, B] = self.rangeImpl(from, until).filterKeys(p)
80+
override def iteratorFrom(start: A) = self iteratorFrom start filter {case (k, _) => p(k)}
81+
override def keysIteratorFrom(start: A) = self keysIteratorFrom start filter p
82+
override def valuesIteratorFrom(start: A) = self iteratorFrom start collect {case (k,v) if p(k) => v}
7983
}
8084

8185
override def mapValues[C](f: B => C): SortedMap[A, C] = new MappedValues(f) with SortedMap.Default[A, C] {
8286
implicit def ordering: Ordering[A] = self.ordering
8387
override def rangeImpl(from : Option[A], until : Option[A]): SortedMap[A, C] = self.rangeImpl(from, until).mapValues(f)
88+
override def iteratorFrom(start: A) = (self iteratorFrom start) map {case (k,v) => (k, f(v))}
89+
override def keysIteratorFrom(start: A) = self keysIteratorFrom start
90+
override def valuesIteratorFrom(start: A) = self valuesIteratorFrom start map f
8491
}
8592

8693
/** Adds a number of elements provided by a traversable object
@@ -91,6 +98,28 @@ self =>
9198
override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): SortedMap[A, B1] =
9299
((repr: SortedMap[A, B1]) /: xs.seq) (_ + _)
93100

101+
/**
102+
* Creates an iterator over all the key/value pairs
103+
* contained in this map having a key greater than or
104+
* equal to `start` according to the ordering of
105+
* this map. x.iteratorFrom(y) is equivalent
106+
* to but often more efficient than x.from(y).iterator.
107+
*
108+
* @param start The lower bound (inclusive)
109+
* on the keys to be returned
110+
*/
111+
def iteratorFrom(start: A): Iterator[(A, B)]
112+
/**
113+
* Creates an iterator over all the values contained in this
114+
* map that are associated with a key greater than or equal to `start`
115+
* according to the ordering of this map. x.valuesIteratorFrom(y) is
116+
* equivalent to but often more efficient than
117+
* x.from(y).valuesIterator.
118+
*
119+
* @param start The lower bound (inclusive)
120+
* on the keys to be returned
121+
*/
122+
def valuesIteratorFrom(start: A): Iterator[B]
94123
}
95124

96125

src/library/scala/collection/SortedSetLike.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,14 @@ self =>
4040
case that: SortedSet[_] if that.ordering == ordering => that.hasAll(this.iterator)
4141
case that => super.subsetOf(that)
4242
}
43+
44+
/**
45+
* Creates an iterator that contains all values from this collection
46+
* greater than or equal to `start` according to the ordering of
47+
* this collection. x.iteratorFrom(y) is equivalent to but will usually
48+
* be more efficient than x.from(y).iterator
49+
*
50+
* @param start The lower-bound (inclusive) of the iterator
51+
*/
52+
def iteratorFrom(start: A): Iterator[A] = keysIteratorFrom(start)
4353
}

src/library/scala/collection/generic/Sorted.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,18 @@ trait Sorted[K, +This <: Sorted[K, This]] {
7878
else
7979
until(next)
8080
}
81+
82+
/**
83+
* Creates an iterator over all the keys(or elements) contained in this
84+
* collection greater than or equal to `start`
85+
* according to the ordering of this collection. x.keysIteratorFrom(y)
86+
* is equivalent to but often more efficient than
87+
* x.from(y).keysIterator.
88+
*
89+
* @param start The lower bound (inclusive)
90+
* on the keys to be returned
91+
*/
92+
def keysIteratorFrom(start: K): Iterator[K]
8193

8294
protected def hasAll(j: Iterator[K]): Boolean = {
8395
val i = keySet.iterator

src/library/scala/collection/immutable/RedBlackTree.scala

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ import scala.annotation.meta.getter
2424
*
2525
* @since 2.10
2626
*/
27-
private[immutable]
27+
private[collection]
2828
object RedBlackTree {
2929

3030
def isEmpty(tree: Tree[_, _]): Boolean = tree eq null
3131

32-
def contains[A](tree: Tree[A, _], x: A)(implicit ordering: Ordering[A]): Boolean = lookup(tree, x) ne null
33-
def get[A, B](tree: Tree[A, B], x: A)(implicit ordering: Ordering[A]): Option[B] = lookup(tree, x) match {
32+
def contains[A: Ordering](tree: Tree[A, _], x: A): Boolean = lookup(tree, x) ne null
33+
def get[A: Ordering, B](tree: Tree[A, B], x: A): Option[B] = lookup(tree, x) match {
3434
case null => None
3535
case tree => Some(tree.value)
3636
}
@@ -44,8 +44,27 @@ object RedBlackTree {
4444
}
4545

4646
def count(tree: Tree[_, _]) = if (tree eq null) 0 else tree.count
47-
def update[A, B, B1 >: B](tree: Tree[A, B], k: A, v: B1, overwrite: Boolean)(implicit ordering: Ordering[A]): Tree[A, B1] = blacken(upd(tree, k, v, overwrite))
48-
def delete[A, B](tree: Tree[A, B], k: A)(implicit ordering: Ordering[A]): Tree[A, B] = blacken(del(tree, k))
47+
/**
48+
* Count all the nodes with keys greater than or equal to the lower bound and less than the upper bound.
49+
* The two bounds are optional.
50+
*/
51+
def countInRange[A](tree: Tree[A, _], from: Option[A], to:Option[A])(implicit ordering: Ordering[A]) : Int =
52+
if (tree eq null) 0 else
53+
(from, to) match {
54+
// with no bounds use this node's count
55+
case (None, None) => tree.count
56+
// if node is less than the lower bound, try the tree on the right, it might be in range
57+
case (Some(lb), _) if ordering.lt(tree.key, lb) => countInRange(tree.right, from, to)
58+
// if node is greater than or equal to the upper bound, try the tree on the left, it might be in range
59+
case (_, Some(ub)) if ordering.gteq(tree.key, ub) => countInRange(tree.left, from, to)
60+
// node is in range so the tree on the left will all be less than the upper bound and the tree on the
61+
// right will all be greater than or equal to the lower bound. So 1 for this node plus
62+
// count the subtrees by stripping off the bounds that we don't need any more
63+
case _ => 1 + countInRange(tree.left, from, None) + countInRange(tree.right, None, to)
64+
65+
}
66+
def update[A: Ordering, B, B1 >: B](tree: Tree[A, B], k: A, v: B1, overwrite: Boolean): Tree[A, B1] = blacken(upd(tree, k, v, overwrite))
67+
def delete[A: Ordering, B](tree: Tree[A, B], k: A): Tree[A, B] = blacken(del(tree, k))
4968
def rangeImpl[A: Ordering, B](tree: Tree[A, B], from: Option[A], until: Option[A]): Tree[A, B] = (from, until) match {
5069
case (Some(from), Some(until)) => this.range(tree, from, until)
5170
case (Some(from), None) => this.from(tree, from)
@@ -91,9 +110,9 @@ object RedBlackTree {
91110
if (tree.right ne null) _foreachKey(tree.right, f)
92111
}
93112

94-
def iterator[A, B](tree: Tree[A, B]): Iterator[(A, B)] = new EntriesIterator(tree)
95-
def keysIterator[A, _](tree: Tree[A, _]): Iterator[A] = new KeysIterator(tree)
96-
def valuesIterator[_, B](tree: Tree[_, B]): Iterator[B] = new ValuesIterator(tree)
113+
def iterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None): Iterator[(A, B)] = new EntriesIterator(tree, start)
114+
def keysIterator[A: Ordering](tree: Tree[A, _], start: Option[A] = None): Iterator[A] = new KeysIterator(tree, start)
115+
def valuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None): Iterator[B] = new ValuesIterator(tree, start)
97116

98117
@tailrec
99118
def nth[A, B](tree: Tree[A, B], n: Int): Tree[A, B] = {
@@ -425,32 +444,28 @@ object RedBlackTree {
425444
def unapply[A, B](t: BlackTree[A, B]) = Some((t.key, t.value, t.left, t.right))
426445
}
427446

428-
private[this] abstract class TreeIterator[A, B, R](tree: Tree[A, B]) extends Iterator[R] {
447+
private[this] abstract class TreeIterator[A, B, R](root: Tree[A, B], start: Option[A])(implicit ordering: Ordering[A]) extends Iterator[R] {
429448
protected[this] def nextResult(tree: Tree[A, B]): R
430449

431-
override def hasNext: Boolean = next ne null
450+
override def hasNext: Boolean = lookahead ne null
432451

433-
override def next: R = next match {
452+
override def next: R = lookahead match {
434453
case null =>
435454
throw new NoSuchElementException("next on empty iterator")
436455
case tree =>
437-
next = findNext(tree.right)
456+
lookahead = findLeftMostOrPopOnEmpty(goRight(tree))
438457
nextResult(tree)
439458
}
440459

441460
@tailrec
442-
private[this] def findNext(tree: Tree[A, B]): Tree[A, B] = {
443-
if (tree eq null) popPath()
461+
private[this] def findLeftMostOrPopOnEmpty(tree: Tree[A, B]): Tree[A, B] =
462+
if (tree eq null) popNext()
444463
else if (tree.left eq null) tree
445-
else {
446-
pushPath(tree)
447-
findNext(tree.left)
448-
}
449-
}
464+
else findLeftMostOrPopOnEmpty(goLeft(tree))
450465

451-
private[this] def pushPath(tree: Tree[A, B]) {
466+
private[this] def pushNext(tree: Tree[A, B]) {
452467
try {
453-
path(index) = tree
468+
stackOfNexts(index) = tree
454469
index += 1
455470
} catch {
456471
case _: ArrayIndexOutOfBoundsException =>
@@ -462,17 +477,17 @@ object RedBlackTree {
462477
* An exception handler is used instead of an if-condition to optimize the normal path.
463478
* This makes a large difference in iteration speed!
464479
*/
465-
assert(index >= path.length)
466-
path :+= null
467-
pushPath(tree)
480+
assert(index >= stackOfNexts.length)
481+
stackOfNexts :+= null
482+
pushNext(tree)
468483
}
469484
}
470-
private[this] def popPath(): Tree[A, B] = if (index == 0) null else {
485+
private[this] def popNext(): Tree[A, B] = if (index == 0) null else {
471486
index -= 1
472-
path(index)
487+
stackOfNexts(index)
473488
}
474489

475-
private[this] var path = if (tree eq null) null else {
490+
private[this] var stackOfNexts = if (root eq null) null else {
476491
/*
477492
* According to "Ralf Hinze. Constructing red-black trees" [http://www.cs.ox.ac.uk/ralf.hinze/publications/#P5]
478493
* the maximum height of a red-black tree is 2*log_2(n + 2) - 2.
@@ -481,22 +496,45 @@ object RedBlackTree {
481496
*
482497
* We also don't store the deepest nodes in the path so the maximum path length is further reduced by one.
483498
*/
484-
val maximumHeight = 2 * (32 - Integer.numberOfLeadingZeros(tree.count + 2 - 1)) - 2 - 1
499+
val maximumHeight = 2 * (32 - Integer.numberOfLeadingZeros(root.count + 2 - 1)) - 2 - 1
485500
new Array[Tree[A, B]](maximumHeight)
486501
}
487502
private[this] var index = 0
488-
private[this] var next: Tree[A, B] = findNext(tree)
503+
private[this] var lookahead: Tree[A, B] = start map startFrom getOrElse findLeftMostOrPopOnEmpty(root)
504+
505+
/**
506+
* Find the leftmost subtree whose key is equal to the given key, or if no such thing,
507+
* the leftmost subtree with the key that would be "next" after it according
508+
* to the ordering. Along the way build up the iterator's path stack so that "next"
509+
* functionality works.
510+
*/
511+
private[this] def startFrom(key: A) : Tree[A,B] = if (root eq null) null else {
512+
@tailrec def find(tree: Tree[A, B]): Tree[A, B] =
513+
if (tree eq null) popNext
514+
else find(
515+
if (ordering.lteq(key, tree.key)) goLeft(tree)
516+
else goRight(tree)
517+
)
518+
find(root)
519+
}
520+
521+
private[this] def goLeft(tree: Tree[A, B]) = {
522+
pushNext(tree)
523+
tree.left
524+
}
525+
526+
private[this] def goRight(tree: Tree[A, B]) = tree.right
489527
}
490528

491-
private[this] class EntriesIterator[A, B](tree: Tree[A, B]) extends TreeIterator[A, B, (A, B)](tree) {
529+
private[this] class EntriesIterator[A: Ordering, B](tree: Tree[A, B], focus: Option[A]) extends TreeIterator[A, B, (A, B)](tree, focus) {
492530
override def nextResult(tree: Tree[A, B]) = (tree.key, tree.value)
493531
}
494532

495-
private[this] class KeysIterator[A, B](tree: Tree[A, B]) extends TreeIterator[A, B, A](tree) {
533+
private[this] class KeysIterator[A: Ordering, B](tree: Tree[A, B], focus: Option[A]) extends TreeIterator[A, B, A](tree, focus) {
496534
override def nextResult(tree: Tree[A, B]) = tree.key
497535
}
498536

499-
private[this] class ValuesIterator[A, B](tree: Tree[A, B]) extends TreeIterator[A, B, B](tree) {
537+
private[this] class ValuesIterator[A: Ordering, B](tree: Tree[A, B], focus: Option[A]) extends TreeIterator[A, B, B](tree, focus) {
500538
override def nextResult(tree: Tree[A, B]) = tree.value
501539
}
502540
}

src/library/scala/collection/immutable/SortedMap.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,17 @@ self =>
8282
override def filterKeys(p: A => Boolean): SortedMap[A, B] = new FilteredKeys(p) with SortedMap.Default[A, B] {
8383
implicit def ordering: Ordering[A] = self.ordering
8484
override def rangeImpl(from : Option[A], until : Option[A]): SortedMap[A, B] = self.rangeImpl(from, until).filterKeys(p)
85+
override def iteratorFrom(start: A) = self iteratorFrom start filter {case (k, _) => p(k)}
86+
override def keysIteratorFrom(start : A) = self keysIteratorFrom start filter p
87+
override def valuesIteratorFrom(start : A) = self iteratorFrom start collect {case (k,v) if p(k) => v}
8588
}
8689

8790
override def mapValues[C](f: B => C): SortedMap[A, C] = new MappedValues(f) with SortedMap.Default[A, C] {
8891
implicit def ordering: Ordering[A] = self.ordering
8992
override def rangeImpl(from : Option[A], until : Option[A]): SortedMap[A, C] = self.rangeImpl(from, until).mapValues(f)
93+
override def iteratorFrom(start: A) = self iteratorFrom start map {case (k, v) => (k, f(v))}
94+
override def keysIteratorFrom(start : A) = self keysIteratorFrom start
95+
override def valuesIteratorFrom(start : A) = self valuesIteratorFrom start map f
9096
}
9197

9298
}

src/library/scala/collection/immutable/TreeMap.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,13 @@ class TreeMap[A, +B] private (tree: RB.Tree[A, B])(implicit val ordering: Orderi
189189
* @return the new iterator
190190
*/
191191
override def iterator: Iterator[(A, B)] = RB.iterator(tree)
192+
override def iteratorFrom(start: A): Iterator[(A, B)] = RB.iterator(tree, Some(start))
192193

193194
override def keysIterator: Iterator[A] = RB.keysIterator(tree)
195+
override def keysIteratorFrom(start: A): Iterator[A] = RB.keysIterator(tree, Some(start))
196+
194197
override def valuesIterator: Iterator[B] = RB.valuesIterator(tree)
198+
override def valuesIteratorFrom(start: A): Iterator[B] = RB.valuesIterator(tree, Some(start))
195199

196200
override def contains(key: A): Boolean = RB.contains(tree, key)
197201
override def isDefinedAt(key: A): Boolean = RB.contains(tree, key)

src/library/scala/collection/immutable/TreeSet.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ class TreeSet[A] private (tree: RB.Tree[A, Unit])(implicit val ordering: Orderin
144144
* @return the new iterator
145145
*/
146146
def iterator: Iterator[A] = RB.keysIterator(tree)
147+
override def keysIteratorFrom(start: A): Iterator[A] = RB.keysIterator(tree, Some(start))
147148

148149
override def foreach[U](f: A => U) = RB.foreachKey(tree, f)
149150

src/library/scala/collection/mutable/AVLTree.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ package mutable
1515
* An immutable AVL Tree implementation used by mutable.TreeSet
1616
*
1717
* @author Lucien Pereira
18-
*
18+
* @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")
1919
*/
2020
private[mutable] sealed trait AVLTree[+A] extends Serializable {
2121
def balance: Int
@@ -65,12 +65,18 @@ private[mutable] sealed trait AVLTree[+A] extends Serializable {
6565
def doubleRightRotation[B >: A]: Node[B] = sys.error("Should not happen.")
6666
}
6767

68+
/**
69+
* @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")
70+
*/
6871
private case object Leaf extends AVLTree[Nothing] {
6972
override val balance: Int = 0
7073

7174
override val depth: Int = -1
7275
}
7376

77+
/**
78+
* @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")
79+
*/
7480
private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree[A]) extends AVLTree[A] {
7581
override val balance: Int = right.depth - left.depth
7682

@@ -205,6 +211,9 @@ private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree
205211
}
206212
}
207213

214+
/**
215+
* @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")
216+
*/
208217
private class AVLIterator[A](root: Node[A]) extends Iterator[A] {
209218
val stack = mutable.ArrayStack[Node[A]](root)
210219
diveLeft()

0 commit comments

Comments
 (0)