Skip to content

Commit d645559

Browse files
authored
Merge pull request scala#7733 from NthPortal/topic/SeqView-sorted/PR
Override SeqView#sorted
2 parents 0c4859c + d448c69 commit d645559

File tree

2 files changed

+81
-11
lines changed

2 files changed

+81
-11
lines changed

src/library/scala/collection/Seq.scala

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -694,18 +694,14 @@ trait SeqOps[+A, +CC[_], +C] extends Any
694694
def sorted[B >: A](implicit ord: Ordering[B]): C = {
695695
val len = this.length
696696
val b = newSpecificBuilder
697-
if (len == 1) b ++= toIterable
697+
if (len == 1) b += head
698698
else if (len > 1) {
699699
b.sizeHint(len)
700-
val arr = new Array[AnyRef](len) // Previously used ArraySeq for more compact but slower code
700+
val arr = new Array[Any](len)
701+
copyToArray(arr)
702+
java.util.Arrays.sort(arr.asInstanceOf[Array[AnyRef]], ord.asInstanceOf[Ordering[AnyRef]])
701703
var i = 0
702-
for (x <- this) {
703-
arr(i) = x.asInstanceOf[AnyRef]
704-
i += 1
705-
}
706-
java.util.Arrays.sort(arr, ord.asInstanceOf[Ordering[Object]])
707-
i = 0
708-
while (i < arr.length) {
704+
while (i < len) {
709705
b += arr(i).asInstanceOf[A]
710706
i += 1
711707
}

src/library/scala/collection/SeqView.scala

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,18 @@ trait SeqView[+A] extends SeqOps[A, View, View[A]] with View[A] {
3030
def concat[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(this, suffix)
3131
def appendedAll[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(this, suffix)
3232
def prependedAll[B >: A](prefix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(prefix, this)
33+
34+
override def sorted[B >: A](implicit ord: Ordering[B]): SeqView[A] = new SeqView.Sorted(this, ord)
3335
}
3436

3537
object SeqView {
3638

3739
/** A `SeqOps` whose collection type and collection type constructor are unknown */
38-
type SomeSeqOps[+A] = SeqOps[A, AnyConstr, _]
40+
private type SomeSeqOps[+A] = SeqOps[A, AnyConstr, _]
3941

4042
/** A view that doesn’t apply any transformation to an underlying sequence */
4143
@SerialVersionUID(3L)
42-
class Id[+A](underlying: SeqOps[A, AnyConstr, _]) extends AbstractSeqView[A] {
44+
class Id[+A](underlying: SomeSeqOps[A]) extends AbstractSeqView[A] {
4345
def apply(idx: Int): A = underlying.apply(idx)
4446
def length: Int = underlying.length
4547
def iterator: Iterator[A] = underlying.iterator
@@ -115,6 +117,78 @@ object SeqView {
115117
@throws[IndexOutOfBoundsException]
116118
def apply(i: Int) = underlying.apply(i)
117119
}
120+
121+
@SerialVersionUID(3L)
122+
class Sorted[A, B >: A](private[this] var underlying: SomeSeqOps[A], ord: Ordering[B]) extends SeqView[A] {
123+
outer =>
124+
125+
@SerialVersionUID(3L)
126+
private[this] class ReverseSorted extends SeqView[A] {
127+
private[this] lazy val _reversed = new SeqView.Reverse(_sorted)
128+
129+
def apply(i: Int): A = _reversed.apply(i)
130+
def length: Int = elems.length
131+
def iterator: Iterator[A] = Iterator.empty ++ _reversed.iterator // very lazy
132+
override def knownSize: Int = elems.knownSize
133+
override def isEmpty: Boolean = elems.isEmpty
134+
override def to[C1](factory: Factory[A, C1]): C1 = _reversed.to(factory)
135+
override def reverse: SeqView[A] = outer
136+
override protected def reversed: Iterable[A] = outer
137+
138+
override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A] =
139+
if (ord1 == Sorted.this.ord) outer
140+
else if (ord1.isReverseOf(Sorted.this.ord)) this
141+
else new Sorted(elems, ord1)
142+
}
143+
144+
@volatile private[this] var evaluated = false
145+
146+
private[this] lazy val _sorted: Seq[A] = {
147+
val res = {
148+
val len = underlying.length
149+
if (len == 0) Nil
150+
else if (len == 1) List(underlying.head)
151+
else {
152+
val arr = new Array[Any](len) // Array[Any] =:= Array[AnyRef]
153+
underlying.copyToArray(arr)
154+
java.util.Arrays.sort(arr.asInstanceOf[Array[AnyRef]], ord.asInstanceOf[Ordering[AnyRef]])
155+
// casting the Array[AnyRef] to Array[A] and creating an ArraySeq from it
156+
// is safe because:
157+
// - the ArraySeq is immutable, and items that are not of type A
158+
// cannot be added to it
159+
// - we know it only contains items of type A (and if this collection
160+
// contains items of another type, we'd get a CCE anyway)
161+
// - the cast doesn't actually do anything in the runtime because the
162+
// type of A is not known and Array[_] is Array[AnyRef]
163+
immutable.ArraySeq.unsafeWrapArray(arr.asInstanceOf[Array[A]])
164+
}
165+
}
166+
evaluated = true
167+
underlying = null
168+
res
169+
}
170+
171+
private[this] def elems: SomeSeqOps[A] = {
172+
val orig = underlying
173+
if (evaluated) _sorted else orig
174+
}
175+
176+
def apply(i: Int): A = _sorted.apply(i)
177+
def length: Int = elems.length
178+
def iterator: Iterator[A] = Iterator.empty ++ _sorted.iterator // very lazy
179+
override def knownSize: Int = elems.knownSize
180+
override def isEmpty: Boolean = elems.isEmpty
181+
override def to[C1](factory: Factory[A, C1]): C1 = _sorted.to(factory)
182+
override def reverse: SeqView[A] = new ReverseSorted
183+
// we know `_sorted` is either tiny or has efficient random access,
184+
// so this is acceptable for `reversed`
185+
override protected def reversed: Iterable[A] = new ReverseSorted
186+
187+
override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A] =
188+
if (ord1 == this.ord) this
189+
else if (ord1.isReverseOf(this.ord)) reverse
190+
else new Sorted(elems, ord1)
191+
}
118192
}
119193

120194
/** Explicit instantiation of the `SeqView` trait to reduce class file size in subclasses. */

0 commit comments

Comments
 (0)