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

Commit

Permalink
Add unsafeHead and unsafeTail for optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
julienrf committed Jan 4, 2017
1 parent 094f5bf commit e4bb517
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 19 deletions.
21 changes: 9 additions & 12 deletions src/main/scala/strawman/collection/Seq.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,7 @@ trait LinearSeq[+A] extends Seq[A] with LinearSeqLike[A, LinearSeq] { self =>
def iterator() = new Iterator[A] {
private[this] var current: LinearSeq[A] = self
def hasNext = !current.isEmpty
def next() = {
val Some((head, tail)) = current.uncons
current = tail
head
}
def next() = { val r = current.unsafeHead; current = current.unsafeTail; r }
}

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

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

/** To be overriden for performance in subclasses */
protected def unsafeHead: A = uncons.get._1
protected def unsafeTail: C[A] = uncons.get._2

/** Optimized version of `drop` that avoids copying
* Note: `drop` is defined here, rather than in a trait like `LinearSeqMonoTransforms`,
* because the `...MonoTransforms` traits make no assumption about the type of `Repr`
Expand All @@ -89,17 +90,13 @@ trait LinearSeqLike[+A, +C[+X] <: LinearSeq[X]] extends SeqLike[A, C] {
*/
override def drop(n: Int): C[A] = {
def loop(n: Int, s: C[A]): C[A] = {
if (n <= 0) s
// implicit contract to guarantee success of asInstanceOf:
// (1) coll is of type C[A]
// (2) The tail of a LinearSeq is of the same type as the type of the sequence itself
// it's surprisingly tricky/ugly to turn this into actual types, so we
// leave this contract implicit.
if (n <= 0) s else {
s.uncons match {
case None => s
case Some((_, t)) => loop(n - 1, t.asInstanceOf[C[A]])
}
}
else loop(n - 1, s.unsafeTail.asInstanceOf[C[A]])
}
loop(n, coll)
}
Expand Down
19 changes: 12 additions & 7 deletions src/main/scala/strawman/collection/immutable/List.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package strawman.collection.immutable

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


/** Concrete collection type: List */
sealed trait List[+A]
extends LinearSeq[A]
with SeqLike[A, List]
with LinearSeqLike[A, List]
with Buildable[A, List[A]] {

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

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

/** When concatenating with another list `xs`, avoid copying `xs` */
override def ++[B >: A](xs: IterableOnce[B]): List[B] = xs match {
Expand All @@ -40,15 +38,22 @@ case class :: [+A](x: A, private[collection] var next: List[A @uncheckedVariance
extends List[A]
with InhabitedSeq[A]
with InhabitedLinearSeqOps[A, List[A]] {

override def isEmpty = false
def head = x
def tail = next

def uncons: Option[(A, List[A])] = Some((x, next))
override protected def unsafeHead: A = x
override protected def unsafeTail: List[A] = next
}

case object Nil extends List[Nothing] {
override def isEmpty = true

def uncons = None
override protected def unsafeHead: Nothing = throw new NoSuchElementException
override protected def unsafeTail: Nothing = throw new UnsupportedOperationException
}

object List extends IterableFactory[List] with InhabitedLinearSeqFactory[::] {
Expand Down

0 comments on commit e4bb517

Please sign in to comment.