Skip to content

Commit eea6bca

Browse files
committed
Add immutable TreeSet and TreeMap to stdlib
1 parent c66c833 commit eea6bca

File tree

5 files changed

+841
-1
lines changed

5 files changed

+841
-1
lines changed

tests/pos-special/stdlib/collection/BuildFrom.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ trait BuildFrom[-From, -A, +C] extends Any { self =>
3131
def fromSpecific(from: From)(it: IterableOnce[A]^): C
3232
// !!! this is wrong, we need two versions of fromSpecific; one mapping
3333
// to C^{it} when C is an Iterable, and one mapping to C when C is a Seq, Map, or Set.
34-
// But that requires a lareg scale refactoring of BuildFrom. The unsafeAssumePure
34+
// But that requires a large scale refactoring of BuildFrom. The unsafeAssumePure
3535
// calls in this file are needed to sweep that problem under the carpet.
3636

3737
/** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
/*
2+
* Scala (https://www.scala-lang.org)
3+
*
4+
* Copyright EPFL and Lightbend, Inc.
5+
*
6+
* Licensed under Apache License 2.0
7+
* (http://www.apache.org/licenses/LICENSE-2.0).
8+
*
9+
* See the NOTICE file distributed with this work for
10+
* additional information regarding copyright ownership.
11+
*/
12+
13+
package scala
14+
package collection
15+
package immutable
16+
17+
import scala.annotation.tailrec
18+
import scala.collection.Stepper.EfficientSplit
19+
import scala.collection.generic.DefaultSerializable
20+
import scala.collection.immutable.{RedBlackTree => RB}
21+
import scala.collection.mutable.ReusableBuilder
22+
import scala.runtime.AbstractFunction2
23+
import language.experimental.captureChecking
24+
import scala.annotation.unchecked.uncheckedCaptures
25+
26+
/** An immutable SortedMap whose values are stored in a red-black tree.
27+
*
28+
* This class is optimal when range queries will be performed,
29+
* or when traversal in order of an ordering is desired.
30+
* If you only need key lookups, and don't care in which order key-values
31+
* are traversed in, consider using * [[scala.collection.immutable.HashMap]],
32+
* which will generally have better performance. If you need insertion order,
33+
* consider a * [[scala.collection.immutable.SeqMap]], which does not need to
34+
* have an ordering supplied.
35+
*
36+
* @example {{{
37+
* import scala.collection.immutable.TreeMap
38+
*
39+
* // Make a TreeMap via the companion object factory
40+
* val weekdays = TreeMap(
41+
* 2 -> "Monday",
42+
* 3 -> "Tuesday",
43+
* 4 -> "Wednesday",
44+
* 5 -> "Thursday",
45+
* 6 -> "Friday"
46+
* )
47+
* // TreeMap(2 -> Monday, 3 -> Tuesday, 4 -> Wednesday, 5 -> Thursday, 6 -> Friday)
48+
*
49+
* val days = weekdays ++ List(1 -> "Sunday", 7 -> "Saturday")
50+
* // TreeMap(1 -> Sunday, 2 -> Monday, 3 -> Tuesday, 4 -> Wednesday, 5 -> Thursday, 6 -> Friday, 7 -> Saturday)
51+
*
52+
* val day3 = days.get(3) // Some("Tuesday")
53+
*
54+
* val rangeOfDays = days.range(2, 5) // TreeMap(2 -> Monday, 3 -> Tuesday, 4 -> Wednesday)
55+
*
56+
* val daysUntil2 = days.rangeUntil(2) // TreeMap(1 -> Sunday)
57+
* val daysTo2 = days.rangeTo(2) // TreeMap(1 -> Sunday, 2 -> Monday)
58+
* val daysAfter5 = days.rangeFrom(5) // TreeMap(5 -> Thursday, 6 -> Friday, 7 -> Saturday)
59+
* }}}
60+
*
61+
* @tparam K the type of the keys contained in this tree map.
62+
* @tparam V the type of the values associated with the keys.
63+
* @param ordering the implicit ordering used to compare objects of type `A`.
64+
*
65+
* @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#red-black-trees "Scala's Collection Library overview"]]
66+
* section on `Red-Black Trees` for more information.
67+
*
68+
* @define Coll immutable.TreeMap
69+
* @define coll immutable tree map
70+
* @define orderDependent
71+
* @define orderDependentFold
72+
* @define mayNotTerminateInf
73+
* @define willNotTerminateInf
74+
*/
75+
final class TreeMap[K, +V] private (private val tree: RB.Tree[K, V])(implicit val ordering: Ordering[K])
76+
extends AbstractMap[K, V]
77+
with SortedMap[K, V]
78+
with StrictOptimizedSortedMapOps[K, V, TreeMap, TreeMap[K, V]]
79+
with SortedMapFactoryDefaults[K, V, TreeMap, Iterable, Map]
80+
with DefaultSerializable {
81+
82+
def this()(implicit ordering: Ordering[K]) = this(null)(ordering)
83+
private[immutable] def tree0: RB.Tree[K, V] = tree
84+
85+
private[this] def newMapOrSelf[V1 >: V](t: RB.Tree[K, V1]): TreeMap[K, V1] = if(t eq tree) this else new TreeMap[K, V1](t)
86+
87+
override def sortedMapFactory: SortedMapFactory[TreeMap] = TreeMap
88+
89+
def iterator: Iterator[(K, V)] = RB.iterator(tree)
90+
91+
def keysIteratorFrom(start: K): Iterator[K] = RB.keysIterator(tree, Some(start))
92+
93+
override def keySet: TreeSet[K] = new TreeSet(tree)(ordering)
94+
95+
def iteratorFrom(start: K): Iterator[(K, V)] = RB.iterator(tree, Some(start))
96+
97+
override def valuesIteratorFrom(start: K): Iterator[V] = RB.valuesIterator(tree, Some(start))
98+
99+
override def stepper[S <: Stepper[_]](implicit shape: StepperShape[(K, V), S]): S with EfficientSplit =
100+
shape.parUnbox(
101+
scala.collection.convert.impl.AnyBinaryTreeStepper.from[(K, V), RB.Tree[K, V]](
102+
size, tree, _.left, _.right, x => (x.key, x.value)
103+
)
104+
)
105+
106+
override def keyStepper[S <: Stepper[_]](implicit shape: StepperShape[K, S]): S with EfficientSplit = {
107+
import scala.collection.convert.impl._
108+
type T = RB.Tree[K, V]
109+
val s = shape.shape match {
110+
case StepperShape.IntShape => IntBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.key.asInstanceOf[Int])
111+
case StepperShape.LongShape => LongBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.key.asInstanceOf[Long])
112+
case StepperShape.DoubleShape => DoubleBinaryTreeStepper.from[T](size, tree, _.left, _.right, _.key.asInstanceOf[Double])
113+
case _ => shape.parUnbox(AnyBinaryTreeStepper.from[K, T](size, tree, _.left, _.right, _.key))
114+
}
115+
s.asInstanceOf[S with EfficientSplit]
116+
}
117+
118+
override def valueStepper[S <: Stepper[_]](implicit shape: StepperShape[V, S]): S with EfficientSplit = {
119+
import scala.collection.convert.impl._
120+
type T = RB.Tree[K, V]
121+
val s = shape.shape match {
122+
case StepperShape.IntShape => IntBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.value.asInstanceOf[Int])
123+
case StepperShape.LongShape => LongBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.value.asInstanceOf[Long])
124+
case StepperShape.DoubleShape => DoubleBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.value.asInstanceOf[Double])
125+
case _ => shape.parUnbox(AnyBinaryTreeStepper.from[V, T] (size, tree, _.left, _.right, _.value.asInstanceOf[V]))
126+
}
127+
s.asInstanceOf[S with EfficientSplit]
128+
}
129+
130+
def get(key: K): Option[V] = RB.get(tree, key)
131+
override def getOrElse[V1 >: V](key: K, default: => V1): V1 = {
132+
val resultOrNull = RB.lookup(tree, key)
133+
if (resultOrNull eq null) default
134+
else resultOrNull.value
135+
}
136+
137+
def removed(key: K): TreeMap[K,V] =
138+
newMapOrSelf(RB.delete(tree, key))
139+
140+
def updated[V1 >: V](key: K, value: V1): TreeMap[K, V1] =
141+
newMapOrSelf(RB.update(tree, key, value, overwrite = true))
142+
143+
override def concat[V1 >: V](that: collection.IterableOnce[(K, V1)]^): TreeMap[K, V1] =
144+
newMapOrSelf(that match {
145+
case tm: TreeMap[K, V] @unchecked if ordering == tm.ordering =>
146+
RB.union(tree, tm.tree)
147+
case ls: LinearSeq[(K,V1)] =>
148+
if (ls.isEmpty) tree //to avoid the creation of the adder
149+
else {
150+
val adder = new Adder[V1]
151+
adder.addAll(ls)
152+
adder.finalTree
153+
}
154+
case _ =>
155+
val adder = new Adder[V1]
156+
val it = that.iterator
157+
while (it.hasNext) {
158+
adder.apply(it.next())
159+
}
160+
adder.finalTree
161+
})
162+
163+
override def removedAll(keys: IterableOnce[K]^): TreeMap[K, V] = keys match {
164+
case ts: TreeSet[K] if ordering == ts.ordering =>
165+
newMapOrSelf(RB.difference(tree, ts.tree))
166+
case _ => super.removedAll(keys)
167+
}
168+
169+
/** A new TreeMap with the entry added is returned,
170+
* assuming that key is <em>not</em> in the TreeMap.
171+
*
172+
* @tparam V1 type of the values of the new bindings, a supertype of `V`
173+
* @param key the key to be inserted
174+
* @param value the value to be associated with `key`
175+
* @return a new $coll with the inserted binding, if it wasn't present in the map
176+
*/
177+
@deprecated("Use `updated` instead", "2.13.0")
178+
def insert[V1 >: V](key: K, value: V1): TreeMap[K, V1] = {
179+
assert(!RB.contains(tree, key))
180+
updated(key, value)
181+
}
182+
183+
def rangeImpl(from: Option[K], until: Option[K]): TreeMap[K, V] = newMapOrSelf(RB.rangeImpl(tree, from, until))
184+
185+
override def minAfter(key: K): Option[(K, V)] = RB.minAfter(tree, key) match {
186+
case null => Option.empty
187+
case x => Some((x.key, x.value))
188+
}
189+
190+
override def maxBefore(key: K): Option[(K, V)] = RB.maxBefore(tree, key) match {
191+
case null => Option.empty
192+
case x => Some((x.key, x.value))
193+
}
194+
195+
override def range(from: K, until: K): TreeMap[K,V] = newMapOrSelf(RB.range(tree, from, until))
196+
197+
override def foreach[U](f: ((K, V)) => U): Unit = RB.foreach(tree, f)
198+
override def foreachEntry[U](f: (K, V) => U): Unit = RB.foreachEntry(tree, f)
199+
override def size: Int = RB.count(tree)
200+
override def knownSize: Int = size
201+
202+
override def isEmpty = size == 0
203+
204+
override def firstKey: K = RB.smallest(tree).key
205+
206+
override def lastKey: K = RB.greatest(tree).key
207+
208+
override def head: (K, V) = {
209+
val smallest = RB.smallest(tree)
210+
(smallest.key, smallest.value)
211+
}
212+
213+
override def last: (K, V) = {
214+
val greatest = RB.greatest(tree)
215+
(greatest.key, greatest.value)
216+
}
217+
218+
override def tail: TreeMap[K, V] = new TreeMap(RB.tail(tree))
219+
220+
override def init: TreeMap[K, V] = new TreeMap(RB.init(tree))
221+
222+
override def drop(n: Int): TreeMap[K, V] = {
223+
if (n <= 0) this
224+
else if (n >= size) empty
225+
else new TreeMap(RB.drop(tree, n))
226+
}
227+
228+
override def take(n: Int): TreeMap[K, V] = {
229+
if (n <= 0) empty
230+
else if (n >= size) this
231+
else new TreeMap(RB.take(tree, n))
232+
}
233+
234+
override def slice(from: Int, until: Int) = {
235+
if (until <= from) empty
236+
else if (from <= 0) take(until)
237+
else if (until >= size) drop(from)
238+
else new TreeMap(RB.slice(tree, from, until))
239+
}
240+
241+
override def dropRight(n: Int): TreeMap[K, V] = take(size - math.max(n, 0))
242+
243+
override def takeRight(n: Int): TreeMap[K, V] = drop(size - math.max(n, 0))
244+
245+
private[this] def countWhile(p: ((K, V)) => Boolean): Int = {
246+
var result = 0
247+
val it = iterator
248+
while (it.hasNext && p(it.next())) result += 1
249+
result
250+
}
251+
252+
override def dropWhile(p: ((K, V)) => Boolean): TreeMap[K, V] = drop(countWhile(p))
253+
254+
override def takeWhile(p: ((K, V)) => Boolean): TreeMap[K, V] = take(countWhile(p))
255+
256+
override def span(p: ((K, V)) => Boolean): (TreeMap[K, V], TreeMap[K, V]) = splitAt(countWhile(p))
257+
258+
override def filter(f: ((K, V)) => Boolean): TreeMap[K, V] =
259+
newMapOrSelf(RB.filterEntries[K, V](tree, (k, v) => f((k, v))))
260+
261+
override def partition(p: ((K, V)) => Boolean): (TreeMap[K, V], TreeMap[K, V]) = {
262+
val (l, r) = RB.partitionEntries[K, V](tree, (k, v) => p((k, v)))
263+
(newMapOrSelf(l), newMapOrSelf(r))
264+
}
265+
266+
override def transform[W](f: (K, V) => W): TreeMap[K, W] = {
267+
val t2 = RB.transform[K, V, W](tree, f)
268+
if(t2 eq tree) this.asInstanceOf[TreeMap[K, W]]
269+
else new TreeMap(t2)
270+
}
271+
272+
private final class Adder[B1 >: V]
273+
extends RB.MapHelper[K, B1] with Function1[(K, B1), Unit] {
274+
private var currentMutableTree: RB.Tree[K,B1] @uncheckedCaptures = tree0
275+
def finalTree = beforePublish(currentMutableTree)
276+
override def apply(kv: (K, B1)): Unit = {
277+
currentMutableTree = mutableUpd(currentMutableTree, kv._1, kv._2)
278+
}
279+
@tailrec def addAll(ls: LinearSeq[(K, B1)]): Unit = {
280+
if (!ls.isEmpty) {
281+
val kv = ls.head
282+
currentMutableTree = mutableUpd(currentMutableTree, kv._1, kv._2)
283+
addAll(ls.tail)
284+
}
285+
}
286+
}
287+
override def equals(obj: Any): Boolean = obj match {
288+
case that: TreeMap[K @unchecked, _] if ordering == that.ordering => RB.entriesEqual(tree, that.tree)
289+
case _ => super.equals(obj)
290+
}
291+
292+
override protected[this] def className = "TreeMap"
293+
}
294+
295+
/** $factoryInfo
296+
* @define Coll immutable.TreeMap
297+
* @define coll immutable tree map
298+
*/
299+
@SerialVersionUID(3L)
300+
object TreeMap extends SortedMapFactory[TreeMap] {
301+
302+
def empty[K : Ordering, V]: TreeMap[K, V] = new TreeMap()
303+
304+
def from[K, V](it: IterableOnce[(K, V)]^)(implicit ordering: Ordering[K]): TreeMap[K, V] =
305+
it match {
306+
case tm: TreeMap[K, V] if ordering == tm.ordering => tm
307+
case sm: scala.collection.SortedMap[K, V] if ordering == sm.ordering =>
308+
new TreeMap[K, V](RB.fromOrderedEntries(sm.iterator, sm.size))
309+
case _ =>
310+
var t: RB.Tree[K, V] = null
311+
val i = it.iterator
312+
while (i.hasNext) {
313+
val (k, v) = i.next()
314+
t = RB.update(t, k, v, overwrite = true)
315+
}
316+
new TreeMap[K, V](t)
317+
}
318+
319+
def newBuilder[K, V](implicit ordering: Ordering[K]): ReusableBuilder[(K, V), TreeMap[K, V]] = new TreeMapBuilder[K, V]
320+
321+
private class TreeMapBuilder[K, V](implicit ordering: Ordering[K])
322+
extends RB.MapHelper[K, V]
323+
with ReusableBuilder[(K, V), TreeMap[K, V]] {
324+
type Tree = RB.Tree[K, V]
325+
private var tree:Tree @uncheckedCaptures = null
326+
327+
def addOne(elem: (K, V)): this.type = {
328+
tree = mutableUpd(tree, elem._1, elem._2)
329+
this
330+
}
331+
private object adder extends AbstractFunction2[K, V, Unit] {
332+
// we cache tree to avoid the outer access to tree
333+
// in the hot path (apply)
334+
private[this] var accumulator: Tree @uncheckedCaptures = null
335+
def addForEach(hasForEach: collection.Map[K, V]): Unit = {
336+
accumulator = tree
337+
hasForEach.foreachEntry(this)
338+
tree = accumulator
339+
// be friendly to GC
340+
accumulator = null
341+
}
342+
343+
override def apply(key: K, value: V): Unit = {
344+
accumulator = mutableUpd(accumulator, key, value)
345+
}
346+
}
347+
348+
override def addAll(xs: IterableOnce[(K, V)]^): this.type = {
349+
xs match {
350+
// TODO consider writing a mutable-safe union for TreeSet/TreeMap builder ++=
351+
// for the moment we have to force immutability before the union
352+
// which will waste some time and space
353+
// calling `beforePublish` makes `tree` immutable
354+
case ts: TreeMap[K, V] if ts.ordering == ordering =>
355+
if (tree eq null) tree = ts.tree0
356+
else tree = RB.union(beforePublish(tree), ts.tree0)
357+
case that: collection.Map[K, V] =>
358+
//add avoiding creation of tuples
359+
adder.addForEach(that)
360+
case _ =>
361+
super.addAll(xs)
362+
}
363+
this
364+
}
365+
366+
override def clear(): Unit = {
367+
tree = null
368+
}
369+
370+
override def result(): TreeMap[K, V] = new TreeMap[K, V](beforePublish(tree))
371+
}
372+
}

0 commit comments

Comments
 (0)