Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Commit e4bb517

Browse files
committed
Add unsafeHead and unsafeTail for optimizations
1 parent 094f5bf commit e4bb517

File tree

2 files changed

+21
-19
lines changed

2 files changed

+21
-19
lines changed

src/main/scala/strawman/collection/Seq.scala

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,7 @@ trait LinearSeq[+A] extends Seq[A] with LinearSeqLike[A, LinearSeq] { self =>
2323
def iterator() = new Iterator[A] {
2424
private[this] var current: LinearSeq[A] = self
2525
def hasNext = !current.isEmpty
26-
def next() = {
27-
val Some((head, tail)) = current.uncons
28-
current = tail
29-
head
30-
}
26+
def next() = { val r = current.unsafeHead; current = current.unsafeTail; r }
3127
}
3228

3329
/** `length` is defined in terms of `iterator` */
@@ -39,7 +35,8 @@ trait LinearSeq[+A] extends Seq[A] with LinearSeqLike[A, LinearSeq] { self =>
3935
override def apply(n: Int): A = {
4036
if (n < 0) throw new IndexOutOfBoundsException(n.toString)
4137
val skipped = drop(n)
42-
skipped.uncons.fold(throw new IndexOutOfBoundsException(n.toString))(_._1)
38+
if (skipped.isEmpty) throw new IndexOutOfBoundsException(n.toString)
39+
skipped.unsafeHead
4340
}
4441
}
4542

@@ -81,6 +78,10 @@ trait LinearSeqLike[+A, +C[+X] <: LinearSeq[X]] extends SeqLike[A, C] {
8178
/** Extract the head and tail, if the collection is not empty */
8279
def uncons: Option[(A, C[A])]
8380

81+
/** To be overriden for performance in subclasses */
82+
protected def unsafeHead: A = uncons.get._1
83+
protected def unsafeTail: C[A] = uncons.get._2
84+
8485
/** Optimized version of `drop` that avoids copying
8586
* Note: `drop` is defined here, rather than in a trait like `LinearSeqMonoTransforms`,
8687
* because the `...MonoTransforms` traits make no assumption about the type of `Repr`
@@ -89,17 +90,13 @@ trait LinearSeqLike[+A, +C[+X] <: LinearSeq[X]] extends SeqLike[A, C] {
8990
*/
9091
override def drop(n: Int): C[A] = {
9192
def loop(n: Int, s: C[A]): C[A] = {
93+
if (n <= 0) s
9294
// implicit contract to guarantee success of asInstanceOf:
9395
// (1) coll is of type C[A]
9496
// (2) The tail of a LinearSeq is of the same type as the type of the sequence itself
9597
// it's surprisingly tricky/ugly to turn this into actual types, so we
9698
// leave this contract implicit.
97-
if (n <= 0) s else {
98-
s.uncons match {
99-
case None => s
100-
case Some((_, t)) => loop(n - 1, t.asInstanceOf[C[A]])
101-
}
102-
}
99+
else loop(n - 1, s.unsafeTail.asInstanceOf[C[A]])
103100
}
104101
loop(n, coll)
105102
}

src/main/scala/strawman/collection/immutable/List.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
package strawman.collection.immutable
22

33
import scala.annotation.unchecked.uncheckedVariance
4-
import scala.{Option, None, Nothing, Some}
4+
import scala.{Option, None, NoSuchElementException, Nothing, Some, UnsupportedOperationException}
55
import scala.Predef.???
6-
import strawman.collection.{InhabitedLinearSeqFactory, InhabitedLinearSeqOps, InhabitedSeq, Iterable, IterableFactory, IterableOnce, LinearSeq, SeqLike, View}
6+
import strawman.collection.{InhabitedLinearSeqFactory, InhabitedLinearSeqOps, InhabitedSeq, Iterable, IterableFactory, IterableOnce, LinearSeq, LinearSeqLike, View}
77
import strawman.collection.mutable.{Buildable, ListBuffer}
88

99

1010
/** Concrete collection type: List */
1111
sealed trait List[+A]
1212
extends LinearSeq[A]
13-
with SeqLike[A, List]
13+
with LinearSeqLike[A, List]
1414
with Buildable[A, List[A]] {
1515

1616
def fromIterable[B](c: Iterable[B]): List[B] = List.fromIterable(c)
@@ -22,10 +22,8 @@ sealed trait List[+A]
2222

2323
/** Prepend operation that avoids copying this list */
2424
def ++:[B >: A](prefix: List[B]): List[B] =
25-
prefix match {
26-
case Nil => this
27-
case h :: t => h :: (t ++: this)
28-
}
25+
if (prefix.isEmpty) this
26+
else (prefix.unsafeHead :: prefix.unsafeTail) ++: this
2927

3028
/** When concatenating with another list `xs`, avoid copying `xs` */
3129
override def ++[B >: A](xs: IterableOnce[B]): List[B] = xs match {
@@ -40,15 +38,22 @@ case class :: [+A](x: A, private[collection] var next: List[A @uncheckedVariance
4038
extends List[A]
4139
with InhabitedSeq[A]
4240
with InhabitedLinearSeqOps[A, List[A]] {
41+
4342
override def isEmpty = false
4443
def head = x
4544
def tail = next
45+
4646
def uncons: Option[(A, List[A])] = Some((x, next))
47+
override protected def unsafeHead: A = x
48+
override protected def unsafeTail: List[A] = next
4749
}
4850

4951
case object Nil extends List[Nothing] {
5052
override def isEmpty = true
53+
5154
def uncons = None
55+
override protected def unsafeHead: Nothing = throw new NoSuchElementException
56+
override protected def unsafeTail: Nothing = throw new UnsupportedOperationException
5257
}
5358

5459
object List extends IterableFactory[List] with InhabitedLinearSeqFactory[::] {

0 commit comments

Comments
 (0)