Skip to content
This repository
Browse code

Add mutable tree sets to the standard library.

This implementation is based on AVL trees.
The current implementation is contributed by Lucien Pereira.

Fixes #4147.
  • Loading branch information...
commit 51ddeb372b3f0b22041d9a51f3faee17acd7b749 1 parent 178d49d
authored January 12, 2012
2  .gitignore
... ...
@@ -1 +1,3 @@
1 1
 *.jar
  2
+build
  3
+*.*~
33  src/library/scala/collection/generic/MutableSortedSetFactory.scala
... ...
@@ -0,0 +1,33 @@
  1
+/*                     __                                               *\
  2
+**     ________ ___   / /  ___     Scala API                            **
  3
+**    / __/ __// _ | / /  / _ |    (c) 2003-2011, LAMP/EPFL             **
  4
+**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
  5
+** /____/\___/_/ |_/____/_/ | |                                         **
  6
+**                          |/                                          **
  7
+\*                                                                      */
  8
+
  9
+package scala.collection
  10
+package generic
  11
+
  12
+import scala.collection.mutable.{ Builder, GrowingBuilder }
  13
+
  14
+/** 
  15
+ * @define Coll mutable.SortedSet
  16
+ * @define coll mutable sorted
  17
+ *
  18
+ * @author Lucien Pereira
  19
+ * 
  20
+ */
  21
+abstract class MutableSortedSetFactory[CC[A] <: mutable.SortedSet[A] with SortedSetLike[A, CC[A]] with mutable.Set[A] with mutable.SetLike[A, CC[A]]] extends SortedSetFactory[CC] {
  22
+
  23
+  /**
  24
+   * mutable.SetBuilder uses '+' which is not a primitive for anything extending mutable.SetLike,
  25
+   * this causes serious perfomances issues since each time 'elems = elems + x'
  26
+   * is evaluated elems is cloned (which is O(n)).
  27
+   *
  28
+   * Fortunately GrowingBuilder comes to rescue.
  29
+   * 
  30
+   */
  31
+  override def newBuilder[A](implicit ord: Ordering[A]): Builder[A, CC[A]] = new GrowingBuilder[A, CC[A]](empty)
  32
+
  33
+}
206  src/library/scala/collection/mutable/AVLTree.scala
... ...
@@ -0,0 +1,206 @@
  1
+/*                     __                                               *\
  2
+**     ________ ___   / /  ___     Scala API                            **
  3
+**    / __/ __// _ | / /  / _ |    (c) 2003-2011, LAMP/EPFL             **
  4
+**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
  5
+** /____/\___/_/ |_/____/_/ | |                                         **
  6
+**                          |/                                          **
  7
+\*                                                                      */
  8
+
  9
+package scala.collection
  10
+package mutable
  11
+
  12
+import annotation.tailrec
  13
+
  14
+/**
  15
+ * An immutable AVL Tree implementation used by mutable.TreeSet
  16
+ * 
  17
+ * @author Lucien Pereira
  18
+ * 
  19
+ */
  20
+private[mutable] sealed trait AVLTree[+A] extends Serializable {
  21
+  def balance: Int
  22
+
  23
+  def depth: Int
  24
+
  25
+}
  26
+
  27
+private case class Node[A](val data: A, val left: AVLTree[A], val right: AVLTree[A]) extends AVLTree[A] {
  28
+  override val balance: Int = right.depth - left.depth
  29
+
  30
+  override val depth: Int = math.max(left.depth, right.depth) + 1
  31
+
  32
+}
  33
+
  34
+private case object Leaf extends AVLTree[Nothing] {
  35
+  override val balance: Int = 0
  36
+
  37
+  override val depth: Int = -1
  38
+
  39
+}
  40
+
  41
+private[mutable] object AVLTree {
  42
+
  43
+  /**
  44
+   * Returns a new tree containing the given element.
  45
+   * Thows an IllegalArgumentException if element is already present.
  46
+   * 
  47
+   */
  48
+  def insert[A](value: A, tree: AVLTree[A], ordering: Ordering[A]): AVLTree[A] = {
  49
+    @tailrec
  50
+    def insertTC(value: A, tree: AVLTree[A], reassemble: AVLTree[A] => AVLTree[A]): AVLTree[A] = tree match {
  51
+      case Leaf => reassemble(Node(value, Leaf, Leaf))
  52
+
  53
+      case Node(a, left, right) => if (0 == ordering.compare(value, a)) {
  54
+        throw new IllegalArgumentException()
  55
+      } else if (-1 == ordering.compare(value, a)) {
  56
+        insertTC(value, left, x => reassemble(rebalance(Node(a, x, right))))
  57
+      } else {
  58
+        insertTC(value, right, x => reassemble(rebalance(Node(a, left, x))))
  59
+      }
  60
+    }
  61
+
  62
+    insertTC(value, tree, x => rebalance(x))
  63
+  }
  64
+
  65
+  def contains[A](value: A, tree: AVLTree[A], ordering: Ordering[A]): Boolean = tree match {
  66
+    case Leaf => false
  67
+
  68
+    case Node(a, left, right) => if (0 == ordering.compare(value, a)) {
  69
+      true
  70
+    } else if (-1 == ordering.compare(value, a)) {
  71
+      contains(value, left, ordering)
  72
+    } else {
  73
+      contains(value, right, ordering)
  74
+    }
  75
+  }
  76
+
  77
+  /**
  78
+   * Return a new tree which not contains given element.
  79
+   * 
  80
+   */
  81
+  def remove[A](value: A, tree: AVLTree[A], ordering: Ordering[A]): AVLTree[A] = tree match {
  82
+    case Leaf => throw new NoSuchElementException()
  83
+
  84
+    case Node(a, Leaf, Leaf) => if (0 == ordering.compare(value, a)) {
  85
+      Leaf
  86
+    } else {
  87
+      throw new NoSuchElementException()
  88
+    }
  89
+
  90
+    case Node(a, left, right@Node(_, _, _)) => if (0 == ordering.compare(value, a)) {
  91
+      val (min, newRight) = removeMin(right)
  92
+      rebalance(Node(min, left, newRight))
  93
+    } else if (-1 == ordering.compare(value, a)) {
  94
+      rebalance(Node(a, remove(value, left, ordering), right))
  95
+    } else {
  96
+      rebalance(Node(a, left, remove(value, right, ordering)))
  97
+    }
  98
+
  99
+    case Node(a, left@Node(_, _, _), right) => if (0 == ordering.compare(value, a)) {
  100
+      val (max, newLeft) = removeMax(left)
  101
+      rebalance(Node(max, newLeft, right))
  102
+    } else if (-1 == ordering.compare(value, a)) {
  103
+      rebalance(Node(a, remove(value, left, ordering), right))
  104
+    } else {
  105
+      rebalance(Node(a, left, remove(value, right, ordering)))
  106
+    }
  107
+  }
  108
+
  109
+  /**
  110
+   * Return a tuple containing the biggest element of the provided tree
  111
+   * and a new tree from which this element has been extracted.
  112
+   * 
  113
+   */
  114
+  def removeMax[A](tree: Node[A]): (A, AVLTree[A]) = {
  115
+    @tailrec
  116
+    def removeMaxTC(tree: AVLTree[A], assemble: (A, AVLTree[A]) => (A, AVLTree[A])): (A, AVLTree[A]) = tree match {
  117
+      case Node(a, Leaf, Leaf) => assemble(a, Leaf)
  118
+      case Node(a, left, Leaf) => assemble(a, left)
  119
+      case Node(a, left, right) => removeMaxTC(right,
  120
+        (max: A, avl: AVLTree[A]) => assemble(max, rebalance(Node(a, left, avl))))
  121
+      case Leaf => sys.error("Should not happen.")
  122
+    }
  123
+
  124
+    removeMaxTC(tree, (a, b) => (a, b))
  125
+  }
  126
+
  127
+  /**
  128
+   * Return a tuple containing the smallest element of the provided tree
  129
+   * and a new tree from which this element has been extracted.
  130
+   * 
  131
+   */
  132
+  def removeMin[A](tree: Node[A]): (A, AVLTree[A]) = {
  133
+    @tailrec
  134
+    def removeMinTC(tree: AVLTree[A], assemble: (A, AVLTree[A]) => (A, AVLTree[A])): (A, AVLTree[A]) = tree match {
  135
+      case Node(a, Leaf, Leaf) => assemble(a, Leaf)
  136
+      case Node(a, Leaf, right) => assemble(a, right)
  137
+      case Node(a, left, right) => removeMinTC(left,
  138
+        (min: A, avl: AVLTree[A]) => assemble(min, rebalance(Node(a, avl, right))))
  139
+      case Leaf => sys.error("Should not happen.")
  140
+    }
  141
+
  142
+    removeMinTC(tree, (a, b) => (a, b))
  143
+  }
  144
+
  145
+  /**
  146
+   * Returns a bounded stream of elements in the tree.
  147
+   * 
  148
+   */
  149
+  def toStream[A](tree: AVLTree[A], isLeftAcceptable: A => Boolean, isRightAcceptable: A => Boolean): Stream[A] = tree match {
  150
+    case Leaf => Stream.empty
  151
+
  152
+    case Node(a, left, right) => if (isLeftAcceptable(a)) {
  153
+      if (isRightAcceptable(a)) {
  154
+        toStream(left, isLeftAcceptable, isRightAcceptable) ++ Stream(a) ++ toStream(right, isLeftAcceptable, isRightAcceptable)
  155
+      } else {
  156
+        toStream(left, isLeftAcceptable, isRightAcceptable)
  157
+      }
  158
+    } else if (isRightAcceptable(a)) {
  159
+      toStream(right, isLeftAcceptable, isRightAcceptable)
  160
+    } else {
  161
+      Stream.empty
  162
+    }
  163
+  }
  164
+
  165
+  /**
  166
+   * Returns a bounded iterator of elements in the tree.
  167
+   * 
  168
+   */
  169
+  def iterator[A](tree: AVLTree[A], isLeftAcceptable: A => Boolean, isRightAcceptable: A => Boolean): Iterator[A] =
  170
+    toStream(tree, isLeftAcceptable, isRightAcceptable).iterator
  171
+
  172
+  def rebalance[A](tree: AVLTree[A]): AVLTree[A] = (tree, tree.balance) match {
  173
+    case (node@Node(_, left, _), -2) => left.balance match {
  174
+      case 1 => doubleRightRotation(node)
  175
+      case _ => rightRotation(node)
  176
+    }
  177
+
  178
+    case (node@Node(_, _, right), 2) => right.balance match {
  179
+      case -1 => doubleLeftRotation(node)
  180
+      case _ => leftRotation(node)
  181
+    }
  182
+
  183
+    case _ => tree
  184
+  }
  185
+
  186
+  def leftRotation[A](tree: Node[A]): AVLTree[A] = tree.right match {
  187
+    case Node(b, left, right) => Node(b, Node(tree.data, tree.left, left), right)
  188
+    case _ => sys.error("Should not happen.")
  189
+  }
  190
+
  191
+  def rightRotation[A](tree: Node[A]): AVLTree[A] = tree.left match {
  192
+    case Node(b, left, right) => Node(b, left, Node(tree.data, right, tree.right))
  193
+    case _ => sys.error("Should not happen.")
  194
+  }
  195
+
  196
+  def doubleLeftRotation[A](tree: Node[A]): AVLTree[A] = tree.right match {
  197
+    case right@Node(b, l, r) => leftRotation(Node(tree.data, tree.left, rightRotation(right)))
  198
+    case _ => sys.error("Should not happen.")
  199
+  }
  200
+
  201
+  def doubleRightRotation[A](tree: Node[A]): AVLTree[A] = tree.left match {
  202
+    case left@Node(b, l, r) => rightRotation(Node(tree.data, leftRotation(left), tree.right))
  203
+    case _ => sys.error("Should not happen.")
  204
+  }
  205
+
  206
+}
49  src/library/scala/collection/mutable/SortedSet.scala
... ...
@@ -0,0 +1,49 @@
  1
+/*                     __                                               *\
  2
+**     ________ ___   / /  ___     Scala API                            **
  3
+**    / __/ __// _ | / /  / _ |    (c) 2003-2011, LAMP/EPFL             **
  4
+**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
  5
+** /____/\___/_/ |_/____/_/ | |                                         **
  6
+**                          |/                                          **
  7
+\*                                                                      */
  8
+
  9
+package scala.collection
  10
+package mutable
  11
+
  12
+import generic._
  13
+
  14
+/**
  15
+ * Base trait for mutable sorted set.
  16
+ * 
  17
+ * @define Coll mutable.SortedSet
  18
+ * @define coll mutable sorted set
  19
+ *
  20
+ * @author Lucien Pereira
  21
+ * 
  22
+ */
  23
+trait SortedSet[A] extends collection.SortedSet[A] with collection.SortedSetLike[A,SortedSet[A]]
  24
+  with mutable.Set[A] with mutable.SetLike[A, SortedSet[A]] {
  25
+
  26
+  /** Needs to be overridden in subclasses. */
  27
+  override def empty: SortedSet[A] = SortedSet.empty[A]
  28
+
  29
+}
  30
+
  31
+/**
  32
+ * A template for mutable sorted set companion objects.
  33
+ *
  34
+ * @define Coll mutable.SortedSet
  35
+ * @define coll mutable sorted set
  36
+ * @define factoryInfo
  37
+ *   This object provides a set of operations needed to create sorted sets of type mutable.SortedSet.
  38
+ * @define sortedSetCanBuildFromInfo
  39
+ *   Standard `CanBuildFrom` instance for sorted sets.
  40
+ *
  41
+ * @author Lucien Pereira
  42
+ * 
  43
+ */
  44
+object SortedSet extends MutableSortedSetFactory[SortedSet] {
  45
+  implicit def canBuildFrom[A](implicit ord: Ordering[A]): CanBuildFrom[Coll, A, SortedSet[A]] = new SortedSetCanBuildFrom[A]
  46
+  
  47
+  def empty[A](implicit ord: Ordering[A]): SortedSet[A] = TreeSet.empty[A]
  48
+  
  49
+}
130  src/library/scala/collection/mutable/TreeSet.scala
... ...
@@ -0,0 +1,130 @@
  1
+/*                     __                                               *\
  2
+**     ________ ___   / /  ___     Scala API                            **
  3
+**    / __/ __// _ | / /  / _ |    (c) 2003-2011, LAMP/EPFL             **
  4
+**  __\ \/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **
  5
+** /____/\___/_/ |_/____/_/ | |                                         **
  6
+**                          |/                                          **
  7
+\*                                                                      */
  8
+
  9
+package scala.collection
  10
+package mutable
  11
+
  12
+
  13
+
  14
+import generic._
  15
+
  16
+
  17
+
  18
+/** 
  19
+ * @define Coll mutable.TreeSet
  20
+ * @define coll mutable tree set
  21
+ * @factoryInfo
  22
+ *   Companion object of TreeSet providing factory related utilities.
  23
+ * 
  24
+ * @author Lucien Pereira
  25
+ * 
  26
+ */
  27
+object TreeSet extends MutableSortedSetFactory[TreeSet] {
  28
+  /**
  29
+   *  The empty set of this type
  30
+   */
  31
+  def empty[A](implicit ordering: Ordering[A]) = new TreeSet[A]()
  32
+
  33
+}
  34
+
  35
+/**
  36
+ * A mutable SortedSet using an immutable AVL Tree as underlying data structure.
  37
+ *
  38
+ * @author Lucien Pereira
  39
+ * 
  40
+ */
  41
+class TreeSet[A](implicit val ordering: Ordering[A]) extends SortedSet[A] with SetLike[A, TreeSet[A]]
  42
+  with SortedSetLike[A, TreeSet[A]] with Set[A] with Serializable {
  43
+
  44
+  // Projection constructor
  45
+  private def this(base: Option[TreeSet[A]], from: Option[A], until: Option[A])(implicit ordering: Ordering[A]) {
  46
+    this();
  47
+    this.base = base
  48
+    this.from = from
  49
+    this.until = until
  50
+  }
  51
+
  52
+  private var base: Option[TreeSet[A]] = None
  53
+
  54
+  private var from: Option[A] = None
  55
+
  56
+  private var until: Option[A] = None
  57
+
  58
+  private var avl: AVLTree[A] = Leaf
  59
+
  60
+  private var cardinality: Int = 0
  61
+
  62
+  def resolve: TreeSet[A] = base.getOrElse(this)
  63
+
  64
+  private def isLeftAcceptable(from: Option[A], ordering: Ordering[A])(a: A): Boolean =
  65
+    from.map(x => ordering.gteq(a, x)).getOrElse(true)
  66
+
  67
+  private def isRightAcceptable(until: Option[A], ordering: Ordering[A])(a: A): Boolean =
  68
+    until.map(x => ordering.lt(a, x)).getOrElse(true)
  69
+
  70
+  /**
  71
+   * Cardinality store the set size, unfortunately a
  72
+   * set view (given by rangeImpl)
  73
+   * cannot take advantage of this optimisation
  74
+   * 
  75
+   */
  76
+  override def size: Int = base.map(_ => super.size).getOrElse(cardinality)
  77
+
  78
+  override def stringPrefix = "TreeSet"
  79
+
  80
+  override def empty: TreeSet[A] = TreeSet.empty
  81
+
  82
+  override def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] = new TreeSet(Some(this), from, until)
  83
+
  84
+  override def -=(elem: A): this.type = {
  85
+    try {
  86
+      resolve.avl = AVLTree.remove(elem, resolve.avl, ordering)
  87
+      resolve.cardinality = resolve.cardinality - 1
  88
+    } catch {
  89
+      case e: NoSuchElementException => ()
  90
+      case a: Any => a.printStackTrace
  91
+    }
  92
+    this
  93
+  }
  94
+
  95
+  override def +=(elem: A): this.type = {
  96
+    try {
  97
+      resolve.avl = AVLTree.insert(elem, resolve.avl, ordering)
  98
+      resolve.cardinality = resolve.cardinality + 1
  99
+    } catch {
  100
+      case e: IllegalArgumentException => ()
  101
+      case a: Any => a.printStackTrace
  102
+    }
  103
+    this
  104
+  }
  105
+
  106
+  /**
  107
+   * Thanks to the nature immutable of the
  108
+   * underlying AVL Tree, we can share it with
  109
+   * the clone. So clone complexity in time is O(1).
  110
+   * 
  111
+   */
  112
+  override def clone: TreeSet[A] = {
  113
+    val clone = new TreeSet[A](base, from, until)
  114
+    clone.avl = resolve.avl
  115
+    clone.cardinality = resolve.cardinality
  116
+    clone
  117
+  }
  118
+
  119
+  override def contains(elem: A): Boolean = {
  120
+    isLeftAcceptable(from, ordering)(elem) &&
  121
+    isRightAcceptable(until, ordering)(elem) &&
  122
+    AVLTree.contains(elem, resolve.avl, ordering)
  123
+  }
  124
+
  125
+  override def iterator: Iterator[A] =
  126
+    AVLTree.iterator(resolve.avl,
  127
+		     isLeftAcceptable(from, ordering),
  128
+		     isRightAcceptable(until, ordering))
  129
+
  130
+}
67  test/benchmarking/AVL-insert-random.scala
... ...
@@ -0,0 +1,67 @@
  1
+package scala.collection
  2
+
  3
+
  4
+
  5
+
  6
+
  7
+class Dummy(val a: Int) extends math.Ordered[Dummy] {
  8
+  def compare(other: Dummy) = this.a - other.a
  9
+  override def toString = a.toString
  10
+}
  11
+
  12
+
  13
+object RandomGlobal {
  14
+  val sz = 500000
  15
+  val data = util.Random.shuffle((0 until sz) map { new Dummy(_) }) toArray;
  16
+}
  17
+
  18
+
  19
+import RandomGlobal._
  20
+
  21
+
  22
+object RandomAVL extends testing.Benchmark {
  23
+  
  24
+  def run() {
  25
+    val avl = new collection.mutable.TreeSet[Dummy]
  26
+    
  27
+    var i = 0
  28
+    while (i < sz) {
  29
+      val elem = data(i)
  30
+      avl += elem
  31
+      i += 1
  32
+    }
  33
+  }
  34
+  
  35
+}
  36
+
  37
+
  38
+object RandomImmutableTreeSet extends testing.Benchmark {
  39
+  
  40
+  def run() {
  41
+    var tree = new collection.immutable.TreeSet[Dummy]
  42
+    
  43
+    var i = 0
  44
+    while (i < sz) {
  45
+      val elem = data(i)
  46
+      tree += elem
  47
+      i += 1
  48
+    }
  49
+  }
  50
+  
  51
+}
  52
+
  53
+
  54
+object RandomJavaTreeSet extends testing.Benchmark {
  55
+  
  56
+  def run() {
  57
+    val tree = new java.util.TreeSet[Dummy]
  58
+    
  59
+    var i = 0
  60
+    while (i < sz) {
  61
+      val elem = data(i)
  62
+      tree add elem
  63
+      i += 1
  64
+    }
  65
+  }
  66
+  
  67
+}
67  test/benchmarking/AVL-insert.scala
... ...
@@ -0,0 +1,67 @@
  1
+package scala.collection
  2
+
  3
+
  4
+
  5
+
  6
+
  7
+class Dummy(val a: Int) extends math.Ordered[Dummy] {
  8
+  def compare(other: Dummy) = this.a - other.a
  9
+  override def toString = a.toString
  10
+}
  11
+
  12
+
  13
+object Global {
  14
+  val sz = 500000
  15
+  val data = (0 until sz) map { new Dummy(_) } toArray
  16
+}
  17
+
  18
+
  19
+import Global._
  20
+
  21
+
  22
+object AVL extends testing.Benchmark {
  23
+  
  24
+  def run() {
  25
+    val avl = new collection.mutable.TreeSet[Dummy]
  26
+    
  27
+    var i = 0
  28
+    while (i < sz) {
  29
+      val elem = data(i)
  30
+      avl += elem
  31
+      i += 1
  32
+    }
  33
+  }
  34
+  
  35
+}
  36
+
  37
+
  38
+object ImmutableTreeSet extends testing.Benchmark {
  39
+  
  40
+  def run() {
  41
+    var tree = new collection.immutable.TreeSet[Dummy]
  42
+    
  43
+    var i = 0
  44
+    while (i < sz) {
  45
+      val elem = data(i)
  46
+      tree += elem
  47
+      i += 1
  48
+    }
  49
+  }
  50
+  
  51
+}
  52
+
  53
+
  54
+object JavaTreeSet extends testing.Benchmark {
  55
+  
  56
+  def run() {
  57
+    val tree = new java.util.TreeSet[Dummy]
  58
+    
  59
+    var i = 0
  60
+    while (i < sz) {
  61
+      val elem = data(i)
  62
+      tree add elem
  63
+      i += 1
  64
+    }
  65
+  }
  66
+  
  67
+}
4  test/files/jvm/serialization.check
@@ -188,6 +188,10 @@ x = WrappedArray(1, 2, 3)
188 188
 y = WrappedArray(1, 2, 3)
189 189
 x equals y: true, y equals x: true
190 190
 
  191
+x = TreeSet(1, 2, 3)
  192
+y = TreeSet(1, 2, 3)
  193
+x equals y: true, y equals x: true
  194
+
191 195
 x =  xml:src="hello"
192 196
 y =  xml:src="hello"
193 197
 x equals y: true, y equals x: true
7  test/files/jvm/serialization.scala
@@ -286,7 +286,7 @@ object Test3_mutable {
286 286
   import scala.collection.mutable.{
287 287
     ArrayBuffer, ArrayBuilder, ArraySeq, ArrayStack, BitSet, DoubleLinkedList,
288 288
     HashMap, HashSet, History, LinkedList, ListBuffer, Publisher, Queue,
289  
-    Stack, StringBuilder, WrappedArray}
  289
+    Stack, StringBuilder, WrappedArray, TreeSet}
290 290
 
291 291
   // in alphabetic order
292 292
   try {
@@ -380,6 +380,11 @@ object Test3_mutable {
380 380
     val wa1 = WrappedArray.make(Array(1, 2, 3))
381 381
     val _wa1: WrappedArray[Int] = read(write(wa1))
382 382
     check(wa1, _wa1)
  383
+    
  384
+    // TreeSet
  385
+    val ts1 = TreeSet[Int]() ++= Array(1, 2, 3)
  386
+    val _ts1: TreeSet[Int] = read(write(ts1))
  387
+    check(ts1, _ts1)
383 388
   }
384 389
   catch {
385 390
     case e: Exception =>
36  test/files/run/si4147.scala
... ...
@@ -0,0 +1,36 @@
  1
+
  2
+
  3
+
  4
+import scala.collection._
  5
+
  6
+
  7
+
  8
+object Test {
  9
+
  10
+  def main(args: Array[String]) {
  11
+    checkElementsAreSorted()
  12
+    checkRangedImpl()
  13
+  }
  14
+
  15
+  def checkElementsAreSorted() {
  16
+    val tree = mutable.SortedSet[Int]()
  17
+    tree ++= List(4, 3, 1, 6, 7, 5, 2)
  18
+    assert(tree == immutable.SortedSet(1, 2, 3, 4, 5, 6, 7))
  19
+    assert(tree.size == 7)
  20
+  }
  21
+
  22
+  def checkRangedImpl() {
  23
+    val tree = mutable.SortedSet[Int](3, 1, 6, 7, 5, 2)
  24
+    val projection = tree.rangeImpl(Some(3), Some(6))
  25
+    assert(projection == immutable.SortedSet(3, 5))
  26
+    assert(projection.size == 2)
  27
+
  28
+    // Let's check that modification are taken into account
  29
+    tree add 4
  30
+    assert(tree == immutable.SortedSet(1, 2, 3, 4, 5, 6, 7))
  31
+    assert(projection == immutable.SortedSet(3, 4, 5))
  32
+    assert(tree.size == 7)
  33
+    assert(projection.size == 3)
  34
+  }
  35
+
  36
+}
67  test/files/scalacheck/si4147.scala
... ...
@@ -0,0 +1,67 @@
  1
+import org.scalacheck.Prop.forAll
  2
+import org.scalacheck.Properties
  3
+import org.scalacheck.ConsoleReporter.testStatsEx
  4
+import org.scalacheck.Gen
  5
+import org.scalacheck.ConsoleReporter
  6
+
  7
+
  8
+import collection.mutable
  9
+
  10
+
  11
+object Test extends Properties("Mutable TreeSet") {
  12
+
  13
+  val generator = Gen.listOfN(1000, Gen.chooseNum(0, 1000))
  14
+
  15
+  val denseGenerator = Gen.listOfN(1000, Gen.chooseNum(0, 200))
  16
+
  17
+  property("Insertion doesn't allow duplicates values.") = forAll(generator) { (s: List[Int]) =>
  18
+    {
  19
+      val t = mutable.TreeSet[Int](s: _*)
  20
+      t == s.toSet
  21
+    }
  22
+  }
  23
+
  24
+  property("Verification of size method validity") = forAll(generator) { (s: List[Int]) =>
  25
+    {
  26
+      val t = mutable.TreeSet[Int](s: _*)
  27
+      for (a <- s) {
  28
+        t -= a
  29
+      }
  30
+      t.size == 0
  31
+    }
  32
+  }
  33
+
  34
+  property("All inserted elements are removed") = forAll(generator) { (s: List[Int]) =>
  35
+    {
  36
+      val t = mutable.TreeSet[Int](s: _*)
  37
+      for (a <- s) {
  38
+        t -= a
  39
+      }
  40
+      t == Set()
  41
+    }
  42
+  }
  43
+
  44
+  property("Elements are sorted.") = forAll(generator) { (s: List[Int]) =>
  45
+    {
  46
+      val t = mutable.TreeSet[Int](s: _*)
  47
+      t.toList == s.distinct.sorted
  48
+    }
  49
+  }
  50
+
  51
+  property("Implicit CanBuildFrom resolution succeeds as well as the \"same-result-type\" principle.") =
  52
+    forAll(generator) { (s: List[Int]) =>
  53
+      {
  54
+        val t = mutable.TreeSet[Int](s: _*)
  55
+        val t2 = t.map(_ * 2)
  56
+        t2.isInstanceOf[collection.mutable.TreeSet[Int]]
  57
+      }
  58
+    }
  59
+
  60
+  property("A view doesn't expose off bounds elements") = forAll(denseGenerator) { (s: List[Int]) =>
  61
+    {
  62
+      val t = mutable.TreeSet[Int](s: _*)
  63
+      val view = t.rangeImpl(Some(50), Some(150))
  64
+      view.filter(_ < 50) == Set[Int]() && view.filter(_ >= 150) == Set[Int]()
  65
+    }
  66
+  }
  67
+}

0 notes on commit 51ddeb3

Jason Zaugg

printStackTrace makes the baby Jesus cry. Same elsewhere below.

Paul Phillips

Baby tears are the fuel that powers me through the day.

Christos KK Loverdos

"nature immutable" --> "immutable nature"

Please sign in to comment.
Something went wrong with that request. Please try again.