Skip to content

Commit fed73bd

Browse files
committed
Add SortedSet classes to stdlib
1 parent d1b9eab commit fed73bd

File tree

3 files changed

+294
-0
lines changed

3 files changed

+294
-0
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
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.collection
14+
15+
import scala.annotation.{implicitNotFound, nowarn}
16+
import scala.annotation.unchecked.uncheckedVariance
17+
18+
/** Base type of sorted sets */
19+
trait SortedSet[A] extends Set[A]
20+
with SortedSetOps[A, SortedSet, SortedSet[A]]
21+
with SortedSetFactoryDefaults[A, SortedSet, Set] {
22+
23+
def unsorted: Set[A] = this
24+
25+
def sortedIterableFactory: SortedIterableFactory[SortedSet] = SortedSet
26+
27+
@nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
28+
override protected[this] def stringPrefix: String = "SortedSet"
29+
30+
override def equals(that: Any): Boolean = that match {
31+
case _ if this eq that.asInstanceOf[AnyRef] => true
32+
case ss: SortedSet[A @unchecked] if ss.ordering == this.ordering =>
33+
(ss canEqual this) &&
34+
(this.size == ss.size) && {
35+
val i1 = this.iterator
36+
val i2 = ss.iterator
37+
var allEqual = true
38+
while (allEqual && i1.hasNext)
39+
allEqual = ordering.equiv(i1.next(), i2.next())
40+
allEqual
41+
}
42+
case _ =>
43+
super.equals(that)
44+
}
45+
46+
}
47+
48+
trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
49+
extends SetOps[A, Set, C]
50+
with SortedOps[A, C] {
51+
52+
/** The companion object of this sorted set, providing various factory methods.
53+
*
54+
* @note When implementing a custom collection type and refining `CC` to the new type, this
55+
* method needs to be overridden to return a factory for the new type (the compiler will
56+
* issue an error otherwise).
57+
*/
58+
def sortedIterableFactory: SortedIterableFactory[CC]
59+
60+
def unsorted: Set[A]
61+
62+
/**
63+
* Creates an iterator that contains all values from this collection
64+
* greater than or equal to `start` according to the ordering of
65+
* this collection. x.iteratorFrom(y) is equivalent to but will usually
66+
* be more efficient than x.from(y).iterator
67+
*
68+
* @param start The lower-bound (inclusive) of the iterator
69+
*/
70+
def iteratorFrom(start: A): Iterator[A]
71+
72+
@deprecated("Use `iteratorFrom` instead.", "2.13.0")
73+
@`inline` def keysIteratorFrom(start: A): Iterator[A] = iteratorFrom(start)
74+
75+
def firstKey: A = head
76+
def lastKey: A = last
77+
78+
/** Find the smallest element larger than or equal to a given key.
79+
* @param key The given key.
80+
* @return `None` if there is no such node.
81+
*/
82+
def minAfter(key: A): Option[A] = rangeFrom(key).headOption
83+
84+
/** Find the largest element less than a given key.
85+
* @param key The given key.
86+
* @return `None` if there is no such node.
87+
*/
88+
def maxBefore(key: A): Option[A] = rangeUntil(key).lastOption
89+
90+
override def min[B >: A](implicit ord: Ordering[B]): A =
91+
if (isEmpty) throw new UnsupportedOperationException("empty.min")
92+
else if (ord == ordering) head
93+
else if (ord isReverseOf ordering) last
94+
else super.min[B] // need the type annotation for it to infer the correct implicit
95+
96+
override def max[B >: A](implicit ord: Ordering[B]): A =
97+
if (isEmpty) throw new UnsupportedOperationException("empty.max")
98+
else if (ord == ordering) last
99+
else if (ord isReverseOf ordering) head
100+
else super.max[B] // need the type annotation for it to infer the correct implicit
101+
102+
def rangeTo(to: A): C = {
103+
val i = rangeFrom(to).iterator
104+
if (i.isEmpty) return coll
105+
val next = i.next()
106+
if (ordering.compare(next, to) == 0)
107+
if (i.isEmpty) coll
108+
else rangeUntil(i.next())
109+
else
110+
rangeUntil(next)
111+
}
112+
113+
/** Builds a new sorted collection by applying a function to all elements of this $coll.
114+
*
115+
* @param f the function to apply to each element.
116+
* @tparam B the element type of the returned collection.
117+
* @return a new $coll resulting from applying the given function
118+
* `f` to each element of this $coll and collecting the results.
119+
*/
120+
def map[B](f: A => B)(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
121+
sortedIterableFactory.from(new View.Map(this, f))
122+
123+
/** Builds a new sorted collection by applying a function to all elements of this $coll
124+
* and using the elements of the resulting collections.
125+
*
126+
* @param f the function to apply to each element.
127+
* @tparam B the element type of the returned collection.
128+
* @return a new $coll resulting from applying the given collection-valued function
129+
* `f` to each element of this $coll and concatenating the results.
130+
*/
131+
def flatMap[B](f: A => IterableOnce[B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
132+
sortedIterableFactory.from(new View.FlatMap(this, f))
133+
134+
/** Returns a $coll formed from this $coll and another iterable collection
135+
* by combining corresponding elements in pairs.
136+
* If one of the two collections is longer than the other, its remaining elements are ignored.
137+
*
138+
* @param that The iterable providing the second half of each result pair
139+
* @tparam B the type of the second half of the returned pairs
140+
* @return a new $coll containing pairs consisting of corresponding elements of this $coll and `that`.
141+
* The length of the returned collection is the minimum of the lengths of this $coll and `that`.
142+
*/
143+
def zip[B](that: IterableOnce[B])(implicit @implicitNotFound(SortedSetOps.zipOrdMsg) ev: Ordering[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] = // sound bcs of VarianceNote
144+
sortedIterableFactory.from(that match {
145+
case that: Iterable[B] => new View.Zip(this, that)
146+
case _ => iterator.zip(that)
147+
})
148+
149+
/** Builds a new sorted collection by applying a partial function to all elements of this $coll
150+
* on which the function is defined.
151+
*
152+
* @param pf the partial function which filters and maps the $coll.
153+
* @tparam B the element type of the returned collection.
154+
* @return a new $coll resulting from applying the given partial function
155+
* `pf` to each element on which it is defined and collecting the results.
156+
* The order of the elements is preserved.
157+
*/
158+
def collect[B](pf: scala.PartialFunction[A, B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
159+
sortedIterableFactory.from(new View.Collect(this, pf))
160+
}
161+
162+
object SortedSetOps {
163+
private[collection] final val ordMsg = "No implicit Ordering[${B}] found to build a SortedSet[${B}]. You may want to upcast to a Set[${A}] first by calling `unsorted`."
164+
private[collection] final val zipOrdMsg = "No implicit Ordering[${B}] found to build a SortedSet[(${A}, ${B})]. You may want to upcast to a Set[${A}] first by calling `unsorted`."
165+
166+
/** Specialize `WithFilter` for sorted collections
167+
*
168+
* @define coll sorted collection
169+
*/
170+
class WithFilter[+A, +IterableCC[_], +CC[X] <: SortedSet[X]](
171+
self: SortedSetOps[A, CC, _] with IterableOps[A, IterableCC, _],
172+
p: A => Boolean
173+
) extends IterableOps.WithFilter[A, IterableCC](self, p) {
174+
175+
def map[B : Ordering](f: A => B): CC[B] =
176+
self.sortedIterableFactory.from(new View.Map(filtered, f))
177+
178+
def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] =
179+
self.sortedIterableFactory.from(new View.FlatMap(filtered, f))
180+
181+
override def withFilter(q: A => Boolean): WithFilter[A, IterableCC, CC] =
182+
new WithFilter[A, IterableCC, CC](self, (a: A) => p(a) && q(a))
183+
}
184+
185+
}
186+
187+
@SerialVersionUID(3L)
188+
object SortedSet extends SortedIterableFactory.Delegate[SortedSet](immutable.SortedSet)
189+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
/** Base trait for sorted sets */
18+
trait SortedSet[A]
19+
extends Set[A]
20+
with collection.SortedSet[A]
21+
with SortedSetOps[A, SortedSet, SortedSet[A]]
22+
with SortedSetFactoryDefaults[A, SortedSet, Set] {
23+
24+
override def unsorted: Set[A] = this
25+
26+
override def sortedIterableFactory: SortedIterableFactory[SortedSet] = SortedSet
27+
}
28+
29+
/**
30+
* @define coll immutable sorted set
31+
* @define Coll `immutable.SortedSet`
32+
*/
33+
trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
34+
extends SetOps[A, Set, C]
35+
with collection.SortedSetOps[A, CC, C] {
36+
37+
def unsorted: Set[A]
38+
}
39+
40+
trait StrictOptimizedSortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
41+
extends SortedSetOps[A, CC, C]
42+
with collection.StrictOptimizedSortedSetOps[A, CC, C]
43+
with StrictOptimizedSetOps[A, Set, C] {
44+
}
45+
46+
/**
47+
* $factoryInfo
48+
* @define coll immutable sorted set
49+
* @define Coll `immutable.SortedSet`
50+
*/
51+
@SerialVersionUID(3L)
52+
object SortedSet extends SortedIterableFactory.Delegate[SortedSet](TreeSet) {
53+
override def from[E: Ordering](it: IterableOnce[E]): SortedSet[E] = it match {
54+
case ss: SortedSet[E] if Ordering[E] == ss.ordering => ss
55+
case _ => super.from(it)
56+
}
57+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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 mutable
16+
17+
/**
18+
* Base type for mutable sorted set collections
19+
*/
20+
trait SortedSet[A]
21+
extends Set[A]
22+
with collection.SortedSet[A]
23+
with SortedSetOps[A, SortedSet, SortedSet[A]]
24+
with SortedSetFactoryDefaults[A, SortedSet, Set] {
25+
26+
override def unsorted: Set[A] = this
27+
28+
override def sortedIterableFactory: SortedIterableFactory[SortedSet] = SortedSet
29+
}
30+
31+
/**
32+
* @define coll mutable sorted set
33+
* @define Coll `mutable.Sortedset`
34+
*/
35+
trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
36+
extends SetOps[A, Set, C]
37+
with collection.SortedSetOps[A, CC, C] {
38+
39+
def unsorted: Set[A]
40+
}
41+
42+
/**
43+
* $factoryInfo
44+
* @define coll mutable sorted set
45+
* @define Coll `mutable.Sortedset`
46+
*/
47+
@SerialVersionUID(3L)
48+
object SortedSet extends SortedIterableFactory.Delegate[SortedSet](TreeSet)

0 commit comments

Comments
 (0)